1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 // MARKER(update_precomp.py): autogen include statement, do not remove
23 #include "precompiled_drawinglayer.hxx"
24 
25 #include <drawinglayer/primitive2d/graphicprimitive2d.hxx>
26 #include <drawinglayer/primitive2d/cropprimitive2d.hxx>
27 #include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
28 #include <drawinglayer/primitive2d/maskprimitive2d.hxx>
29 #include <drawinglayer/primitive2d/graphicprimitivehelper2d.hxx>
30 #include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx>
31 #include <drawinglayer/primitive2d/modifiedcolorprimitive2d.hxx>
32 #include <basegfx/matrix/b2dhommatrixtools.hxx>
33 #include <vcl/svapp.hxx>
34 #include <vcl/outdev.hxx>
35 
36 //////////////////////////////////////////////////////////////////////////////
37 
38 namespace drawinglayer
39 {
40     namespace primitive2d
41     {
42         Primitive2DSequence GraphicPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D&
43 #ifdef USE_DEBUG_CODE_TO_TEST_METAFILE_DECOMPOSE
44             rViewInformation
45 #else
46             /*rViewInformation*/
47 #endif // USE_DEBUG_CODE_TO_TEST_METAFILE_DECOMPOSE
48             ) const
49         {
50             Primitive2DSequence aRetval;
51 
52             if(255L == getGraphicAttr().GetTransparency())
53             {
54                 // content is invisible, done
55                 return aRetval;
56             }
57 
58             // do not apply mirroring from GraphicAttr to the Metafile by calling
59             // GetTransformedGraphic, this will try to mirror the Metafile using Scale()
60             // at the Metafile. This again calls Scale at the single MetaFile actions,
61             // but this implementation never worked. I reworked that implementations,
62             // but for security reasons i will try not to use it.
63             basegfx::B2DHomMatrix aTransform(getTransform());
64 
65             if(getGraphicAttr().IsMirrored())
66             {
67                 // content needs mirroring
68                 const bool bHMirr(getGraphicAttr().GetMirrorFlags() & BMP_MIRROR_HORZ);
69                 const bool bVMirr(getGraphicAttr().GetMirrorFlags() & BMP_MIRROR_VERT);
70 
71                 // mirror by applying negative scale to the unit primitive and
72                 // applying the object transformation on it.
73                 aTransform = basegfx::tools::createScaleB2DHomMatrix(
74                     bHMirr ? -1.0 : 1.0,
75                     bVMirr ? -1.0 : 1.0);
76                 aTransform.translate(
77                     bHMirr ? 1.0 : 0.0,
78                     bVMirr ? 1.0 : 0.0);
79                 aTransform = getTransform() * aTransform;
80             }
81 
82             // Get transformed graphic. Suppress rotation and cropping, only filtering is needed
83             // here (and may be replaced later on). Cropping is handled below as mask primitive (if set).
84             // Also need to suppress mirroring, it is part of the transformation now (see above).
85             // Also move transparency handling to embedding to a UnifiedTransparencePrimitive2D; do
86             // that by remembering original transparency and applying that later if needed
87             GraphicAttr aSuppressGraphicAttr(getGraphicAttr());
88 
89             aSuppressGraphicAttr.SetCrop(0, 0, 0, 0);
90             aSuppressGraphicAttr.SetRotation(0);
91             aSuppressGraphicAttr.SetMirrorFlags(0);
92             aSuppressGraphicAttr.SetTransparency(0);
93 
94             const GraphicObject& rGraphicObject = getGraphicObject();
95             Graphic aTransformedGraphic(rGraphicObject.GetGraphic());
96             const bool isBitmap(GRAPHIC_BITMAP == aTransformedGraphic.GetType() && !aTransformedGraphic.getSvgData().get());
97             const bool isAdjusted(getGraphicAttr().IsAdjusted());
98             const bool isDrawMode(GRAPHICDRAWMODE_STANDARD != getGraphicAttr().GetDrawMode());
99 
100             if(isBitmap && (isAdjusted || isDrawMode))
101             {
102                 // the pure primitive solution with the color modifiers works well, too, but when
103                 // it is a bitmap graphic the old modification currently is faster; so use it here
104                 // instead of creating all as in create2DColorModifierEmbeddingsAsNeeded (see below).
105                 // Still, crop, rotation, mirroring and transparency is handled by primitives already
106                 // (see above).
107                 // This could even be done when vector graphic, but we explicitely want to have the
108                 // pure primitive solution for this; this will allow vector graphics to stay vector
109                 // geraphics, independent from the color filtering stuff. This will enhance e.g.
110                 // SVG and print quality while reducing data size at the same time.
111                 // The other way around the old modifications when only used on already bitmap objects
112                 // will not loose any quality.
113                 aTransformedGraphic = rGraphicObject.GetTransformedGraphic(&aSuppressGraphicAttr);
114 
115                 // reset GraphicAttr after use to not apply double
116                 aSuppressGraphicAttr = GraphicAttr();
117             }
118 
119             // create sub-content; helper takes care of correct handling of
120             // bitmap, svg or metafile content
121             aRetval = create2DDecompositionOfGraphic(
122                 aTransformedGraphic,
123                 aTransform);
124 
125             if(!aRetval.getLength())
126             {
127                 // content is invisible, done
128                 return aRetval;
129             }
130 
131             if(isAdjusted || isDrawMode)
132             {
133                 // embed to needed ModifiedColorPrimitive2D's if necessary. Do this for
134                 // adjustments and draw mode specials
135                 aRetval = create2DColorModifierEmbeddingsAsNeeded(
136                     aRetval,
137                     aSuppressGraphicAttr.GetDrawMode(),
138                     basegfx::clamp(aSuppressGraphicAttr.GetLuminance() * 0.01, -1.0, 1.0),
139                     basegfx::clamp(aSuppressGraphicAttr.GetContrast() * 0.01, -1.0, 1.0),
140                     basegfx::clamp(aSuppressGraphicAttr.GetChannelR() * 0.01, -1.0, 1.0),
141                     basegfx::clamp(aSuppressGraphicAttr.GetChannelG() * 0.01, -1.0, 1.0),
142                     basegfx::clamp(aSuppressGraphicAttr.GetChannelB() * 0.01, -1.0, 1.0),
143                     basegfx::clamp(aSuppressGraphicAttr.GetGamma(), 0.0, 10.0),
144                     aSuppressGraphicAttr.IsInvert());
145 
146                 if(!aRetval.getLength())
147                 {
148                     // content is invisible, done
149                     return aRetval;
150                 }
151             }
152 
153             if(getGraphicAttr().IsTransparent())
154             {
155                 // check for transparency
156                 const double fTransparency(basegfx::clamp(getGraphicAttr().GetTransparency() * (1.0 / 255.0), 0.0, 1.0));
157 
158                 if(!basegfx::fTools::equalZero(fTransparency))
159                 {
160                     const Primitive2DReference aUnifiedTransparence(
161                         new UnifiedTransparencePrimitive2D(
162                             aRetval,
163                             fTransparency));
164 
165                     aRetval = Primitive2DSequence(&aUnifiedTransparence, 1);
166                 }
167             }
168 
169             if(getGraphicAttr().IsCropped())
170             {
171                 // check for cropping
172                 // calculate scalings between real image size and logic object size. This
173                 // is necessary since the crop values are relative to original bitmap size
174                 const basegfx::B2DVector aObjectScale(aTransform * basegfx::B2DVector(1.0, 1.0));
175                 const basegfx::B2DVector aCropScaleFactor(
176                     rGraphicObject.calculateCropScaling(
177                         aObjectScale.getX(),
178                         aObjectScale.getY(),
179                         getGraphicAttr().GetLeftCrop(),
180                         getGraphicAttr().GetTopCrop(),
181                         getGraphicAttr().GetRightCrop(),
182                         getGraphicAttr().GetBottomCrop()));
183 
184                 // embed content in cropPrimitive
185                 Primitive2DReference xPrimitive(
186                     new CropPrimitive2D(
187                         aRetval,
188                         aTransform,
189                         getGraphicAttr().GetLeftCrop() * aCropScaleFactor.getX(),
190                         getGraphicAttr().GetTopCrop() * aCropScaleFactor.getY(),
191                         getGraphicAttr().GetRightCrop() * aCropScaleFactor.getX(),
192                         getGraphicAttr().GetBottomCrop() * aCropScaleFactor.getY()));
193 
194                 aRetval = Primitive2DSequence(&xPrimitive, 1);
195             }
196 
197             return aRetval;
198         }
199 
200         GraphicPrimitive2D::GraphicPrimitive2D(
201             const basegfx::B2DHomMatrix& rTransform,
202             const GraphicObject& rGraphicObject,
203             const GraphicAttr& rGraphicAttr)
204         :	BufferedDecompositionPrimitive2D(),
205             maTransform(rTransform),
206             maGraphicObject(rGraphicObject),
207             maGraphicAttr(rGraphicAttr)
208         {
209         }
210 
211         GraphicPrimitive2D::GraphicPrimitive2D(
212             const basegfx::B2DHomMatrix& rTransform,
213             const GraphicObject& rGraphicObject)
214         :	BufferedDecompositionPrimitive2D(),
215             maTransform(rTransform),
216             maGraphicObject(rGraphicObject),
217             maGraphicAttr()
218         {
219         }
220 
221         bool GraphicPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
222         {
223             if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
224             {
225                 const GraphicPrimitive2D& rCompare = (GraphicPrimitive2D&)rPrimitive;
226 
227                 return (getTransform() == rCompare.getTransform()
228                     && getGraphicObject() == rCompare.getGraphicObject()
229                     && getGraphicAttr() == rCompare.getGraphicAttr());
230             }
231 
232             return false;
233         }
234 
235         basegfx::B2DRange GraphicPrimitive2D::getB2DRange(const geometry::ViewInformation2D& /*rViewInformation*/) const
236         {
237             basegfx::B2DRange aRetval(0.0, 0.0, 1.0, 1.0);
238             aRetval.transform(getTransform());
239             return aRetval;
240         }
241 
242         // provide unique ID
243         ImplPrimitrive2DIDBlock(GraphicPrimitive2D, PRIMITIVE2D_ID_GRAPHICPRIMITIVE2D)
244 
245     } // end of namespace primitive2d
246 } // end of namespace drawinglayer
247 
248 //////////////////////////////////////////////////////////////////////////////
249 // eof
250