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