xref: /trunk/main/svx/source/svdraw/svdotextdecomposition.cxx (revision 85122fc3aed302e23add2a54c7564ef22b646162)
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 
22cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove
23cdf0e10cSrcweir #include "precompiled_svx.hxx"
24cdf0e10cSrcweir 
25cdf0e10cSrcweir #include <svx/svdotext.hxx>
26cdf0e10cSrcweir #include <svx/svdoutl.hxx>
27cdf0e10cSrcweir #include <basegfx/vector/b2dvector.hxx>
28cdf0e10cSrcweir #include <svx/sdr/primitive2d/sdrtextprimitive2d.hxx>
29cdf0e10cSrcweir #include <drawinglayer/primitive2d/textprimitive2d.hxx>
30cdf0e10cSrcweir #include <drawinglayer/primitive2d/textdecoratedprimitive2d.hxx>
31cdf0e10cSrcweir #include <basegfx/range/b2drange.hxx>
32cdf0e10cSrcweir #include <editeng/editstat.hxx>
33cdf0e10cSrcweir #include <vcl/salbtype.hxx>
34cdf0e10cSrcweir #include <svx/sdtfchim.hxx>
35cdf0e10cSrcweir #include <svl/itemset.hxx>
36cdf0e10cSrcweir #include <basegfx/polygon/b2dpolygontools.hxx>
37cdf0e10cSrcweir #include <basegfx/polygon/b2dpolygon.hxx>
38cdf0e10cSrcweir #include <drawinglayer/animation/animationtiming.hxx>
39cdf0e10cSrcweir #include <basegfx/color/bcolor.hxx>
40cdf0e10cSrcweir #include <vcl/svapp.hxx>
41cdf0e10cSrcweir #include <editeng/eeitemid.hxx>
42cdf0e10cSrcweir #include <editeng/escpitem.hxx>
43cdf0e10cSrcweir #include <editeng/svxenum.hxx>
44cdf0e10cSrcweir #include <editeng/flditem.hxx>
45cdf0e10cSrcweir #include <drawinglayer/primitive2d/texthierarchyprimitive2d.hxx>
46cdf0e10cSrcweir #include <vcl/metaact.hxx>
47cdf0e10cSrcweir #include <drawinglayer/primitive2d/wrongspellprimitive2d.hxx>
48cdf0e10cSrcweir #include <drawinglayer/primitive2d/graphicprimitive2d.hxx>
49cdf0e10cSrcweir #include <drawinglayer/primitive2d/textlayoutdevice.hxx>
50cdf0e10cSrcweir #include <svx/unoapi.hxx>
51cdf0e10cSrcweir #include <drawinglayer/geometry/viewinformation2d.hxx>
52cdf0e10cSrcweir #include <editeng/outlobj.hxx>
53cdf0e10cSrcweir #include <basegfx/matrix/b2dhommatrixtools.hxx>
54cdf0e10cSrcweir 
55cdf0e10cSrcweir //////////////////////////////////////////////////////////////////////////////
56cdf0e10cSrcweir // helpers
57cdf0e10cSrcweir 
58cdf0e10cSrcweir namespace
59cdf0e10cSrcweir {
impConvertVectorToPrimitive2DSequence(const std::vector<drawinglayer::primitive2d::BasePrimitive2D * > & rPrimitiveVector)60cdf0e10cSrcweir     drawinglayer::primitive2d::Primitive2DSequence impConvertVectorToPrimitive2DSequence(const std::vector< drawinglayer::primitive2d::BasePrimitive2D* >& rPrimitiveVector)
61cdf0e10cSrcweir     {
62cdf0e10cSrcweir         const sal_Int32 nCount(rPrimitiveVector.size());
63cdf0e10cSrcweir         drawinglayer::primitive2d::Primitive2DSequence aRetval(nCount);
64cdf0e10cSrcweir 
65cdf0e10cSrcweir         for(sal_Int32 a(0L); a < nCount; a++)
66cdf0e10cSrcweir         {
67cdf0e10cSrcweir             aRetval[a] = drawinglayer::primitive2d::Primitive2DReference(rPrimitiveVector[a]);
68cdf0e10cSrcweir         }
69cdf0e10cSrcweir 
70cdf0e10cSrcweir         return aRetval;
71cdf0e10cSrcweir     }
72cdf0e10cSrcweir 
73cdf0e10cSrcweir     class impTextBreakupHandler
74cdf0e10cSrcweir     {
75cdf0e10cSrcweir     private:
76cdf0e10cSrcweir         std::vector< drawinglayer::primitive2d::BasePrimitive2D* >  maTextPortionPrimitives;
77cdf0e10cSrcweir         std::vector< drawinglayer::primitive2d::BasePrimitive2D* >  maLinePrimitives;
78cdf0e10cSrcweir         std::vector< drawinglayer::primitive2d::BasePrimitive2D* >  maParagraphPrimitives;
79cdf0e10cSrcweir 
80cdf0e10cSrcweir         SdrOutliner&                                                mrOutliner;
81cdf0e10cSrcweir         basegfx::B2DHomMatrix                                       maNewTransformA;
82cdf0e10cSrcweir         basegfx::B2DHomMatrix                                       maNewTransformB;
83cdf0e10cSrcweir 
84cdf0e10cSrcweir         // the visible area for contour text decomposition
85cdf0e10cSrcweir         basegfx::B2DVector                                          maScale;
86cdf0e10cSrcweir 
87cdf0e10cSrcweir         // #SJ# ClipRange for BlockText decomposition; only text portions completely
88cdf0e10cSrcweir         // inside are to be accepted, so this is different from geometric clipping
89cdf0e10cSrcweir         // (which would allow e.g. upper parts of portions to remain). Only used for
90cdf0e10cSrcweir         // BlockText (see there)
91cdf0e10cSrcweir         basegfx::B2DRange                                           maClipRange;
92cdf0e10cSrcweir 
93cdf0e10cSrcweir         DECL_LINK(decomposeContourTextPrimitive, DrawPortionInfo* );
94cdf0e10cSrcweir         DECL_LINK(decomposeBlockTextPrimitive, DrawPortionInfo* );
95cdf0e10cSrcweir         DECL_LINK(decomposeStretchTextPrimitive, DrawPortionInfo* );
96cdf0e10cSrcweir 
97cdf0e10cSrcweir         DECL_LINK(decomposeContourBulletPrimitive, DrawBulletInfo* );
98cdf0e10cSrcweir         DECL_LINK(decomposeBlockBulletPrimitive, DrawBulletInfo* );
99cdf0e10cSrcweir         DECL_LINK(decomposeStretchBulletPrimitive, DrawBulletInfo* );
100cdf0e10cSrcweir 
101cdf0e10cSrcweir         bool impIsUnderlineAbove(const Font& rFont) const;
102cdf0e10cSrcweir         void impCreateTextPortionPrimitive(const DrawPortionInfo& rInfo);
103cdf0e10cSrcweir         drawinglayer::primitive2d::BasePrimitive2D* impCheckFieldPrimitive(drawinglayer::primitive2d::BasePrimitive2D* pPrimitive, const DrawPortionInfo& rInfo) const;
104cdf0e10cSrcweir         void impFlushTextPortionPrimitivesToLinePrimitives();
105cdf0e10cSrcweir         void impFlushLinePrimitivesToParagraphPrimitives();
106cdf0e10cSrcweir         void impHandleDrawPortionInfo(const DrawPortionInfo& rInfo);
107cdf0e10cSrcweir         void impHandleDrawBulletInfo(const DrawBulletInfo& rInfo);
108cdf0e10cSrcweir 
109cdf0e10cSrcweir     public:
impTextBreakupHandler(SdrOutliner & rOutliner)110cdf0e10cSrcweir         impTextBreakupHandler(SdrOutliner& rOutliner)
111cdf0e10cSrcweir         :   maTextPortionPrimitives(),
112cdf0e10cSrcweir             maLinePrimitives(),
113cdf0e10cSrcweir             maParagraphPrimitives(),
114cdf0e10cSrcweir             mrOutliner(rOutliner),
115cdf0e10cSrcweir             maNewTransformA(),
116cdf0e10cSrcweir             maNewTransformB(),
117cdf0e10cSrcweir             maScale(),
118cdf0e10cSrcweir             maClipRange()
119cdf0e10cSrcweir         {
120cdf0e10cSrcweir         }
121cdf0e10cSrcweir 
decomposeContourTextPrimitive(const basegfx::B2DHomMatrix & rNewTransformA,const basegfx::B2DHomMatrix & rNewTransformB,const basegfx::B2DVector & rScale)122cdf0e10cSrcweir         void decomposeContourTextPrimitive(const basegfx::B2DHomMatrix& rNewTransformA, const basegfx::B2DHomMatrix& rNewTransformB, const basegfx::B2DVector& rScale)
123cdf0e10cSrcweir         {
124cdf0e10cSrcweir             maScale = rScale;
125cdf0e10cSrcweir             maNewTransformA = rNewTransformA;
126cdf0e10cSrcweir             maNewTransformB = rNewTransformB;
127cdf0e10cSrcweir             mrOutliner.SetDrawPortionHdl(LINK(this, impTextBreakupHandler, decomposeContourTextPrimitive));
128cdf0e10cSrcweir             mrOutliner.SetDrawBulletHdl(LINK(this, impTextBreakupHandler, decomposeContourBulletPrimitive));
129cdf0e10cSrcweir             mrOutliner.StripPortions();
130cdf0e10cSrcweir             mrOutliner.SetDrawPortionHdl(Link());
131cdf0e10cSrcweir             mrOutliner.SetDrawBulletHdl(Link());
132cdf0e10cSrcweir         }
133cdf0e10cSrcweir 
decomposeBlockTextPrimitive(const basegfx::B2DHomMatrix & rNewTransformA,const basegfx::B2DHomMatrix & rNewTransformB,const basegfx::B2DRange & rClipRange)134cdf0e10cSrcweir         void decomposeBlockTextPrimitive(
135cdf0e10cSrcweir             const basegfx::B2DHomMatrix& rNewTransformA,
136cdf0e10cSrcweir             const basegfx::B2DHomMatrix& rNewTransformB,
137cdf0e10cSrcweir             const basegfx::B2DRange& rClipRange)
138cdf0e10cSrcweir         {
139cdf0e10cSrcweir             maNewTransformA = rNewTransformA;
140cdf0e10cSrcweir             maNewTransformB = rNewTransformB;
141cdf0e10cSrcweir             maClipRange = rClipRange;
142cdf0e10cSrcweir             mrOutliner.SetDrawPortionHdl(LINK(this, impTextBreakupHandler, decomposeBlockTextPrimitive));
143cdf0e10cSrcweir             mrOutliner.SetDrawBulletHdl(LINK(this, impTextBreakupHandler, decomposeBlockBulletPrimitive));
144cdf0e10cSrcweir             mrOutliner.StripPortions();
145cdf0e10cSrcweir             mrOutliner.SetDrawPortionHdl(Link());
146cdf0e10cSrcweir             mrOutliner.SetDrawBulletHdl(Link());
147cdf0e10cSrcweir         }
148cdf0e10cSrcweir 
decomposeStretchTextPrimitive(const basegfx::B2DHomMatrix & rNewTransformA,const basegfx::B2DHomMatrix & rNewTransformB)149cdf0e10cSrcweir         void decomposeStretchTextPrimitive(const basegfx::B2DHomMatrix& rNewTransformA, const basegfx::B2DHomMatrix& rNewTransformB)
150cdf0e10cSrcweir         {
151cdf0e10cSrcweir             maNewTransformA = rNewTransformA;
152cdf0e10cSrcweir             maNewTransformB = rNewTransformB;
153cdf0e10cSrcweir             mrOutliner.SetDrawPortionHdl(LINK(this, impTextBreakupHandler, decomposeStretchTextPrimitive));
154cdf0e10cSrcweir             mrOutliner.SetDrawBulletHdl(LINK(this, impTextBreakupHandler, decomposeStretchBulletPrimitive));
155cdf0e10cSrcweir             mrOutliner.StripPortions();
156cdf0e10cSrcweir             mrOutliner.SetDrawPortionHdl(Link());
157cdf0e10cSrcweir             mrOutliner.SetDrawBulletHdl(Link());
158cdf0e10cSrcweir         }
159cdf0e10cSrcweir 
160cdf0e10cSrcweir         drawinglayer::primitive2d::Primitive2DSequence getPrimitive2DSequence();
161cdf0e10cSrcweir     };
162cdf0e10cSrcweir 
impIsUnderlineAbove(const Font & rFont) const163cdf0e10cSrcweir     bool impTextBreakupHandler::impIsUnderlineAbove(const Font& rFont) const
164cdf0e10cSrcweir     {
165cdf0e10cSrcweir         if(!rFont.IsVertical())
166cdf0e10cSrcweir         {
167cdf0e10cSrcweir             return false;
168cdf0e10cSrcweir         }
169cdf0e10cSrcweir 
170cdf0e10cSrcweir         if((LANGUAGE_JAPANESE == rFont.GetLanguage()) || (LANGUAGE_JAPANESE == rFont.GetCJKContextLanguage()))
171cdf0e10cSrcweir         {
172cdf0e10cSrcweir             // the underline is right for Japanese only
173cdf0e10cSrcweir             return true;
174cdf0e10cSrcweir         }
175cdf0e10cSrcweir 
176cdf0e10cSrcweir         return false;
177cdf0e10cSrcweir     }
178cdf0e10cSrcweir 
impCreateTextPortionPrimitive(const DrawPortionInfo & rInfo)179cdf0e10cSrcweir     void impTextBreakupHandler::impCreateTextPortionPrimitive(const DrawPortionInfo& rInfo)
180cdf0e10cSrcweir     {
181cdf0e10cSrcweir         if(rInfo.mrText.Len() && rInfo.mnTextLen)
182cdf0e10cSrcweir         {
183cdf0e10cSrcweir             basegfx::B2DVector aFontScaling;
184cdf0e10cSrcweir             drawinglayer::attribute::FontAttribute aFontAttribute(
185cdf0e10cSrcweir                 drawinglayer::primitive2d::getFontAttributeFromVclFont(
186cdf0e10cSrcweir                     aFontScaling,
187cdf0e10cSrcweir                     rInfo.mrFont,
188cdf0e10cSrcweir                     rInfo.IsRTL(),
189cdf0e10cSrcweir                     false));
190cdf0e10cSrcweir             basegfx::B2DHomMatrix aNewTransform;
191cdf0e10cSrcweir 
192cdf0e10cSrcweir             // add font scale to new transform
193cdf0e10cSrcweir             aNewTransform.scale(aFontScaling.getX(), aFontScaling.getY());
194cdf0e10cSrcweir 
195cdf0e10cSrcweir             // look for proportional font scaling, evtl scale accordingly
196cdf0e10cSrcweir             if(100 != rInfo.mrFont.GetPropr())
197cdf0e10cSrcweir             {
198cdf0e10cSrcweir                 const double fFactor(rInfo.mrFont.GetPropr() / 100.0);
199cdf0e10cSrcweir                 aNewTransform.scale(fFactor, fFactor);
200cdf0e10cSrcweir             }
201cdf0e10cSrcweir 
202cdf0e10cSrcweir             // apply font rotate
203cdf0e10cSrcweir             if(rInfo.mrFont.GetOrientation())
204cdf0e10cSrcweir             {
205cdf0e10cSrcweir                 aNewTransform.rotate(-rInfo.mrFont.GetOrientation() * F_PI1800);
206cdf0e10cSrcweir             }
207cdf0e10cSrcweir 
208cdf0e10cSrcweir             // look for escapement, evtl translate accordingly
209cdf0e10cSrcweir             if(rInfo.mrFont.GetEscapement())
210cdf0e10cSrcweir             {
211cdf0e10cSrcweir                 sal_Int16 nEsc(rInfo.mrFont.GetEscapement());
212cdf0e10cSrcweir 
213cdf0e10cSrcweir                 if(DFLT_ESC_AUTO_SUPER == nEsc)
214cdf0e10cSrcweir                 {
215cdf0e10cSrcweir                     nEsc = 33;
216cdf0e10cSrcweir                 }
217cdf0e10cSrcweir                 else if(DFLT_ESC_AUTO_SUB == nEsc)
218cdf0e10cSrcweir                 {
219cdf0e10cSrcweir                     nEsc = -20;
220cdf0e10cSrcweir                 }
221cdf0e10cSrcweir 
222cdf0e10cSrcweir                 if(nEsc > 100)
223cdf0e10cSrcweir                 {
224cdf0e10cSrcweir                     nEsc = 100;
225cdf0e10cSrcweir                 }
226cdf0e10cSrcweir                 else if(nEsc < -100)
227cdf0e10cSrcweir                 {
228cdf0e10cSrcweir                     nEsc = -100;
229cdf0e10cSrcweir                 }
230cdf0e10cSrcweir 
231cdf0e10cSrcweir                 const double fEscapement(nEsc / -100.0);
232cdf0e10cSrcweir                 aNewTransform.translate(0.0, fEscapement * aFontScaling.getY());
233cdf0e10cSrcweir             }
234cdf0e10cSrcweir 
235cdf0e10cSrcweir             // apply transformA
236cdf0e10cSrcweir             aNewTransform *= maNewTransformA;
237cdf0e10cSrcweir 
238cdf0e10cSrcweir             // apply local offset
239cdf0e10cSrcweir             aNewTransform.translate(rInfo.mrStartPos.X(), rInfo.mrStartPos.Y());
240cdf0e10cSrcweir 
241cdf0e10cSrcweir             // also apply embedding object's transform
242cdf0e10cSrcweir             aNewTransform *= maNewTransformB;
243cdf0e10cSrcweir 
244cdf0e10cSrcweir             // prepare DXArray content. To make it independent from font size (and such from
245cdf0e10cSrcweir             // the text transformation), scale it to unit coordinates
246cdf0e10cSrcweir             ::std::vector< double > aDXArray;
247cdf0e10cSrcweir             static bool bDisableTextArray(false);
248cdf0e10cSrcweir 
249cdf0e10cSrcweir             if(!bDisableTextArray && rInfo.mpDXArray && rInfo.mnTextLen)
250cdf0e10cSrcweir             {
251cdf0e10cSrcweir                 aDXArray.reserve(rInfo.mnTextLen);
252cdf0e10cSrcweir 
253cdf0e10cSrcweir                 for(xub_StrLen a(0); a < rInfo.mnTextLen; a++)
254cdf0e10cSrcweir                 {
255cdf0e10cSrcweir                     aDXArray.push_back((double)rInfo.mpDXArray[a]);
256cdf0e10cSrcweir                 }
257cdf0e10cSrcweir             }
258cdf0e10cSrcweir 
259cdf0e10cSrcweir             // create complex text primitive and append
260cdf0e10cSrcweir             const Color aFontColor(rInfo.mrFont.GetColor());
261cdf0e10cSrcweir             const basegfx::BColor aBFontColor(aFontColor.getBColor());
262cdf0e10cSrcweir 
263cdf0e10cSrcweir             // prepare wordLineMode (for underline and strikeout)
264cdf0e10cSrcweir             // NOT for bullet texts. It is set (this may be an error by itself), but needs to be suppressed to hinder e.g. '1)'
265*85122fc3Smseidel             // to be split which would not look like the original
266cdf0e10cSrcweir             const bool bWordLineMode(rInfo.mrFont.IsWordLineMode() && !rInfo.mbEndOfBullet);
267cdf0e10cSrcweir 
268cdf0e10cSrcweir             // prepare new primitive
269cdf0e10cSrcweir             drawinglayer::primitive2d::BasePrimitive2D* pNewPrimitive = 0;
270cdf0e10cSrcweir             const bool bDecoratedIsNeeded(
271cdf0e10cSrcweir                    UNDERLINE_NONE != rInfo.mrFont.GetOverline()
272cdf0e10cSrcweir                 || UNDERLINE_NONE != rInfo.mrFont.GetUnderline()
273cdf0e10cSrcweir                 || STRIKEOUT_NONE != rInfo.mrFont.GetStrikeout()
274cdf0e10cSrcweir                 || EMPHASISMARK_NONE != (rInfo.mrFont.GetEmphasisMark() & EMPHASISMARK_STYLE)
275cdf0e10cSrcweir                 || RELIEF_NONE != rInfo.mrFont.GetRelief()
276cdf0e10cSrcweir                 || rInfo.mrFont.IsShadow()
277cdf0e10cSrcweir                 || bWordLineMode);
278cdf0e10cSrcweir 
279cdf0e10cSrcweir             if(bDecoratedIsNeeded)
280cdf0e10cSrcweir             {
281cdf0e10cSrcweir                 // TextDecoratedPortionPrimitive2D needed, prepare some more data
282cdf0e10cSrcweir                 // get overline and underline color. If it's on automatic (0xffffffff) use FontColor instead
283cdf0e10cSrcweir                 const Color aUnderlineColor(rInfo.maTextLineColor);
284cdf0e10cSrcweir                 const basegfx::BColor aBUnderlineColor((0xffffffff == aUnderlineColor.GetColor()) ? aBFontColor : aUnderlineColor.getBColor());
285cdf0e10cSrcweir                 const Color aOverlineColor(rInfo.maOverlineColor);
286cdf0e10cSrcweir                 const basegfx::BColor aBOverlineColor((0xffffffff == aOverlineColor.GetColor()) ? aBFontColor : aOverlineColor.getBColor());
287cdf0e10cSrcweir 
288cdf0e10cSrcweir                 // prepare overline and underline data
289cdf0e10cSrcweir                 const drawinglayer::primitive2d::TextLine eFontOverline(
290cdf0e10cSrcweir                     drawinglayer::primitive2d::mapFontUnderlineToTextLine(rInfo.mrFont.GetOverline()));
291cdf0e10cSrcweir                 const drawinglayer::primitive2d::TextLine eFontUnderline(
292cdf0e10cSrcweir                     drawinglayer::primitive2d::mapFontUnderlineToTextLine(rInfo.mrFont.GetUnderline()));
293cdf0e10cSrcweir 
294*85122fc3Smseidel                 // check UnderlineAbove
295cdf0e10cSrcweir                 const bool bUnderlineAbove(
296cdf0e10cSrcweir                     drawinglayer::primitive2d::TEXT_LINE_NONE != eFontUnderline && impIsUnderlineAbove(rInfo.mrFont));
297cdf0e10cSrcweir 
298cdf0e10cSrcweir                 // prepare strikeout data
299cdf0e10cSrcweir                 const drawinglayer::primitive2d::TextStrikeout eTextStrikeout(
300cdf0e10cSrcweir                     drawinglayer::primitive2d::mapFontStrikeoutToTextStrikeout(rInfo.mrFont.GetStrikeout()));
301cdf0e10cSrcweir 
302cdf0e10cSrcweir                 // prepare emphasis mark data
303cdf0e10cSrcweir                 drawinglayer::primitive2d::TextEmphasisMark eTextEmphasisMark(drawinglayer::primitive2d::TEXT_EMPHASISMARK_NONE);
304cdf0e10cSrcweir 
305cdf0e10cSrcweir                 switch(rInfo.mrFont.GetEmphasisMark() & EMPHASISMARK_STYLE)
306cdf0e10cSrcweir                 {
307cdf0e10cSrcweir                     case EMPHASISMARK_DOT : eTextEmphasisMark = drawinglayer::primitive2d::TEXT_EMPHASISMARK_DOT; break;
308cdf0e10cSrcweir                     case EMPHASISMARK_CIRCLE : eTextEmphasisMark = drawinglayer::primitive2d::TEXT_EMPHASISMARK_CIRCLE; break;
309cdf0e10cSrcweir                     case EMPHASISMARK_DISC : eTextEmphasisMark = drawinglayer::primitive2d::TEXT_EMPHASISMARK_DISC; break;
310cdf0e10cSrcweir                     case EMPHASISMARK_ACCENT : eTextEmphasisMark = drawinglayer::primitive2d::TEXT_EMPHASISMARK_ACCENT; break;
311cdf0e10cSrcweir                 }
312cdf0e10cSrcweir 
313cdf0e10cSrcweir                 const bool bEmphasisMarkAbove(rInfo.mrFont.GetEmphasisMark() & EMPHASISMARK_POS_ABOVE);
314cdf0e10cSrcweir                 const bool bEmphasisMarkBelow(rInfo.mrFont.GetEmphasisMark() & EMPHASISMARK_POS_BELOW);
315cdf0e10cSrcweir 
316cdf0e10cSrcweir                 // prepare font relief data
317cdf0e10cSrcweir                 drawinglayer::primitive2d::TextRelief eTextRelief(drawinglayer::primitive2d::TEXT_RELIEF_NONE);
318cdf0e10cSrcweir 
319cdf0e10cSrcweir                 switch(rInfo.mrFont.GetRelief())
320cdf0e10cSrcweir                 {
321cdf0e10cSrcweir                     case RELIEF_EMBOSSED : eTextRelief = drawinglayer::primitive2d::TEXT_RELIEF_EMBOSSED; break;
322cdf0e10cSrcweir                     case RELIEF_ENGRAVED : eTextRelief = drawinglayer::primitive2d::TEXT_RELIEF_ENGRAVED; break;
323cdf0e10cSrcweir                     default : break; // RELIEF_NONE, FontRelief_FORCE_EQUAL_SIZE
324cdf0e10cSrcweir                 }
325cdf0e10cSrcweir 
326cdf0e10cSrcweir                 // prepare shadow/outline data
327cdf0e10cSrcweir                 const bool bShadow(rInfo.mrFont.IsShadow());
328cdf0e10cSrcweir 
329cdf0e10cSrcweir                 // TextDecoratedPortionPrimitive2D is needed, create one
330cdf0e10cSrcweir                 pNewPrimitive = new drawinglayer::primitive2d::TextDecoratedPortionPrimitive2D(
331cdf0e10cSrcweir 
332cdf0e10cSrcweir                     // attributes for TextSimplePortionPrimitive2D
333cdf0e10cSrcweir                     aNewTransform,
334cdf0e10cSrcweir                     rInfo.mrText,
335cdf0e10cSrcweir                     rInfo.mnTextStart,
336cdf0e10cSrcweir                     rInfo.mnTextLen,
337cdf0e10cSrcweir                     aDXArray,
338cdf0e10cSrcweir                     aFontAttribute,
339cdf0e10cSrcweir                     rInfo.mpLocale ? *rInfo.mpLocale : ::com::sun::star::lang::Locale(),
340cdf0e10cSrcweir                     aBFontColor,
341cdf0e10cSrcweir 
342cdf0e10cSrcweir                     // attributes for TextDecoratedPortionPrimitive2D
343cdf0e10cSrcweir                     aBOverlineColor,
344cdf0e10cSrcweir                     aBUnderlineColor,
345cdf0e10cSrcweir                     eFontOverline,
346cdf0e10cSrcweir                     eFontUnderline,
347cdf0e10cSrcweir                     bUnderlineAbove,
348cdf0e10cSrcweir                     eTextStrikeout,
349cdf0e10cSrcweir                     bWordLineMode,
350cdf0e10cSrcweir                     eTextEmphasisMark,
351cdf0e10cSrcweir                     bEmphasisMarkAbove,
352cdf0e10cSrcweir                     bEmphasisMarkBelow,
353cdf0e10cSrcweir                     eTextRelief,
354cdf0e10cSrcweir                     bShadow);
355cdf0e10cSrcweir             }
356cdf0e10cSrcweir             else
357cdf0e10cSrcweir             {
358cdf0e10cSrcweir                 // TextSimplePortionPrimitive2D is enough
359cdf0e10cSrcweir                 pNewPrimitive = new drawinglayer::primitive2d::TextSimplePortionPrimitive2D(
360cdf0e10cSrcweir                     aNewTransform,
361cdf0e10cSrcweir                     rInfo.mrText,
362cdf0e10cSrcweir                     rInfo.mnTextStart,
363cdf0e10cSrcweir                     rInfo.mnTextLen,
364cdf0e10cSrcweir                     aDXArray,
365cdf0e10cSrcweir                     aFontAttribute,
366cdf0e10cSrcweir                     rInfo.mpLocale ? *rInfo.mpLocale : ::com::sun::star::lang::Locale(),
367cdf0e10cSrcweir                     aBFontColor);
368cdf0e10cSrcweir             }
369cdf0e10cSrcweir 
370cdf0e10cSrcweir             if(rInfo.mbEndOfBullet)
371cdf0e10cSrcweir             {
372cdf0e10cSrcweir                 // embed in TextHierarchyBulletPrimitive2D
373cdf0e10cSrcweir                 const drawinglayer::primitive2d::Primitive2DReference aNewReference(pNewPrimitive);
374cdf0e10cSrcweir                 const drawinglayer::primitive2d::Primitive2DSequence aNewSequence(&aNewReference, 1);
375cdf0e10cSrcweir                 pNewPrimitive = new drawinglayer::primitive2d::TextHierarchyBulletPrimitive2D(aNewSequence);
376cdf0e10cSrcweir             }
377cdf0e10cSrcweir 
378cdf0e10cSrcweir             if(rInfo.mpFieldData)
379cdf0e10cSrcweir             {
380cdf0e10cSrcweir                 pNewPrimitive = impCheckFieldPrimitive(pNewPrimitive, rInfo);
381cdf0e10cSrcweir             }
382cdf0e10cSrcweir 
383cdf0e10cSrcweir             maTextPortionPrimitives.push_back(pNewPrimitive);
384cdf0e10cSrcweir 
385cdf0e10cSrcweir             // support for WrongSpellVector. Create WrongSpellPrimitives as needed
386cdf0e10cSrcweir             if(rInfo.mpWrongSpellVector && !aDXArray.empty())
387cdf0e10cSrcweir             {
388cdf0e10cSrcweir                 const sal_uInt32 nSize(rInfo.mpWrongSpellVector->size());
389cdf0e10cSrcweir                 const sal_uInt32 nDXCount(aDXArray.size());
390cdf0e10cSrcweir                 const basegfx::BColor aSpellColor(1.0, 0.0, 0.0); // red, hard coded
391cdf0e10cSrcweir 
392cdf0e10cSrcweir                 for(sal_uInt32 a(0); a < nSize; a++)
393cdf0e10cSrcweir                 {
394cdf0e10cSrcweir                     const EEngineData::WrongSpellClass& rCandidate = (*rInfo.mpWrongSpellVector)[a];
395cdf0e10cSrcweir 
396cdf0e10cSrcweir                     if(rCandidate.nStart >= rInfo.mnTextStart && rCandidate.nEnd >= rInfo.mnTextStart && rCandidate.nEnd > rCandidate.nStart)
397cdf0e10cSrcweir                     {
398cdf0e10cSrcweir                         const sal_uInt32 nStart(rCandidate.nStart - rInfo.mnTextStart);
399cdf0e10cSrcweir                         const sal_uInt32 nEnd(rCandidate.nEnd - rInfo.mnTextStart);
400cdf0e10cSrcweir                         double fStart(0.0);
401cdf0e10cSrcweir                         double fEnd(0.0);
402cdf0e10cSrcweir 
403cdf0e10cSrcweir                         if(nStart > 0 && nStart - 1 < nDXCount)
404cdf0e10cSrcweir                         {
405cdf0e10cSrcweir                             fStart = aDXArray[nStart - 1];
406cdf0e10cSrcweir                         }
407cdf0e10cSrcweir 
408cdf0e10cSrcweir                         if(nEnd > 0 && nEnd - 1 < nDXCount)
409cdf0e10cSrcweir                         {
410cdf0e10cSrcweir                             fEnd = aDXArray[nEnd - 1];
411cdf0e10cSrcweir                         }
412cdf0e10cSrcweir 
413cdf0e10cSrcweir                         if(!basegfx::fTools::equal(fStart, fEnd))
414cdf0e10cSrcweir                         {
415cdf0e10cSrcweir                             if(rInfo.IsRTL())
416cdf0e10cSrcweir                             {
417cdf0e10cSrcweir                                 // #i98523#
418cdf0e10cSrcweir                                 // When the portion is RTL, mirror the redlining using the
419cdf0e10cSrcweir                                 // full portion width
420cdf0e10cSrcweir                                 const double fTextWidth(aDXArray[aDXArray.size() - 1]);
421cdf0e10cSrcweir 
422cdf0e10cSrcweir                                 fStart = fTextWidth - fStart;
423cdf0e10cSrcweir                                 fEnd = fTextWidth - fEnd;
424cdf0e10cSrcweir                             }
425cdf0e10cSrcweir 
426cdf0e10cSrcweir                             // need to take FontScaling out of values; it's already part of
427cdf0e10cSrcweir                             // aNewTransform and would be double applied
428cdf0e10cSrcweir                             const double fFontScaleX(aFontScaling.getX());
429cdf0e10cSrcweir 
430cdf0e10cSrcweir                             if(!basegfx::fTools::equal(fFontScaleX, 1.0)
431cdf0e10cSrcweir                                 && !basegfx::fTools::equalZero(fFontScaleX))
432cdf0e10cSrcweir                             {
433cdf0e10cSrcweir                                 fStart /= fFontScaleX;
434cdf0e10cSrcweir                                 fEnd /= fFontScaleX;
435cdf0e10cSrcweir                             }
436cdf0e10cSrcweir 
437cdf0e10cSrcweir                             maTextPortionPrimitives.push_back(new drawinglayer::primitive2d::WrongSpellPrimitive2D(
438cdf0e10cSrcweir                                 aNewTransform,
439cdf0e10cSrcweir                                 fStart,
440cdf0e10cSrcweir                                 fEnd,
441cdf0e10cSrcweir                                 aSpellColor));
442cdf0e10cSrcweir                         }
443cdf0e10cSrcweir                     }
444cdf0e10cSrcweir                 }
445cdf0e10cSrcweir             }
446cdf0e10cSrcweir         }
447cdf0e10cSrcweir     }
448cdf0e10cSrcweir 
impCheckFieldPrimitive(drawinglayer::primitive2d::BasePrimitive2D * pPrimitive,const DrawPortionInfo & rInfo) const449cdf0e10cSrcweir     drawinglayer::primitive2d::BasePrimitive2D* impTextBreakupHandler::impCheckFieldPrimitive(drawinglayer::primitive2d::BasePrimitive2D* pPrimitive, const DrawPortionInfo& rInfo) const
450cdf0e10cSrcweir     {
451cdf0e10cSrcweir         if(rInfo.mpFieldData)
452cdf0e10cSrcweir         {
453cdf0e10cSrcweir             // Support for FIELD_SEQ_BEGIN, FIELD_SEQ_END. If used, create a TextHierarchyFieldPrimitive2D
454cdf0e10cSrcweir             // which holds the field type and evtl. the URL
455cdf0e10cSrcweir             const SvxURLField* pURLField = dynamic_cast< const SvxURLField* >(rInfo.mpFieldData);
456cdf0e10cSrcweir             const SvxPageField* pPageField = dynamic_cast< const SvxPageField* >(rInfo.mpFieldData);
457cdf0e10cSrcweir 
458cdf0e10cSrcweir             // embed current primitive to a sequence
459cdf0e10cSrcweir             drawinglayer::primitive2d::Primitive2DSequence aSequence;
460cdf0e10cSrcweir 
461cdf0e10cSrcweir             if(pPrimitive)
462cdf0e10cSrcweir             {
463cdf0e10cSrcweir                 aSequence.realloc(1);
464cdf0e10cSrcweir                 aSequence[0] = drawinglayer::primitive2d::Primitive2DReference(pPrimitive);
465cdf0e10cSrcweir             }
466cdf0e10cSrcweir 
467cdf0e10cSrcweir             if(pURLField)
468cdf0e10cSrcweir             {
469cdf0e10cSrcweir                 pPrimitive = new drawinglayer::primitive2d::TextHierarchyFieldPrimitive2D(aSequence, drawinglayer::primitive2d::FIELD_TYPE_URL, pURLField->GetURL());
470cdf0e10cSrcweir             }
471cdf0e10cSrcweir             else if(pPageField)
472cdf0e10cSrcweir             {
473cdf0e10cSrcweir                 pPrimitive = new drawinglayer::primitive2d::TextHierarchyFieldPrimitive2D(aSequence, drawinglayer::primitive2d::FIELD_TYPE_PAGE, String());
474cdf0e10cSrcweir             }
475cdf0e10cSrcweir             else
476cdf0e10cSrcweir             {
477cdf0e10cSrcweir                 pPrimitive = new drawinglayer::primitive2d::TextHierarchyFieldPrimitive2D(aSequence, drawinglayer::primitive2d::FIELD_TYPE_COMMON, String());
478cdf0e10cSrcweir             }
479cdf0e10cSrcweir         }
480cdf0e10cSrcweir 
481cdf0e10cSrcweir         return pPrimitive;
482cdf0e10cSrcweir     }
483cdf0e10cSrcweir 
impFlushTextPortionPrimitivesToLinePrimitives()484cdf0e10cSrcweir     void impTextBreakupHandler::impFlushTextPortionPrimitivesToLinePrimitives()
485cdf0e10cSrcweir     {
486cdf0e10cSrcweir         // only create a line primitive when we had content; there is no need for
487cdf0e10cSrcweir         // empty line primitives (contrary to paragraphs, see below).
488cdf0e10cSrcweir         if(!maTextPortionPrimitives.empty())
489cdf0e10cSrcweir         {
490cdf0e10cSrcweir             drawinglayer::primitive2d::Primitive2DSequence aLineSequence(impConvertVectorToPrimitive2DSequence(maTextPortionPrimitives));
491cdf0e10cSrcweir             maTextPortionPrimitives.clear();
492cdf0e10cSrcweir             maLinePrimitives.push_back(new drawinglayer::primitive2d::TextHierarchyLinePrimitive2D(aLineSequence));
493cdf0e10cSrcweir         }
494cdf0e10cSrcweir     }
495cdf0e10cSrcweir 
impFlushLinePrimitivesToParagraphPrimitives()496cdf0e10cSrcweir     void impTextBreakupHandler::impFlushLinePrimitivesToParagraphPrimitives()
497cdf0e10cSrcweir     {
498cdf0e10cSrcweir         // ALWAYS create a paragraph primitive, even when no content was added. This is done to
499cdf0e10cSrcweir         // have the correct paragraph count even with empty paragraphs. Those paragraphs will
500cdf0e10cSrcweir         // have an empty sub-PrimitiveSequence.
501cdf0e10cSrcweir         drawinglayer::primitive2d::Primitive2DSequence aParagraphSequence(impConvertVectorToPrimitive2DSequence(maLinePrimitives));
502cdf0e10cSrcweir         maLinePrimitives.clear();
503cdf0e10cSrcweir         maParagraphPrimitives.push_back(new drawinglayer::primitive2d::TextHierarchyParagraphPrimitive2D(aParagraphSequence));
504cdf0e10cSrcweir     }
505cdf0e10cSrcweir 
impHandleDrawPortionInfo(const DrawPortionInfo & rInfo)506cdf0e10cSrcweir     void impTextBreakupHandler::impHandleDrawPortionInfo(const DrawPortionInfo& rInfo)
507cdf0e10cSrcweir     {
508cdf0e10cSrcweir         impCreateTextPortionPrimitive(rInfo);
509cdf0e10cSrcweir 
510cdf0e10cSrcweir         if(rInfo.mbEndOfLine || rInfo.mbEndOfParagraph)
511cdf0e10cSrcweir         {
512cdf0e10cSrcweir             impFlushTextPortionPrimitivesToLinePrimitives();
513cdf0e10cSrcweir         }
514cdf0e10cSrcweir 
515cdf0e10cSrcweir         if(rInfo.mbEndOfParagraph)
516cdf0e10cSrcweir         {
517cdf0e10cSrcweir             impFlushLinePrimitivesToParagraphPrimitives();
518cdf0e10cSrcweir         }
519cdf0e10cSrcweir     }
520cdf0e10cSrcweir 
impHandleDrawBulletInfo(const DrawBulletInfo & rInfo)521cdf0e10cSrcweir     void impTextBreakupHandler::impHandleDrawBulletInfo(const DrawBulletInfo& rInfo)
522cdf0e10cSrcweir     {
523cdf0e10cSrcweir         basegfx::B2DHomMatrix aNewTransform;
524cdf0e10cSrcweir 
525cdf0e10cSrcweir         // add size to new transform
526cdf0e10cSrcweir         aNewTransform.scale(rInfo.maBulletSize.getWidth(), rInfo.maBulletSize.getHeight());
527cdf0e10cSrcweir 
528cdf0e10cSrcweir         // apply transformA
529cdf0e10cSrcweir         aNewTransform *= maNewTransformA;
530cdf0e10cSrcweir 
531cdf0e10cSrcweir         // apply local offset
532cdf0e10cSrcweir         aNewTransform.translate(rInfo.maBulletPosition.X(), rInfo.maBulletPosition.Y());
533cdf0e10cSrcweir 
534cdf0e10cSrcweir         // also apply embedding object's transform
535cdf0e10cSrcweir         aNewTransform *= maNewTransformB;
536cdf0e10cSrcweir 
537cdf0e10cSrcweir         // prepare empty GraphicAttr
538cdf0e10cSrcweir         const GraphicAttr aGraphicAttr;
539cdf0e10cSrcweir 
540cdf0e10cSrcweir         // create GraphicPrimitive2D
541cdf0e10cSrcweir         const drawinglayer::primitive2d::Primitive2DReference aNewReference(new drawinglayer::primitive2d::GraphicPrimitive2D(
542cdf0e10cSrcweir             aNewTransform,
543cdf0e10cSrcweir             rInfo.maBulletGraphicObject,
544cdf0e10cSrcweir             aGraphicAttr));
545cdf0e10cSrcweir 
546cdf0e10cSrcweir         // embed in TextHierarchyBulletPrimitive2D
547cdf0e10cSrcweir         const drawinglayer::primitive2d::Primitive2DSequence aNewSequence(&aNewReference, 1);
548cdf0e10cSrcweir         drawinglayer::primitive2d::BasePrimitive2D* pNewPrimitive = new drawinglayer::primitive2d::TextHierarchyBulletPrimitive2D(aNewSequence);
549cdf0e10cSrcweir 
550cdf0e10cSrcweir         // add to output
551cdf0e10cSrcweir         maTextPortionPrimitives.push_back(pNewPrimitive);
552cdf0e10cSrcweir     }
553cdf0e10cSrcweir 
IMPL_LINK(impTextBreakupHandler,decomposeContourTextPrimitive,DrawPortionInfo *,pInfo)554cdf0e10cSrcweir     IMPL_LINK(impTextBreakupHandler, decomposeContourTextPrimitive, DrawPortionInfo*, pInfo)
555cdf0e10cSrcweir     {
556cdf0e10cSrcweir         // for contour text, ignore (clip away) all portions which are below
557cdf0e10cSrcweir         // the visible area given by maScale
558cdf0e10cSrcweir         if(pInfo && (double)pInfo->mrStartPos.Y() < maScale.getY())
559cdf0e10cSrcweir         {
560cdf0e10cSrcweir             impHandleDrawPortionInfo(*pInfo);
561cdf0e10cSrcweir         }
562cdf0e10cSrcweir 
563cdf0e10cSrcweir         return 0;
564cdf0e10cSrcweir     }
565cdf0e10cSrcweir 
IMPL_LINK(impTextBreakupHandler,decomposeBlockTextPrimitive,DrawPortionInfo *,pInfo)566cdf0e10cSrcweir     IMPL_LINK(impTextBreakupHandler, decomposeBlockTextPrimitive, DrawPortionInfo*, pInfo)
567cdf0e10cSrcweir     {
568cdf0e10cSrcweir         if(pInfo)
569cdf0e10cSrcweir         {
570cdf0e10cSrcweir             // #SJ# Is clipping wanted? This is text clipping; only accept a portion
571cdf0e10cSrcweir             // if it's completely in the range
572cdf0e10cSrcweir             if(!maClipRange.isEmpty())
573cdf0e10cSrcweir             {
574cdf0e10cSrcweir                 // Test start position first; this allows to not get the text range at
575cdf0e10cSrcweir                 // all if text is far outside
576cdf0e10cSrcweir                 const basegfx::B2DPoint aStartPosition(pInfo->mrStartPos.X(), pInfo->mrStartPos.Y());
577cdf0e10cSrcweir 
578cdf0e10cSrcweir                 if(!maClipRange.isInside(aStartPosition))
579cdf0e10cSrcweir                 {
580cdf0e10cSrcweir                     return 0;
581cdf0e10cSrcweir                 }
582cdf0e10cSrcweir 
583cdf0e10cSrcweir                 // Start position is inside. Get TextBoundRect and TopLeft next
584cdf0e10cSrcweir                 drawinglayer::primitive2d::TextLayouterDevice aTextLayouterDevice;
585cdf0e10cSrcweir                 aTextLayouterDevice.setFont(pInfo->mrFont);
586cdf0e10cSrcweir 
587cdf0e10cSrcweir                 const basegfx::B2DRange aTextBoundRect(
588cdf0e10cSrcweir                     aTextLayouterDevice.getTextBoundRect(
589cdf0e10cSrcweir                         pInfo->mrText, pInfo->mnTextStart, pInfo->mnTextLen));
590cdf0e10cSrcweir                 const basegfx::B2DPoint aTopLeft(aTextBoundRect.getMinimum() + aStartPosition);
591cdf0e10cSrcweir 
592cdf0e10cSrcweir                 if(!maClipRange.isInside(aTopLeft))
593cdf0e10cSrcweir                 {
594cdf0e10cSrcweir                     return 0;
595cdf0e10cSrcweir                 }
596cdf0e10cSrcweir 
597cdf0e10cSrcweir                 // TopLeft is inside. Get BottomRight and check
598cdf0e10cSrcweir                 const basegfx::B2DPoint aBottomRight(aTextBoundRect.getMaximum() + aStartPosition);
599cdf0e10cSrcweir 
600cdf0e10cSrcweir                 if(!maClipRange.isInside(aBottomRight))
601cdf0e10cSrcweir                 {
602cdf0e10cSrcweir                     return 0;
603cdf0e10cSrcweir                 }
604cdf0e10cSrcweir 
605cdf0e10cSrcweir                 // all inside, clip was successful
606cdf0e10cSrcweir             }
607cdf0e10cSrcweir             impHandleDrawPortionInfo(*pInfo);
608cdf0e10cSrcweir         }
609cdf0e10cSrcweir 
610cdf0e10cSrcweir         return 0;
611cdf0e10cSrcweir     }
612cdf0e10cSrcweir 
IMPL_LINK(impTextBreakupHandler,decomposeStretchTextPrimitive,DrawPortionInfo *,pInfo)613cdf0e10cSrcweir     IMPL_LINK(impTextBreakupHandler, decomposeStretchTextPrimitive, DrawPortionInfo*, pInfo)
614cdf0e10cSrcweir     {
615cdf0e10cSrcweir         if(pInfo)
616cdf0e10cSrcweir         {
617cdf0e10cSrcweir             impHandleDrawPortionInfo(*pInfo);
618cdf0e10cSrcweir         }
619cdf0e10cSrcweir 
620cdf0e10cSrcweir         return 0;
621cdf0e10cSrcweir     }
622cdf0e10cSrcweir 
IMPL_LINK(impTextBreakupHandler,decomposeContourBulletPrimitive,DrawBulletInfo *,pInfo)623cdf0e10cSrcweir     IMPL_LINK(impTextBreakupHandler, decomposeContourBulletPrimitive, DrawBulletInfo*, pInfo)
624cdf0e10cSrcweir     {
625cdf0e10cSrcweir         if(pInfo)
626cdf0e10cSrcweir         {
627cdf0e10cSrcweir             impHandleDrawBulletInfo(*pInfo);
628cdf0e10cSrcweir         }
629cdf0e10cSrcweir 
630cdf0e10cSrcweir         return 0;
631cdf0e10cSrcweir     }
632cdf0e10cSrcweir 
IMPL_LINK(impTextBreakupHandler,decomposeBlockBulletPrimitive,DrawBulletInfo *,pInfo)633cdf0e10cSrcweir     IMPL_LINK(impTextBreakupHandler, decomposeBlockBulletPrimitive, DrawBulletInfo*, pInfo)
634cdf0e10cSrcweir     {
635cdf0e10cSrcweir         if(pInfo)
636cdf0e10cSrcweir         {
637cdf0e10cSrcweir             impHandleDrawBulletInfo(*pInfo);
638cdf0e10cSrcweir         }
639cdf0e10cSrcweir 
640cdf0e10cSrcweir         return 0;
641cdf0e10cSrcweir     }
642cdf0e10cSrcweir 
IMPL_LINK(impTextBreakupHandler,decomposeStretchBulletPrimitive,DrawBulletInfo *,pInfo)643cdf0e10cSrcweir     IMPL_LINK(impTextBreakupHandler, decomposeStretchBulletPrimitive, DrawBulletInfo*, pInfo)
644cdf0e10cSrcweir     {
645cdf0e10cSrcweir         if(pInfo)
646cdf0e10cSrcweir         {
647cdf0e10cSrcweir             impHandleDrawBulletInfo(*pInfo);
648cdf0e10cSrcweir         }
649cdf0e10cSrcweir 
650cdf0e10cSrcweir         return 0;
651cdf0e10cSrcweir     }
652cdf0e10cSrcweir 
getPrimitive2DSequence()653cdf0e10cSrcweir     drawinglayer::primitive2d::Primitive2DSequence impTextBreakupHandler::getPrimitive2DSequence()
654cdf0e10cSrcweir     {
655cdf0e10cSrcweir         if(!maTextPortionPrimitives.empty())
656cdf0e10cSrcweir         {
657cdf0e10cSrcweir             // collect non-closed lines
658cdf0e10cSrcweir             impFlushTextPortionPrimitivesToLinePrimitives();
659cdf0e10cSrcweir         }
660cdf0e10cSrcweir 
661cdf0e10cSrcweir         if(!maLinePrimitives.empty())
662cdf0e10cSrcweir         {
663cdf0e10cSrcweir             // collect non-closed paragraphs
664cdf0e10cSrcweir             impFlushLinePrimitivesToParagraphPrimitives();
665cdf0e10cSrcweir         }
666cdf0e10cSrcweir 
667cdf0e10cSrcweir         return impConvertVectorToPrimitive2DSequence(maParagraphPrimitives);
668cdf0e10cSrcweir     }
669cdf0e10cSrcweir } // end of anonymous namespace
670cdf0e10cSrcweir 
671cdf0e10cSrcweir //////////////////////////////////////////////////////////////////////////////
672cdf0e10cSrcweir // primitive decompositions
673cdf0e10cSrcweir 
impDecomposeContourTextPrimitive(drawinglayer::primitive2d::Primitive2DSequence & rTarget,const drawinglayer::primitive2d::SdrContourTextPrimitive2D & rSdrContourTextPrimitive,const drawinglayer::geometry::ViewInformation2D & aViewInformation) const674cdf0e10cSrcweir void SdrTextObj::impDecomposeContourTextPrimitive(
675cdf0e10cSrcweir     drawinglayer::primitive2d::Primitive2DSequence& rTarget,
676cdf0e10cSrcweir     const drawinglayer::primitive2d::SdrContourTextPrimitive2D& rSdrContourTextPrimitive,
677cdf0e10cSrcweir     const drawinglayer::geometry::ViewInformation2D& aViewInformation) const
678cdf0e10cSrcweir {
679cdf0e10cSrcweir     // decompose matrix to have position and size of text
680cdf0e10cSrcweir     basegfx::B2DVector aScale, aTranslate;
681cdf0e10cSrcweir     double fRotate, fShearX;
682cdf0e10cSrcweir     rSdrContourTextPrimitive.getObjectTransform().decompose(aScale, aTranslate, fRotate, fShearX);
683cdf0e10cSrcweir 
684cdf0e10cSrcweir     // prepare contour polygon, force to non-mirrored for layouting
685cdf0e10cSrcweir     basegfx::B2DPolyPolygon aPolyPolygon(rSdrContourTextPrimitive.getUnitPolyPolygon());
686cdf0e10cSrcweir     aPolyPolygon.transform(basegfx::tools::createScaleB2DHomMatrix(fabs(aScale.getX()), fabs(aScale.getY())));
687cdf0e10cSrcweir 
688cdf0e10cSrcweir     // prepare outliner
689cdf0e10cSrcweir     SdrOutliner& rOutliner = ImpGetDrawOutliner();
690cdf0e10cSrcweir     const Size aNullSize;
691cdf0e10cSrcweir     rOutliner.SetPaperSize(aNullSize);
692cdf0e10cSrcweir     rOutliner.SetPolygon(aPolyPolygon);
693cdf0e10cSrcweir     rOutliner.SetUpdateMode(true);
694cdf0e10cSrcweir     rOutliner.SetText(rSdrContourTextPrimitive.getOutlinerParaObject());
695cdf0e10cSrcweir 
696cdf0e10cSrcweir     // set visualizing page at Outliner; needed e.g. for PageNumberField decomposition
697cdf0e10cSrcweir     rOutliner.setVisualizedPage(GetSdrPageFromXDrawPage(aViewInformation.getVisualizedPage()));
698cdf0e10cSrcweir 
699cdf0e10cSrcweir     // prepare matrices to apply to newly created primitives
700cdf0e10cSrcweir     basegfx::B2DHomMatrix aNewTransformA;
701cdf0e10cSrcweir 
702cdf0e10cSrcweir     // mirroring. We are now in the polygon sizes. When mirroring in X and Y,
703cdf0e10cSrcweir     // move the null point which was top left to bottom right.
704cdf0e10cSrcweir     const bool bMirrorX(basegfx::fTools::less(aScale.getX(), 0.0));
705cdf0e10cSrcweir     const bool bMirrorY(basegfx::fTools::less(aScale.getY(), 0.0));
706cdf0e10cSrcweir 
707cdf0e10cSrcweir     // in-between the translations of the single primitives will take place. Afterwards,
708cdf0e10cSrcweir     // the object's transformations need to be applied
709cdf0e10cSrcweir     const basegfx::B2DHomMatrix aNewTransformB(basegfx::tools::createScaleShearXRotateTranslateB2DHomMatrix(
710cdf0e10cSrcweir         bMirrorX ? -1.0 : 1.0, bMirrorY ? -1.0 : 1.0,
711cdf0e10cSrcweir         fShearX, fRotate, aTranslate.getX(), aTranslate.getY()));
712cdf0e10cSrcweir 
713cdf0e10cSrcweir     // now break up text primitives.
714cdf0e10cSrcweir     impTextBreakupHandler aConverter(rOutliner);
715cdf0e10cSrcweir     aConverter.decomposeContourTextPrimitive(aNewTransformA, aNewTransformB, aScale);
716cdf0e10cSrcweir 
717cdf0e10cSrcweir     // cleanup outliner
718cdf0e10cSrcweir     rOutliner.Clear();
719cdf0e10cSrcweir     rOutliner.setVisualizedPage(0);
720cdf0e10cSrcweir 
721cdf0e10cSrcweir     rTarget = aConverter.getPrimitive2DSequence();
722cdf0e10cSrcweir }
723cdf0e10cSrcweir 
impDecomposeBlockTextPrimitive(drawinglayer::primitive2d::Primitive2DSequence & rTarget,const drawinglayer::primitive2d::SdrBlockTextPrimitive2D & rSdrBlockTextPrimitive,const drawinglayer::geometry::ViewInformation2D & aViewInformation) const724cdf0e10cSrcweir void SdrTextObj::impDecomposeBlockTextPrimitive(
725cdf0e10cSrcweir     drawinglayer::primitive2d::Primitive2DSequence& rTarget,
726cdf0e10cSrcweir     const drawinglayer::primitive2d::SdrBlockTextPrimitive2D& rSdrBlockTextPrimitive,
727cdf0e10cSrcweir     const drawinglayer::geometry::ViewInformation2D& aViewInformation) const
728cdf0e10cSrcweir {
729cdf0e10cSrcweir     // decompose matrix to have position and size of text
730cdf0e10cSrcweir     basegfx::B2DVector aScale, aTranslate;
731cdf0e10cSrcweir     double fRotate, fShearX;
732cdf0e10cSrcweir     rSdrBlockTextPrimitive.getTextRangeTransform().decompose(aScale, aTranslate, fRotate, fShearX);
733cdf0e10cSrcweir 
734cdf0e10cSrcweir     // use B2DRange aAnchorTextRange for calculations
735cdf0e10cSrcweir     basegfx::B2DRange aAnchorTextRange(aTranslate);
736cdf0e10cSrcweir     aAnchorTextRange.expand(aTranslate + aScale);
737cdf0e10cSrcweir 
738cdf0e10cSrcweir     // prepare outliner
739cdf0e10cSrcweir     const bool bIsCell(rSdrBlockTextPrimitive.getCellText());
740cdf0e10cSrcweir     SdrOutliner& rOutliner = ImpGetDrawOutliner();
741cdf0e10cSrcweir     SdrTextHorzAdjust eHAdj = rSdrBlockTextPrimitive.getSdrTextHorzAdjust();
742cdf0e10cSrcweir     SdrTextVertAdjust eVAdj = rSdrBlockTextPrimitive.getSdrTextVertAdjust();
743cdf0e10cSrcweir     const sal_uInt32 nOriginalControlWord(rOutliner.GetControlWord());
744cdf0e10cSrcweir     const Size aNullSize;
745cdf0e10cSrcweir 
746cdf0e10cSrcweir     // set visualizing page at Outliner; needed e.g. for PageNumberField decomposition
747cdf0e10cSrcweir     rOutliner.setVisualizedPage(GetSdrPageFromXDrawPage(aViewInformation.getVisualizedPage()));
748cdf0e10cSrcweir     rOutliner.SetFixedCellHeight(rSdrBlockTextPrimitive.isFixedCellHeight());
749cdf0e10cSrcweir     rOutliner.SetControlWord(nOriginalControlWord|EE_CNTRL_AUTOPAGESIZE);
750cdf0e10cSrcweir     rOutliner.SetMinAutoPaperSize(aNullSize);
751cdf0e10cSrcweir     rOutliner.SetMaxAutoPaperSize(Size(1000000,1000000));
752cdf0e10cSrcweir 
753cdf0e10cSrcweir     // add one to rage sizes to get back to the old Rectangle and outliner measurements
754cdf0e10cSrcweir     const sal_uInt32 nAnchorTextWidth(FRound(aAnchorTextRange.getWidth() + 1L));
755cdf0e10cSrcweir     const sal_uInt32 nAnchorTextHeight(FRound(aAnchorTextRange.getHeight() + 1L));
756cdf0e10cSrcweir     const bool bVerticalWritintg(rSdrBlockTextPrimitive.getOutlinerParaObject().IsVertical());
757cdf0e10cSrcweir     const Size aAnchorTextSize(Size(nAnchorTextWidth, nAnchorTextHeight));
758cdf0e10cSrcweir 
759cdf0e10cSrcweir     if(bIsCell)
760cdf0e10cSrcweir     {
761cdf0e10cSrcweir         // cell text is formated neither like a text object nor like a object
762cdf0e10cSrcweir         // text, so use a special setup here
763cdf0e10cSrcweir         rOutliner.SetMaxAutoPaperSize(aAnchorTextSize);
764cdf0e10cSrcweir 
765cdf0e10cSrcweir         // #i106214# To work with an unchangeable PaperSize (CellSize in
766cdf0e10cSrcweir         // this case) Set(Min|Max)AutoPaperSize and SetPaperSize have to be used.
767cdf0e10cSrcweir         // #i106214# This was not completely correct; to still measure the real
768cdf0e10cSrcweir         // text height to allow vertical adjust (and vice versa for VerticalWritintg)
769cdf0e10cSrcweir         // only one aspect has to be set, but the other one to zero
770cdf0e10cSrcweir         if(bVerticalWritintg)
771cdf0e10cSrcweir         {
772cdf0e10cSrcweir             // measure the horizontal text size
773cdf0e10cSrcweir             rOutliner.SetMinAutoPaperSize(Size(0, aAnchorTextSize.Height()));
774cdf0e10cSrcweir         }
775cdf0e10cSrcweir         else
776cdf0e10cSrcweir         {
777cdf0e10cSrcweir             // measure the vertical text size
778cdf0e10cSrcweir             rOutliner.SetMinAutoPaperSize(Size(aAnchorTextSize.Width(), 0));
779cdf0e10cSrcweir         }
780cdf0e10cSrcweir 
781cdf0e10cSrcweir         rOutliner.SetPaperSize(aAnchorTextSize);
782cdf0e10cSrcweir         rOutliner.SetUpdateMode(true);
783cdf0e10cSrcweir         rOutliner.SetText(rSdrBlockTextPrimitive.getOutlinerParaObject());
784cdf0e10cSrcweir     }
785cdf0e10cSrcweir     else
786cdf0e10cSrcweir     {
787cdf0e10cSrcweir         // check if block text is used (only one of them can be true)
788cdf0e10cSrcweir         const bool bHorizontalIsBlock(SDRTEXTHORZADJUST_BLOCK == eHAdj && !bVerticalWritintg);
789cdf0e10cSrcweir         const bool bVerticalIsBlock(SDRTEXTVERTADJUST_BLOCK == eVAdj && bVerticalWritintg);
790cdf0e10cSrcweir 
791cdf0e10cSrcweir         // set minimal paper size hor/ver if needed
792cdf0e10cSrcweir         if(bHorizontalIsBlock)
793cdf0e10cSrcweir         {
794cdf0e10cSrcweir             rOutliner.SetMinAutoPaperSize(Size(nAnchorTextWidth, 0));
795cdf0e10cSrcweir         }
796cdf0e10cSrcweir         else if(bVerticalIsBlock)
797cdf0e10cSrcweir         {
798cdf0e10cSrcweir             rOutliner.SetMinAutoPaperSize(Size(0, nAnchorTextHeight));
799cdf0e10cSrcweir         }
800cdf0e10cSrcweir 
801cdf0e10cSrcweir         if((rSdrBlockTextPrimitive.getWordWrap() || IsTextFrame()) && !rSdrBlockTextPrimitive.getUnlimitedPage())
802cdf0e10cSrcweir         {
803cdf0e10cSrcweir             // #i103454# maximal paper size hor/ver needs to be limited to text
804cdf0e10cSrcweir             // frame size. If it's block text, still allow the 'other' direction
805cdf0e10cSrcweir             // to grow to get a correct real text size when using GetPaperSize().
806cdf0e10cSrcweir             // When just using aAnchorTextSize as maximum, GetPaperSize()
807cdf0e10cSrcweir             // would just return aAnchorTextSize again: this means, the wanted
808cdf0e10cSrcweir             // 'measurement' of the real size of block text would not work
809cdf0e10cSrcweir             Size aMaxAutoPaperSize(aAnchorTextSize);
810cdf0e10cSrcweir 
811cdf0e10cSrcweir             if(bHorizontalIsBlock)
812cdf0e10cSrcweir             {
813cdf0e10cSrcweir                 // allow to grow vertical for horizontal blocks
814cdf0e10cSrcweir                 aMaxAutoPaperSize.setHeight(1000000);
815cdf0e10cSrcweir             }
816cdf0e10cSrcweir             else if(bVerticalIsBlock)
817cdf0e10cSrcweir             {
818cdf0e10cSrcweir                 // allow to grow horizontal for vertical blocks
819cdf0e10cSrcweir                 aMaxAutoPaperSize.setWidth(1000000);
820cdf0e10cSrcweir             }
821cdf0e10cSrcweir 
822cdf0e10cSrcweir             rOutliner.SetMaxAutoPaperSize(aMaxAutoPaperSize);
823cdf0e10cSrcweir         }
824cdf0e10cSrcweir 
825cdf0e10cSrcweir         rOutliner.SetPaperSize(aNullSize);
826cdf0e10cSrcweir         rOutliner.SetUpdateMode(true);
827cdf0e10cSrcweir         rOutliner.SetText(rSdrBlockTextPrimitive.getOutlinerParaObject());
828cdf0e10cSrcweir     }
829cdf0e10cSrcweir 
830cdf0e10cSrcweir     rOutliner.SetControlWord(nOriginalControlWord);
831cdf0e10cSrcweir 
832cdf0e10cSrcweir     // now get back the layouted text size from outliner
833cdf0e10cSrcweir     const Size aOutlinerTextSiz(rOutliner.GetPaperSize());
834cdf0e10cSrcweir     const basegfx::B2DVector aOutlinerScale(aOutlinerTextSiz.Width(), aOutlinerTextSiz.Height());
835cdf0e10cSrcweir     basegfx::B2DVector aAdjustTranslate(0.0, 0.0);
836cdf0e10cSrcweir 
837cdf0e10cSrcweir     // For draw objects containing text correct hor/ver alignment if text is bigger
838cdf0e10cSrcweir     // than the object itself. Without that correction, the text would always be
839cdf0e10cSrcweir     // formatted to the left edge (or top edge when vertical) of the draw object.
840cdf0e10cSrcweir     if(!IsTextFrame() && !bIsCell)
841cdf0e10cSrcweir     {
842cdf0e10cSrcweir         if(aAnchorTextRange.getWidth() < aOutlinerScale.getX() && !bVerticalWritintg)
843cdf0e10cSrcweir         {
844cdf0e10cSrcweir             // Horizontal case here. Correct only if eHAdj == SDRTEXTHORZADJUST_BLOCK,
845cdf0e10cSrcweir             // else the alignment is wanted.
846cdf0e10cSrcweir             if(SDRTEXTHORZADJUST_BLOCK == eHAdj)
847cdf0e10cSrcweir             {
848cdf0e10cSrcweir                 eHAdj = SDRTEXTHORZADJUST_CENTER;
849cdf0e10cSrcweir             }
850cdf0e10cSrcweir         }
851cdf0e10cSrcweir 
852cdf0e10cSrcweir         if(aAnchorTextRange.getHeight() < aOutlinerScale.getY() && bVerticalWritintg)
853cdf0e10cSrcweir         {
854cdf0e10cSrcweir             // Vertical case here. Correct only if eHAdj == SDRTEXTVERTADJUST_BLOCK,
855cdf0e10cSrcweir             // else the alignment is wanted.
856cdf0e10cSrcweir             if(SDRTEXTVERTADJUST_BLOCK == eVAdj)
857cdf0e10cSrcweir             {
858cdf0e10cSrcweir                 eVAdj = SDRTEXTVERTADJUST_CENTER;
859cdf0e10cSrcweir             }
860cdf0e10cSrcweir         }
861cdf0e10cSrcweir     }
862cdf0e10cSrcweir 
863cdf0e10cSrcweir     // correct horizontal translation using the now known text size
864cdf0e10cSrcweir     if(SDRTEXTHORZADJUST_CENTER == eHAdj || SDRTEXTHORZADJUST_RIGHT == eHAdj)
865cdf0e10cSrcweir     {
866cdf0e10cSrcweir         const double fFree(aAnchorTextRange.getWidth() - aOutlinerScale.getX());
867cdf0e10cSrcweir 
868cdf0e10cSrcweir         if(SDRTEXTHORZADJUST_CENTER == eHAdj)
869cdf0e10cSrcweir         {
870cdf0e10cSrcweir             aAdjustTranslate.setX(fFree / 2.0);
871cdf0e10cSrcweir         }
872cdf0e10cSrcweir 
873cdf0e10cSrcweir         if(SDRTEXTHORZADJUST_RIGHT == eHAdj)
874cdf0e10cSrcweir         {
875cdf0e10cSrcweir             aAdjustTranslate.setX(fFree);
876cdf0e10cSrcweir         }
877cdf0e10cSrcweir     }
878cdf0e10cSrcweir 
879cdf0e10cSrcweir     // correct vertical translation using the now known text size
880cdf0e10cSrcweir     if(SDRTEXTVERTADJUST_CENTER == eVAdj || SDRTEXTVERTADJUST_BOTTOM == eVAdj)
881cdf0e10cSrcweir     {
882cdf0e10cSrcweir         const double fFree(aAnchorTextRange.getHeight() - aOutlinerScale.getY());
883cdf0e10cSrcweir 
884cdf0e10cSrcweir         if(SDRTEXTVERTADJUST_CENTER == eVAdj)
885cdf0e10cSrcweir         {
886cdf0e10cSrcweir             aAdjustTranslate.setY(fFree / 2.0);
887cdf0e10cSrcweir         }
888cdf0e10cSrcweir 
889cdf0e10cSrcweir         if(SDRTEXTVERTADJUST_BOTTOM == eVAdj)
890cdf0e10cSrcweir         {
891cdf0e10cSrcweir             aAdjustTranslate.setY(fFree);
892cdf0e10cSrcweir         }
893cdf0e10cSrcweir     }
894cdf0e10cSrcweir 
895cdf0e10cSrcweir     // prepare matrices to apply to newly created primitives. aNewTransformA
896cdf0e10cSrcweir     // will get coordinates in aOutlinerScale size and positive in X, Y.
897cdf0e10cSrcweir     // Translate relative to given primitive to get same rotation and shear
898cdf0e10cSrcweir     // as the master shape we are working on. For vertical, use the top-right
899cdf0e10cSrcweir     // corner
900cdf0e10cSrcweir     const double fStartInX(bVerticalWritintg ? aAdjustTranslate.getX() + aOutlinerScale.getX() : aAdjustTranslate.getX());
901cdf0e10cSrcweir     const basegfx::B2DTuple aAdjOffset(fStartInX, aAdjustTranslate.getY());
902cdf0e10cSrcweir     basegfx::B2DHomMatrix aNewTransformA(basegfx::tools::createTranslateB2DHomMatrix(aAdjOffset.getX(), aAdjOffset.getY()));
903cdf0e10cSrcweir 
904cdf0e10cSrcweir     // mirroring. We are now in aAnchorTextRange sizes. When mirroring in X and Y,
905cdf0e10cSrcweir     // move the null point which was top left to bottom right.
906cdf0e10cSrcweir     const bool bMirrorX(basegfx::fTools::less(aScale.getX(), 0.0));
907cdf0e10cSrcweir     const bool bMirrorY(basegfx::fTools::less(aScale.getY(), 0.0));
908cdf0e10cSrcweir 
909cdf0e10cSrcweir     // in-between the translations of the single primitives will take place. Afterwards,
910cdf0e10cSrcweir     // the object's transformations need to be applied
911cdf0e10cSrcweir     const basegfx::B2DHomMatrix aNewTransformB(basegfx::tools::createScaleShearXRotateTranslateB2DHomMatrix(
912cdf0e10cSrcweir         bMirrorX ? -1.0 : 1.0, bMirrorY ? -1.0 : 1.0,
913cdf0e10cSrcweir         fShearX, fRotate, aTranslate.getX(), aTranslate.getY()));
914cdf0e10cSrcweir 
915cdf0e10cSrcweir     // #SJ# create ClipRange (if needed)
916cdf0e10cSrcweir     basegfx::B2DRange aClipRange;
917cdf0e10cSrcweir 
918cdf0e10cSrcweir     if(rSdrBlockTextPrimitive.getClipOnBounds())
919cdf0e10cSrcweir     {
920cdf0e10cSrcweir         aClipRange.expand(-aAdjOffset);
921cdf0e10cSrcweir         aClipRange.expand(basegfx::B2DTuple(aAnchorTextSize.Width(), aAnchorTextSize.Height()) - aAdjOffset);
922cdf0e10cSrcweir     }
923cdf0e10cSrcweir 
924cdf0e10cSrcweir     // now break up text primitives.
925cdf0e10cSrcweir     impTextBreakupHandler aConverter(rOutliner);
926cdf0e10cSrcweir     aConverter.decomposeBlockTextPrimitive(aNewTransformA, aNewTransformB, aClipRange);
927cdf0e10cSrcweir 
928cdf0e10cSrcweir     // cleanup outliner
929cdf0e10cSrcweir     rOutliner.Clear();
930cdf0e10cSrcweir     rOutliner.setVisualizedPage(0);
931cdf0e10cSrcweir 
932cdf0e10cSrcweir     rTarget = aConverter.getPrimitive2DSequence();
933cdf0e10cSrcweir }
934cdf0e10cSrcweir 
impDecomposeStretchTextPrimitive(drawinglayer::primitive2d::Primitive2DSequence & rTarget,const drawinglayer::primitive2d::SdrStretchTextPrimitive2D & rSdrStretchTextPrimitive,const drawinglayer::geometry::ViewInformation2D & aViewInformation) const935cdf0e10cSrcweir void SdrTextObj::impDecomposeStretchTextPrimitive(
936cdf0e10cSrcweir     drawinglayer::primitive2d::Primitive2DSequence& rTarget,
937cdf0e10cSrcweir     const drawinglayer::primitive2d::SdrStretchTextPrimitive2D& rSdrStretchTextPrimitive,
938cdf0e10cSrcweir     const drawinglayer::geometry::ViewInformation2D& aViewInformation) const
939cdf0e10cSrcweir {
940cdf0e10cSrcweir     // decompose matrix to have position and size of text
941cdf0e10cSrcweir     basegfx::B2DVector aScale, aTranslate;
942cdf0e10cSrcweir     double fRotate, fShearX;
943cdf0e10cSrcweir     rSdrStretchTextPrimitive.getTextRangeTransform().decompose(aScale, aTranslate, fRotate, fShearX);
944cdf0e10cSrcweir 
945cdf0e10cSrcweir     // use non-mirrored B2DRange aAnchorTextRange for calculations
946cdf0e10cSrcweir     basegfx::B2DRange aAnchorTextRange(aTranslate);
947cdf0e10cSrcweir     aAnchorTextRange.expand(aTranslate + aScale);
948cdf0e10cSrcweir 
949cdf0e10cSrcweir     // prepare outliner
950cdf0e10cSrcweir     SdrOutliner& rOutliner = ImpGetDrawOutliner();
951cdf0e10cSrcweir     const sal_uInt32 nOriginalControlWord(rOutliner.GetControlWord());
952cdf0e10cSrcweir     const Size aNullSize;
953cdf0e10cSrcweir 
954cdf0e10cSrcweir     rOutliner.SetControlWord(nOriginalControlWord|EE_CNTRL_STRETCHING|EE_CNTRL_AUTOPAGESIZE);
955cdf0e10cSrcweir     rOutliner.SetFixedCellHeight(rSdrStretchTextPrimitive.isFixedCellHeight());
956cdf0e10cSrcweir     rOutliner.SetMinAutoPaperSize(aNullSize);
957cdf0e10cSrcweir     rOutliner.SetMaxAutoPaperSize(Size(1000000,1000000));
958cdf0e10cSrcweir     rOutliner.SetPaperSize(aNullSize);
959cdf0e10cSrcweir     rOutliner.SetUpdateMode(true);
960cdf0e10cSrcweir     rOutliner.SetText(rSdrStretchTextPrimitive.getOutlinerParaObject());
961cdf0e10cSrcweir 
962cdf0e10cSrcweir     // set visualizing page at Outliner; needed e.g. for PageNumberField decomposition
963cdf0e10cSrcweir     rOutliner.setVisualizedPage(GetSdrPageFromXDrawPage(aViewInformation.getVisualizedPage()));
964cdf0e10cSrcweir 
965cdf0e10cSrcweir     // now get back the layouted text size from outliner
966cdf0e10cSrcweir     const Size aOutlinerTextSiz(rOutliner.CalcTextSize());
967cdf0e10cSrcweir     const basegfx::B2DVector aOutlinerScale(
968cdf0e10cSrcweir         basegfx::fTools::equalZero(aOutlinerTextSiz.Width()) ? 1.0 : aOutlinerTextSiz.Width(),
969cdf0e10cSrcweir         basegfx::fTools::equalZero(aOutlinerTextSiz.Height()) ? 1.0 : aOutlinerTextSiz.Height());
970cdf0e10cSrcweir 
971cdf0e10cSrcweir     // prepare matrices to apply to newly created primitives
972cdf0e10cSrcweir     basegfx::B2DHomMatrix aNewTransformA;
973cdf0e10cSrcweir 
974cdf0e10cSrcweir     // #i101957# Check for vertical text. If used, aNewTransformA
975cdf0e10cSrcweir     // needs to translate the text initially around object width to orient
976cdf0e10cSrcweir     // it relative to the topper right instead of the topper left
977cdf0e10cSrcweir     const bool bVertical(rSdrStretchTextPrimitive.getOutlinerParaObject().IsVertical());
978cdf0e10cSrcweir 
979cdf0e10cSrcweir     if(bVertical)
980cdf0e10cSrcweir     {
981cdf0e10cSrcweir         aNewTransformA.translate(aScale.getX(), 0.0);
982cdf0e10cSrcweir     }
983cdf0e10cSrcweir 
984cdf0e10cSrcweir     // calculate global char stretching scale parameters. Use non-mirrored sizes
985cdf0e10cSrcweir     // to layout without mirroring
986cdf0e10cSrcweir     const double fScaleX(fabs(aScale.getX()) / aOutlinerScale.getX());
987cdf0e10cSrcweir     const double fScaleY(fabs(aScale.getY()) / aOutlinerScale.getY());
988cdf0e10cSrcweir     rOutliner.SetGlobalCharStretching((sal_Int16)FRound(fScaleX * 100.0), (sal_Int16)FRound(fScaleY * 100.0));
989cdf0e10cSrcweir 
990cdf0e10cSrcweir     // mirroring. We are now in aAnchorTextRange sizes. When mirroring in X and Y,
991cdf0e10cSrcweir     // move the null point which was top left to bottom right.
992cdf0e10cSrcweir     const bool bMirrorX(basegfx::fTools::less(aScale.getX(), 0.0));
993cdf0e10cSrcweir     const bool bMirrorY(basegfx::fTools::less(aScale.getY(), 0.0));
994cdf0e10cSrcweir 
995cdf0e10cSrcweir     // in-between the translations of the single primitives will take place. Afterwards,
996cdf0e10cSrcweir     // the object's transformations need to be applied
997cdf0e10cSrcweir     const basegfx::B2DHomMatrix aNewTransformB(basegfx::tools::createScaleShearXRotateTranslateB2DHomMatrix(
998cdf0e10cSrcweir         bMirrorX ? -1.0 : 1.0, bMirrorY ? -1.0 : 1.0,
999cdf0e10cSrcweir         fShearX, fRotate, aTranslate.getX(), aTranslate.getY()));
1000cdf0e10cSrcweir 
1001cdf0e10cSrcweir     // now break up text primitives.
1002cdf0e10cSrcweir     impTextBreakupHandler aConverter(rOutliner);
1003cdf0e10cSrcweir     aConverter.decomposeStretchTextPrimitive(aNewTransformA, aNewTransformB);
1004cdf0e10cSrcweir 
1005cdf0e10cSrcweir     // cleanup outliner
1006cdf0e10cSrcweir     rOutliner.SetControlWord(nOriginalControlWord);
1007cdf0e10cSrcweir     rOutliner.Clear();
1008cdf0e10cSrcweir     rOutliner.setVisualizedPage(0);
1009cdf0e10cSrcweir 
1010cdf0e10cSrcweir     rTarget = aConverter.getPrimitive2DSequence();
1011cdf0e10cSrcweir }
1012cdf0e10cSrcweir 
1013cdf0e10cSrcweir //////////////////////////////////////////////////////////////////////////////
1014cdf0e10cSrcweir // timing generators
1015cdf0e10cSrcweir #define ENDLESS_LOOP    (0xffffffff)
1016cdf0e10cSrcweir #define ENDLESS_TIME    ((double)0xffffffff)
1017cdf0e10cSrcweir #define PIXEL_DPI       (96.0)
1018cdf0e10cSrcweir 
impGetBlinkTextTiming(drawinglayer::animation::AnimationEntryList & rAnimList) const1019cdf0e10cSrcweir void SdrTextObj::impGetBlinkTextTiming(drawinglayer::animation::AnimationEntryList& rAnimList) const
1020cdf0e10cSrcweir {
1021cdf0e10cSrcweir     if(SDRTEXTANI_BLINK == GetTextAniKind())
1022cdf0e10cSrcweir     {
1023cdf0e10cSrcweir         // get values
1024cdf0e10cSrcweir         const SfxItemSet& rSet = GetObjectItemSet();
1025cdf0e10cSrcweir         const sal_uInt32 nRepeat((sal_uInt32)((SdrTextAniCountItem&)rSet.Get(SDRATTR_TEXT_ANICOUNT)).GetValue());
1026cdf0e10cSrcweir         bool bVisisbleWhenStopped(((SdrTextAniStopInsideItem&)rSet.Get(SDRATTR_TEXT_ANISTOPINSIDE)).GetValue());
1027cdf0e10cSrcweir         double fDelay((double)((SdrTextAniDelayItem&)rSet.Get(SDRATTR_TEXT_ANIDELAY)).GetValue());
1028cdf0e10cSrcweir 
1029cdf0e10cSrcweir         if(0.0 == fDelay)
1030cdf0e10cSrcweir         {
1031cdf0e10cSrcweir             // use default
1032cdf0e10cSrcweir             fDelay = 250.0;
1033cdf0e10cSrcweir         }
1034cdf0e10cSrcweir 
1035cdf0e10cSrcweir         // prepare loop and add
1036cdf0e10cSrcweir         drawinglayer::animation::AnimationEntryLoop  aLoop(nRepeat ? nRepeat : ENDLESS_LOOP);
1037cdf0e10cSrcweir         drawinglayer::animation::AnimationEntryFixed aStart(fDelay, 0.0);
1038cdf0e10cSrcweir         aLoop.append(aStart);
1039cdf0e10cSrcweir         drawinglayer::animation::AnimationEntryFixed aEnd(fDelay, 1.0);
1040cdf0e10cSrcweir         aLoop.append(aEnd);
1041cdf0e10cSrcweir         rAnimList.append(aLoop);
1042cdf0e10cSrcweir 
1043cdf0e10cSrcweir         // add stopped state if loop is not endless
1044cdf0e10cSrcweir         if(0L != nRepeat)
1045cdf0e10cSrcweir         {
1046cdf0e10cSrcweir             drawinglayer::animation::AnimationEntryFixed aStop(ENDLESS_TIME, bVisisbleWhenStopped ? 0.0 : 1.0);
1047cdf0e10cSrcweir             rAnimList.append(aStop);
1048cdf0e10cSrcweir         }
1049cdf0e10cSrcweir     }
1050cdf0e10cSrcweir }
1051cdf0e10cSrcweir 
impCreateScrollTiming(const SfxItemSet & rSet,drawinglayer::animation::AnimationEntryList & rAnimList,bool bForward,double fTimeFullPath,double fFrequency)1052cdf0e10cSrcweir void impCreateScrollTiming(const SfxItemSet& rSet, drawinglayer::animation::AnimationEntryList& rAnimList, bool bForward, double fTimeFullPath, double fFrequency)
1053cdf0e10cSrcweir {
1054cdf0e10cSrcweir     bool bVisisbleWhenStopped(((SdrTextAniStopInsideItem&)rSet.Get(SDRATTR_TEXT_ANISTOPINSIDE)).GetValue());
1055cdf0e10cSrcweir     bool bVisisbleWhenStarted(((SdrTextAniStartInsideItem&)rSet.Get(SDRATTR_TEXT_ANISTOPINSIDE )).GetValue());
1056cdf0e10cSrcweir     const sal_uInt32 nRepeat(((SdrTextAniCountItem&)rSet.Get(SDRATTR_TEXT_ANICOUNT)).GetValue());
1057cdf0e10cSrcweir 
1058cdf0e10cSrcweir     if(bVisisbleWhenStarted)
1059cdf0e10cSrcweir     {
1060cdf0e10cSrcweir         // move from center to outside
1061cdf0e10cSrcweir         drawinglayer::animation::AnimationEntryLinear aInOut(fTimeFullPath * 0.5, fFrequency, 0.5, bForward ? 1.0 : 0.0);
1062cdf0e10cSrcweir         rAnimList.append(aInOut);
1063cdf0e10cSrcweir     }
1064cdf0e10cSrcweir 
1065cdf0e10cSrcweir     // loop. In loop, move through
1066cdf0e10cSrcweir     if(nRepeat || 0L == nRepeat)
1067cdf0e10cSrcweir     {
1068cdf0e10cSrcweir         drawinglayer::animation::AnimationEntryLoop aLoop(nRepeat ? nRepeat : ENDLESS_LOOP);
1069cdf0e10cSrcweir         drawinglayer::animation::AnimationEntryLinear aThrough(fTimeFullPath, fFrequency, bForward ? 0.0 : 1.0, bForward ? 1.0 : 0.0);
1070cdf0e10cSrcweir         aLoop.append(aThrough);
1071cdf0e10cSrcweir         rAnimList.append(aLoop);
1072cdf0e10cSrcweir     }
1073cdf0e10cSrcweir 
1074cdf0e10cSrcweir     if(0L != nRepeat && bVisisbleWhenStopped)
1075cdf0e10cSrcweir     {
1076cdf0e10cSrcweir         // move from outside to center
1077cdf0e10cSrcweir         drawinglayer::animation::AnimationEntryLinear aOutIn(fTimeFullPath * 0.5, fFrequency, bForward ? 0.0 : 1.0, 0.5);
1078cdf0e10cSrcweir         rAnimList.append(aOutIn);
1079cdf0e10cSrcweir 
1080cdf0e10cSrcweir         // add timing for staying at the end
1081cdf0e10cSrcweir         drawinglayer::animation::AnimationEntryFixed aEnd(ENDLESS_TIME, 0.5);
1082cdf0e10cSrcweir         rAnimList.append(aEnd);
1083cdf0e10cSrcweir     }
1084cdf0e10cSrcweir }
1085cdf0e10cSrcweir 
impCreateAlternateTiming(const SfxItemSet & rSet,drawinglayer::animation::AnimationEntryList & rAnimList,double fRelativeTextLength,bool bForward,double fTimeFullPath,double fFrequency)1086cdf0e10cSrcweir void impCreateAlternateTiming(const SfxItemSet& rSet, drawinglayer::animation::AnimationEntryList& rAnimList, double fRelativeTextLength, bool bForward, double fTimeFullPath, double fFrequency)
1087cdf0e10cSrcweir {
1088cdf0e10cSrcweir     if(basegfx::fTools::more(fRelativeTextLength, 0.5))
1089cdf0e10cSrcweir     {
1090cdf0e10cSrcweir         // this is the case when fTextLength > fFrameLength, text is bigger than animation frame.
1091cdf0e10cSrcweir         // In that case, correct direction
1092cdf0e10cSrcweir         bForward = !bForward;
1093cdf0e10cSrcweir     }
1094cdf0e10cSrcweir 
1095cdf0e10cSrcweir     const double fStartPosition(bForward ? fRelativeTextLength : 1.0 - fRelativeTextLength);
1096cdf0e10cSrcweir     const double fEndPosition(bForward ? 1.0 - fRelativeTextLength : fRelativeTextLength);
1097cdf0e10cSrcweir     bool bVisisbleWhenStopped(((SdrTextAniStopInsideItem&)rSet.Get(SDRATTR_TEXT_ANISTOPINSIDE)).GetValue());
1098cdf0e10cSrcweir     bool bVisisbleWhenStarted(((SdrTextAniStartInsideItem&)rSet.Get(SDRATTR_TEXT_ANISTOPINSIDE )).GetValue());
1099cdf0e10cSrcweir     const sal_uInt32 nRepeat(((SdrTextAniCountItem&)rSet.Get(SDRATTR_TEXT_ANICOUNT)).GetValue());
1100cdf0e10cSrcweir 
1101cdf0e10cSrcweir     if(!bVisisbleWhenStarted)
1102cdf0e10cSrcweir     {
1103cdf0e10cSrcweir         // move from outside to center
1104cdf0e10cSrcweir         drawinglayer::animation::AnimationEntryLinear aOutIn(fTimeFullPath * 0.5, fFrequency, bForward ? 0.0 : 1.0, 0.5);
1105cdf0e10cSrcweir         rAnimList.append(aOutIn);
1106cdf0e10cSrcweir     }
1107cdf0e10cSrcweir 
1108cdf0e10cSrcweir     // loop. In loop, move out and in again. fInnerMovePath may be negative when text is bigger then frame,
1109cdf0e10cSrcweir     // so use absolute value
1110cdf0e10cSrcweir     const double fInnerMovePath(fabs(1.0 - (fRelativeTextLength * 2.0)));
1111cdf0e10cSrcweir     const double fTimeForInnerPath(fTimeFullPath * fInnerMovePath);
1112cdf0e10cSrcweir     const double fHalfInnerPath(fTimeForInnerPath * 0.5);
1113cdf0e10cSrcweir     const sal_uInt32 nDoubleRepeat(nRepeat / 2L);
1114cdf0e10cSrcweir 
1115cdf0e10cSrcweir     if(nDoubleRepeat || 0L == nRepeat)
1116cdf0e10cSrcweir     {
1117cdf0e10cSrcweir         // double forth and back loop
1118cdf0e10cSrcweir         drawinglayer::animation::AnimationEntryLoop aLoop(nDoubleRepeat ? nDoubleRepeat : ENDLESS_LOOP);
1119cdf0e10cSrcweir         drawinglayer::animation::AnimationEntryLinear aTime0(fHalfInnerPath, fFrequency, 0.5, fEndPosition);
1120cdf0e10cSrcweir         aLoop.append(aTime0);
1121cdf0e10cSrcweir         drawinglayer::animation::AnimationEntryLinear aTime1(fTimeForInnerPath, fFrequency, fEndPosition, fStartPosition);
1122cdf0e10cSrcweir         aLoop.append(aTime1);
1123cdf0e10cSrcweir         drawinglayer::animation::AnimationEntryLinear aTime2(fHalfInnerPath, fFrequency, fStartPosition, 0.5);
1124cdf0e10cSrcweir         aLoop.append(aTime2);
1125cdf0e10cSrcweir         rAnimList.append(aLoop);
1126cdf0e10cSrcweir     }
1127cdf0e10cSrcweir 
1128cdf0e10cSrcweir     if(nRepeat % 2L)
1129cdf0e10cSrcweir     {
1130cdf0e10cSrcweir         // repeat is uneven, so we need one more forth and back to center
1131cdf0e10cSrcweir         drawinglayer::animation::AnimationEntryLinear aTime0(fHalfInnerPath, fFrequency, 0.5, fEndPosition);
1132cdf0e10cSrcweir         rAnimList.append(aTime0);
1133cdf0e10cSrcweir         drawinglayer::animation::AnimationEntryLinear aTime1(fHalfInnerPath, fFrequency, fEndPosition, 0.5);
1134cdf0e10cSrcweir         rAnimList.append(aTime1);
1135cdf0e10cSrcweir     }
1136cdf0e10cSrcweir 
1137cdf0e10cSrcweir     if(0L != nRepeat)
1138cdf0e10cSrcweir     {
1139cdf0e10cSrcweir         if(bVisisbleWhenStopped)
1140cdf0e10cSrcweir         {
1141cdf0e10cSrcweir             // add timing for staying at the end
1142cdf0e10cSrcweir             drawinglayer::animation::AnimationEntryFixed aEnd(ENDLESS_TIME, 0.5);
1143cdf0e10cSrcweir             rAnimList.append(aEnd);
1144cdf0e10cSrcweir         }
1145cdf0e10cSrcweir         else
1146cdf0e10cSrcweir         {
1147cdf0e10cSrcweir             // move from center to outside
1148cdf0e10cSrcweir             drawinglayer::animation::AnimationEntryLinear aInOut(fTimeFullPath * 0.5, fFrequency, 0.5, bForward ? 1.0 : 0.0);
1149cdf0e10cSrcweir             rAnimList.append(aInOut);
1150cdf0e10cSrcweir         }
1151cdf0e10cSrcweir     }
1152cdf0e10cSrcweir }
1153cdf0e10cSrcweir 
impCreateSlideTiming(const SfxItemSet & rSet,drawinglayer::animation::AnimationEntryList & rAnimList,bool bForward,double fTimeFullPath,double fFrequency)1154cdf0e10cSrcweir void impCreateSlideTiming(const SfxItemSet& rSet, drawinglayer::animation::AnimationEntryList& rAnimList, bool bForward, double fTimeFullPath, double fFrequency)
1155cdf0e10cSrcweir {
1156cdf0e10cSrcweir     // move in from outside, start outside
1157cdf0e10cSrcweir     const double fStartPosition(bForward ? 0.0 : 1.0);
1158cdf0e10cSrcweir     const sal_uInt32 nRepeat(((SdrTextAniCountItem&)rSet.Get(SDRATTR_TEXT_ANICOUNT)).GetValue());
1159cdf0e10cSrcweir 
1160cdf0e10cSrcweir     // move from outside to center
1161cdf0e10cSrcweir     drawinglayer::animation::AnimationEntryLinear aOutIn(fTimeFullPath * 0.5, fFrequency, fStartPosition, 0.5);
1162cdf0e10cSrcweir     rAnimList.append(aOutIn);
1163cdf0e10cSrcweir 
1164cdf0e10cSrcweir     // loop. In loop, move out and in again
1165cdf0e10cSrcweir     if(nRepeat > 1L || 0L == nRepeat)
1166cdf0e10cSrcweir     {
1167cdf0e10cSrcweir         drawinglayer::animation::AnimationEntryLoop aLoop(nRepeat ? nRepeat - 1L : ENDLESS_LOOP);
1168cdf0e10cSrcweir         drawinglayer::animation::AnimationEntryLinear aTime0(fTimeFullPath * 0.5, fFrequency, 0.5, fStartPosition);
1169cdf0e10cSrcweir         aLoop.append(aTime0);
1170cdf0e10cSrcweir         drawinglayer::animation::AnimationEntryLinear aTime1(fTimeFullPath * 0.5, fFrequency, fStartPosition, 0.5);
1171cdf0e10cSrcweir         aLoop.append(aTime1);
1172cdf0e10cSrcweir         rAnimList.append(aLoop);
1173cdf0e10cSrcweir     }
1174cdf0e10cSrcweir 
1175cdf0e10cSrcweir     // always visible when stopped, so add timing for staying at the end when not endless
1176cdf0e10cSrcweir     if(0L != nRepeat)
1177cdf0e10cSrcweir     {
1178cdf0e10cSrcweir         drawinglayer::animation::AnimationEntryFixed aEnd(ENDLESS_TIME, 0.5);
1179cdf0e10cSrcweir         rAnimList.append(aEnd);
1180cdf0e10cSrcweir     }
1181cdf0e10cSrcweir }
1182cdf0e10cSrcweir 
impGetScrollTextTiming(drawinglayer::animation::AnimationEntryList & rAnimList,double fFrameLength,double fTextLength) const1183cdf0e10cSrcweir void SdrTextObj::impGetScrollTextTiming(drawinglayer::animation::AnimationEntryList& rAnimList, double fFrameLength, double fTextLength) const
1184cdf0e10cSrcweir {
1185cdf0e10cSrcweir     const SdrTextAniKind eAniKind(GetTextAniKind());
1186cdf0e10cSrcweir 
1187cdf0e10cSrcweir     if(SDRTEXTANI_SCROLL == eAniKind || SDRTEXTANI_ALTERNATE == eAniKind || SDRTEXTANI_SLIDE == eAniKind)
1188cdf0e10cSrcweir     {
1189cdf0e10cSrcweir         // get data. Goal is to calculate fTimeFullPath which is the time needed to
1190cdf0e10cSrcweir         // move animation from (0.0) to (1.0) state
1191cdf0e10cSrcweir         const SfxItemSet& rSet = GetObjectItemSet();
1192cdf0e10cSrcweir         double fAnimationDelay((double)((SdrTextAniDelayItem&)rSet.Get(SDRATTR_TEXT_ANIDELAY)).GetValue());
1193cdf0e10cSrcweir         double fSingleStepWidth((double)((SdrTextAniAmountItem&)rSet.Get(SDRATTR_TEXT_ANIAMOUNT)).GetValue());
1194cdf0e10cSrcweir         const SdrTextAniDirection eDirection(GetTextAniDirection());
1195cdf0e10cSrcweir         const bool bForward(SDRTEXTANI_RIGHT == eDirection || SDRTEXTANI_DOWN == eDirection);
1196cdf0e10cSrcweir 
1197cdf0e10cSrcweir         if(basegfx::fTools::equalZero(fAnimationDelay))
1198cdf0e10cSrcweir         {
1199cdf0e10cSrcweir             // default to 1/20 second
1200cdf0e10cSrcweir             fAnimationDelay = 50.0;
1201cdf0e10cSrcweir         }
1202cdf0e10cSrcweir 
1203cdf0e10cSrcweir         if(basegfx::fTools::less(fSingleStepWidth, 0.0))
1204cdf0e10cSrcweir         {
1205cdf0e10cSrcweir             // data is in pixels, convert to logic. Imply PIXEL_DPI dpi.
1206cdf0e10cSrcweir             // It makes no sense to keep the view-transformation centered
1207cdf0e10cSrcweir             // definitions, so get rid of them here.
1208cdf0e10cSrcweir             fSingleStepWidth = (-fSingleStepWidth * (2540.0 / PIXEL_DPI));
1209cdf0e10cSrcweir         }
1210cdf0e10cSrcweir 
1211cdf0e10cSrcweir         if(basegfx::fTools::equalZero(fSingleStepWidth))
1212cdf0e10cSrcweir         {
1213*85122fc3Smseidel             // default to 1 millimeter
1214cdf0e10cSrcweir             fSingleStepWidth = 100.0;
1215cdf0e10cSrcweir         }
1216cdf0e10cSrcweir 
1217cdf0e10cSrcweir         // use the length of the full animation path and the number of steps
1218cdf0e10cSrcweir         // to get the full path time
1219cdf0e10cSrcweir         const double fFullPathLength(fFrameLength + fTextLength);
1220cdf0e10cSrcweir         const double fNumberOfSteps(fFullPathLength / fSingleStepWidth);
1221cdf0e10cSrcweir         double fTimeFullPath(fNumberOfSteps * fAnimationDelay);
1222cdf0e10cSrcweir 
1223cdf0e10cSrcweir         if(fTimeFullPath < fAnimationDelay)
1224cdf0e10cSrcweir         {
1225cdf0e10cSrcweir             fTimeFullPath = fAnimationDelay;
1226cdf0e10cSrcweir         }
1227cdf0e10cSrcweir 
1228cdf0e10cSrcweir         switch(eAniKind)
1229cdf0e10cSrcweir         {
1230cdf0e10cSrcweir             case SDRTEXTANI_SCROLL :
1231cdf0e10cSrcweir             {
1232cdf0e10cSrcweir                 impCreateScrollTiming(rSet, rAnimList, bForward, fTimeFullPath, fAnimationDelay);
1233cdf0e10cSrcweir                 break;
1234cdf0e10cSrcweir             }
1235cdf0e10cSrcweir             case SDRTEXTANI_ALTERNATE :
1236cdf0e10cSrcweir             {
1237cdf0e10cSrcweir                 double fRelativeTextLength(fTextLength / (fFrameLength + fTextLength));
1238cdf0e10cSrcweir                 impCreateAlternateTiming(rSet, rAnimList, fRelativeTextLength, bForward, fTimeFullPath, fAnimationDelay);
1239cdf0e10cSrcweir                 break;
1240cdf0e10cSrcweir             }
1241cdf0e10cSrcweir             case SDRTEXTANI_SLIDE :
1242cdf0e10cSrcweir             {
1243cdf0e10cSrcweir                 impCreateSlideTiming(rSet, rAnimList, bForward, fTimeFullPath, fAnimationDelay);
1244cdf0e10cSrcweir                 break;
1245cdf0e10cSrcweir             }
1246cdf0e10cSrcweir             default : break; // SDRTEXTANI_NONE, SDRTEXTANI_BLINK
1247cdf0e10cSrcweir         }
1248cdf0e10cSrcweir     }
1249cdf0e10cSrcweir }
1250cdf0e10cSrcweir 
1251*85122fc3Smseidel /* vim: set noet sw=4 ts=4: */
1252