1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #pragma once
21 
22 #include <drawinglayer/drawinglayerdllapi.h>
23 
24 #include <cppuhelper/compbase.hxx>
25 #include <drawinglayer/primitive2d/Primitive2DContainer.hxx>
26 #include <com/sun/star/util/XAccounting.hpp>
27 #include <cppuhelper/basemutex.hxx>
28 #include <basegfx/range/b2drange.hxx>
29 
30 /** defines ImplPrimitive2DIDBlock
31     Added to be able to simply change identification stuff later, e.g. add
32     an identification string and/or ID to the interface and to the implementation
33     ATM used to delclare implement getPrimitive2DID()
34 */
35 
36 #define ImplPrimitive2DIDBlock(TheClass, TheID)                                                    \
37     sal_uInt32 TheClass::getPrimitive2DID() const { return TheID; }
38 
39 namespace drawinglayer::geometry
40 {
41 class ViewInformation2D;
42 }
43 
44 namespace drawinglayer::primitive2d
45 {
46 typedef cppu::WeakComponentImplHelper<css::graphic::XPrimitive2D, css::util::XAccounting>
47     BasePrimitive2DImplBase;
48 
49 /** BasePrimitive2D class
50 
51     Baseclass for all C++ implementations of css::graphic::XPrimitive2D
52 
53     This class is strongly virtual due to the lack of getPrimitiveID() implementation.
54     This is by purpose, this base class shall not be incarnated and be used directly as
55     a XPrimitive2D.
56 
57     It is noncopyable to make clear that a primitive is a read-only
58     instance and copying or changing values is not intended. The idea is to hold all data
59     needed for visualisation of this primitive in unchangeable form.
60 
61     It is derived from cppu::BaseMutex to have a Mutex at hand; in a base
62     implementation this may not be needed, but e.g. when buffering at last decomposition
63     in a local member, multiple threads may try to decompose at the same time, so locking
64     is needed to avoid race conditions seen from the UNO object implementation.
65 
66     A method to get a simplified representation is provided by get2DDecomposition. The
67     default implementation returns an empty sequence. The idea is that processors
68     using this primitive and do not know it, may get the decomposition and process
69     these instead. An example is e.g. a fat line, who's decomposition may contain
70     the geometric representation of that line using filled polygon primitives. When
71     the renderer knows how to handle fat lines, he may process this primitive directly;
72     if not he can use the decomposition. With this functionality, renderers may operate by
73     knowing only a small set of primitives.
74 
75     When a primitive does not implement get2DDecomposition, it is called a 'Basic Primitive' and
76     belongs to the set of primitives which a processor should be able to handle. Practice
77     will define this minimal sets of primitives. When defined and the concept is proved,
78     unique UNO APIs may be defined/implemented for these set to allow more intense work
79     with primitives using UNO.
80 
81     Current Basic 2D Primitives are:
82 
83     - BitmapPrimitive2D (bitmap data, evtl. with transparence)
84     - PointArrayPrimitive2D (single points)
85     - PolygonHairlinePrimitive2D (hairline curves/polygons)
86     - PolyPolygonColorPrimitive2D (colored polygons)
87 
88     UPDATE: MetafilePrimitive2D (VCL Metafile) is taken off this list since
89     it is implemented with the integration of CWS aw078 into DV300m69.
90 
91     All other implemented primitives have a defined decomposition and can thus be
92     decomposed down to this small set.
93 
94     A renderer implementing support for this minimal set of primitives can completely
95     render primitive-based visualisations. Of course, he also has to take states into account
96     which are represented by GroupPrimitive2D derivations, see groupprimitive2d.hxx
97 
98     To support getting the geometric BoundRect, getB2DRange is used. The default
99     implementation will use the get2DDecomposition result and merge a range from the
100     entries. Thus, an implementation is only necessary for the Basic Primitives, but
101     of course speedups are possible (and are used) by implementing the method at higher-level
102     primitives.
103 
104     For primitive identification, getPrimitiveID is used currently in this implementations
105     to allow a fast switch/case processing. This needs a unique identifier mechanism which
106     currently uses defines (see drawinglayer_primitivetypes2d.hxx). For UNO primitive API
107     it will be needed to add a unique descriptor (Name?) later to the API.
108 
109     This base implementation provides mappings from the methods from XPrimitive2D
110     (getDecomposition/getRange) to the appropriate methods in the C++ implementations
111     (get2DDecomposition/getB2DRange). The PropertyValue ViewParameters is converted to
112     the appropriate C++ implementation class ViewInformation2D.
113 
114     This base class does not implement any buffering; e.g. buffering the decomposition
115     and/or the range. These may be buffered anytime since the definition is that the primitive
116     is read-only and thus unchangeable. This implies that the decomposition and/or getting
117     the range will lead to the same result as last time, under the precondition that
118     the parameter ViewInformation2D is the same as the last one. This is usually the case
119     for view-independent primitives which are defined by not using ViewInformation2D
120     in their get2DDecomposition/getB2DRange implementations.
121 */
122 class DRAWINGLAYER_DLLPUBLIC BasePrimitive2D : protected cppu::BaseMutex,
123                                                public BasePrimitive2DImplBase
124 {
125     BasePrimitive2D(const BasePrimitive2D&) = delete;
126     BasePrimitive2D& operator=(const BasePrimitive2D&) = delete;
127 
128 public:
129     // constructor/destructor
130     BasePrimitive2D();
131     virtual ~BasePrimitive2D() override;
132 
133     /** the ==operator is mainly needed to allow testing newly-created primitives against their last
134         incarnation which buffers/holds the made decompositions. The default implementation
135         uses getPrimitive2DID()-calls to test if it's the same ID at last.
136         Overridden implementations are then based on this implementation
137      */
138     virtual bool operator==(const BasePrimitive2D& rPrimitive) const;
operator !=(const BasePrimitive2D & rPrimitive) const139     bool operator!=(const BasePrimitive2D& rPrimitive) const { return !operator==(rPrimitive); }
140 
141     /// The default implementation will use getDecomposition results to create the range
142     virtual basegfx::B2DRange
143     getB2DRange(const geometry::ViewInformation2D& rViewInformation) const;
144 
145     /** provide unique ID for fast identifying of known primitive implementations in renderers. These use
146         the defines from drawinglayer_primitivetypes2d.hxx to define unique IDs.
147      */
148     virtual sal_uInt32 getPrimitive2DID() const = 0;
149 
150     /// The default implementation will return an empty sequence
151     virtual void get2DDecomposition(Primitive2DDecompositionVisitor& rVisitor,
152                                     const geometry::ViewInformation2D& rViewInformation) const;
153 
154     // Methods from XPrimitive2D
155 
156     /** The getDecomposition implementation for UNO API will use getDecomposition from this implementation. It
157         will construct a ViewInformation2D from the ViewParameters for that purpose
158      */
159     virtual css::uno::Sequence<::css::uno::Reference<::css::graphic::XPrimitive2D>> SAL_CALL
160     getDecomposition(const css::uno::Sequence<css::beans::PropertyValue>& rViewParameters) override;
161 
162     /** The getRange implementation for UNO API will use getRange from this implementation. It
163         will construct a ViewInformation2D from the ViewParameters for that purpose
164      */
165     virtual css::geometry::RealRectangle2D SAL_CALL
166     getRange(const css::uno::Sequence<css::beans::PropertyValue>& rViewParameters) override;
167 
168     // XAccounting
169     virtual sal_Int64 SAL_CALL estimateUsage() override;
170 };
171 
172 /** BufferedDecompositionPrimitive2D class
173 
174     Baseclass for all C++ implementations of css::graphic::XPrimitive2D
175     which want to buffer the decomposition result
176 
177     Buffering the decomposition is the most-used buffering and is thus used my most
178     primitive implementations which support a decomposition as base class.
179 
180     The buffering is done by holding the last decomposition in the local parameter
181     maBuffered2DDecomposition. The default implementation of get2DDecomposition checks
182     if maBuffered2DDecomposition is empty. If yes, it uses create2DDecomposition
183     to create the content. In all cases, maBuffered2DDecomposition is returned.
184 
185     For view-dependent primitives derived from Primitive2DBufferDecomposition more needs
186     to be done when the decomposition depends on parts of the parameter ViewInformation2D.
187     This defines a standard method for processing these:
188 
189     Implement a view-dependent get2DDecomposition doing the following steps:
190     (a) Locally extract needed parameters from ViewInformation2D to new, local parameters
191         (this may be a complete local copy of ViewInformation2D)
192     (b) If a buffered decomposition exists, ckeck if one of the new local parameters
193         differs from the corresponding locally remembered (as member) ones. If yes,
194         clear maBuffered2DDecomposition
195     (d) call baseclass::get2DDecomposition which will use create2DDecomposition
196         to fill maBuffered2DDecomposition if it's empty
197     (e) copy the new local parameters to the corresponding locally remembered ones
198         to identify if a new decomposition is needed at the next call
199     (f) return maBuffered2DDecomposition
200  */
201 class DRAWINGLAYER_DLLPUBLIC BufferedDecompositionPrimitive2D : public BasePrimitive2D
202 {
203 private:
204     /// a sequence used for buffering the last create2DDecomposition() result
205     Primitive2DContainer maBuffered2DDecomposition;
206 
207     /// When a shadow wraps a list of primitives, this primitive wants to influence the transparency
208     /// of the shadow.
209     sal_uInt16 mnTransparenceForShadow = 0;
210 
211 protected:
212     /** access methods to maBuffered2DDecomposition. The usage of this methods may allow
213         later thread-safe stuff to be added if needed. Only to be used by getDecomposition()
214         implementations for buffering the last decomposition.
215      */
getBuffered2DDecomposition() const216     const Primitive2DContainer& getBuffered2DDecomposition() const
217     {
218         return maBuffered2DDecomposition;
219     }
setBuffered2DDecomposition(const Primitive2DContainer & rNew)220     void setBuffered2DDecomposition(const Primitive2DContainer& rNew)
221     {
222         maBuffered2DDecomposition = rNew;
223     }
224 
225     /** method which is to be used to implement the local decomposition of a 2D primitive. */
226     virtual void
227     create2DDecomposition(Primitive2DContainer& rContainer,
228                           const geometry::ViewInformation2D& rViewInformation) const = 0;
229 
230 public:
231     // constructor/destructor
232     BufferedDecompositionPrimitive2D();
233 
234     /** The getDecomposition default implementation will on demand use create2DDecomposition() if
235         maBuffered2DDecomposition is empty. It will set maBuffered2DDecomposition to this obtained decomposition
236         to buffer it. If the decomposition is also ViewInformation2D-dependent, this method needs to be
237         overridden and the ViewInformation2D for the last decomposition need to be remembered, too, and
238         be used in the next call to decide if the buffered decomposition may be reused or not.
239      */
240     virtual void
241     get2DDecomposition(Primitive2DDecompositionVisitor& rVisitor,
242                        const geometry::ViewInformation2D& rViewInformation) const override;
243 
setTransparenceForShadow(sal_uInt16 nTransparenceForShadow)244     void setTransparenceForShadow(sal_uInt16 nTransparenceForShadow)
245     {
246         mnTransparenceForShadow = nTransparenceForShadow;
247     }
248 
getTransparenceForShadow() const249     sal_uInt16 getTransparenceForShadow() const { return mnTransparenceForShadow; }
250 };
251 
252 } // end of namespace drawinglayer::primitive2d
253 
254 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
255