xref: /trunk/main/svx/source/sdr/primitive2d/sdrdecompositiontools.cxx (revision 54c55739d259b6c09a298acbd77515f3caadc8c1)
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
10cdf0e10cSrcweir  *
11f6e50924SAndrew Rist  *   http://www.apache.org/licenses/LICENSE-2.0
12cdf0e10cSrcweir  *
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.
19cdf0e10cSrcweir  *
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>
35035a2f44SArmin Le Grand #include <drawinglayer/attribute/sdrfillgraphicattribute.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     {
createPolyPolygonFillPrimitive(const basegfx::B2DPolyPolygon & rPolyPolygon,const attribute::SdrFillAttribute & rFill,const attribute::FillGradientAttribute & rFillGradient)63cdf0e10cSrcweir         Primitive2DReference createPolyPolygonFillPrimitive(
6464b14621SArmin Le Grand             const basegfx::B2DPolyPolygon& rPolyPolygon,
65cdf0e10cSrcweir             const attribute::SdrFillAttribute& rFill,
66cdf0e10cSrcweir             const attribute::FillGradientAttribute& rFillGradient)
67cdf0e10cSrcweir         {
6864b14621SArmin Le Grand             // when we have no given definition range, use the range of the given geometry
6964b14621SArmin Le Grand             // also for definition (simplest case)
7064b14621SArmin Le Grand             const basegfx::B2DRange aRange(basegfx::tools::getRange(rPolyPolygon));
7164b14621SArmin Le Grand 
7264b14621SArmin Le Grand             return createPolyPolygonFillPrimitive(
7364b14621SArmin Le Grand                 rPolyPolygon,
7464b14621SArmin Le Grand                 aRange,
7564b14621SArmin Le Grand                 rFill,
7664b14621SArmin Le Grand                 rFillGradient);
7764b14621SArmin Le Grand         }
7864b14621SArmin Le Grand 
createPolyPolygonFillPrimitive(const basegfx::B2DPolyPolygon & rPolyPolygon,const basegfx::B2DRange & rDefinitionRange,const attribute::SdrFillAttribute & rFill,const attribute::FillGradientAttribute & rFillGradient)7964b14621SArmin Le Grand         Primitive2DReference createPolyPolygonFillPrimitive(
8064b14621SArmin Le Grand             const basegfx::B2DPolyPolygon& rPolyPolygon,
8164b14621SArmin Le Grand             const basegfx::B2DRange& rDefinitionRange,
8264b14621SArmin Le Grand             const attribute::SdrFillAttribute& rFill,
8364b14621SArmin Le Grand             const attribute::FillGradientAttribute& rFillGradient)
8464b14621SArmin Le Grand         {
8564b14621SArmin Le Grand             if(basegfx::fTools::moreOrEqual(rFill.getTransparence(), 1.0))
8664b14621SArmin Le Grand             {
8764b14621SArmin Le Grand                 return Primitive2DReference();
8864b14621SArmin Le Grand             }
8964b14621SArmin Le Grand 
90cdf0e10cSrcweir             // prepare fully scaled polygon
91cdf0e10cSrcweir             BasePrimitive2D* pNewFillPrimitive = 0;
92cdf0e10cSrcweir 
93cdf0e10cSrcweir             if(!rFill.getGradient().isDefault())
94cdf0e10cSrcweir             {
9564b14621SArmin Le Grand                 pNewFillPrimitive = new PolyPolygonGradientPrimitive2D(
9664b14621SArmin Le Grand                     rPolyPolygon,
9764b14621SArmin Le Grand                     rDefinitionRange,
9864b14621SArmin Le Grand                     rFill.getGradient());
99cdf0e10cSrcweir             }
100cdf0e10cSrcweir             else if(!rFill.getHatch().isDefault())
101cdf0e10cSrcweir             {
10264b14621SArmin Le Grand                 pNewFillPrimitive = new PolyPolygonHatchPrimitive2D(
10364b14621SArmin Le Grand                     rPolyPolygon,
10464b14621SArmin Le Grand                     rDefinitionRange,
10564b14621SArmin Le Grand                     rFill.getColor(),
10664b14621SArmin Le Grand                     rFill.getHatch());
107cdf0e10cSrcweir             }
108035a2f44SArmin Le Grand             else if(!rFill.getFillGraphic().isDefault())
109cdf0e10cSrcweir             {
11064b14621SArmin Le Grand                 pNewFillPrimitive = new PolyPolygonGraphicPrimitive2D(
11164b14621SArmin Le Grand                     rPolyPolygon,
11264b14621SArmin Le Grand                     rDefinitionRange,
11364b14621SArmin Le Grand                     rFill.getFillGraphic().createFillGraphicAttribute(rDefinitionRange));
114cdf0e10cSrcweir             }
115cdf0e10cSrcweir             else
116cdf0e10cSrcweir             {
11764b14621SArmin Le Grand                 pNewFillPrimitive = new PolyPolygonColorPrimitive2D(
11864b14621SArmin Le Grand                     rPolyPolygon,
11964b14621SArmin Le Grand                     rFill.getColor());
120cdf0e10cSrcweir             }
121cdf0e10cSrcweir 
122cdf0e10cSrcweir             if(0.0 != rFill.getTransparence())
123cdf0e10cSrcweir             {
124cdf0e10cSrcweir                 // create simpleTransparencePrimitive, add created fill primitive
125cdf0e10cSrcweir                 const Primitive2DReference xRefA(pNewFillPrimitive);
126cdf0e10cSrcweir                 const Primitive2DSequence aContent(&xRefA, 1L);
127cdf0e10cSrcweir                 return Primitive2DReference(new UnifiedTransparencePrimitive2D(aContent, rFill.getTransparence()));
128cdf0e10cSrcweir             }
129cdf0e10cSrcweir             else if(!rFillGradient.isDefault())
130cdf0e10cSrcweir             {
131cdf0e10cSrcweir                 // create sequence with created fill primitive
132cdf0e10cSrcweir                 const Primitive2DReference xRefA(pNewFillPrimitive);
133cdf0e10cSrcweir                 const Primitive2DSequence aContent(&xRefA, 1L);
134cdf0e10cSrcweir 
135cdf0e10cSrcweir                 // create FillGradientPrimitive2D for transparence and add to new sequence
136cdf0e10cSrcweir                 // fillGradientPrimitive is enough here (compared to PolyPolygonGradientPrimitive2D) since float transparence will be masked anyways
13764b14621SArmin Le Grand                 const basegfx::B2DRange aRange(basegfx::tools::getRange(rPolyPolygon));
13856b35d86SArmin Le Grand                 const Primitive2DReference xRefB(
13956b35d86SArmin Le Grand                     new FillGradientPrimitive2D(
14056b35d86SArmin Le Grand                         aRange,
14156b35d86SArmin Le Grand                         rDefinitionRange,
14256b35d86SArmin Le Grand                         rFillGradient));
143cdf0e10cSrcweir                 const Primitive2DSequence aAlpha(&xRefB, 1L);
144cdf0e10cSrcweir 
145cdf0e10cSrcweir                 // create TransparencePrimitive2D using alpha and content
146cdf0e10cSrcweir                 return Primitive2DReference(new TransparencePrimitive2D(aContent, aAlpha));
147cdf0e10cSrcweir             }
148cdf0e10cSrcweir             else
149cdf0e10cSrcweir             {
150cdf0e10cSrcweir                 // add to decomposition
151cdf0e10cSrcweir                 return Primitive2DReference(pNewFillPrimitive);
152cdf0e10cSrcweir             }
153cdf0e10cSrcweir         }
154cdf0e10cSrcweir 
createPolygonLinePrimitive(const basegfx::B2DPolygon & rPolygon,const attribute::SdrLineAttribute & rLine,const attribute::SdrLineStartEndAttribute & rStroke)155cdf0e10cSrcweir         Primitive2DReference createPolygonLinePrimitive(
15664b14621SArmin Le Grand             const basegfx::B2DPolygon& rPolygon,
157cdf0e10cSrcweir             const attribute::SdrLineAttribute& rLine,
158cdf0e10cSrcweir             const attribute::SdrLineStartEndAttribute& rStroke)
159cdf0e10cSrcweir         {
160cdf0e10cSrcweir             // create line and stroke attribute
1615aaf853bSArmin Le Grand             const attribute::LineAttribute aLineAttribute(rLine.getColor(), rLine.getWidth(), rLine.getJoin(), rLine.getCap());
162cdf0e10cSrcweir             const attribute::StrokeAttribute aStrokeAttribute(rLine.getDotDashArray(), rLine.getFullDotDashLen());
163cdf0e10cSrcweir             BasePrimitive2D* pNewLinePrimitive = 0L;
164cdf0e10cSrcweir 
16564b14621SArmin Le Grand             if(!rPolygon.isClosed() && !rStroke.isDefault())
166cdf0e10cSrcweir             {
167cdf0e10cSrcweir                 attribute::LineStartEndAttribute aStart(rStroke.getStartWidth(), rStroke.getStartPolyPolygon(), rStroke.isStartCentered());
168cdf0e10cSrcweir                 attribute::LineStartEndAttribute aEnd(rStroke.getEndWidth(), rStroke.getEndPolyPolygon(), rStroke.isEndCentered());
169cdf0e10cSrcweir 
170cdf0e10cSrcweir                 // create data
17164b14621SArmin Le Grand                 pNewLinePrimitive = new PolygonStrokeArrowPrimitive2D(rPolygon, aLineAttribute, aStrokeAttribute, aStart, aEnd);
172cdf0e10cSrcweir             }
173cdf0e10cSrcweir             else
174cdf0e10cSrcweir             {
175cdf0e10cSrcweir                 // create data
17664b14621SArmin Le Grand                 pNewLinePrimitive = new PolygonStrokePrimitive2D(rPolygon, aLineAttribute, aStrokeAttribute);
177cdf0e10cSrcweir             }
178cdf0e10cSrcweir 
179cdf0e10cSrcweir             if(0.0 != rLine.getTransparence())
180cdf0e10cSrcweir             {
181cdf0e10cSrcweir                 // create simpleTransparencePrimitive, add created fill primitive
182cdf0e10cSrcweir                 const Primitive2DReference xRefA(pNewLinePrimitive);
183cdf0e10cSrcweir                 const Primitive2DSequence aContent(&xRefA, 1L);
184cdf0e10cSrcweir                 return Primitive2DReference(new UnifiedTransparencePrimitive2D(aContent, rLine.getTransparence()));
185cdf0e10cSrcweir             }
186cdf0e10cSrcweir             else
187cdf0e10cSrcweir             {
188cdf0e10cSrcweir                 // add to decomposition
189cdf0e10cSrcweir                 return Primitive2DReference(pNewLinePrimitive);
190cdf0e10cSrcweir             }
191cdf0e10cSrcweir         }
192cdf0e10cSrcweir 
createTextPrimitive(const basegfx::B2DPolyPolygon & rUnitPolyPolygon,const basegfx::B2DHomMatrix & rObjectTransform,const attribute::SdrTextAttribute & rText,const attribute::SdrLineAttribute & rStroke,bool bCellText,bool bWordWrap,bool bClipOnBounds)193cdf0e10cSrcweir         Primitive2DReference createTextPrimitive(
194cdf0e10cSrcweir             const basegfx::B2DPolyPolygon& rUnitPolyPolygon,
195cdf0e10cSrcweir             const basegfx::B2DHomMatrix& rObjectTransform,
196cdf0e10cSrcweir             const attribute::SdrTextAttribute& rText,
197cdf0e10cSrcweir             const attribute::SdrLineAttribute& rStroke,
198cdf0e10cSrcweir             bool bCellText,
199cdf0e10cSrcweir             bool bWordWrap,
200cdf0e10cSrcweir             bool bClipOnBounds)
201cdf0e10cSrcweir         {
202cdf0e10cSrcweir             basegfx::B2DHomMatrix aAnchorTransform(rObjectTransform);
203cdf0e10cSrcweir             SdrTextPrimitive2D* pNew = 0;
204cdf0e10cSrcweir 
205cdf0e10cSrcweir             if(rText.isContour())
206cdf0e10cSrcweir             {
207cdf0e10cSrcweir                 // contour text
208cdf0e10cSrcweir                 if(!rStroke.isDefault() && 0.0 != rStroke.getWidth())
209cdf0e10cSrcweir                 {
210cdf0e10cSrcweir                     // take line width into account and shrink contour polygon accordingly
211cdf0e10cSrcweir                     // decompose to get scale
212cdf0e10cSrcweir                     basegfx::B2DVector aScale, aTranslate;
213cdf0e10cSrcweir                     double fRotate, fShearX;
214cdf0e10cSrcweir                     rObjectTransform.decompose(aScale, aTranslate, fRotate, fShearX);
215cdf0e10cSrcweir 
216cdf0e10cSrcweir                     // scale outline to object's size to allow growing with value relative to that size
217cdf0e10cSrcweir                     // and also to keep aspect ratio
218cdf0e10cSrcweir                     basegfx::B2DPolyPolygon aScaledUnitPolyPolygon(rUnitPolyPolygon);
219cdf0e10cSrcweir                     aScaledUnitPolyPolygon.transform(basegfx::tools::createScaleB2DHomMatrix(
220cdf0e10cSrcweir                         fabs(aScale.getX()), fabs(aScale.getY())));
221cdf0e10cSrcweir 
222cdf0e10cSrcweir                     // grow the polygon. To shrink, use negative value (half width)
223cdf0e10cSrcweir                     aScaledUnitPolyPolygon = basegfx::tools::growInNormalDirection(aScaledUnitPolyPolygon, -(rStroke.getWidth() * 0.5));
224cdf0e10cSrcweir 
225cdf0e10cSrcweir                     // scale back to unit polygon
226cdf0e10cSrcweir                     aScaledUnitPolyPolygon.transform(basegfx::tools::createScaleB2DHomMatrix(
227cdf0e10cSrcweir                         0.0 != aScale.getX() ? 1.0 / aScale.getX() : 1.0,
228cdf0e10cSrcweir                         0.0 != aScale.getY() ? 1.0 / aScale.getY() : 1.0));
229cdf0e10cSrcweir 
230cdf0e10cSrcweir                     // create with unit polygon
231cdf0e10cSrcweir                     pNew = new SdrContourTextPrimitive2D(
232cdf0e10cSrcweir                         &rText.getSdrText(),
233cdf0e10cSrcweir                         rText.getOutlinerParaObject(),
234cdf0e10cSrcweir                         aScaledUnitPolyPolygon,
235cdf0e10cSrcweir                         rObjectTransform);
236cdf0e10cSrcweir                 }
237cdf0e10cSrcweir                 else
238cdf0e10cSrcweir                 {
239cdf0e10cSrcweir                     // create with unit polygon
240cdf0e10cSrcweir                     pNew = new SdrContourTextPrimitive2D(
241cdf0e10cSrcweir                         &rText.getSdrText(),
242cdf0e10cSrcweir                         rText.getOutlinerParaObject(),
243cdf0e10cSrcweir                         rUnitPolyPolygon,
244cdf0e10cSrcweir                         rObjectTransform);
245cdf0e10cSrcweir                 }
246cdf0e10cSrcweir             }
247cdf0e10cSrcweir             else if(!rText.getSdrFormTextAttribute().isDefault())
248cdf0e10cSrcweir             {
249cdf0e10cSrcweir                 // text on path, use scaled polygon
250cdf0e10cSrcweir                 basegfx::B2DPolyPolygon aScaledPolyPolygon(rUnitPolyPolygon);
251cdf0e10cSrcweir                 aScaledPolyPolygon.transform(rObjectTransform);
252cdf0e10cSrcweir                 pNew = new SdrPathTextPrimitive2D(
253cdf0e10cSrcweir                     &rText.getSdrText(),
254cdf0e10cSrcweir                     rText.getOutlinerParaObject(),
255cdf0e10cSrcweir                     aScaledPolyPolygon,
256cdf0e10cSrcweir                     rText.getSdrFormTextAttribute());
257cdf0e10cSrcweir             }
258cdf0e10cSrcweir             else
259cdf0e10cSrcweir             {
260cdf0e10cSrcweir                 // rObjectTransform is the whole SdrObject transformation from unit rectangle
261cdf0e10cSrcweir                 // to it's size and position. Decompose to allow working with single values.
262cdf0e10cSrcweir                 basegfx::B2DVector aScale, aTranslate;
263cdf0e10cSrcweir                 double fRotate, fShearX;
264cdf0e10cSrcweir                 rObjectTransform.decompose(aScale, aTranslate, fRotate, fShearX);
265cdf0e10cSrcweir 
266cdf0e10cSrcweir                 // extract mirroring
267cdf0e10cSrcweir                 const bool bMirrorX(basegfx::fTools::less(aScale.getX(), 0.0));
268cdf0e10cSrcweir                 const bool bMirrorY(basegfx::fTools::less(aScale.getY(), 0.0));
269cdf0e10cSrcweir                 aScale = basegfx::absolute(aScale);
270cdf0e10cSrcweir 
271*54c55739SJohn Bampton                 // Get the real size, since polygon outline and scale
272cdf0e10cSrcweir                 // from the object transformation may vary (e.g. ellipse segments)
273cdf0e10cSrcweir                 basegfx::B2DHomMatrix aJustScaleTransform;
274cdf0e10cSrcweir                 aJustScaleTransform.set(0, 0, aScale.getX());
275cdf0e10cSrcweir                 aJustScaleTransform.set(1, 1, aScale.getY());
276cdf0e10cSrcweir                 basegfx::B2DPolyPolygon aScaledUnitPolyPolygon(rUnitPolyPolygon);
277cdf0e10cSrcweir                 aScaledUnitPolyPolygon.transform(aJustScaleTransform);
278cdf0e10cSrcweir                 const basegfx::B2DRange aSnapRange(basegfx::tools::getRange(aScaledUnitPolyPolygon));
279cdf0e10cSrcweir 
280cdf0e10cSrcweir                 // create a range describing the wanted text position and size (aTextAnchorRange). This
281cdf0e10cSrcweir                 // means to use the text distance values here
282cdf0e10cSrcweir                 const basegfx::B2DPoint aTopLeft(aSnapRange.getMinX() + rText.getTextLeftDistance(), aSnapRange.getMinY() + rText.getTextUpperDistance());
283cdf0e10cSrcweir                 const basegfx::B2DPoint aBottomRight(aSnapRange.getMaxX() - rText.getTextRightDistance(), aSnapRange.getMaxY() - rText.getTextLowerDistance());
284cdf0e10cSrcweir                 basegfx::B2DRange aTextAnchorRange;
285cdf0e10cSrcweir                 aTextAnchorRange.expand(aTopLeft);
286cdf0e10cSrcweir                 aTextAnchorRange.expand(aBottomRight);
287cdf0e10cSrcweir 
288cdf0e10cSrcweir                 // now create a transformation from this basic range (aTextAnchorRange)
289e0fd3963SArmin Le Grand                 // #121494# if we have no scale use at least 1.0 to have a carrier e.g. for
290e0fd3963SArmin Le Grand                 // mirror values, else these will get lost
291cdf0e10cSrcweir                 aAnchorTransform = basegfx::tools::createScaleTranslateB2DHomMatrix(
292e0fd3963SArmin Le Grand                     basegfx::fTools::equalZero(aTextAnchorRange.getWidth()) ? 1.0 : aTextAnchorRange.getWidth(),
293e0fd3963SArmin Le Grand                     basegfx::fTools::equalZero(aTextAnchorRange.getHeight()) ? 1.0 : aTextAnchorRange.getHeight(),
294cdf0e10cSrcweir                     aTextAnchorRange.getMinX(), aTextAnchorRange.getMinY());
295cdf0e10cSrcweir 
296cdf0e10cSrcweir                 // apply mirroring
297cdf0e10cSrcweir                 aAnchorTransform.scale(bMirrorX ? -1.0 : 1.0, bMirrorY ? -1.0 : 1.0);
298cdf0e10cSrcweir 
299cdf0e10cSrcweir                 // apply object's other transforms
300cdf0e10cSrcweir                 aAnchorTransform = basegfx::tools::createShearXRotateTranslateB2DHomMatrix(fShearX, fRotate, aTranslate)
301cdf0e10cSrcweir                     * aAnchorTransform;
302cdf0e10cSrcweir 
303cdf0e10cSrcweir                 if(rText.isFitToSize())
304cdf0e10cSrcweir                 {
305cdf0e10cSrcweir                     // streched text in range
306cdf0e10cSrcweir                     pNew = new SdrStretchTextPrimitive2D(
307cdf0e10cSrcweir                         &rText.getSdrText(),
308cdf0e10cSrcweir                         rText.getOutlinerParaObject(),
309cdf0e10cSrcweir                         aAnchorTransform,
310cdf0e10cSrcweir                         rText.isFixedCellHeight());
311cdf0e10cSrcweir                 }
312cdf0e10cSrcweir                 else // text in range
313cdf0e10cSrcweir                 {
314cdf0e10cSrcweir                     // build new primitive
315cdf0e10cSrcweir                     pNew = new SdrBlockTextPrimitive2D(
316cdf0e10cSrcweir                         &rText.getSdrText(),
317cdf0e10cSrcweir                         rText.getOutlinerParaObject(),
318cdf0e10cSrcweir                         aAnchorTransform,
319cdf0e10cSrcweir                         rText.getSdrTextHorzAdjust(),
320cdf0e10cSrcweir                         rText.getSdrTextVertAdjust(),
321cdf0e10cSrcweir                         rText.isFixedCellHeight(),
322cdf0e10cSrcweir                         rText.isScroll(),
323cdf0e10cSrcweir                         bCellText,
324cdf0e10cSrcweir                         bWordWrap,
325cdf0e10cSrcweir                         bClipOnBounds);
326cdf0e10cSrcweir                 }
327cdf0e10cSrcweir             }
328cdf0e10cSrcweir 
329cdf0e10cSrcweir             OSL_ENSURE(pNew != 0, "createTextPrimitive: no text primitive created (!)");
330cdf0e10cSrcweir 
331cdf0e10cSrcweir             if(rText.isBlink())
332cdf0e10cSrcweir             {
333cdf0e10cSrcweir                 // prepare animation and primitive list
334cdf0e10cSrcweir                 drawinglayer::animation::AnimationEntryList aAnimationList;
335cdf0e10cSrcweir                 rText.getBlinkTextTiming(aAnimationList);
336cdf0e10cSrcweir 
337cdf0e10cSrcweir                 if(0.0 != aAnimationList.getDuration())
338cdf0e10cSrcweir                 {
339cdf0e10cSrcweir                     // create content sequence
340cdf0e10cSrcweir                     const Primitive2DReference xRefA(pNew);
341cdf0e10cSrcweir                     const Primitive2DSequence aContent(&xRefA, 1L);
342cdf0e10cSrcweir 
343cdf0e10cSrcweir                     // create and add animated switch primitive
344cdf0e10cSrcweir                     return Primitive2DReference(new AnimatedBlinkPrimitive2D(aAnimationList, aContent, true));
345cdf0e10cSrcweir                 }
346cdf0e10cSrcweir                 else
347cdf0e10cSrcweir                 {
348cdf0e10cSrcweir                     // add to decomposition
349cdf0e10cSrcweir                     return Primitive2DReference(pNew);
350cdf0e10cSrcweir                 }
351cdf0e10cSrcweir             }
352cdf0e10cSrcweir 
353cdf0e10cSrcweir             if(rText.isScroll())
354cdf0e10cSrcweir             {
355cdf0e10cSrcweir                 // suppress scroll when FontWork
356cdf0e10cSrcweir                 if(rText.getSdrFormTextAttribute().isDefault())
357cdf0e10cSrcweir                 {
358cdf0e10cSrcweir                     // get scroll direction
359cdf0e10cSrcweir                     const SdrTextAniDirection eDirection(rText.getSdrText().GetObject().GetTextAniDirection());
360cdf0e10cSrcweir                     const bool bHorizontal(SDRTEXTANI_LEFT == eDirection || SDRTEXTANI_RIGHT == eDirection);
361cdf0e10cSrcweir 
362cdf0e10cSrcweir                     // decompose to get separated values for the scroll box
363cdf0e10cSrcweir                     basegfx::B2DVector aScale, aTranslate;
364cdf0e10cSrcweir                     double fRotate, fShearX;
365cdf0e10cSrcweir                     aAnchorTransform.decompose(aScale, aTranslate, fRotate, fShearX);
366cdf0e10cSrcweir 
367cdf0e10cSrcweir                     // build transform from scaled only to full AnchorTransform and inverse
368cdf0e10cSrcweir                     const basegfx::B2DHomMatrix aSRT(basegfx::tools::createShearXRotateTranslateB2DHomMatrix(
369cdf0e10cSrcweir                         fShearX, fRotate, aTranslate));
370cdf0e10cSrcweir                     basegfx::B2DHomMatrix aISRT(aSRT);
371cdf0e10cSrcweir                     aISRT.invert();
372cdf0e10cSrcweir 
373cdf0e10cSrcweir                     // bring the primitive back to scaled only and get scaled range, create new clone for this
374cdf0e10cSrcweir                     SdrTextPrimitive2D* pNew2 = pNew->createTransformedClone(aISRT);
375cdf0e10cSrcweir                     OSL_ENSURE(pNew2, "createTextPrimitive: Could not create transformed clone of text primitive (!)");
376cdf0e10cSrcweir                     delete pNew;
377cdf0e10cSrcweir                     pNew = pNew2;
378cdf0e10cSrcweir 
379cdf0e10cSrcweir                     // create neutral geometry::ViewInformation2D for local range and decompose calls. This is okay
380cdf0e10cSrcweir                     // since the decompose is view-independent
381cdf0e10cSrcweir                     const uno::Sequence< beans::PropertyValue > xViewParameters;
382cdf0e10cSrcweir                     geometry::ViewInformation2D aViewInformation2D(xViewParameters);
383cdf0e10cSrcweir 
384cdf0e10cSrcweir                     // get range
385cdf0e10cSrcweir                     const basegfx::B2DRange aScaledRange(pNew->getB2DRange(aViewInformation2D));
386cdf0e10cSrcweir 
387cdf0e10cSrcweir                     // create left outside and right outside transformations. Also take care
388cdf0e10cSrcweir                     // of the clip rectangle
389cdf0e10cSrcweir                     basegfx::B2DHomMatrix aLeft, aRight;
390cdf0e10cSrcweir                     basegfx::B2DPoint aClipTopLeft(0.0, 0.0);
391cdf0e10cSrcweir                     basegfx::B2DPoint aClipBottomRight(aScale.getX(), aScale.getY());
392cdf0e10cSrcweir 
393cdf0e10cSrcweir                     if(bHorizontal)
394cdf0e10cSrcweir                     {
395cdf0e10cSrcweir                         aClipTopLeft.setY(aScaledRange.getMinY());
396cdf0e10cSrcweir                         aClipBottomRight.setY(aScaledRange.getMaxY());
397cdf0e10cSrcweir                         aLeft.translate(-aScaledRange.getMaxX(), 0.0);
398cdf0e10cSrcweir                         aRight.translate(aScale.getX() - aScaledRange.getMinX(), 0.0);
399cdf0e10cSrcweir                     }
400cdf0e10cSrcweir                     else
401cdf0e10cSrcweir                     {
402cdf0e10cSrcweir                         aClipTopLeft.setX(aScaledRange.getMinX());
403cdf0e10cSrcweir                         aClipBottomRight.setX(aScaledRange.getMaxX());
404cdf0e10cSrcweir                         aLeft.translate(0.0, -aScaledRange.getMaxY());
405cdf0e10cSrcweir                         aRight.translate(0.0, aScale.getY() - aScaledRange.getMinY());
406cdf0e10cSrcweir                     }
407cdf0e10cSrcweir 
408cdf0e10cSrcweir                     aLeft *= aSRT;
409cdf0e10cSrcweir                     aRight *= aSRT;
410cdf0e10cSrcweir 
411cdf0e10cSrcweir                     // prepare animation list
412cdf0e10cSrcweir                     drawinglayer::animation::AnimationEntryList aAnimationList;
413cdf0e10cSrcweir 
414cdf0e10cSrcweir                     if(bHorizontal)
415cdf0e10cSrcweir                     {
416cdf0e10cSrcweir                         rText.getScrollTextTiming(aAnimationList, aScale.getX(), aScaledRange.getWidth());
417cdf0e10cSrcweir                     }
418cdf0e10cSrcweir                     else
419cdf0e10cSrcweir                     {
420cdf0e10cSrcweir                         rText.getScrollTextTiming(aAnimationList, aScale.getY(), aScaledRange.getHeight());
421cdf0e10cSrcweir                     }
422cdf0e10cSrcweir 
423cdf0e10cSrcweir                     if(0.0 != aAnimationList.getDuration())
424cdf0e10cSrcweir                     {
425cdf0e10cSrcweir                         // create a new Primitive2DSequence containing the animated text in it's scaled only state.
426cdf0e10cSrcweir                         // use the decomposition to force to simple text primitives, those will no longer
427cdf0e10cSrcweir                         // need the outliner for formatting (alternatively it is also possible to just add
428cdf0e10cSrcweir                         // pNew to aNewPrimitiveSequence)
429cdf0e10cSrcweir                         Primitive2DSequence aAnimSequence(pNew->get2DDecomposition(aViewInformation2D));
430cdf0e10cSrcweir                         delete pNew;
431cdf0e10cSrcweir 
432cdf0e10cSrcweir                         // create a new animatedInterpolatePrimitive and add it
433cdf0e10cSrcweir                         std::vector< basegfx::B2DHomMatrix > aMatrixStack;
434cdf0e10cSrcweir                         aMatrixStack.push_back(aLeft);
435cdf0e10cSrcweir                         aMatrixStack.push_back(aRight);
436cdf0e10cSrcweir                         const Primitive2DReference xRefA(new AnimatedInterpolatePrimitive2D(aMatrixStack, aAnimationList, aAnimSequence, true));
437cdf0e10cSrcweir                         const Primitive2DSequence aContent(&xRefA, 1L);
438cdf0e10cSrcweir 
439cdf0e10cSrcweir                         // scrolling needs an encapsulating clipping primitive
440cdf0e10cSrcweir                         const basegfx::B2DRange aClipRange(aClipTopLeft, aClipBottomRight);
441cdf0e10cSrcweir                         basegfx::B2DPolygon aClipPolygon(basegfx::tools::createPolygonFromRect(aClipRange));
442cdf0e10cSrcweir                         aClipPolygon.transform(aSRT);
443cdf0e10cSrcweir                         return Primitive2DReference(new MaskPrimitive2D(basegfx::B2DPolyPolygon(aClipPolygon), aContent));
444cdf0e10cSrcweir                     }
445cdf0e10cSrcweir                     else
446cdf0e10cSrcweir                     {
447cdf0e10cSrcweir                         // add to decomposition
448cdf0e10cSrcweir                         return Primitive2DReference(pNew);
449cdf0e10cSrcweir                     }
450cdf0e10cSrcweir                 }
451cdf0e10cSrcweir             }
452cdf0e10cSrcweir 
453cdf0e10cSrcweir             if(rText.isInEditMode())
454cdf0e10cSrcweir             {
455cdf0e10cSrcweir                 // #i97628#
456cdf0e10cSrcweir                 // encapsulate with TextHierarchyEditPrimitive2D to allow renderers
457cdf0e10cSrcweir                 // to suppress actively edited content if needed
458cdf0e10cSrcweir                 const Primitive2DReference xRefA(pNew);
459cdf0e10cSrcweir                 const Primitive2DSequence aContent(&xRefA, 1L);
460cdf0e10cSrcweir 
461cdf0e10cSrcweir                 // create and add TextHierarchyEditPrimitive2D primitive
462cdf0e10cSrcweir                 return Primitive2DReference(new TextHierarchyEditPrimitive2D(aContent));
463cdf0e10cSrcweir             }
464cdf0e10cSrcweir             else
465cdf0e10cSrcweir             {
466cdf0e10cSrcweir                 // add to decomposition
467cdf0e10cSrcweir                 return Primitive2DReference(pNew);
468cdf0e10cSrcweir             }
469cdf0e10cSrcweir         }
470cdf0e10cSrcweir 
createEmbeddedShadowPrimitive(const Primitive2DSequence & rContent,const attribute::SdrShadowAttribute & rShadow)471cdf0e10cSrcweir         Primitive2DSequence createEmbeddedShadowPrimitive(
472cdf0e10cSrcweir             const Primitive2DSequence& rContent,
473cdf0e10cSrcweir             const attribute::SdrShadowAttribute& rShadow)
474cdf0e10cSrcweir         {
475cdf0e10cSrcweir             if(rContent.hasElements())
476cdf0e10cSrcweir             {
477cdf0e10cSrcweir                 Primitive2DSequence aRetval(2);
478cdf0e10cSrcweir                 basegfx::B2DHomMatrix aShadowOffset;
479cdf0e10cSrcweir 
480cdf0e10cSrcweir                 // prepare shadow offset
481cdf0e10cSrcweir                 aShadowOffset.set(0, 2, rShadow.getOffset().getX());
482cdf0e10cSrcweir                 aShadowOffset.set(1, 2, rShadow.getOffset().getY());
483cdf0e10cSrcweir 
484cdf0e10cSrcweir                 // create shadow primitive and add content
485cdf0e10cSrcweir                 aRetval[0] = Primitive2DReference(
486cdf0e10cSrcweir                     new ShadowPrimitive2D(
487cdf0e10cSrcweir                         aShadowOffset,
488cdf0e10cSrcweir                         rShadow.getColor(),
489cdf0e10cSrcweir                         rContent));
490cdf0e10cSrcweir 
491cdf0e10cSrcweir                 if(0.0 != rShadow.getTransparence())
492cdf0e10cSrcweir                 {
493cdf0e10cSrcweir                     // create SimpleTransparencePrimitive2D
494cdf0e10cSrcweir                     const Primitive2DSequence aTempContent(&aRetval[0], 1);
495cdf0e10cSrcweir 
496cdf0e10cSrcweir                     aRetval[0] = Primitive2DReference(
497cdf0e10cSrcweir                         new UnifiedTransparencePrimitive2D(
498cdf0e10cSrcweir                             aTempContent,
499cdf0e10cSrcweir                             rShadow.getTransparence()));
500cdf0e10cSrcweir                 }
501cdf0e10cSrcweir 
502cdf0e10cSrcweir                 aRetval[1] = Primitive2DReference(new GroupPrimitive2D(rContent));
503cdf0e10cSrcweir                 return aRetval;
504cdf0e10cSrcweir             }
505cdf0e10cSrcweir             else
506cdf0e10cSrcweir             {
507cdf0e10cSrcweir                 return rContent;
508cdf0e10cSrcweir             }
509cdf0e10cSrcweir         }
510cdf0e10cSrcweir     } // end of namespace primitive2d
511cdf0e10cSrcweir } // end of namespace drawinglayer
512cdf0e10cSrcweir 
513cdf0e10cSrcweir //////////////////////////////////////////////////////////////////////////////
514cdf0e10cSrcweir // eof
515