1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <vclhelperbitmaprender.hxx>
21 #include <svtools/grfmgr.hxx>
22 #include <basegfx/vector/b2dvector.hxx>
23 #include <basegfx/matrix/b2dhommatrix.hxx>
24 #include <basegfx/range/b2drange.hxx>
25 #include <vcl/outdev.hxx>
26 #include <vclhelperbitmaptransform.hxx>
27 #include <basegfx/matrix/b2dhommatrixtools.hxx>
29 //////////////////////////////////////////////////////////////////////////////
30 // support for different kinds of bitmap rendering using vcl
32 namespace drawinglayer
34 void RenderBitmapPrimitive2D_GraphicManager(
35 OutputDevice
& rOutDev
,
36 const BitmapEx
& rBitmapEx
,
37 const basegfx::B2DHomMatrix
& rTransform
)
40 GraphicAttr aAttributes
;
42 // decompose matrix to check for shear, rotate and mirroring
43 basegfx::B2DVector aScale
, aTranslate
;
44 double fRotate
, fShearX
;
45 rTransform
.decompose(aScale
, aTranslate
, fRotate
, fShearX
);
48 const bool bMirrorX(basegfx::fTools::less(aScale
.getX(), 0.0));
49 const bool bMirrorY(basegfx::fTools::less(aScale
.getY(), 0.0));
50 aAttributes
.SetMirrorFlags((bMirrorX
? BMP_MIRROR_HORZ
: 0)|(bMirrorY
? BMP_MIRROR_VERT
: 0));
53 if(!basegfx::fTools::equalZero(fRotate
))
55 double fRotation(fmod(3600.0 - (fRotate
* (10.0 / F_PI180
)), 3600.0));
56 aAttributes
.SetRotation((sal_uInt16
)(fRotation
));
60 basegfx::B2DRange
aOutlineRange(0.0, 0.0, 1.0, 1.0);
62 if(basegfx::fTools::equalZero(fRotate
))
64 aOutlineRange
.transform(rTransform
);
68 // if rotated, create the unrotated output rectangle for the GraphicManager paint
69 // #118824# Caution! When mirrored, adapt transformation accordingly
70 const basegfx::B2DHomMatrix
aSimpleObjectMatrix(
71 basegfx::tools::createScaleTranslateB2DHomMatrix(
74 bMirrorX
? aTranslate
.getX() - fabs(aScale
.getX()): aTranslate
.getX(),
75 bMirrorY
? aTranslate
.getY() - fabs(aScale
.getY()): aTranslate
.getY()));
77 aOutlineRange
.transform(aSimpleObjectMatrix
);
80 // prepare dest coordinates
82 basegfx::fround(aOutlineRange
.getMinX()),
83 basegfx::fround(aOutlineRange
.getMinY()));
85 basegfx::fround(aOutlineRange
.getWidth()),
86 basegfx::fround(aOutlineRange
.getHeight()));
88 // paint it using GraphicManager
89 Graphic
aGraphic(rBitmapEx
);
90 GraphicObject
aGraphicObject(aGraphic
);
91 aGraphicObject
.Draw(&rOutDev
, aPoint
, aSize
, &aAttributes
);
94 void RenderBitmapPrimitive2D_BitmapEx(
95 OutputDevice
& rOutDev
,
96 const BitmapEx
& rBitmapEx
,
97 const basegfx::B2DHomMatrix
& rTransform
)
99 // only translate and scale, use vcl's DrawBitmapEx().
100 BitmapEx
aContent(rBitmapEx
);
102 // prepare dest coor. Necessary to expand since vcl's DrawBitmapEx draws one pix less
103 basegfx::B2DRange
aOutlineRange(0.0, 0.0, 1.0, 1.0);
104 aOutlineRange
.transform(rTransform
);
105 // prepare dest coordinates
107 basegfx::fround(aOutlineRange
.getMinX()),
108 basegfx::fround(aOutlineRange
.getMinY()));
110 basegfx::fround(aOutlineRange
.getWidth()),
111 basegfx::fround(aOutlineRange
.getHeight()));
113 // decompose matrix to check for shear, rotate and mirroring
114 basegfx::B2DVector aScale
, aTranslate
;
115 double fRotate
, fShearX
;
116 rTransform
.decompose(aScale
, aTranslate
, fRotate
, fShearX
);
119 sal_uInt32
nMirrorFlags(BMP_MIRROR_NONE
);
121 if(basegfx::fTools::less(aScale
.getX(), 0.0))
123 nMirrorFlags
|= BMP_MIRROR_HORZ
;
126 if(basegfx::fTools::less(aScale
.getY(), 0.0))
128 nMirrorFlags
|= BMP_MIRROR_VERT
;
131 if(BMP_MIRROR_NONE
!= nMirrorFlags
)
133 aContent
.Mirror(nMirrorFlags
);
137 rOutDev
.DrawBitmapEx(aPoint
, aSize
, aContent
);
140 void RenderBitmapPrimitive2D_self(
141 OutputDevice
& rOutDev
,
142 const BitmapEx
& rBitmapEx
,
143 const basegfx::B2DHomMatrix
& rTransform
)
145 // process self with free transformation (containing shear and rotate). Get dest rect in pixels.
146 basegfx::B2DRange
aOutlineRange(0.0, 0.0, 1.0, 1.0);
147 aOutlineRange
.transform(rTransform
);
148 const Rectangle
aDestRectLogic(
149 basegfx::fround(aOutlineRange
.getMinX()),
150 basegfx::fround(aOutlineRange
.getMinY()),
151 basegfx::fround(aOutlineRange
.getMaxX()),
152 basegfx::fround(aOutlineRange
.getMaxY()));
153 const Rectangle
aDestRectPixel(rOutDev
.LogicToPixel(aDestRectLogic
));
155 // #i96708# check if Metafile is recorded
156 const GDIMetaFile
* pMetaFile
= rOutDev
.GetConnectMetaFile();
157 const bool bRecordToMetaFile(pMetaFile
&& pMetaFile
->IsRecord() && !pMetaFile
->IsPause());
159 // intersect with output pixel size, but only
160 // when not recording to metafile
161 const Rectangle
aOutputRectPixel(Point(), rOutDev
.GetOutputSizePixel());
162 Rectangle
aCroppedRectPixel(bRecordToMetaFile
? aDestRectPixel
: aDestRectPixel
.GetIntersection(aOutputRectPixel
));
164 if(!aCroppedRectPixel
.IsEmpty())
166 // as maximum for destination, orientate at aOutputRectPixel, but
167 // take a rotation of 45 degrees (sqrt(2)) as maximum expansion into account
168 const Size
aSourceSizePixel(rBitmapEx
.GetSizePixel());
169 const double fMaximumArea(
170 (double)aOutputRectPixel
.getWidth() *
171 (double)aOutputRectPixel
.getHeight() *
172 1.4142136); // 1.4142136 taken as sqrt(2.0)
174 // test if discrete view size (pixel) maybe too big and limit it
175 const double fArea(aCroppedRectPixel
.getWidth() * aCroppedRectPixel
.getHeight());
176 const bool bNeedToReduce(fArea
> fMaximumArea
);
177 double fReduceFactor(1.0);
178 const Size
aDestSizePixel(aCroppedRectPixel
.GetSize());
182 fReduceFactor
= sqrt(fMaximumArea
/ fArea
);
183 aCroppedRectPixel
.setWidth(basegfx::fround(aCroppedRectPixel
.getWidth() * fReduceFactor
));
184 aCroppedRectPixel
.setHeight(basegfx::fround(aCroppedRectPixel
.getHeight() * fReduceFactor
));
187 // build transform from pixel in aDestination to pixel in rBitmapEx
188 // from relative in aCroppedRectPixel to relative in aDestRectPixel
189 // No need to take bNeedToReduce into account, TopLeft is unchanged
190 basegfx::B2DHomMatrix
aTransform(basegfx::tools::createTranslateB2DHomMatrix(
191 aCroppedRectPixel
.Left() - aDestRectPixel
.Left(),
192 aCroppedRectPixel
.Top() - aDestRectPixel
.Top()));
194 // from relative in aDestRectPixel to absolute Logic. Here it
195 // is essential to adapt to reduce factor (if used)
196 double fAdaptedDRPWidth((double)aDestRectPixel
.getWidth());
197 double fAdaptedDRPHeight((double)aDestRectPixel
.getHeight());
201 fAdaptedDRPWidth
*= fReduceFactor
;
202 fAdaptedDRPHeight
*= fReduceFactor
;
205 aTransform
= basegfx::tools::createScaleTranslateB2DHomMatrix(
206 aDestRectLogic
.getWidth() / fAdaptedDRPWidth
, aDestRectLogic
.getHeight() / fAdaptedDRPHeight
,
207 aDestRectLogic
.Left(), aDestRectLogic
.Top())
210 // from absolute in Logic to unified object coordinates (0.0 .. 1.0 in x and y)
211 basegfx::B2DHomMatrix
aInvBitmapTransform(rTransform
);
212 aInvBitmapTransform
.invert();
213 aTransform
= aInvBitmapTransform
* aTransform
;
215 // from unit object coordinates to rBitmapEx pixel coordintes
216 aTransform
.scale(aSourceSizePixel
.getWidth() - 1L, aSourceSizePixel
.getHeight() - 1L);
218 // create bitmap using source, destination and linear back-transformation
219 BitmapEx aDestination
= impTransformBitmapEx(rBitmapEx
, aCroppedRectPixel
, aTransform
);
224 // paint in target size
225 if(bRecordToMetaFile
)
227 rOutDev
.DrawBitmapEx(
228 rOutDev
.PixelToLogic(aCroppedRectPixel
.TopLeft()),
229 rOutDev
.PixelToLogic(aDestSizePixel
),
234 const bool bWasEnabled(rOutDev
.IsMapModeEnabled());
235 rOutDev
.EnableMapMode(false);
237 rOutDev
.DrawBitmapEx(
238 aCroppedRectPixel
.TopLeft(),
242 rOutDev
.EnableMapMode(bWasEnabled
);
247 if(bRecordToMetaFile
)
249 rOutDev
.DrawBitmapEx(
250 rOutDev
.PixelToLogic(aCroppedRectPixel
.TopLeft()),
255 const bool bWasEnabled(rOutDev
.IsMapModeEnabled());
256 rOutDev
.EnableMapMode(false);
258 rOutDev
.DrawBitmapEx(
259 aCroppedRectPixel
.TopLeft(),
262 rOutDev
.EnableMapMode(bWasEnabled
);
267 } // end of namespace drawinglayer
269 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */