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