1*cdf0e10cSrcweir /*************************************************************************
2*cdf0e10cSrcweir  *
3*cdf0e10cSrcweir  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4*cdf0e10cSrcweir  *
5*cdf0e10cSrcweir  * Copyright 2000, 2010 Oracle and/or its affiliates.
6*cdf0e10cSrcweir  *
7*cdf0e10cSrcweir  * OpenOffice.org - a multi-platform office productivity suite
8*cdf0e10cSrcweir  *
9*cdf0e10cSrcweir  * This file is part of OpenOffice.org.
10*cdf0e10cSrcweir  *
11*cdf0e10cSrcweir  * OpenOffice.org is free software: you can redistribute it and/or modify
12*cdf0e10cSrcweir  * it under the terms of the GNU Lesser General Public License version 3
13*cdf0e10cSrcweir  * only, as published by the Free Software Foundation.
14*cdf0e10cSrcweir  *
15*cdf0e10cSrcweir  * OpenOffice.org is distributed in the hope that it will be useful,
16*cdf0e10cSrcweir  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17*cdf0e10cSrcweir  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18*cdf0e10cSrcweir  * GNU Lesser General Public License version 3 for more details
19*cdf0e10cSrcweir  * (a copy is included in the LICENSE file that accompanied this code).
20*cdf0e10cSrcweir  *
21*cdf0e10cSrcweir  * You should have received a copy of the GNU Lesser General Public License
22*cdf0e10cSrcweir  * version 3 along with OpenOffice.org.  If not, see
23*cdf0e10cSrcweir  * <http://www.openoffice.org/license.html>
24*cdf0e10cSrcweir  * for a copy of the LGPLv3 License.
25*cdf0e10cSrcweir  *
26*cdf0e10cSrcweir  ************************************************************************/
27*cdf0e10cSrcweir 
28*cdf0e10cSrcweir #include "precompiled_svx.hxx"
29*cdf0e10cSrcweir #include <svx/sdr/primitive2d/sdrdecompositiontools.hxx>
30*cdf0e10cSrcweir #include <drawinglayer/primitive2d/baseprimitive2d.hxx>
31*cdf0e10cSrcweir #include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx>
32*cdf0e10cSrcweir #include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx>
33*cdf0e10cSrcweir #include <drawinglayer/primitive2d/transparenceprimitive2d.hxx>
34*cdf0e10cSrcweir #include <basegfx/polygon/b2dpolypolygontools.hxx>
35*cdf0e10cSrcweir #include <drawinglayer/primitive2d/fillgradientprimitive2d.hxx>
36*cdf0e10cSrcweir #include <drawinglayer/attribute/strokeattribute.hxx>
37*cdf0e10cSrcweir #include <drawinglayer/attribute/linestartendattribute.hxx>
38*cdf0e10cSrcweir #include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
39*cdf0e10cSrcweir #include <drawinglayer/attribute/sdrfillbitmapattribute.hxx>
40*cdf0e10cSrcweir #include <basegfx/matrix/b2dhommatrix.hxx>
41*cdf0e10cSrcweir #include <drawinglayer/primitive2d/shadowprimitive2d.hxx>
42*cdf0e10cSrcweir #include <svx/sdr/attribute/sdrtextattribute.hxx>
43*cdf0e10cSrcweir #include <svx/sdr/primitive2d/sdrtextprimitive2d.hxx>
44*cdf0e10cSrcweir #include <svx/svdotext.hxx>
45*cdf0e10cSrcweir #include <basegfx/polygon/b2dpolygontools.hxx>
46*cdf0e10cSrcweir #include <drawinglayer/primitive2d/animatedprimitive2d.hxx>
47*cdf0e10cSrcweir #include <drawinglayer/animation/animationtiming.hxx>
48*cdf0e10cSrcweir #include <drawinglayer/primitive2d/maskprimitive2d.hxx>
49*cdf0e10cSrcweir #include <basegfx/tools/canvastools.hxx>
50*cdf0e10cSrcweir #include <drawinglayer/geometry/viewinformation2d.hxx>
51*cdf0e10cSrcweir #include <drawinglayer/primitive2d/texthierarchyprimitive2d.hxx>
52*cdf0e10cSrcweir #include <drawinglayer/attribute/sdrfillattribute.hxx>
53*cdf0e10cSrcweir #include <drawinglayer/attribute/sdrlineattribute.hxx>
54*cdf0e10cSrcweir #include <drawinglayer/attribute/sdrlinestartendattribute.hxx>
55*cdf0e10cSrcweir #include <drawinglayer/attribute/sdrshadowattribute.hxx>
56*cdf0e10cSrcweir 
57*cdf0e10cSrcweir //////////////////////////////////////////////////////////////////////////////
58*cdf0e10cSrcweir 
59*cdf0e10cSrcweir using namespace com::sun::star;
60*cdf0e10cSrcweir 
61*cdf0e10cSrcweir //////////////////////////////////////////////////////////////////////////////
62*cdf0e10cSrcweir 
63*cdf0e10cSrcweir namespace drawinglayer
64*cdf0e10cSrcweir {
65*cdf0e10cSrcweir 	namespace primitive2d
66*cdf0e10cSrcweir 	{
67*cdf0e10cSrcweir 		Primitive2DReference createPolyPolygonFillPrimitive(
68*cdf0e10cSrcweir 			const basegfx::B2DPolyPolygon& rUnitPolyPolygon,
69*cdf0e10cSrcweir 			const basegfx::B2DHomMatrix& rObjectTransform,
70*cdf0e10cSrcweir 			const attribute::SdrFillAttribute& rFill,
71*cdf0e10cSrcweir 			const attribute::FillGradientAttribute& rFillGradient)
72*cdf0e10cSrcweir 		{
73*cdf0e10cSrcweir 			// prepare fully scaled polygon
74*cdf0e10cSrcweir 			basegfx::B2DPolyPolygon aScaledPolyPolygon(rUnitPolyPolygon);
75*cdf0e10cSrcweir 			aScaledPolyPolygon.transform(rObjectTransform);
76*cdf0e10cSrcweir 			BasePrimitive2D* pNewFillPrimitive = 0;
77*cdf0e10cSrcweir 
78*cdf0e10cSrcweir 			if(!rFill.getGradient().isDefault())
79*cdf0e10cSrcweir 			{
80*cdf0e10cSrcweir 				pNewFillPrimitive = new PolyPolygonGradientPrimitive2D(aScaledPolyPolygon, rFill.getGradient());
81*cdf0e10cSrcweir 			}
82*cdf0e10cSrcweir 			else if(!rFill.getHatch().isDefault())
83*cdf0e10cSrcweir 			{
84*cdf0e10cSrcweir 				pNewFillPrimitive = new PolyPolygonHatchPrimitive2D(aScaledPolyPolygon, rFill.getColor(), rFill.getHatch());
85*cdf0e10cSrcweir 			}
86*cdf0e10cSrcweir 			else if(!rFill.getBitmap().isDefault())
87*cdf0e10cSrcweir 			{
88*cdf0e10cSrcweir 				const basegfx::B2DRange aRange(basegfx::tools::getRange(aScaledPolyPolygon));
89*cdf0e10cSrcweir 				pNewFillPrimitive = new PolyPolygonBitmapPrimitive2D(aScaledPolyPolygon, rFill.getBitmap().getFillBitmapAttribute(aRange));
90*cdf0e10cSrcweir 			}
91*cdf0e10cSrcweir 			else
92*cdf0e10cSrcweir 			{
93*cdf0e10cSrcweir 				pNewFillPrimitive = new PolyPolygonColorPrimitive2D(aScaledPolyPolygon, rFill.getColor());
94*cdf0e10cSrcweir 			}
95*cdf0e10cSrcweir 
96*cdf0e10cSrcweir 			if(0.0 != rFill.getTransparence())
97*cdf0e10cSrcweir 			{
98*cdf0e10cSrcweir 				// create simpleTransparencePrimitive, add created fill primitive
99*cdf0e10cSrcweir 				const Primitive2DReference xRefA(pNewFillPrimitive);
100*cdf0e10cSrcweir 				const Primitive2DSequence aContent(&xRefA, 1L);
101*cdf0e10cSrcweir 				return Primitive2DReference(new UnifiedTransparencePrimitive2D(aContent, rFill.getTransparence()));
102*cdf0e10cSrcweir 			}
103*cdf0e10cSrcweir 			else if(!rFillGradient.isDefault())
104*cdf0e10cSrcweir 			{
105*cdf0e10cSrcweir 				// create sequence with created fill primitive
106*cdf0e10cSrcweir 				const Primitive2DReference xRefA(pNewFillPrimitive);
107*cdf0e10cSrcweir 				const Primitive2DSequence aContent(&xRefA, 1L);
108*cdf0e10cSrcweir 
109*cdf0e10cSrcweir 				// create FillGradientPrimitive2D for transparence and add to new sequence
110*cdf0e10cSrcweir 				// fillGradientPrimitive is enough here (compared to PolyPolygonGradientPrimitive2D) since float transparence will be masked anyways
111*cdf0e10cSrcweir 				const basegfx::B2DRange aRange(basegfx::tools::getRange(aScaledPolyPolygon));
112*cdf0e10cSrcweir 				const Primitive2DReference xRefB(new FillGradientPrimitive2D(aRange, rFillGradient));
113*cdf0e10cSrcweir 				const Primitive2DSequence aAlpha(&xRefB, 1L);
114*cdf0e10cSrcweir 
115*cdf0e10cSrcweir 				// create TransparencePrimitive2D using alpha and content
116*cdf0e10cSrcweir 				return Primitive2DReference(new TransparencePrimitive2D(aContent, aAlpha));
117*cdf0e10cSrcweir 			}
118*cdf0e10cSrcweir 			else
119*cdf0e10cSrcweir 			{
120*cdf0e10cSrcweir 				// add to decomposition
121*cdf0e10cSrcweir 				return Primitive2DReference(pNewFillPrimitive);
122*cdf0e10cSrcweir 			}
123*cdf0e10cSrcweir 		}
124*cdf0e10cSrcweir 
125*cdf0e10cSrcweir 		Primitive2DReference createPolygonLinePrimitive(
126*cdf0e10cSrcweir 			const basegfx::B2DPolygon& rUnitPolygon,
127*cdf0e10cSrcweir 			const basegfx::B2DHomMatrix& rObjectTransform,
128*cdf0e10cSrcweir 			const attribute::SdrLineAttribute& rLine,
129*cdf0e10cSrcweir 			const attribute::SdrLineStartEndAttribute& rStroke)
130*cdf0e10cSrcweir 		{
131*cdf0e10cSrcweir 			// prepare fully scaled polygon
132*cdf0e10cSrcweir 			basegfx::B2DPolygon aScaledPolygon(rUnitPolygon);
133*cdf0e10cSrcweir 			aScaledPolygon.transform(rObjectTransform);
134*cdf0e10cSrcweir 
135*cdf0e10cSrcweir 			// create line and stroke attribute
136*cdf0e10cSrcweir 			const attribute::LineAttribute aLineAttribute(rLine.getColor(), rLine.getWidth(), rLine.getJoin());
137*cdf0e10cSrcweir 			const attribute::StrokeAttribute aStrokeAttribute(rLine.getDotDashArray(), rLine.getFullDotDashLen());
138*cdf0e10cSrcweir 			BasePrimitive2D* pNewLinePrimitive = 0L;
139*cdf0e10cSrcweir 
140*cdf0e10cSrcweir 			if(!rUnitPolygon.isClosed() && !rStroke.isDefault())
141*cdf0e10cSrcweir 			{
142*cdf0e10cSrcweir 				attribute::LineStartEndAttribute aStart(rStroke.getStartWidth(), rStroke.getStartPolyPolygon(), rStroke.isStartCentered());
143*cdf0e10cSrcweir 				attribute::LineStartEndAttribute aEnd(rStroke.getEndWidth(), rStroke.getEndPolyPolygon(), rStroke.isEndCentered());
144*cdf0e10cSrcweir 
145*cdf0e10cSrcweir 				// create data
146*cdf0e10cSrcweir 				pNewLinePrimitive = new PolygonStrokeArrowPrimitive2D(aScaledPolygon, aLineAttribute, aStrokeAttribute, aStart, aEnd);
147*cdf0e10cSrcweir 			}
148*cdf0e10cSrcweir 			else
149*cdf0e10cSrcweir 			{
150*cdf0e10cSrcweir 				// create data
151*cdf0e10cSrcweir 				pNewLinePrimitive = new PolygonStrokePrimitive2D(aScaledPolygon, aLineAttribute, aStrokeAttribute);
152*cdf0e10cSrcweir 			}
153*cdf0e10cSrcweir 
154*cdf0e10cSrcweir 			if(0.0 != rLine.getTransparence())
155*cdf0e10cSrcweir 			{
156*cdf0e10cSrcweir 				// create simpleTransparencePrimitive, add created fill primitive
157*cdf0e10cSrcweir 				const Primitive2DReference xRefA(pNewLinePrimitive);
158*cdf0e10cSrcweir 				const Primitive2DSequence aContent(&xRefA, 1L);
159*cdf0e10cSrcweir 				return Primitive2DReference(new UnifiedTransparencePrimitive2D(aContent, rLine.getTransparence()));
160*cdf0e10cSrcweir 			}
161*cdf0e10cSrcweir 			else
162*cdf0e10cSrcweir 			{
163*cdf0e10cSrcweir 				// add to decomposition
164*cdf0e10cSrcweir 				return Primitive2DReference(pNewLinePrimitive);
165*cdf0e10cSrcweir 			}
166*cdf0e10cSrcweir 		}
167*cdf0e10cSrcweir 
168*cdf0e10cSrcweir 		Primitive2DReference createTextPrimitive(
169*cdf0e10cSrcweir 			const basegfx::B2DPolyPolygon& rUnitPolyPolygon,
170*cdf0e10cSrcweir 			const basegfx::B2DHomMatrix& rObjectTransform,
171*cdf0e10cSrcweir 			const attribute::SdrTextAttribute& rText,
172*cdf0e10cSrcweir 			const attribute::SdrLineAttribute& rStroke,
173*cdf0e10cSrcweir 			bool bCellText,
174*cdf0e10cSrcweir             bool bWordWrap,
175*cdf0e10cSrcweir 			bool bClipOnBounds)
176*cdf0e10cSrcweir 		{
177*cdf0e10cSrcweir 			basegfx::B2DHomMatrix aAnchorTransform(rObjectTransform);
178*cdf0e10cSrcweir 			SdrTextPrimitive2D* pNew = 0;
179*cdf0e10cSrcweir 
180*cdf0e10cSrcweir 			if(rText.isContour())
181*cdf0e10cSrcweir 			{
182*cdf0e10cSrcweir 				// contour text
183*cdf0e10cSrcweir 				if(!rStroke.isDefault() && 0.0 != rStroke.getWidth())
184*cdf0e10cSrcweir 				{
185*cdf0e10cSrcweir 					// take line width into account and shrink contour polygon accordingly
186*cdf0e10cSrcweir 					// decompose to get scale
187*cdf0e10cSrcweir 					basegfx::B2DVector aScale, aTranslate;
188*cdf0e10cSrcweir 					double fRotate, fShearX;
189*cdf0e10cSrcweir 					rObjectTransform.decompose(aScale, aTranslate, fRotate, fShearX);
190*cdf0e10cSrcweir 
191*cdf0e10cSrcweir 					// scale outline to object's size to allow growing with value relative to that size
192*cdf0e10cSrcweir 					// and also to keep aspect ratio
193*cdf0e10cSrcweir 					basegfx::B2DPolyPolygon aScaledUnitPolyPolygon(rUnitPolyPolygon);
194*cdf0e10cSrcweir 					aScaledUnitPolyPolygon.transform(basegfx::tools::createScaleB2DHomMatrix(
195*cdf0e10cSrcweir 						fabs(aScale.getX()), fabs(aScale.getY())));
196*cdf0e10cSrcweir 
197*cdf0e10cSrcweir 					// grow the polygon. To shrink, use negative value (half width)
198*cdf0e10cSrcweir 					aScaledUnitPolyPolygon = basegfx::tools::growInNormalDirection(aScaledUnitPolyPolygon, -(rStroke.getWidth() * 0.5));
199*cdf0e10cSrcweir 
200*cdf0e10cSrcweir 					// scale back to unit polygon
201*cdf0e10cSrcweir 					aScaledUnitPolyPolygon.transform(basegfx::tools::createScaleB2DHomMatrix(
202*cdf0e10cSrcweir 						0.0 != aScale.getX() ? 1.0 / aScale.getX() : 1.0,
203*cdf0e10cSrcweir 						0.0 != aScale.getY() ? 1.0 / aScale.getY() : 1.0));
204*cdf0e10cSrcweir 
205*cdf0e10cSrcweir 					// create with unit polygon
206*cdf0e10cSrcweir 					pNew = new SdrContourTextPrimitive2D(
207*cdf0e10cSrcweir                         &rText.getSdrText(),
208*cdf0e10cSrcweir                         rText.getOutlinerParaObject(),
209*cdf0e10cSrcweir                         aScaledUnitPolyPolygon,
210*cdf0e10cSrcweir                         rObjectTransform);
211*cdf0e10cSrcweir 				}
212*cdf0e10cSrcweir 				else
213*cdf0e10cSrcweir 				{
214*cdf0e10cSrcweir 					// create with unit polygon
215*cdf0e10cSrcweir 					pNew = new SdrContourTextPrimitive2D(
216*cdf0e10cSrcweir                         &rText.getSdrText(),
217*cdf0e10cSrcweir                         rText.getOutlinerParaObject(),
218*cdf0e10cSrcweir                         rUnitPolyPolygon,
219*cdf0e10cSrcweir                         rObjectTransform);
220*cdf0e10cSrcweir 				}
221*cdf0e10cSrcweir 			}
222*cdf0e10cSrcweir 			else if(!rText.getSdrFormTextAttribute().isDefault())
223*cdf0e10cSrcweir 			{
224*cdf0e10cSrcweir 				// text on path, use scaled polygon
225*cdf0e10cSrcweir 				basegfx::B2DPolyPolygon aScaledPolyPolygon(rUnitPolyPolygon);
226*cdf0e10cSrcweir 				aScaledPolyPolygon.transform(rObjectTransform);
227*cdf0e10cSrcweir 				pNew = new SdrPathTextPrimitive2D(
228*cdf0e10cSrcweir                     &rText.getSdrText(),
229*cdf0e10cSrcweir                     rText.getOutlinerParaObject(),
230*cdf0e10cSrcweir                     aScaledPolyPolygon,
231*cdf0e10cSrcweir                     rText.getSdrFormTextAttribute());
232*cdf0e10cSrcweir 			}
233*cdf0e10cSrcweir 			else
234*cdf0e10cSrcweir 			{
235*cdf0e10cSrcweir 				// rObjectTransform is the whole SdrObject transformation from unit rectangle
236*cdf0e10cSrcweir 				// to it's size and position. Decompose to allow working with single values.
237*cdf0e10cSrcweir 				basegfx::B2DVector aScale, aTranslate;
238*cdf0e10cSrcweir 				double fRotate, fShearX;
239*cdf0e10cSrcweir 				rObjectTransform.decompose(aScale, aTranslate, fRotate, fShearX);
240*cdf0e10cSrcweir 
241*cdf0e10cSrcweir 				// extract mirroring
242*cdf0e10cSrcweir 				const bool bMirrorX(basegfx::fTools::less(aScale.getX(), 0.0));
243*cdf0e10cSrcweir 				const bool bMirrorY(basegfx::fTools::less(aScale.getY(), 0.0));
244*cdf0e10cSrcweir 				aScale = basegfx::absolute(aScale);
245*cdf0e10cSrcweir 
246*cdf0e10cSrcweir 				// Get the real size, since polygon ountline and scale
247*cdf0e10cSrcweir 				// from the object transformation may vary (e.g. ellipse segments)
248*cdf0e10cSrcweir 				basegfx::B2DHomMatrix aJustScaleTransform;
249*cdf0e10cSrcweir 				aJustScaleTransform.set(0, 0, aScale.getX());
250*cdf0e10cSrcweir 				aJustScaleTransform.set(1, 1, aScale.getY());
251*cdf0e10cSrcweir 				basegfx::B2DPolyPolygon aScaledUnitPolyPolygon(rUnitPolyPolygon);
252*cdf0e10cSrcweir 				aScaledUnitPolyPolygon.transform(aJustScaleTransform);
253*cdf0e10cSrcweir 				const basegfx::B2DRange aSnapRange(basegfx::tools::getRange(aScaledUnitPolyPolygon));
254*cdf0e10cSrcweir 
255*cdf0e10cSrcweir 				// create a range describing the wanted text position and size (aTextAnchorRange). This
256*cdf0e10cSrcweir 				// means to use the text distance values here
257*cdf0e10cSrcweir 				const basegfx::B2DPoint aTopLeft(aSnapRange.getMinX() + rText.getTextLeftDistance(), aSnapRange.getMinY() + rText.getTextUpperDistance());
258*cdf0e10cSrcweir 				const basegfx::B2DPoint aBottomRight(aSnapRange.getMaxX() - rText.getTextRightDistance(), aSnapRange.getMaxY() - rText.getTextLowerDistance());
259*cdf0e10cSrcweir 				basegfx::B2DRange aTextAnchorRange;
260*cdf0e10cSrcweir 				aTextAnchorRange.expand(aTopLeft);
261*cdf0e10cSrcweir 				aTextAnchorRange.expand(aBottomRight);
262*cdf0e10cSrcweir 
263*cdf0e10cSrcweir 				// now create a transformation from this basic range (aTextAnchorRange)
264*cdf0e10cSrcweir 				aAnchorTransform = basegfx::tools::createScaleTranslateB2DHomMatrix(
265*cdf0e10cSrcweir 					aTextAnchorRange.getWidth(), aTextAnchorRange.getHeight(),
266*cdf0e10cSrcweir 					aTextAnchorRange.getMinX(), aTextAnchorRange.getMinY());
267*cdf0e10cSrcweir 
268*cdf0e10cSrcweir 				// apply mirroring
269*cdf0e10cSrcweir 				aAnchorTransform.scale(bMirrorX ? -1.0 : 1.0, bMirrorY ? -1.0 : 1.0);
270*cdf0e10cSrcweir 
271*cdf0e10cSrcweir 				// apply object's other transforms
272*cdf0e10cSrcweir 				aAnchorTransform = basegfx::tools::createShearXRotateTranslateB2DHomMatrix(fShearX, fRotate, aTranslate)
273*cdf0e10cSrcweir 					* aAnchorTransform;
274*cdf0e10cSrcweir 
275*cdf0e10cSrcweir 				if(rText.isFitToSize())
276*cdf0e10cSrcweir 				{
277*cdf0e10cSrcweir 					// streched text in range
278*cdf0e10cSrcweir 					pNew = new SdrStretchTextPrimitive2D(
279*cdf0e10cSrcweir                         &rText.getSdrText(),
280*cdf0e10cSrcweir                         rText.getOutlinerParaObject(),
281*cdf0e10cSrcweir                         aAnchorTransform,
282*cdf0e10cSrcweir                         rText.isFixedCellHeight());
283*cdf0e10cSrcweir 				}
284*cdf0e10cSrcweir 				else // text in range
285*cdf0e10cSrcweir 				{
286*cdf0e10cSrcweir 					// build new primitive
287*cdf0e10cSrcweir 					pNew = new SdrBlockTextPrimitive2D(
288*cdf0e10cSrcweir                         &rText.getSdrText(),
289*cdf0e10cSrcweir                         rText.getOutlinerParaObject(),
290*cdf0e10cSrcweir                         aAnchorTransform,
291*cdf0e10cSrcweir                         rText.getSdrTextHorzAdjust(),
292*cdf0e10cSrcweir                         rText.getSdrTextVertAdjust(),
293*cdf0e10cSrcweir                         rText.isFixedCellHeight(),
294*cdf0e10cSrcweir                         rText.isScroll(),
295*cdf0e10cSrcweir                         bCellText,
296*cdf0e10cSrcweir                         bWordWrap,
297*cdf0e10cSrcweir 						bClipOnBounds);
298*cdf0e10cSrcweir 				}
299*cdf0e10cSrcweir 			}
300*cdf0e10cSrcweir 
301*cdf0e10cSrcweir 			OSL_ENSURE(pNew != 0, "createTextPrimitive: no text primitive created (!)");
302*cdf0e10cSrcweir 
303*cdf0e10cSrcweir 			if(rText.isBlink())
304*cdf0e10cSrcweir 			{
305*cdf0e10cSrcweir 				// prepare animation and primitive list
306*cdf0e10cSrcweir 				drawinglayer::animation::AnimationEntryList aAnimationList;
307*cdf0e10cSrcweir 				rText.getBlinkTextTiming(aAnimationList);
308*cdf0e10cSrcweir 
309*cdf0e10cSrcweir 				if(0.0 != aAnimationList.getDuration())
310*cdf0e10cSrcweir 				{
311*cdf0e10cSrcweir 					// create content sequence
312*cdf0e10cSrcweir 					const Primitive2DReference xRefA(pNew);
313*cdf0e10cSrcweir 					const Primitive2DSequence aContent(&xRefA, 1L);
314*cdf0e10cSrcweir 
315*cdf0e10cSrcweir 					// create and add animated switch primitive
316*cdf0e10cSrcweir 					return Primitive2DReference(new AnimatedBlinkPrimitive2D(aAnimationList, aContent, true));
317*cdf0e10cSrcweir 				}
318*cdf0e10cSrcweir 				else
319*cdf0e10cSrcweir 				{
320*cdf0e10cSrcweir 					// add to decomposition
321*cdf0e10cSrcweir 					return Primitive2DReference(pNew);
322*cdf0e10cSrcweir 				}
323*cdf0e10cSrcweir 			}
324*cdf0e10cSrcweir 
325*cdf0e10cSrcweir             if(rText.isScroll())
326*cdf0e10cSrcweir 			{
327*cdf0e10cSrcweir                 // suppress scroll when FontWork
328*cdf0e10cSrcweir 			    if(rText.getSdrFormTextAttribute().isDefault())
329*cdf0e10cSrcweir 			    {
330*cdf0e10cSrcweir 				    // get scroll direction
331*cdf0e10cSrcweir 				    const SdrTextAniDirection eDirection(rText.getSdrText().GetObject().GetTextAniDirection());
332*cdf0e10cSrcweir 				    const bool bHorizontal(SDRTEXTANI_LEFT == eDirection || SDRTEXTANI_RIGHT == eDirection);
333*cdf0e10cSrcweir 
334*cdf0e10cSrcweir 				    // decompose to get separated values for the scroll box
335*cdf0e10cSrcweir 				    basegfx::B2DVector aScale, aTranslate;
336*cdf0e10cSrcweir 				    double fRotate, fShearX;
337*cdf0e10cSrcweir 				    aAnchorTransform.decompose(aScale, aTranslate, fRotate, fShearX);
338*cdf0e10cSrcweir 
339*cdf0e10cSrcweir 				    // build transform from scaled only to full AnchorTransform and inverse
340*cdf0e10cSrcweir 					const basegfx::B2DHomMatrix aSRT(basegfx::tools::createShearXRotateTranslateB2DHomMatrix(
341*cdf0e10cSrcweir 						fShearX, fRotate, aTranslate));
342*cdf0e10cSrcweir 				    basegfx::B2DHomMatrix aISRT(aSRT);
343*cdf0e10cSrcweir 				    aISRT.invert();
344*cdf0e10cSrcweir 
345*cdf0e10cSrcweir 				    // bring the primitive back to scaled only and get scaled range, create new clone for this
346*cdf0e10cSrcweir 				    SdrTextPrimitive2D* pNew2 = pNew->createTransformedClone(aISRT);
347*cdf0e10cSrcweir 				    OSL_ENSURE(pNew2, "createTextPrimitive: Could not create transformed clone of text primitive (!)");
348*cdf0e10cSrcweir 				    delete pNew;
349*cdf0e10cSrcweir 				    pNew = pNew2;
350*cdf0e10cSrcweir 
351*cdf0e10cSrcweir 				    // create neutral geometry::ViewInformation2D for local range and decompose calls. This is okay
352*cdf0e10cSrcweir 				    // since the decompose is view-independent
353*cdf0e10cSrcweir 				    const uno::Sequence< beans::PropertyValue > xViewParameters;
354*cdf0e10cSrcweir 				    geometry::ViewInformation2D aViewInformation2D(xViewParameters);
355*cdf0e10cSrcweir 
356*cdf0e10cSrcweir 				    // get range
357*cdf0e10cSrcweir 				    const basegfx::B2DRange aScaledRange(pNew->getB2DRange(aViewInformation2D));
358*cdf0e10cSrcweir 
359*cdf0e10cSrcweir 				    // create left outside and right outside transformations. Also take care
360*cdf0e10cSrcweir 				    // of the clip rectangle
361*cdf0e10cSrcweir 				    basegfx::B2DHomMatrix aLeft, aRight;
362*cdf0e10cSrcweir 				    basegfx::B2DPoint aClipTopLeft(0.0, 0.0);
363*cdf0e10cSrcweir 				    basegfx::B2DPoint aClipBottomRight(aScale.getX(), aScale.getY());
364*cdf0e10cSrcweir 
365*cdf0e10cSrcweir 				    if(bHorizontal)
366*cdf0e10cSrcweir 				    {
367*cdf0e10cSrcweir 					    aClipTopLeft.setY(aScaledRange.getMinY());
368*cdf0e10cSrcweir 					    aClipBottomRight.setY(aScaledRange.getMaxY());
369*cdf0e10cSrcweir 					    aLeft.translate(-aScaledRange.getMaxX(), 0.0);
370*cdf0e10cSrcweir 					    aRight.translate(aScale.getX() - aScaledRange.getMinX(), 0.0);
371*cdf0e10cSrcweir 				    }
372*cdf0e10cSrcweir 				    else
373*cdf0e10cSrcweir 				    {
374*cdf0e10cSrcweir 					    aClipTopLeft.setX(aScaledRange.getMinX());
375*cdf0e10cSrcweir 					    aClipBottomRight.setX(aScaledRange.getMaxX());
376*cdf0e10cSrcweir 					    aLeft.translate(0.0, -aScaledRange.getMaxY());
377*cdf0e10cSrcweir 					    aRight.translate(0.0, aScale.getY() - aScaledRange.getMinY());
378*cdf0e10cSrcweir 				    }
379*cdf0e10cSrcweir 
380*cdf0e10cSrcweir 				    aLeft *= aSRT;
381*cdf0e10cSrcweir 				    aRight *= aSRT;
382*cdf0e10cSrcweir 
383*cdf0e10cSrcweir 				    // prepare animation list
384*cdf0e10cSrcweir 				    drawinglayer::animation::AnimationEntryList aAnimationList;
385*cdf0e10cSrcweir 
386*cdf0e10cSrcweir 				    if(bHorizontal)
387*cdf0e10cSrcweir 				    {
388*cdf0e10cSrcweir 					    rText.getScrollTextTiming(aAnimationList, aScale.getX(), aScaledRange.getWidth());
389*cdf0e10cSrcweir 				    }
390*cdf0e10cSrcweir 				    else
391*cdf0e10cSrcweir 				    {
392*cdf0e10cSrcweir 					    rText.getScrollTextTiming(aAnimationList, aScale.getY(), aScaledRange.getHeight());
393*cdf0e10cSrcweir 				    }
394*cdf0e10cSrcweir 
395*cdf0e10cSrcweir 				    if(0.0 != aAnimationList.getDuration())
396*cdf0e10cSrcweir 				    {
397*cdf0e10cSrcweir 					    // create a new Primitive2DSequence containing the animated text in it's scaled only state.
398*cdf0e10cSrcweir 					    // use the decomposition to force to simple text primitives, those will no longer
399*cdf0e10cSrcweir 					    // need the outliner for formatting (alternatively it is also possible to just add
400*cdf0e10cSrcweir 					    // pNew to aNewPrimitiveSequence)
401*cdf0e10cSrcweir 					    Primitive2DSequence aAnimSequence(pNew->get2DDecomposition(aViewInformation2D));
402*cdf0e10cSrcweir 					    delete pNew;
403*cdf0e10cSrcweir 
404*cdf0e10cSrcweir 					    // create a new animatedInterpolatePrimitive and add it
405*cdf0e10cSrcweir 					    std::vector< basegfx::B2DHomMatrix > aMatrixStack;
406*cdf0e10cSrcweir 					    aMatrixStack.push_back(aLeft);
407*cdf0e10cSrcweir 					    aMatrixStack.push_back(aRight);
408*cdf0e10cSrcweir 					    const Primitive2DReference xRefA(new AnimatedInterpolatePrimitive2D(aMatrixStack, aAnimationList, aAnimSequence, true));
409*cdf0e10cSrcweir 					    const Primitive2DSequence aContent(&xRefA, 1L);
410*cdf0e10cSrcweir 
411*cdf0e10cSrcweir 					    // scrolling needs an encapsulating clipping primitive
412*cdf0e10cSrcweir 					    const basegfx::B2DRange aClipRange(aClipTopLeft, aClipBottomRight);
413*cdf0e10cSrcweir 					    basegfx::B2DPolygon aClipPolygon(basegfx::tools::createPolygonFromRect(aClipRange));
414*cdf0e10cSrcweir 					    aClipPolygon.transform(aSRT);
415*cdf0e10cSrcweir 					    return Primitive2DReference(new MaskPrimitive2D(basegfx::B2DPolyPolygon(aClipPolygon), aContent));
416*cdf0e10cSrcweir 				    }
417*cdf0e10cSrcweir 				    else
418*cdf0e10cSrcweir 				    {
419*cdf0e10cSrcweir 					    // add to decomposition
420*cdf0e10cSrcweir 					    return Primitive2DReference(pNew);
421*cdf0e10cSrcweir 				    }
422*cdf0e10cSrcweir                 }
423*cdf0e10cSrcweir 			}
424*cdf0e10cSrcweir 
425*cdf0e10cSrcweir             if(rText.isInEditMode())
426*cdf0e10cSrcweir             {
427*cdf0e10cSrcweir                 // #i97628#
428*cdf0e10cSrcweir                 // encapsulate with TextHierarchyEditPrimitive2D to allow renderers
429*cdf0e10cSrcweir                 // to suppress actively edited content if needed
430*cdf0e10cSrcweir 			    const Primitive2DReference xRefA(pNew);
431*cdf0e10cSrcweir 			    const Primitive2DSequence aContent(&xRefA, 1L);
432*cdf0e10cSrcweir 
433*cdf0e10cSrcweir 			    // create and add TextHierarchyEditPrimitive2D primitive
434*cdf0e10cSrcweir 			    return Primitive2DReference(new TextHierarchyEditPrimitive2D(aContent));
435*cdf0e10cSrcweir             }
436*cdf0e10cSrcweir             else
437*cdf0e10cSrcweir             {
438*cdf0e10cSrcweir 				// add to decomposition
439*cdf0e10cSrcweir     			return Primitive2DReference(pNew);
440*cdf0e10cSrcweir             }
441*cdf0e10cSrcweir 		}
442*cdf0e10cSrcweir 
443*cdf0e10cSrcweir         Primitive2DSequence createEmbeddedShadowPrimitive(
444*cdf0e10cSrcweir             const Primitive2DSequence& rContent,
445*cdf0e10cSrcweir             const attribute::SdrShadowAttribute& rShadow)
446*cdf0e10cSrcweir         {
447*cdf0e10cSrcweir 			if(rContent.hasElements())
448*cdf0e10cSrcweir 			{
449*cdf0e10cSrcweir 				Primitive2DSequence aRetval(2);
450*cdf0e10cSrcweir 		        basegfx::B2DHomMatrix aShadowOffset;
451*cdf0e10cSrcweir 
452*cdf0e10cSrcweir 		        // prepare shadow offset
453*cdf0e10cSrcweir                 aShadowOffset.set(0, 2, rShadow.getOffset().getX());
454*cdf0e10cSrcweir 		        aShadowOffset.set(1, 2, rShadow.getOffset().getY());
455*cdf0e10cSrcweir 
456*cdf0e10cSrcweir 		        // create shadow primitive and add content
457*cdf0e10cSrcweir 		        aRetval[0] = Primitive2DReference(
458*cdf0e10cSrcweir                     new ShadowPrimitive2D(
459*cdf0e10cSrcweir                         aShadowOffset,
460*cdf0e10cSrcweir                         rShadow.getColor(),
461*cdf0e10cSrcweir                         rContent));
462*cdf0e10cSrcweir 
463*cdf0e10cSrcweir 		        if(0.0 != rShadow.getTransparence())
464*cdf0e10cSrcweir 		        {
465*cdf0e10cSrcweir 			        // create SimpleTransparencePrimitive2D
466*cdf0e10cSrcweir 			        const Primitive2DSequence aTempContent(&aRetval[0], 1);
467*cdf0e10cSrcweir 
468*cdf0e10cSrcweir                     aRetval[0] = Primitive2DReference(
469*cdf0e10cSrcweir                         new UnifiedTransparencePrimitive2D(
470*cdf0e10cSrcweir                             aTempContent,
471*cdf0e10cSrcweir                             rShadow.getTransparence()));
472*cdf0e10cSrcweir 		        }
473*cdf0e10cSrcweir 
474*cdf0e10cSrcweir                 aRetval[1] = Primitive2DReference(new GroupPrimitive2D(rContent));
475*cdf0e10cSrcweir                 return aRetval;
476*cdf0e10cSrcweir 			}
477*cdf0e10cSrcweir             else
478*cdf0e10cSrcweir             {
479*cdf0e10cSrcweir                 return rContent;
480*cdf0e10cSrcweir             }
481*cdf0e10cSrcweir         }
482*cdf0e10cSrcweir 	} // end of namespace primitive2d
483*cdf0e10cSrcweir } // end of namespace drawinglayer
484*cdf0e10cSrcweir 
485*cdf0e10cSrcweir //////////////////////////////////////////////////////////////////////////////
486*cdf0e10cSrcweir // eof
487