summaryrefslogtreecommitdiff
path: root/drawinglayer/inc/drawinglayer/processor2d/baseprocessor2d.hxx
blob: d93fb68c932c3ff1e65d35efd8cb9f8bc7da109c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#ifndef INCLUDED_DRAWINGLAYER_PROCESSOR2D_BASEPROCESSOR2D_HXX
#define INCLUDED_DRAWINGLAYER_PROCESSOR2D_BASEPROCESSOR2D_HXX

#include <drawinglayer/primitive2d/baseprimitive2d.hxx>
#include <drawinglayer/geometry/viewinformation2d.hxx>

//////////////////////////////////////////////////////////////////////////////

namespace drawinglayer
{
    namespace processor2d
    {
        /** BaseProcessor2D class

            Baseclass for all C++ implementations of instances which process
            primitives.

            Instances which process primitives can be renderers, but also stuff
            for HitTests, BoundRect calculations and/or animation processing. The
            main usage are renderers, but they are supposed to handle any primitive
            processing.

            The base implementation is constructed with a ViewInformation2D which
            is accessible throughout the processor implementations. The idea is
            to construct any processor with a given ViewInformation2D. To be able
            to handle primitives which need to change the current transformation
            (as e.g. TransformPrimitive2D) it is allowed for the processor implementation
            to change tis local value using updateViewInformation.

            The basic processing method is process(..) which gets handed over the
            sequence of primitives to process. For convenience of the C++ implementations,
            the default implementation of process(..) maps all accesses to primitives to
            single calls to processBasePrimitive2D(..) where the primitive in question is
            already casted to the C++ implementation class.

            The process(..) implementation makes a complete iteration over the given
            sequence of primitives. If the Primitive is not derived from BasePrimitive2D
            and thus not part of the C++ implementations, it converts ViewInformation2D
            to the corresponding API implementation (an uno::Sequence< beans::PropertyValue >)
            and recursively calls the method process(..) at the primitive with the decomposition
            derived from that primitive. This is the preparation to handle unknown implementations
            of the com::sun::star::graphic::XPrimitive2D interface in the future.

            So, to implement a basic processor, it is necessary to overload and implement the
            processBasePrimitive2D(..) method. A minimal renderer has to support the
            Basic Primitives (see baseprimitive2d.hxx) and the Grouping Primitives (see
            groupprimitive2d.hxx). These are (currently):

            Basic Primitives:

            - BitmapPrimitive2D (bitmap data, evtl. with transparence)
            - PointArrayPrimitive2D (single points)
            - PolygonHairlinePrimitive2D (hairline curves/polygons)
            - PolyPolygonColorPrimitive2D (colored polygons)

            Grouping Primitives:

            - TransparencePrimitive2D (objects with freely defined transparence)
            - InvertPrimitive2D (for XOR)
            - MaskPrimitive2D (for masking)
            - ModifiedColorPrimitive2D (for a stack of color modifications)
            - TransformPrimitive2D (for a transformation stack)

            A processor doing so is a minimal processor. Of course a processor may
            handle any higher-level prmitive (that has a decomposition implementation)
            for more direct data access or performance reasons, too.

            The main part of a processBasePrimitive2D implementation is a switch..case
            construct, looking like the following:

            void foo::processBasePrimitive2D(const BasePrimitive2D& rCandidate)
            {
                switch(rCandidate.getPrimitive2DID())
                {
                    case PRIMITIVE2D_ID_??? :
                    {
                        // process PRIMITIVE2D_ID_??? here...

                        ...

                        break;
                    }

                    ...

                    default :
                    {
                        // process recursively
                        process(rCandidate.get2DDecomposition(getViewInformation2D()));
                        break;
                    }
                }
            }

            The default case makes the processor work with all complex primitives
            by recursively using their decomposition.

            You can also add a case for ignoring primitives by using:

                    case PRIMITIVE2D_ID_...IGNORE.A.. :
                    case PRIMITIVE2D_ID_...IGNORE.B.. :
                    case PRIMITIVE2D_ID_...IGNORE.C.. :
                    {
                        // ignore these primitives by neither processing nor
                        // recursively processing their decomposition
                        break;
                    }

            Another useful case is embedding the processing of a complex primitive by
            bracketing it with some actions:

                    case PRIMITIVE2D_ID_SOME_TEXT :
                    {
                        // encapsulate e.g. with changing local varibles, e.g.
                        // sometimes it's good to know if a basic primitive is
                        // part of a text, especially when not handling the text
                        // self but by purpose want to handle the decomposed
                        // geometries in the processor
                        startText();
                        process(rCandidate.get2DDecomposition(getViewInformation2D()));
                        endText();
                        break;
                    }

            As an example a processor collecting the outlines of a sequence of primitives
            only needs to handle some Basic Primitives and create outline and collect
            outline polygons e.g. for primitives with area like BitmapPrimitive2D (a
            rectangle) and PolyPolygonColorPrimitive2D. When also handling the Grouping
            Primitives MaskPrimitive2D (e.g. ignoring it's content, using the mask polyPolygon)
            and TransformPrimitive2D (to have the correct local transformation), a processor
            creating the outline can be written using just four (4) primitives. As a tipp, it can
            be helpful to add many for the purpose not interesting higher level primitives
            to not force their decomposition to be created and/or parsed.
         */
        class BaseProcessor2D
        {
        private:
            /// The ViewInformation2D itself. It's private to isolate accesses to it
            geometry::ViewInformation2D                     maViewInformation2D;

        protected:
            /*  access method to allow the implementations to change the current
                ViewInformation2D if needed. This allows isolating these accesses
                later if needed
             */
            void updateViewInformation(const geometry::ViewInformation2D& rViewInformation2D)
            {
                maViewInformation2D = rViewInformation2D;
            }

            /*  as tooling, the process() implementation takes over API handling and calls this
                virtual render method when the primitive implementation is BasePrimitive2D-based.
                Default implementation does nothing
             */
            virtual void processBasePrimitive2D(const primitive2d::BasePrimitive2D& rCandidate);

        public:
            /// constructor/destructor
            BaseProcessor2D(const geometry::ViewInformation2D& rViewInformation);
            virtual ~BaseProcessor2D();

            /// the central processing method
            virtual void process(const primitive2d::Primitive2DSequence& rSource);

            /// data read access
            const geometry::ViewInformation2D& getViewInformation2D() const { return maViewInformation2D; }
        };
    } // end of namespace processor2d
} // end of namespace drawinglayer

//////////////////////////////////////////////////////////////////////////////

namespace drawinglayer
{
    namespace processor2d
    {
        /** CollectingProcessor2D class

            A processor which just collects all primitives given to it in
            process(..) calls to maPrimitive2DSequence. This can e.g. be used to
            hand around as instance over various methods where every called
            method can add graphic content to it.
         */
        class CollectingProcessor2D : public BaseProcessor2D
        {
        private:
            primitive2d::Primitive2DSequence                        maPrimitive2DSequence;

        public:
            CollectingProcessor2D(const geometry::ViewInformation2D& rViewInformation);
            virtual ~CollectingProcessor2D();

            /// the central processing method
            virtual void process(const primitive2d::Primitive2DSequence& rSource);

            /// helpers for adding to local sequence
            void appendPrimitive2DReference(const primitive2d::Primitive2DReference& rSource)
            {
                primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(maPrimitive2DSequence, rSource);
            }

            /// data access and reset
            const primitive2d::Primitive2DSequence& getPrimitive2DSequence() const { return maPrimitive2DSequence; }
            void reset() { maPrimitive2DSequence = primitive2d::Primitive2DSequence(); }
        };
    } // end of namespace processor2d
} // end of namespace drawinglayer

//////////////////////////////////////////////////////////////////////////////

#endif //INCLUDED_DRAWINGLAYER_PROCESSOR2D_BASEPROCESSOR2D_HXX

// eof