1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <svx/svdetc.hxx>
22 #include <svx/svdoutl.hxx>
23 #include <svx/svdpage.hxx>
24 #include <svx/svdotext.hxx>
25 #include <svx/svdmodel.hxx>
26 #include <svx/sdasitm.hxx>
27 #include <textchain.hxx>
28 #include <textchainflow.hxx>
29 #include <svx/sdtacitm.hxx>
30 #include <svx/sdtayitm.hxx>
31 #include <svx/sdtaiitm.hxx>
32 #include <svx/sdtaaitm.hxx>
33 #include <svx/xfillit0.hxx>
34 #include <svx/xbtmpit.hxx>
35 #include <basegfx/vector/b2dvector.hxx>
36 #include <sdr/primitive2d/sdrtextprimitive2d.hxx>
37 #include <drawinglayer/primitive2d/textprimitive2d.hxx>
38 #include <drawinglayer/primitive2d/textdecoratedprimitive2d.hxx>
39 #include <basegfx/range/b2drange.hxx>
40 #include <editeng/eeitem.hxx>
41 #include <editeng/editstat.hxx>
42 #include <tools/helpers.hxx>
43 #include <svl/itemset.hxx>
44 #include <drawinglayer/animation/animationtiming.hxx>
45 #include <basegfx/color/bcolor.hxx>
46 #include <vcl/svapp.hxx>
47 #include <vcl/canvastools.hxx>
48 #include <editeng/escapementitem.hxx>
49 #include <editeng/svxenum.hxx>
50 #include <editeng/flditem.hxx>
51 #include <editeng/adjustitem.hxx>
52 #include <drawinglayer/primitive2d/texthierarchyprimitive2d.hxx>
53 #include <drawinglayer/primitive2d/wrongspellprimitive2d.hxx>
54 #include <drawinglayer/primitive2d/graphicprimitive2d.hxx>
55 #include <drawinglayer/primitive2d/textlayoutdevice.hxx>
56 #include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx>
57 #include <svx/unoapi.hxx>
58 #include <drawinglayer/geometry/viewinformation2d.hxx>
59 #include <editeng/outlobj.hxx>
60 #include <basegfx/matrix/b2dhommatrixtools.hxx>
61 #include <sal/log.hxx>
63 using namespace com::sun::star
;
69 class impTextBreakupHandler
72 drawinglayer::primitive2d::Primitive2DContainer maTextPortionPrimitives
;
73 drawinglayer::primitive2d::Primitive2DContainer maLinePrimitives
;
74 drawinglayer::primitive2d::Primitive2DContainer maParagraphPrimitives
;
76 SdrOutliner
& mrOutliner
;
77 basegfx::B2DHomMatrix maNewTransformA
;
78 basegfx::B2DHomMatrix maNewTransformB
;
80 // the visible area for contour text decomposition
81 basegfx::B2DVector maScale
;
83 // ClipRange for BlockText decomposition; only text portions completely
84 // inside are to be accepted, so this is different from geometric clipping
85 // (which would allow e.g. upper parts of portions to remain). Only used for
86 // BlockText (see there)
87 basegfx::B2DRange maClipRange
;
89 DECL_LINK(decomposeContourTextPrimitive
, DrawPortionInfo
*, void);
90 DECL_LINK(decomposeBlockTextPrimitive
, DrawPortionInfo
*, void);
91 DECL_LINK(decomposeStretchTextPrimitive
, DrawPortionInfo
*, void);
93 DECL_LINK(decomposeContourBulletPrimitive
, DrawBulletInfo
*, void);
94 DECL_LINK(decomposeBlockBulletPrimitive
, DrawBulletInfo
*, void);
95 DECL_LINK(decomposeStretchBulletPrimitive
, DrawBulletInfo
*, void);
97 void impCreateTextPortionPrimitive(const DrawPortionInfo
& rInfo
);
98 static drawinglayer::primitive2d::BasePrimitive2D
* impCheckFieldPrimitive(drawinglayer::primitive2d::BasePrimitive2D
* pPrimitive
, const DrawPortionInfo
& rInfo
);
99 void impFlushTextPortionPrimitivesToLinePrimitives();
100 void impFlushLinePrimitivesToParagraphPrimitives(sal_Int32 nPara
);
101 void impHandleDrawPortionInfo(const DrawPortionInfo
& rInfo
);
102 void impHandleDrawBulletInfo(const DrawBulletInfo
& rInfo
);
105 explicit impTextBreakupHandler(SdrOutliner
& rOutliner
)
106 : maTextPortionPrimitives(),
108 maParagraphPrimitives(),
109 mrOutliner(rOutliner
),
117 void decomposeContourTextPrimitive(const basegfx::B2DHomMatrix
& rNewTransformA
, const basegfx::B2DHomMatrix
& rNewTransformB
, const basegfx::B2DVector
& rScale
)
120 maNewTransformA
= rNewTransformA
;
121 maNewTransformB
= rNewTransformB
;
122 mrOutliner
.SetDrawPortionHdl(LINK(this, impTextBreakupHandler
, decomposeContourTextPrimitive
));
123 mrOutliner
.SetDrawBulletHdl(LINK(this, impTextBreakupHandler
, decomposeContourBulletPrimitive
));
124 mrOutliner
.StripPortions();
125 mrOutliner
.SetDrawPortionHdl(Link
<DrawPortionInfo
*,void>());
126 mrOutliner
.SetDrawBulletHdl(Link
<DrawBulletInfo
*,void>());
129 void decomposeBlockTextPrimitive(
130 const basegfx::B2DHomMatrix
& rNewTransformA
,
131 const basegfx::B2DHomMatrix
& rNewTransformB
,
132 const basegfx::B2DRange
& rClipRange
)
134 maNewTransformA
= rNewTransformA
;
135 maNewTransformB
= rNewTransformB
;
136 maClipRange
= rClipRange
;
137 mrOutliner
.SetDrawPortionHdl(LINK(this, impTextBreakupHandler
, decomposeBlockTextPrimitive
));
138 mrOutliner
.SetDrawBulletHdl(LINK(this, impTextBreakupHandler
, decomposeBlockBulletPrimitive
));
139 mrOutliner
.StripPortions();
140 mrOutliner
.SetDrawPortionHdl(Link
<DrawPortionInfo
*,void>());
141 mrOutliner
.SetDrawBulletHdl(Link
<DrawBulletInfo
*,void>());
144 void decomposeStretchTextPrimitive(const basegfx::B2DHomMatrix
& rNewTransformA
, const basegfx::B2DHomMatrix
& rNewTransformB
)
146 maNewTransformA
= rNewTransformA
;
147 maNewTransformB
= rNewTransformB
;
148 mrOutliner
.SetDrawPortionHdl(LINK(this, impTextBreakupHandler
, decomposeStretchTextPrimitive
));
149 mrOutliner
.SetDrawBulletHdl(LINK(this, impTextBreakupHandler
, decomposeStretchBulletPrimitive
));
150 mrOutliner
.StripPortions();
151 mrOutliner
.SetDrawPortionHdl(Link
<DrawPortionInfo
*,void>());
152 mrOutliner
.SetDrawBulletHdl(Link
<DrawBulletInfo
*,void>());
155 drawinglayer::primitive2d::Primitive2DContainer
const & getPrimitive2DSequence();
158 void impTextBreakupHandler::impCreateTextPortionPrimitive(const DrawPortionInfo
& rInfo
)
160 if(rInfo
.maText
.isEmpty() || !rInfo
.mnTextLen
)
163 OUString caseMappedText
= rInfo
.mrFont
.CalcCaseMap( rInfo
.maText
);
164 basegfx::B2DVector aFontScaling
;
165 drawinglayer::attribute::FontAttribute
aFontAttribute(
166 drawinglayer::primitive2d::getFontAttributeFromVclFont(
171 basegfx::B2DHomMatrix aNewTransform
;
173 // add font scale to new transform
174 aNewTransform
.scale(aFontScaling
.getX(), aFontScaling
.getY());
176 // look for proportional font scaling, if necessary, scale accordingly
177 sal_Int8
nPropr(rInfo
.mrFont
.GetPropr());
180 const double fFactor(rInfo
.mrFont
.GetPropr() / 100.0);
181 aNewTransform
.scale(fFactor
, fFactor
);
185 if(rInfo
.mrFont
.GetOrientation())
187 aNewTransform
.rotate(-rInfo
.mrFont
.GetOrientation().get() * F_PI1800
);
190 // look for escapement, if necessary, translate accordingly
191 if(rInfo
.mrFont
.GetEscapement())
193 sal_Int16
nEsc(rInfo
.mrFont
.GetEscapement());
195 if(DFLT_ESC_AUTO_SUPER
== nEsc
)
197 nEsc
= .8 * (100 - nPropr
);
198 assert (nEsc
== DFLT_ESC_SUPER
&& "I'm sure this formula needs to be changed, but how to confirm that???");
199 nEsc
= DFLT_ESC_SUPER
;
201 else if(DFLT_ESC_AUTO_SUB
== nEsc
)
203 nEsc
= .2 * -(100 - nPropr
);
204 assert (nEsc
== -20 && "I'm sure this formula needs to be changed, but how to confirm that???");
208 if(nEsc
> MAX_ESC_POS
)
212 else if(nEsc
< -MAX_ESC_POS
)
217 const double fEscapement(nEsc
/ -100.0);
218 aNewTransform
.translate(0.0, fEscapement
* aFontScaling
.getY());
222 aNewTransform
*= maNewTransformA
;
224 // apply local offset
225 aNewTransform
.translate(rInfo
.mrStartPos
.X(), rInfo
.mrStartPos
.Y());
227 // also apply embedding object's transform
228 aNewTransform
*= maNewTransformB
;
230 // prepare DXArray content. To make it independent from font size (and such from
231 // the text transformation), scale it to unit coordinates
232 ::std::vector
< double > aDXArray
;
234 if(rInfo
.mpDXArray
&& rInfo
.mnTextLen
)
236 aDXArray
.reserve(rInfo
.mnTextLen
);
238 for(sal_Int32 a
=0; a
< rInfo
.mnTextLen
; a
++)
240 aDXArray
.push_back(static_cast<double>(rInfo
.mpDXArray
[a
]));
244 // create complex text primitive and append
245 const Color
aFontColor(rInfo
.mrFont
.GetColor());
246 const basegfx::BColor
aBFontColor(aFontColor
.getBColor());
248 const Color
aTextFillColor(rInfo
.mrFont
.GetFillColor());
250 // prepare wordLineMode (for underline and strikeout)
251 // NOT for bullet texts. It is set (this may be an error by itself), but needs to be suppressed to hinder e.g. '1)'
252 // to be split which would not look like the original
253 const bool bWordLineMode(rInfo
.mrFont
.IsWordLineMode() && !rInfo
.mbEndOfBullet
);
255 // prepare new primitive
256 drawinglayer::primitive2d::BasePrimitive2D
* pNewPrimitive
= nullptr;
257 const bool bDecoratedIsNeeded(
258 LINESTYLE_NONE
!= rInfo
.mrFont
.GetOverline()
259 || LINESTYLE_NONE
!= rInfo
.mrFont
.GetUnderline()
260 || STRIKEOUT_NONE
!= rInfo
.mrFont
.GetStrikeout()
261 || FontEmphasisMark::NONE
!= (rInfo
.mrFont
.GetEmphasisMark() & FontEmphasisMark::Style
)
262 || FontRelief::NONE
!= rInfo
.mrFont
.GetRelief()
263 || rInfo
.mrFont
.IsShadow()
266 if(bDecoratedIsNeeded
)
268 // TextDecoratedPortionPrimitive2D needed, prepare some more data
269 // get overline and underline color. If it's on automatic (0xffffffff) use FontColor instead
270 const Color
aUnderlineColor(rInfo
.maTextLineColor
);
271 const basegfx::BColor
aBUnderlineColor((aUnderlineColor
== COL_AUTO
) ? aBFontColor
: aUnderlineColor
.getBColor());
272 const Color
aOverlineColor(rInfo
.maOverlineColor
);
273 const basegfx::BColor
aBOverlineColor((aOverlineColor
== COL_AUTO
) ? aBFontColor
: aOverlineColor
.getBColor());
275 // prepare overline and underline data
276 const drawinglayer::primitive2d::TextLine
eFontOverline(
277 drawinglayer::primitive2d::mapFontLineStyleToTextLine(rInfo
.mrFont
.GetOverline()));
278 const drawinglayer::primitive2d::TextLine
eFontLineStyle(
279 drawinglayer::primitive2d::mapFontLineStyleToTextLine(rInfo
.mrFont
.GetUnderline()));
281 // check UnderlineAbove
282 const bool bUnderlineAbove(
283 drawinglayer::primitive2d::TEXT_LINE_NONE
!= eFontLineStyle
&& rInfo
.mrFont
.IsUnderlineAbove());
285 // prepare strikeout data
286 const drawinglayer::primitive2d::TextStrikeout
eTextStrikeout(
287 drawinglayer::primitive2d::mapFontStrikeoutToTextStrikeout(rInfo
.mrFont
.GetStrikeout()));
289 // prepare emphasis mark data
290 drawinglayer::primitive2d::TextEmphasisMark
eTextEmphasisMark(drawinglayer::primitive2d::TEXT_FONT_EMPHASIS_MARK_NONE
);
292 switch(rInfo
.mrFont
.GetEmphasisMark() & FontEmphasisMark::Style
)
294 case FontEmphasisMark::Dot
: eTextEmphasisMark
= drawinglayer::primitive2d::TEXT_FONT_EMPHASIS_MARK_DOT
; break;
295 case FontEmphasisMark::Circle
: eTextEmphasisMark
= drawinglayer::primitive2d::TEXT_FONT_EMPHASIS_MARK_CIRCLE
; break;
296 case FontEmphasisMark::Disc
: eTextEmphasisMark
= drawinglayer::primitive2d::TEXT_FONT_EMPHASIS_MARK_DISC
; break;
297 case FontEmphasisMark::Accent
: eTextEmphasisMark
= drawinglayer::primitive2d::TEXT_FONT_EMPHASIS_MARK_ACCENT
; break;
301 const bool bEmphasisMarkAbove(rInfo
.mrFont
.GetEmphasisMark() & FontEmphasisMark::PosAbove
);
302 const bool bEmphasisMarkBelow(rInfo
.mrFont
.GetEmphasisMark() & FontEmphasisMark::PosBelow
);
304 // prepare font relief data
305 drawinglayer::primitive2d::TextRelief
eTextRelief(drawinglayer::primitive2d::TEXT_RELIEF_NONE
);
307 switch(rInfo
.mrFont
.GetRelief())
309 case FontRelief::Embossed
: eTextRelief
= drawinglayer::primitive2d::TEXT_RELIEF_EMBOSSED
; break;
310 case FontRelief::Engraved
: eTextRelief
= drawinglayer::primitive2d::TEXT_RELIEF_ENGRAVED
; break;
311 default : break; // RELIEF_NONE, FontRelief_FORCE_EQUAL_SIZE
314 // prepare shadow/outline data
315 const bool bShadow(rInfo
.mrFont
.IsShadow());
317 // TextDecoratedPortionPrimitive2D is needed, create one
318 pNewPrimitive
= new drawinglayer::primitive2d::TextDecoratedPortionPrimitive2D(
320 // attributes for TextSimplePortionPrimitive2D
327 rInfo
.mpLocale
? *rInfo
.mpLocale
: css::lang::Locale(),
331 // attributes for TextDecoratedPortionPrimitive2D
347 // TextSimplePortionPrimitive2D is enough
348 pNewPrimitive
= new drawinglayer::primitive2d::TextSimplePortionPrimitive2D(
355 rInfo
.mpLocale
? *rInfo
.mpLocale
: css::lang::Locale(),
362 if (aFontColor
.GetTransparency() != 0)
364 // Handle semi-transparent text for both the decorated and simple case here.
365 pNewPrimitive
= new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D(
366 drawinglayer::primitive2d::Primitive2DContainer
{ pNewPrimitive
},
367 aFontColor
.GetTransparency() / 255.0);
370 if(rInfo
.mbEndOfBullet
)
372 // embed in TextHierarchyBulletPrimitive2D
373 const drawinglayer::primitive2d::Primitive2DReference
aNewReference(pNewPrimitive
);
374 const drawinglayer::primitive2d::Primitive2DContainer aNewSequence
{ aNewReference
} ;
375 pNewPrimitive
= new drawinglayer::primitive2d::TextHierarchyBulletPrimitive2D(aNewSequence
);
378 if(rInfo
.mpFieldData
)
380 pNewPrimitive
= impCheckFieldPrimitive(pNewPrimitive
, rInfo
);
383 maTextPortionPrimitives
.push_back(pNewPrimitive
);
385 // support for WrongSpellVector. Create WrongSpellPrimitives as needed
386 if(!rInfo
.mpWrongSpellVector
|| aDXArray
.empty())
389 const sal_Int32
nSize(rInfo
.mpWrongSpellVector
->size());
390 const sal_Int32
nDXCount(aDXArray
.size());
391 const basegfx::BColor
aSpellColor(1.0, 0.0, 0.0); // red, hard coded
393 for(sal_Int32
a(0); a
< nSize
; a
++)
395 const EEngineData::WrongSpellClass
& rCandidate
= (*rInfo
.mpWrongSpellVector
)[a
];
397 if(rCandidate
.nStart
>= rInfo
.mnTextStart
&& rCandidate
.nEnd
>= rInfo
.mnTextStart
&& rCandidate
.nEnd
> rCandidate
.nStart
)
399 const sal_Int32
nStart(rCandidate
.nStart
- rInfo
.mnTextStart
);
400 const sal_Int32
nEnd(rCandidate
.nEnd
- rInfo
.mnTextStart
);
404 if(nStart
> 0 && nStart
- 1 < nDXCount
)
406 fStart
= aDXArray
[nStart
- 1];
409 if(nEnd
> 0 && nEnd
- 1 < nDXCount
)
411 fEnd
= aDXArray
[nEnd
- 1];
414 if(!basegfx::fTools::equal(fStart
, fEnd
))
419 // When the portion is RTL, mirror the redlining using the
420 // full portion width
421 const double fTextWidth(aDXArray
[aDXArray
.size() - 1]);
423 fStart
= fTextWidth
- fStart
;
424 fEnd
= fTextWidth
- fEnd
;
427 // need to take FontScaling out of values; it's already part of
428 // aNewTransform and would be double applied
429 const double fFontScaleX(aFontScaling
.getX());
431 if(!basegfx::fTools::equal(fFontScaleX
, 1.0)
432 && !basegfx::fTools::equalZero(fFontScaleX
))
434 fStart
/= fFontScaleX
;
438 maTextPortionPrimitives
.push_back(new drawinglayer::primitive2d::WrongSpellPrimitive2D(
448 drawinglayer::primitive2d::BasePrimitive2D
* impTextBreakupHandler::impCheckFieldPrimitive(drawinglayer::primitive2d::BasePrimitive2D
* pPrimitive
, const DrawPortionInfo
& rInfo
)
450 if(rInfo
.mpFieldData
)
452 // Support for FIELD_SEQ_BEGIN, FIELD_SEQ_END. If used, create a TextHierarchyFieldPrimitive2D
453 // which holds the field type and, if applicable, the URL
454 const SvxURLField
* pURLField
= dynamic_cast< const SvxURLField
* >(rInfo
.mpFieldData
);
455 const SvxPageField
* pPageField
= dynamic_cast< const SvxPageField
* >(rInfo
.mpFieldData
);
457 // embed current primitive to a sequence
458 drawinglayer::primitive2d::Primitive2DContainer aSequence
;
463 aSequence
[0] = drawinglayer::primitive2d::Primitive2DReference(pPrimitive
);
468 // extended this to hold more of the contents of the original
469 // SvxURLField since that stuff is still used in HitTest and e.g. Calc
470 std::vector
< std::pair
< OUString
, OUString
>> meValues
;
471 meValues
.emplace_back("URL", pURLField
->GetURL());
472 meValues
.emplace_back("Representation", pURLField
->GetRepresentation());
473 meValues
.emplace_back("TargetFrame", pURLField
->GetTargetFrame());
474 meValues
.emplace_back("SvxURLFormat", OUString::number(static_cast<sal_uInt16
>(pURLField
->GetFormat())));
475 pPrimitive
= new drawinglayer::primitive2d::TextHierarchyFieldPrimitive2D(aSequence
, drawinglayer::primitive2d::FIELD_TYPE_URL
, &meValues
);
479 pPrimitive
= new drawinglayer::primitive2d::TextHierarchyFieldPrimitive2D(aSequence
, drawinglayer::primitive2d::FIELD_TYPE_PAGE
);
483 pPrimitive
= new drawinglayer::primitive2d::TextHierarchyFieldPrimitive2D(aSequence
, drawinglayer::primitive2d::FIELD_TYPE_COMMON
);
490 void impTextBreakupHandler::impFlushTextPortionPrimitivesToLinePrimitives()
492 // only create a line primitive when we had content; there is no need for
493 // empty line primitives (contrary to paragraphs, see below).
494 if(!maTextPortionPrimitives
.empty())
496 maLinePrimitives
.push_back(new drawinglayer::primitive2d::TextHierarchyLinePrimitive2D(maTextPortionPrimitives
));
497 maTextPortionPrimitives
.clear();
501 void impTextBreakupHandler::impFlushLinePrimitivesToParagraphPrimitives(sal_Int32 nPara
)
503 sal_Int16 nDepth
= mrOutliner
.GetDepth(nPara
);
504 EBulletInfo eInfo
= mrOutliner
.GetBulletInfo(nPara
);
505 // Pass -1 to signal VclMetafileProcessor2D that there is no active
506 // bullets/numbering in this paragraph (i.e. this is normal text)
507 const sal_Int16
nOutlineLevel( eInfo
.bVisible
? nDepth
: -1);
509 // ALWAYS create a paragraph primitive, even when no content was added. This is done to
510 // have the correct paragraph count even with empty paragraphs. Those paragraphs will
511 // have an empty sub-PrimitiveSequence.
512 maParagraphPrimitives
.push_back(
513 new drawinglayer::primitive2d::TextHierarchyParagraphPrimitive2D(
516 maLinePrimitives
.clear();
519 void impTextBreakupHandler::impHandleDrawPortionInfo(const DrawPortionInfo
& rInfo
)
521 impCreateTextPortionPrimitive(rInfo
);
523 if(rInfo
.mbEndOfLine
|| rInfo
.mbEndOfParagraph
)
525 impFlushTextPortionPrimitivesToLinePrimitives();
528 if(rInfo
.mbEndOfParagraph
)
530 impFlushLinePrimitivesToParagraphPrimitives(rInfo
.mnPara
);
534 void impTextBreakupHandler::impHandleDrawBulletInfo(const DrawBulletInfo
& rInfo
)
536 basegfx::B2DHomMatrix aNewTransform
;
538 // add size to new transform
539 aNewTransform
.scale(rInfo
.maBulletSize
.getWidth(), rInfo
.maBulletSize
.getHeight());
542 aNewTransform
*= maNewTransformA
;
544 // apply local offset
545 aNewTransform
.translate(rInfo
.maBulletPosition
.X(), rInfo
.maBulletPosition
.Y());
547 // also apply embedding object's transform
548 aNewTransform
*= maNewTransformB
;
550 // prepare empty GraphicAttr
551 const GraphicAttr aGraphicAttr
;
553 // create GraphicPrimitive2D
554 const drawinglayer::primitive2d::Primitive2DReference
aNewReference(new drawinglayer::primitive2d::GraphicPrimitive2D(
556 rInfo
.maBulletGraphicObject
,
559 // embed in TextHierarchyBulletPrimitive2D
560 const drawinglayer::primitive2d::Primitive2DContainer aNewSequence
{ aNewReference
};
561 drawinglayer::primitive2d::BasePrimitive2D
* pNewPrimitive
= new drawinglayer::primitive2d::TextHierarchyBulletPrimitive2D(aNewSequence
);
564 maTextPortionPrimitives
.push_back(pNewPrimitive
);
567 IMPL_LINK(impTextBreakupHandler
, decomposeContourTextPrimitive
, DrawPortionInfo
*, pInfo
, void)
569 // for contour text, ignore (clip away) all portions which are below
570 // the visible area given by maScale
571 if(pInfo
&& static_cast<double>(pInfo
->mrStartPos
.Y()) < maScale
.getY())
573 impHandleDrawPortionInfo(*pInfo
);
577 IMPL_LINK(impTextBreakupHandler
, decomposeBlockTextPrimitive
, DrawPortionInfo
*, pInfo
, void)
582 // Is clipping wanted? This is text clipping; only accept a portion
583 // if it's completely in the range
584 if(!maClipRange
.isEmpty())
586 // Test start position first; this allows to not get the text range at
587 // all if text is far outside
588 const basegfx::B2DPoint
aStartPosition(pInfo
->mrStartPos
.X(), pInfo
->mrStartPos
.Y());
590 if(!maClipRange
.isInside(aStartPosition
))
595 // Start position is inside. Get TextBoundRect and TopLeft next
596 drawinglayer::primitive2d::TextLayouterDevice aTextLayouterDevice
;
597 aTextLayouterDevice
.setFont(pInfo
->mrFont
);
599 const basegfx::B2DRange
aTextBoundRect(
600 aTextLayouterDevice
.getTextBoundRect(
601 pInfo
->maText
, pInfo
->mnTextStart
, pInfo
->mnTextLen
));
602 const basegfx::B2DPoint
aTopLeft(aTextBoundRect
.getMinimum() + aStartPosition
);
604 if(!maClipRange
.isInside(aTopLeft
))
609 // TopLeft is inside. Get BottomRight and check
610 const basegfx::B2DPoint
aBottomRight(aTextBoundRect
.getMaximum() + aStartPosition
);
612 if(!maClipRange
.isInside(aBottomRight
))
617 // all inside, clip was successful
619 impHandleDrawPortionInfo(*pInfo
);
622 IMPL_LINK(impTextBreakupHandler
, decomposeStretchTextPrimitive
, DrawPortionInfo
*, pInfo
, void)
626 impHandleDrawPortionInfo(*pInfo
);
630 IMPL_LINK(impTextBreakupHandler
, decomposeContourBulletPrimitive
, DrawBulletInfo
*, pInfo
, void)
634 impHandleDrawBulletInfo(*pInfo
);
638 IMPL_LINK(impTextBreakupHandler
, decomposeBlockBulletPrimitive
, DrawBulletInfo
*, pInfo
, void)
642 impHandleDrawBulletInfo(*pInfo
);
646 IMPL_LINK(impTextBreakupHandler
, decomposeStretchBulletPrimitive
, DrawBulletInfo
*, pInfo
, void)
650 impHandleDrawBulletInfo(*pInfo
);
654 drawinglayer::primitive2d::Primitive2DContainer
const & impTextBreakupHandler::getPrimitive2DSequence()
656 if(!maTextPortionPrimitives
.empty())
658 // collect non-closed lines
659 impFlushTextPortionPrimitivesToLinePrimitives();
662 if(!maLinePrimitives
.empty())
664 // collect non-closed paragraphs
665 impFlushLinePrimitivesToParagraphPrimitives(mrOutliner
.GetParagraphCount() - 1);
668 return maParagraphPrimitives
;
670 } // end of anonymous namespace
673 // primitive decompositions
675 void SdrTextObj::impDecomposeContourTextPrimitive(
676 drawinglayer::primitive2d::Primitive2DContainer
& rTarget
,
677 const drawinglayer::primitive2d::SdrContourTextPrimitive2D
& rSdrContourTextPrimitive
,
678 const drawinglayer::geometry::ViewInformation2D
& aViewInformation
) const
680 // decompose matrix to have position and size of text
681 basegfx::B2DVector aScale
, aTranslate
;
682 double fRotate
, fShearX
;
683 rSdrContourTextPrimitive
.getObjectTransform().decompose(aScale
, aTranslate
, fRotate
, fShearX
);
685 // prepare contour polygon, force to non-mirrored for laying out
686 basegfx::B2DPolyPolygon
aPolyPolygon(rSdrContourTextPrimitive
.getUnitPolyPolygon());
687 aPolyPolygon
.transform(basegfx::utils::createScaleB2DHomMatrix(fabs(aScale
.getX()), fabs(aScale
.getY())));
690 SolarMutexGuard aSolarGuard
;
691 SdrOutliner
& rOutliner
= ImpGetDrawOutliner();
692 const Size aNullSize
;
693 rOutliner
.SetPaperSize(aNullSize
);
694 rOutliner
.SetPolygon(aPolyPolygon
);
695 rOutliner
.SetUpdateMode(true);
696 rOutliner
.SetText(rSdrContourTextPrimitive
.getOutlinerParaObject());
698 // set visualizing page at Outliner; needed e.g. for PageNumberField decomposition
699 rOutliner
.setVisualizedPage(GetSdrPageFromXDrawPage(aViewInformation
.getVisualizedPage()));
701 // prepare matrices to apply to newly created primitives
702 basegfx::B2DHomMatrix aNewTransformA
;
704 // mirroring. We are now in the polygon sizes. When mirroring in X and Y,
705 // move the null point which was top left to bottom right.
706 const bool bMirrorX(basegfx::fTools::less(aScale
.getX(), 0.0));
707 const bool bMirrorY(basegfx::fTools::less(aScale
.getY(), 0.0));
709 // in-between the translations of the single primitives will take place. Afterwards,
710 // the object's transformations need to be applied
711 const basegfx::B2DHomMatrix
aNewTransformB(basegfx::utils::createScaleShearXRotateTranslateB2DHomMatrix(
712 bMirrorX
? -1.0 : 1.0, bMirrorY
? -1.0 : 1.0,
713 fShearX
, fRotate
, aTranslate
.getX(), aTranslate
.getY()));
715 // now break up text primitives.
716 impTextBreakupHandler
aConverter(rOutliner
);
717 aConverter
.decomposeContourTextPrimitive(aNewTransformA
, aNewTransformB
, aScale
);
721 rOutliner
.setVisualizedPage(nullptr);
723 rTarget
= aConverter
.getPrimitive2DSequence();
726 void SdrTextObj::impDecomposeAutoFitTextPrimitive(
727 drawinglayer::primitive2d::Primitive2DContainer
& rTarget
,
728 const drawinglayer::primitive2d::SdrAutoFitTextPrimitive2D
& rSdrAutofitTextPrimitive
,
729 const drawinglayer::geometry::ViewInformation2D
& aViewInformation
) const
731 // decompose matrix to have position and size of text
732 basegfx::B2DVector aScale
, aTranslate
;
733 double fRotate
, fShearX
;
734 rSdrAutofitTextPrimitive
.getTextRangeTransform().decompose(aScale
, aTranslate
, fRotate
, fShearX
);
736 // use B2DRange aAnchorTextRange for calculations
737 basegfx::B2DRange
aAnchorTextRange(aTranslate
);
738 aAnchorTextRange
.expand(aTranslate
+ aScale
);
741 const SfxItemSet
& rTextItemSet
= rSdrAutofitTextPrimitive
.getSdrText()->GetItemSet();
742 SolarMutexGuard aSolarGuard
;
743 SdrOutliner
& rOutliner
= ImpGetDrawOutliner();
744 SdrTextVertAdjust eVAdj
= GetTextVerticalAdjust(rTextItemSet
);
745 SdrTextHorzAdjust eHAdj
= GetTextHorizontalAdjust(rTextItemSet
);
746 const EEControlBits
nOriginalControlWord(rOutliner
.GetControlWord());
747 const Size aNullSize
;
749 // set visualizing page at Outliner; needed e.g. for PageNumberField decomposition
750 rOutliner
.setVisualizedPage(GetSdrPageFromXDrawPage(aViewInformation
.getVisualizedPage()));
752 rOutliner
.SetControlWord(nOriginalControlWord
|EEControlBits::AUTOPAGESIZE
|EEControlBits::STRETCHING
);
753 rOutliner
.SetMinAutoPaperSize(aNullSize
);
754 rOutliner
.SetMaxAutoPaperSize(Size(1000000,1000000));
756 // add one to rage sizes to get back to the old Rectangle and outliner measurements
757 const sal_uInt32
nAnchorTextWidth(FRound(aAnchorTextRange
.getWidth() + 1));
758 const sal_uInt32
nAnchorTextHeight(FRound(aAnchorTextRange
.getHeight() + 1));
759 const OutlinerParaObject
* pOutlinerParaObject
= rSdrAutofitTextPrimitive
.getSdrText()->GetOutlinerParaObject();
760 OSL_ENSURE(pOutlinerParaObject
, "impDecomposeBlockTextPrimitive used with no OutlinerParaObject (!)");
761 const bool bVerticalWriting(pOutlinerParaObject
->IsVertical());
762 const bool bTopToBottom(pOutlinerParaObject
->IsTopToBottom());
763 const Size
aAnchorTextSize(Size(nAnchorTextWidth
, nAnchorTextHeight
));
765 if(rSdrAutofitTextPrimitive
.getWordWrap() || IsTextFrame())
767 rOutliner
.SetMaxAutoPaperSize(aAnchorTextSize
);
770 if(SDRTEXTHORZADJUST_BLOCK
== eHAdj
&& !bVerticalWriting
)
772 rOutliner
.SetMinAutoPaperSize(Size(nAnchorTextWidth
, 0));
775 if(SDRTEXTVERTADJUST_BLOCK
== eVAdj
&& bVerticalWriting
)
777 rOutliner
.SetMinAutoPaperSize(Size(0, nAnchorTextHeight
));
780 rOutliner
.SetPaperSize(aNullSize
);
781 rOutliner
.SetUpdateMode(true);
782 rOutliner
.SetText(*pOutlinerParaObject
);
783 ImpAutoFitText(rOutliner
,aAnchorTextSize
,bVerticalWriting
);
785 // set visualizing page at Outliner; needed e.g. for PageNumberField decomposition
786 rOutliner
.setVisualizedPage(GetSdrPageFromXDrawPage(aViewInformation
.getVisualizedPage()));
788 // now get back the layouted text size from outliner
789 const Size
aOutlinerTextSize(rOutliner
.GetPaperSize());
790 const basegfx::B2DVector
aOutlinerScale(aOutlinerTextSize
.Width(), aOutlinerTextSize
.Height());
791 basegfx::B2DVector
aAdjustTranslate(0.0, 0.0);
793 // correct horizontal translation using the now known text size
794 if(SDRTEXTHORZADJUST_CENTER
== eHAdj
|| SDRTEXTHORZADJUST_RIGHT
== eHAdj
)
796 const double fFree(aAnchorTextRange
.getWidth() - aOutlinerScale
.getX());
798 if(SDRTEXTHORZADJUST_CENTER
== eHAdj
)
800 aAdjustTranslate
.setX(fFree
/ 2.0);
803 if(SDRTEXTHORZADJUST_RIGHT
== eHAdj
)
805 aAdjustTranslate
.setX(fFree
);
809 // correct vertical translation using the now known text size
810 if(SDRTEXTVERTADJUST_CENTER
== eVAdj
|| SDRTEXTVERTADJUST_BOTTOM
== eVAdj
)
812 const double fFree(aAnchorTextRange
.getHeight() - aOutlinerScale
.getY());
814 if(SDRTEXTVERTADJUST_CENTER
== eVAdj
)
816 aAdjustTranslate
.setY(fFree
/ 2.0);
819 if(SDRTEXTVERTADJUST_BOTTOM
== eVAdj
)
821 aAdjustTranslate
.setY(fFree
);
825 // prepare matrices to apply to newly created primitives. aNewTransformA
826 // will get coordinates in aOutlinerScale size and positive in X, Y.
827 basegfx::B2DHomMatrix aNewTransformA
;
828 basegfx::B2DHomMatrix aNewTransformB
;
830 // translate relative to given primitive to get same rotation and shear
831 // as the master shape we are working on. For vertical, use the top-right
833 const double fStartInX(bVerticalWriting
&& bTopToBottom
? aAdjustTranslate
.getX() + aOutlinerScale
.getX() : aAdjustTranslate
.getX());
834 const double fStartInY(bVerticalWriting
&& !bTopToBottom
? aAdjustTranslate
.getY() + aOutlinerScale
.getY() : aAdjustTranslate
.getY());
835 aNewTransformA
.translate(fStartInX
, fStartInY
);
837 // mirroring. We are now in aAnchorTextRange sizes. When mirroring in X and Y,
838 // move the null point which was top left to bottom right.
839 const bool bMirrorX(basegfx::fTools::less(aScale
.getX(), 0.0));
840 const bool bMirrorY(basegfx::fTools::less(aScale
.getY(), 0.0));
841 aNewTransformB
.scale(bMirrorX
? -1.0 : 1.0, bMirrorY
? -1.0 : 1.0);
843 // in-between the translations of the single primitives will take place. Afterwards,
844 // the object's transformations need to be applied
845 aNewTransformB
.shearX(fShearX
);
846 aNewTransformB
.rotate(fRotate
);
847 aNewTransformB
.translate(aTranslate
.getX(), aTranslate
.getY());
849 basegfx::B2DRange aClipRange
;
851 // now break up text primitives.
852 impTextBreakupHandler
aConverter(rOutliner
);
853 aConverter
.decomposeBlockTextPrimitive(aNewTransformA
, aNewTransformB
, aClipRange
);
857 rOutliner
.setVisualizedPage(nullptr);
858 rOutliner
.SetControlWord(nOriginalControlWord
);
860 rTarget
= aConverter
.getPrimitive2DSequence();
863 // Resolves: fdo#35779 set background color of this shape as the editeng background if there
864 // is one. Check the shape itself, then the host page, then that page's master page.
865 void SdrObject::setSuitableOutlinerBg(::Outliner
& rOutliner
) const
867 const SfxItemSet
* pBackgroundFillSet
= getBackgroundFillSet();
868 if (drawing::FillStyle_NONE
!= pBackgroundFillSet
->Get(XATTR_FILLSTYLE
).GetValue())
870 Color
aColor(rOutliner
.GetBackgroundColor());
871 GetDraftFillColor(*pBackgroundFillSet
, aColor
);
872 rOutliner
.SetBackgroundColor(aColor
);
876 const SfxItemSet
* SdrObject::getBackgroundFillSet() const
878 const SfxItemSet
* pBackgroundFillSet
= &GetObjectItemSet();
880 if (drawing::FillStyle_NONE
== pBackgroundFillSet
->Get(XATTR_FILLSTYLE
).GetValue())
882 SdrPage
* pOwnerPage(getSdrPageFromSdrObject());
885 pBackgroundFillSet
= &pOwnerPage
->getSdrPageProperties().GetItemSet();
887 if (drawing::FillStyle_NONE
== pBackgroundFillSet
->Get(XATTR_FILLSTYLE
).GetValue())
889 if (!pOwnerPage
->IsMasterPage() && pOwnerPage
->TRG_HasMasterPage())
891 pBackgroundFillSet
= &pOwnerPage
->TRG_GetMasterPage().getSdrPageProperties().GetItemSet();
896 return pBackgroundFillSet
;
899 const Graphic
* SdrObject::getFillGraphic() const
901 if(IsGroupObject()) // Doesn't make sense, and GetObjectItemSet() asserts.
903 const SfxItemSet
* pBackgroundFillSet
= getBackgroundFillSet();
904 if (drawing::FillStyle_BITMAP
!= pBackgroundFillSet
->Get(XATTR_FILLSTYLE
).GetValue())
906 return &pBackgroundFillSet
->Get(XATTR_FILLBITMAP
).GetGraphicObject().GetGraphic();
909 void SdrTextObj::impDecomposeBlockTextPrimitive(
910 drawinglayer::primitive2d::Primitive2DContainer
& rTarget
,
911 const drawinglayer::primitive2d::SdrBlockTextPrimitive2D
& rSdrBlockTextPrimitive
,
912 const drawinglayer::geometry::ViewInformation2D
& aViewInformation
) const
914 // decompose matrix to have position and size of text
915 basegfx::B2DVector aScale
, aTranslate
;
916 double fRotate
, fShearX
;
917 rSdrBlockTextPrimitive
.getTextRangeTransform().decompose(aScale
, aTranslate
, fRotate
, fShearX
);
919 // use B2DRange aAnchorTextRange for calculations
920 basegfx::B2DRange
aAnchorTextRange(aTranslate
);
921 aAnchorTextRange
.expand(aTranslate
+ aScale
);
924 const bool bIsCell(rSdrBlockTextPrimitive
.getCellText());
925 SolarMutexGuard aSolarGuard
;
926 SdrOutliner
& rOutliner
= ImpGetDrawOutliner();
927 SdrTextHorzAdjust eHAdj
= rSdrBlockTextPrimitive
.getSdrTextHorzAdjust();
928 SdrTextVertAdjust eVAdj
= rSdrBlockTextPrimitive
.getSdrTextVertAdjust();
929 const EEControlBits
nOriginalControlWord(rOutliner
.GetControlWord());
930 const Size aNullSize
;
932 // set visualizing page at Outliner; needed e.g. for PageNumberField decomposition
933 rOutliner
.setVisualizedPage(GetSdrPageFromXDrawPage(aViewInformation
.getVisualizedPage()));
934 rOutliner
.SetFixedCellHeight(rSdrBlockTextPrimitive
.isFixedCellHeight());
935 rOutliner
.SetControlWord(nOriginalControlWord
|EEControlBits::AUTOPAGESIZE
);
936 rOutliner
.SetMinAutoPaperSize(aNullSize
);
937 rOutliner
.SetMaxAutoPaperSize(Size(1000000,1000000));
939 // That color needs to be restored on leaving this method
940 Color
aOriginalBackColor(rOutliner
.GetBackgroundColor());
941 setSuitableOutlinerBg(rOutliner
);
943 // add one to rage sizes to get back to the old Rectangle and outliner measurements
944 const sal_uInt32
nAnchorTextWidth(FRound(aAnchorTextRange
.getWidth() + 1));
945 const sal_uInt32
nAnchorTextHeight(FRound(aAnchorTextRange
.getHeight() + 1));
946 const bool bVerticalWriting(rSdrBlockTextPrimitive
.getOutlinerParaObject().IsVertical());
947 const bool bTopToBottom(rSdrBlockTextPrimitive
.getOutlinerParaObject().IsTopToBottom());
948 const Size
aAnchorTextSize(Size(nAnchorTextWidth
, nAnchorTextHeight
));
952 // cell text is formatted neither like a text object nor like an object
953 // text, so use a special setup here
954 rOutliner
.SetMaxAutoPaperSize(aAnchorTextSize
);
956 // #i106214# To work with an unchangeable PaperSize (CellSize in
957 // this case) Set(Min|Max)AutoPaperSize and SetPaperSize have to be used.
958 // #i106214# This was not completely correct; to still measure the real
959 // text height to allow vertical adjust (and vice versa for VerticalWritintg)
960 // only one aspect has to be set, but the other one to zero
963 // measure the horizontal text size
964 rOutliner
.SetMinAutoPaperSize(Size(0, aAnchorTextSize
.Height()));
968 // measure the vertical text size
969 rOutliner
.SetMinAutoPaperSize(Size(aAnchorTextSize
.Width(), 0));
972 rOutliner
.SetPaperSize(aAnchorTextSize
);
973 rOutliner
.SetUpdateMode(true);
974 rOutliner
.SetText(rSdrBlockTextPrimitive
.getOutlinerParaObject());
978 // check if block text is used (only one of them can be true)
979 const bool bHorizontalIsBlock(SDRTEXTHORZADJUST_BLOCK
== eHAdj
&& !bVerticalWriting
);
980 const bool bVerticalIsBlock(SDRTEXTVERTADJUST_BLOCK
== eVAdj
&& bVerticalWriting
);
982 // set minimal paper size horizontally/vertically if needed
983 if(bHorizontalIsBlock
)
985 rOutliner
.SetMinAutoPaperSize(Size(nAnchorTextWidth
, 0));
987 else if(bVerticalIsBlock
)
989 rOutliner
.SetMinAutoPaperSize(Size(0, nAnchorTextHeight
));
992 if((rSdrBlockTextPrimitive
.getWordWrap() || IsTextFrame()) && !rSdrBlockTextPrimitive
.getUnlimitedPage())
994 // #i103454# maximal paper size hor/ver needs to be limited to text
995 // frame size. If it's block text, still allow the 'other' direction
996 // to grow to get a correct real text size when using GetPaperSize().
997 // When just using aAnchorTextSize as maximum, GetPaperSize()
998 // would just return aAnchorTextSize again: this means, the wanted
999 // 'measurement' of the real size of block text would not work
1000 Size
aMaxAutoPaperSize(aAnchorTextSize
);
1002 // Usual processing - always grow in one of directions
1003 bool bAllowGrowVertical
= !bVerticalWriting
;
1004 bool bAllowGrowHorizontal
= bVerticalWriting
;
1006 // Compatibility mode for tdf#99729
1007 if (getSdrModelFromSdrObject().IsAnchoredTextOverflowLegacy())
1009 bAllowGrowVertical
= bHorizontalIsBlock
;
1010 bAllowGrowHorizontal
= bVerticalIsBlock
;
1013 if (bAllowGrowVertical
)
1015 // allow to grow vertical for horizontal texts
1016 aMaxAutoPaperSize
.setHeight(1000000);
1018 else if (bAllowGrowHorizontal
)
1020 // allow to grow horizontal for vertical texts
1021 aMaxAutoPaperSize
.setWidth(1000000);
1024 rOutliner
.SetMaxAutoPaperSize(aMaxAutoPaperSize
);
1027 rOutliner
.SetPaperSize(aNullSize
);
1028 rOutliner
.SetUpdateMode(true);
1029 rOutliner
.SetText(rSdrBlockTextPrimitive
.getOutlinerParaObject());
1032 rOutliner
.SetControlWord(nOriginalControlWord
);
1034 // now get back the layouted text size from outliner
1035 const Size
aOutlinerTextSize(rOutliner
.GetPaperSize());
1036 const basegfx::B2DVector
aOutlinerScale(aOutlinerTextSize
.Width(), aOutlinerTextSize
.Height());
1037 basegfx::B2DVector
aAdjustTranslate(0.0, 0.0);
1039 // For draw objects containing text correct hor/ver alignment if text is bigger
1040 // than the object itself. Without that correction, the text would always be
1041 // formatted to the left edge (or top edge when vertical) of the draw object.
1042 if(!IsTextFrame() && !bIsCell
)
1044 if(aAnchorTextRange
.getWidth() < aOutlinerScale
.getX() && !bVerticalWriting
)
1046 // Horizontal case here. Correct only if eHAdj == SDRTEXTHORZADJUST_BLOCK,
1047 // else the alignment is wanted.
1048 if(SDRTEXTHORZADJUST_BLOCK
== eHAdj
)
1050 SvxAdjust eAdjust
= GetObjectItemSet().Get(EE_PARA_JUST
).GetAdjust();
1053 case SvxAdjust::Left
: eHAdj
= SDRTEXTHORZADJUST_LEFT
; break;
1054 case SvxAdjust::Right
: eHAdj
= SDRTEXTHORZADJUST_RIGHT
; break;
1055 case SvxAdjust::Center
: eHAdj
= SDRTEXTHORZADJUST_CENTER
; break;
1061 if(aAnchorTextRange
.getHeight() < aOutlinerScale
.getY() && bVerticalWriting
)
1063 // Vertical case here. Correct only if eHAdj == SDRTEXTVERTADJUST_BLOCK,
1064 // else the alignment is wanted.
1065 if(SDRTEXTVERTADJUST_BLOCK
== eVAdj
)
1067 eVAdj
= SDRTEXTVERTADJUST_CENTER
;
1072 // correct horizontal translation using the now known text size
1073 if(SDRTEXTHORZADJUST_CENTER
== eHAdj
|| SDRTEXTHORZADJUST_RIGHT
== eHAdj
)
1075 const double fFree(aAnchorTextRange
.getWidth() - aOutlinerScale
.getX());
1077 if(SDRTEXTHORZADJUST_CENTER
== eHAdj
)
1079 aAdjustTranslate
.setX(fFree
/ 2.0);
1082 if(SDRTEXTHORZADJUST_RIGHT
== eHAdj
)
1084 aAdjustTranslate
.setX(fFree
);
1088 // correct vertical translation using the now known text size
1089 if(SDRTEXTVERTADJUST_CENTER
== eVAdj
|| SDRTEXTVERTADJUST_BOTTOM
== eVAdj
)
1091 const double fFree(aAnchorTextRange
.getHeight() - aOutlinerScale
.getY());
1093 if(SDRTEXTVERTADJUST_CENTER
== eVAdj
)
1095 aAdjustTranslate
.setY(fFree
/ 2.0);
1098 if(SDRTEXTVERTADJUST_BOTTOM
== eVAdj
)
1100 aAdjustTranslate
.setY(fFree
);
1104 // prepare matrices to apply to newly created primitives. aNewTransformA
1105 // will get coordinates in aOutlinerScale size and positive in X, Y.
1106 // Translate relative to given primitive to get same rotation and shear
1107 // as the master shape we are working on. For vertical, use the top-right
1109 const double fStartInX(bVerticalWriting
&& bTopToBottom
? aAdjustTranslate
.getX() + aOutlinerScale
.getX() : aAdjustTranslate
.getX());
1110 const double fStartInY(bVerticalWriting
&& !bTopToBottom
? aAdjustTranslate
.getY() + aOutlinerScale
.getY() : aAdjustTranslate
.getY());
1111 const basegfx::B2DTuple
aAdjOffset(fStartInX
, fStartInY
);
1112 basegfx::B2DHomMatrix
aNewTransformA(basegfx::utils::createTranslateB2DHomMatrix(aAdjOffset
.getX(), aAdjOffset
.getY()));
1114 // Apply the camera rotation. It have to be applied after adjustment of
1115 // the text (top, bottom, center, left, right).
1116 if(GetCameraZRotation() != 0)
1118 // First find the text rect.
1119 basegfx::B2DRange
aTextRectangle(/*x1=*/aTranslate
.getX() + aAdjustTranslate
.getX(),
1120 /*y1=*/aTranslate
.getY() + aAdjustTranslate
.getY(),
1121 /*x2=*/aTranslate
.getX() + aOutlinerScale
.getX() - aAdjustTranslate
.getX(),
1122 /*y2=*/aTranslate
.getY() + aOutlinerScale
.getY() - aAdjustTranslate
.getY());
1124 // Rotate the text from the center point.
1125 basegfx::B2DVector
aTranslateToCenter(aTextRectangle
.getWidth() / 2, aTextRectangle
.getHeight() / 2);
1126 aNewTransformA
.translate(-aTranslateToCenter
.getX(), -aTranslateToCenter
.getY());
1127 aNewTransformA
.rotate(basegfx::deg2rad(360.0 - GetCameraZRotation() ));
1128 aNewTransformA
.translate(aTranslateToCenter
.getX(), aTranslateToCenter
.getY());
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 const bool bMirrorX(basegfx::fTools::less(aScale
.getX(), 0.0));
1134 const bool bMirrorY(basegfx::fTools::less(aScale
.getY(), 0.0));
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::utils::createScaleShearXRotateTranslateB2DHomMatrix(
1139 bMirrorX
? -1.0 : 1.0, bMirrorY
? -1.0 : 1.0,
1140 fShearX
, fRotate
, aTranslate
.getX(), aTranslate
.getY()));
1143 // create ClipRange (if needed)
1144 basegfx::B2DRange aClipRange
;
1146 // now break up text primitives.
1147 impTextBreakupHandler
aConverter(rOutliner
);
1148 aConverter
.decomposeBlockTextPrimitive(aNewTransformA
, aNewTransformB
, aClipRange
);
1151 rOutliner
.SetBackgroundColor(aOriginalBackColor
);
1153 rOutliner
.setVisualizedPage(nullptr);
1155 rTarget
= aConverter
.getPrimitive2DSequence();
1158 void SdrTextObj::impDecomposeStretchTextPrimitive(
1159 drawinglayer::primitive2d::Primitive2DContainer
& rTarget
,
1160 const drawinglayer::primitive2d::SdrStretchTextPrimitive2D
& rSdrStretchTextPrimitive
,
1161 const drawinglayer::geometry::ViewInformation2D
& aViewInformation
) const
1163 // decompose matrix to have position and size of text
1164 basegfx::B2DVector aScale
, aTranslate
;
1165 double fRotate
, fShearX
;
1166 rSdrStretchTextPrimitive
.getTextRangeTransform().decompose(aScale
, aTranslate
, fRotate
, fShearX
);
1169 SolarMutexGuard aSolarGuard
;
1170 SdrOutliner
& rOutliner
= ImpGetDrawOutliner();
1171 const EEControlBits
nOriginalControlWord(rOutliner
.GetControlWord());
1172 const Size aNullSize
;
1174 rOutliner
.SetControlWord(nOriginalControlWord
|EEControlBits::STRETCHING
|EEControlBits::AUTOPAGESIZE
);
1175 rOutliner
.SetFixedCellHeight(rSdrStretchTextPrimitive
.isFixedCellHeight());
1176 rOutliner
.SetMinAutoPaperSize(aNullSize
);
1177 rOutliner
.SetMaxAutoPaperSize(Size(1000000,1000000));
1178 rOutliner
.SetPaperSize(aNullSize
);
1179 rOutliner
.SetUpdateMode(true);
1180 rOutliner
.SetText(rSdrStretchTextPrimitive
.getOutlinerParaObject());
1182 // set visualizing page at Outliner; needed e.g. for PageNumberField decomposition
1183 rOutliner
.setVisualizedPage(GetSdrPageFromXDrawPage(aViewInformation
.getVisualizedPage()));
1185 // now get back the laid out text size from outliner
1186 const Size
aOutlinerTextSize(rOutliner
.CalcTextSize());
1187 const basegfx::B2DVector
aOutlinerScale(
1188 basegfx::fTools::equalZero(aOutlinerTextSize
.Width()) ? 1.0 : aOutlinerTextSize
.Width(),
1189 basegfx::fTools::equalZero(aOutlinerTextSize
.Height()) ? 1.0 : aOutlinerTextSize
.Height());
1191 // prepare matrices to apply to newly created primitives
1192 basegfx::B2DHomMatrix aNewTransformA
;
1194 // #i101957# Check for vertical text. If used, aNewTransformA
1195 // needs to translate the text initially around object width to orient
1196 // it relative to the topper right instead of the topper left
1197 const bool bVertical(rSdrStretchTextPrimitive
.getOutlinerParaObject().IsVertical());
1198 const bool bTopToBottom(rSdrStretchTextPrimitive
.getOutlinerParaObject().IsTopToBottom());
1203 aNewTransformA
.translate(aScale
.getX(), 0.0);
1205 aNewTransformA
.translate(0.0, aScale
.getY());
1208 // calculate global char stretching scale parameters. Use non-mirrored sizes
1209 // to layout without mirroring
1210 const double fScaleX(fabs(aScale
.getX()) / aOutlinerScale
.getX());
1211 const double fScaleY(fabs(aScale
.getY()) / aOutlinerScale
.getY());
1212 rOutliner
.SetGlobalCharStretching(static_cast<sal_Int16
>(FRound(fScaleX
* 100.0)), static_cast<sal_Int16
>(FRound(fScaleY
* 100.0)));
1214 // When mirroring in X and Y,
1215 // move the null point which was top left to bottom right.
1216 const bool bMirrorX(basegfx::fTools::less(aScale
.getX(), 0.0));
1217 const bool bMirrorY(basegfx::fTools::less(aScale
.getY(), 0.0));
1219 // in-between the translations of the single primitives will take place. Afterwards,
1220 // the object's transformations need to be applied
1221 const basegfx::B2DHomMatrix
aNewTransformB(basegfx::utils::createScaleShearXRotateTranslateB2DHomMatrix(
1222 bMirrorX
? -1.0 : 1.0, bMirrorY
? -1.0 : 1.0,
1223 fShearX
, fRotate
, aTranslate
.getX(), aTranslate
.getY()));
1225 // now break up text primitives.
1226 impTextBreakupHandler
aConverter(rOutliner
);
1227 aConverter
.decomposeStretchTextPrimitive(aNewTransformA
, aNewTransformB
);
1230 rOutliner
.SetControlWord(nOriginalControlWord
);
1232 rOutliner
.setVisualizedPage(nullptr);
1234 rTarget
= aConverter
.getPrimitive2DSequence();
1238 // timing generators
1239 #define ENDLESS_LOOP (0xffffffff)
1240 #define ENDLESS_TIME (double(0xffffffff))
1241 #define PIXEL_DPI (96.0)
1243 void SdrTextObj::impGetBlinkTextTiming(drawinglayer::animation::AnimationEntryList
& rAnimList
) const
1245 if(SdrTextAniKind::Blink
!= GetTextAniKind())
1249 const SfxItemSet
& rSet
= GetObjectItemSet();
1250 const sal_uInt32
nRepeat(static_cast<sal_uInt32
>(rSet
.Get(SDRATTR_TEXT_ANICOUNT
).GetValue()));
1251 double fDelay(static_cast<double>(rSet
.Get(SDRATTR_TEXT_ANIDELAY
).GetValue()));
1259 // prepare loop and add
1260 drawinglayer::animation::AnimationEntryLoop
aLoop(nRepeat
? nRepeat
: ENDLESS_LOOP
);
1261 drawinglayer::animation::AnimationEntryFixed
aStart(fDelay
, 0.0);
1262 aLoop
.append(aStart
);
1263 drawinglayer::animation::AnimationEntryFixed
aEnd(fDelay
, 1.0);
1265 rAnimList
.append(aLoop
);
1267 // add stopped state if loop is not endless
1270 bool bVisibleWhenStopped(rSet
.Get(SDRATTR_TEXT_ANISTOPINSIDE
).GetValue());
1271 drawinglayer::animation::AnimationEntryFixed
aStop(ENDLESS_TIME
, bVisibleWhenStopped
? 0.0 : 1.0);
1272 rAnimList
.append(aStop
);
1276 static void impCreateScrollTiming(const SfxItemSet
& rSet
, drawinglayer::animation::AnimationEntryList
& rAnimList
, bool bForward
, double fTimeFullPath
, double fFrequency
)
1278 bool bVisibleWhenStopped(rSet
.Get(SDRATTR_TEXT_ANISTOPINSIDE
).GetValue());
1279 bool bVisibleWhenStarted(rSet
.Get(SDRATTR_TEXT_ANISTARTINSIDE
).GetValue());
1280 const sal_uInt32
nRepeat(rSet
.Get(SDRATTR_TEXT_ANICOUNT
).GetValue());
1282 if(bVisibleWhenStarted
)
1284 // move from center to outside
1285 drawinglayer::animation::AnimationEntryLinear
aInOut(fTimeFullPath
* 0.5, fFrequency
, 0.5, bForward
? 1.0 : 0.0);
1286 rAnimList
.append(aInOut
);
1289 // loop. In loop, move through
1290 drawinglayer::animation::AnimationEntryLoop
aLoop(nRepeat
? nRepeat
: ENDLESS_LOOP
);
1291 drawinglayer::animation::AnimationEntryLinear
aThrough(fTimeFullPath
, fFrequency
, bForward
? 0.0 : 1.0, bForward
? 1.0 : 0.0);
1292 aLoop
.append(aThrough
);
1293 rAnimList
.append(aLoop
);
1295 if(0 != nRepeat
&& bVisibleWhenStopped
)
1297 // move from outside to center
1298 drawinglayer::animation::AnimationEntryLinear
aOutIn(fTimeFullPath
* 0.5, fFrequency
, bForward
? 0.0 : 1.0, 0.5);
1299 rAnimList
.append(aOutIn
);
1301 // add timing for staying at the end
1302 drawinglayer::animation::AnimationEntryFixed
aEnd(ENDLESS_TIME
, 0.5);
1303 rAnimList
.append(aEnd
);
1307 static void impCreateAlternateTiming(const SfxItemSet
& rSet
, drawinglayer::animation::AnimationEntryList
& rAnimList
, double fRelativeTextLength
, bool bForward
, double fTimeFullPath
, double fFrequency
)
1309 if(basegfx::fTools::more(fRelativeTextLength
, 0.5))
1311 // this is the case when fTextLength > fFrameLength, text is bigger than animation frame.
1312 // In that case, correct direction
1313 bForward
= !bForward
;
1316 const double fStartPosition(bForward
? fRelativeTextLength
: 1.0 - fRelativeTextLength
);
1317 const double fEndPosition(bForward
? 1.0 - fRelativeTextLength
: fRelativeTextLength
);
1318 bool bVisibleWhenStarted(rSet
.Get(SDRATTR_TEXT_ANISTARTINSIDE
).GetValue());
1319 const sal_uInt32
nRepeat(rSet
.Get(SDRATTR_TEXT_ANICOUNT
).GetValue());
1321 if(!bVisibleWhenStarted
)
1323 // move from outside to center
1324 drawinglayer::animation::AnimationEntryLinear
aOutIn(fTimeFullPath
* 0.5, fFrequency
, bForward
? 0.0 : 1.0, 0.5);
1325 rAnimList
.append(aOutIn
);
1328 // loop. In loop, move out and in again. fInnerMovePath may be negative when text is bigger then frame,
1329 // so use absolute value
1330 const double fInnerMovePath(fabs(1.0 - (fRelativeTextLength
* 2.0)));
1331 const double fTimeForInnerPath(fTimeFullPath
* fInnerMovePath
);
1332 const double fHalfInnerPath(fTimeForInnerPath
* 0.5);
1333 const sal_uInt32
nDoubleRepeat(nRepeat
/ 2L);
1335 if(nDoubleRepeat
|| 0 == nRepeat
)
1337 // double forth and back loop
1338 drawinglayer::animation::AnimationEntryLoop
aLoop(nDoubleRepeat
? nDoubleRepeat
: ENDLESS_LOOP
);
1339 drawinglayer::animation::AnimationEntryLinear
aTime0(fHalfInnerPath
, fFrequency
, 0.5, fEndPosition
);
1340 aLoop
.append(aTime0
);
1341 drawinglayer::animation::AnimationEntryLinear
aTime1(fTimeForInnerPath
, fFrequency
, fEndPosition
, fStartPosition
);
1342 aLoop
.append(aTime1
);
1343 drawinglayer::animation::AnimationEntryLinear
aTime2(fHalfInnerPath
, fFrequency
, fStartPosition
, 0.5);
1344 aLoop
.append(aTime2
);
1345 rAnimList
.append(aLoop
);
1350 // repeat is uneven, so we need one more forth and back to center
1351 drawinglayer::animation::AnimationEntryLinear
aTime0(fHalfInnerPath
, fFrequency
, 0.5, fEndPosition
);
1352 rAnimList
.append(aTime0
);
1353 drawinglayer::animation::AnimationEntryLinear
aTime1(fHalfInnerPath
, fFrequency
, fEndPosition
, 0.5);
1354 rAnimList
.append(aTime1
);
1360 bool bVisibleWhenStopped(rSet
.Get(SDRATTR_TEXT_ANISTOPINSIDE
).GetValue());
1361 if(bVisibleWhenStopped
)
1363 // add timing for staying at the end
1364 drawinglayer::animation::AnimationEntryFixed
aEnd(ENDLESS_TIME
, 0.5);
1365 rAnimList
.append(aEnd
);
1369 // move from center to outside
1370 drawinglayer::animation::AnimationEntryLinear
aInOut(fTimeFullPath
* 0.5, fFrequency
, 0.5, bForward
? 1.0 : 0.0);
1371 rAnimList
.append(aInOut
);
1375 static void impCreateSlideTiming(const SfxItemSet
& rSet
, drawinglayer::animation::AnimationEntryList
& rAnimList
, bool bForward
, double fTimeFullPath
, double fFrequency
)
1377 // move in from outside, start outside
1378 const double fStartPosition(bForward
? 0.0 : 1.0);
1379 const sal_uInt32
nRepeat(rSet
.Get(SDRATTR_TEXT_ANICOUNT
).GetValue());
1381 // move from outside to center
1382 drawinglayer::animation::AnimationEntryLinear
aOutIn(fTimeFullPath
* 0.5, fFrequency
, fStartPosition
, 0.5);
1383 rAnimList
.append(aOutIn
);
1385 // loop. In loop, move out and in again
1386 if(nRepeat
> 1 || 0 == nRepeat
)
1388 drawinglayer::animation::AnimationEntryLoop
aLoop(nRepeat
? nRepeat
- 1 : ENDLESS_LOOP
);
1389 drawinglayer::animation::AnimationEntryLinear
aTime0(fTimeFullPath
* 0.5, fFrequency
, 0.5, fStartPosition
);
1390 aLoop
.append(aTime0
);
1391 drawinglayer::animation::AnimationEntryLinear
aTime1(fTimeFullPath
* 0.5, fFrequency
, fStartPosition
, 0.5);
1392 aLoop
.append(aTime1
);
1393 rAnimList
.append(aLoop
);
1396 // always visible when stopped, so add timing for staying at the end when not endless
1399 drawinglayer::animation::AnimationEntryFixed
aEnd(ENDLESS_TIME
, 0.5);
1400 rAnimList
.append(aEnd
);
1404 void SdrTextObj::impGetScrollTextTiming(drawinglayer::animation::AnimationEntryList
& rAnimList
, double fFrameLength
, double fTextLength
) const
1406 const SdrTextAniKind
eAniKind(GetTextAniKind());
1408 if(SdrTextAniKind::Scroll
!= eAniKind
&& SdrTextAniKind::Alternate
!= eAniKind
&& SdrTextAniKind::Slide
!= eAniKind
)
1411 // get data. Goal is to calculate fTimeFullPath which is the time needed to
1412 // move animation from (0.0) to (1.0) state
1413 const SfxItemSet
& rSet
= GetObjectItemSet();
1414 double fAnimationDelay(static_cast<double>(rSet
.Get(SDRATTR_TEXT_ANIDELAY
).GetValue()));
1415 double fSingleStepWidth(static_cast<double>(rSet
.Get(SDRATTR_TEXT_ANIAMOUNT
).GetValue()));
1416 const SdrTextAniDirection
eDirection(GetTextAniDirection());
1417 const bool bForward(SdrTextAniDirection::Right
== eDirection
|| SdrTextAniDirection::Down
== eDirection
);
1419 if(basegfx::fTools::equalZero(fAnimationDelay
))
1421 // default to 1/20 second
1422 fAnimationDelay
= 50.0;
1425 if(basegfx::fTools::less(fSingleStepWidth
, 0.0))
1427 // data is in pixels, convert to logic. Imply PIXEL_DPI dpi.
1428 // It makes no sense to keep the view-transformation centered
1429 // definitions, so get rid of them here.
1430 fSingleStepWidth
= (-fSingleStepWidth
* (2540.0 / PIXEL_DPI
));
1433 if(basegfx::fTools::equalZero(fSingleStepWidth
))
1435 // default to 1 millimeter
1436 fSingleStepWidth
= 100.0;
1439 // use the length of the full animation path and the number of steps
1440 // to get the full path time
1441 const double fFullPathLength(fFrameLength
+ fTextLength
);
1442 const double fNumberOfSteps(fFullPathLength
/ fSingleStepWidth
);
1443 double fTimeFullPath(fNumberOfSteps
* fAnimationDelay
);
1445 if(fTimeFullPath
< fAnimationDelay
)
1447 fTimeFullPath
= fAnimationDelay
;
1452 case SdrTextAniKind::Scroll
:
1454 impCreateScrollTiming(rSet
, rAnimList
, bForward
, fTimeFullPath
, fAnimationDelay
);
1457 case SdrTextAniKind::Alternate
:
1459 double fRelativeTextLength(fTextLength
/ (fFrameLength
+ fTextLength
));
1460 impCreateAlternateTiming(rSet
, rAnimList
, fRelativeTextLength
, bForward
, fTimeFullPath
, fAnimationDelay
);
1463 case SdrTextAniKind::Slide
:
1465 impCreateSlideTiming(rSet
, rAnimList
, bForward
, fTimeFullPath
, fAnimationDelay
);
1468 default : break; // SdrTextAniKind::NONE, SdrTextAniKind::Blink
1472 void SdrTextObj::impHandleChainingEventsDuringDecomposition(SdrOutliner
&rOutliner
) const
1474 if (GetTextChain()->GetNilChainingEvent(this))
1477 GetTextChain()->SetNilChainingEvent(this, true);
1479 TextChainFlow
aTxtChainFlow(const_cast<SdrTextObj
*>(this));
1483 // Some debug output
1484 size_t nObjCount(getSdrPageFromSdrObject()->GetObjCount());
1485 for (size_t i
= 0; i
< nObjCount
; i
++)
1487 SdrTextObj
* pCurObj(dynamic_cast< SdrTextObj
* >(getSdrPageFromSdrObject()->GetObj(i
)));
1490 SAL_INFO("svx.chaining", "Working on TextBox " << i
);
1496 aTxtChainFlow
.CheckForFlowEvents(&rOutliner
);
1498 if (aTxtChainFlow
.IsUnderflow() && !IsInEditMode())
1500 // underflow-induced overflow
1501 aTxtChainFlow
.ExecuteUnderflow(&rOutliner
);
1502 bIsOverflow
= aTxtChainFlow
.IsOverflow();
1504 // standard overflow (no underflow before)
1505 bIsOverflow
= aTxtChainFlow
.IsOverflow();
1508 if (bIsOverflow
&& !IsInEditMode()) {
1509 // Initialize Chaining Outliner
1510 SdrOutliner
&rChainingOutl(getSdrModelFromSdrObject().GetChainingOutliner(this));
1511 ImpInitDrawOutliner( rChainingOutl
);
1512 rChainingOutl
.SetUpdateMode(true);
1513 // We must pass the chaining outliner otherwise we would mess up decomposition
1514 aTxtChainFlow
.ExecuteOverflow(&rOutliner
, &rChainingOutl
);
1517 GetTextChain()->SetNilChainingEvent(this, false);
1520 void SdrTextObj::impDecomposeChainedTextPrimitive(
1521 drawinglayer::primitive2d::Primitive2DContainer
& rTarget
,
1522 const drawinglayer::primitive2d::SdrChainedTextPrimitive2D
& rSdrChainedTextPrimitive
,
1523 const drawinglayer::geometry::ViewInformation2D
& aViewInformation
) const
1525 // decompose matrix to have position and size of text
1526 basegfx::B2DVector aScale
, aTranslate
;
1527 double fRotate
, fShearX
;
1528 rSdrChainedTextPrimitive
.getTextRangeTransform().decompose(aScale
, aTranslate
, fRotate
, fShearX
);
1530 // use B2DRange aAnchorTextRange for calculations
1531 basegfx::B2DRange
aAnchorTextRange(aTranslate
);
1532 aAnchorTextRange
.expand(aTranslate
+ aScale
);
1535 const SfxItemSet
& rTextItemSet
= rSdrChainedTextPrimitive
.getSdrText()->GetItemSet();
1536 SolarMutexGuard aSolarGuard
;
1537 SdrOutliner
& rOutliner
= ImpGetDrawOutliner();
1539 SdrTextVertAdjust eVAdj
= GetTextVerticalAdjust(rTextItemSet
);
1540 SdrTextHorzAdjust eHAdj
= GetTextHorizontalAdjust(rTextItemSet
);
1541 const EEControlBits
nOriginalControlWord(rOutliner
.GetControlWord());
1542 const Size aNullSize
;
1544 // set visualizing page at Outliner; needed e.g. for PageNumberField decomposition
1545 rOutliner
.setVisualizedPage(GetSdrPageFromXDrawPage(aViewInformation
.getVisualizedPage()));
1547 rOutliner
.SetControlWord(nOriginalControlWord
|EEControlBits::AUTOPAGESIZE
|EEControlBits::STRETCHING
);
1548 rOutliner
.SetMinAutoPaperSize(aNullSize
);
1549 rOutliner
.SetMaxAutoPaperSize(Size(1000000,1000000));
1551 // add one to rage sizes to get back to the old Rectangle and outliner measurements
1552 const sal_uInt32
nAnchorTextWidth(FRound(aAnchorTextRange
.getWidth() + 1));
1553 const sal_uInt32
nAnchorTextHeight(FRound(aAnchorTextRange
.getHeight() + 1));
1556 const OutlinerParaObject
* pOutlinerParaObject
= rSdrChainedTextPrimitive
.getSdrText()->GetOutlinerParaObject();
1557 OSL_ENSURE(pOutlinerParaObject
, "impDecomposeBlockTextPrimitive used with no OutlinerParaObject (!)");
1559 const bool bVerticalWriting(pOutlinerParaObject
->IsVertical());
1560 const bool bTopToBottom(pOutlinerParaObject
->IsTopToBottom());
1561 const Size
aAnchorTextSize(Size(nAnchorTextWidth
, nAnchorTextHeight
));
1565 rOutliner
.SetMaxAutoPaperSize(aAnchorTextSize
);
1568 if(SDRTEXTHORZADJUST_BLOCK
== eHAdj
&& !bVerticalWriting
)
1570 rOutliner
.SetMinAutoPaperSize(Size(nAnchorTextWidth
, 0));
1573 if(SDRTEXTVERTADJUST_BLOCK
== eVAdj
&& bVerticalWriting
)
1575 rOutliner
.SetMinAutoPaperSize(Size(0, nAnchorTextHeight
));
1578 rOutliner
.SetPaperSize(aNullSize
);
1579 rOutliner
.SetUpdateMode(true);
1580 // Sets original text
1581 rOutliner
.SetText(*pOutlinerParaObject
);
1583 /* Begin overflow/underflow handling */
1585 impHandleChainingEventsDuringDecomposition(rOutliner
);
1587 /* End overflow/underflow handling */
1589 // set visualizing page at Outliner; needed e.g. for PageNumberField decomposition
1590 rOutliner
.setVisualizedPage(GetSdrPageFromXDrawPage(aViewInformation
.getVisualizedPage()));
1592 // now get back the layouted text size from outliner
1593 const Size
aOutlinerTextSize(rOutliner
.GetPaperSize());
1594 const basegfx::B2DVector
aOutlinerScale(aOutlinerTextSize
.Width(), aOutlinerTextSize
.Height());
1595 basegfx::B2DVector
aAdjustTranslate(0.0, 0.0);
1597 // correct horizontal translation using the now known text size
1598 if(SDRTEXTHORZADJUST_CENTER
== eHAdj
|| SDRTEXTHORZADJUST_RIGHT
== eHAdj
)
1600 const double fFree(aAnchorTextRange
.getWidth() - aOutlinerScale
.getX());
1602 if(SDRTEXTHORZADJUST_CENTER
== eHAdj
)
1604 aAdjustTranslate
.setX(fFree
/ 2.0);
1607 if(SDRTEXTHORZADJUST_RIGHT
== eHAdj
)
1609 aAdjustTranslate
.setX(fFree
);
1613 // correct vertical translation using the now known text size
1614 if(SDRTEXTVERTADJUST_CENTER
== eVAdj
|| SDRTEXTVERTADJUST_BOTTOM
== eVAdj
)
1616 const double fFree(aAnchorTextRange
.getHeight() - aOutlinerScale
.getY());
1618 if(SDRTEXTVERTADJUST_CENTER
== eVAdj
)
1620 aAdjustTranslate
.setY(fFree
/ 2.0);
1623 if(SDRTEXTVERTADJUST_BOTTOM
== eVAdj
)
1625 aAdjustTranslate
.setY(fFree
);
1629 // prepare matrices to apply to newly created primitives. aNewTransformA
1630 // will get coordinates in aOutlinerScale size and positive in X, Y.
1631 basegfx::B2DHomMatrix aNewTransformA
;
1632 basegfx::B2DHomMatrix aNewTransformB
;
1634 // translate relative to given primitive to get same rotation and shear
1635 // as the master shape we are working on. For vertical, use the top-right
1637 const double fStartInX(bVerticalWriting
&& bTopToBottom
? aAdjustTranslate
.getX() + aOutlinerScale
.getX() : aAdjustTranslate
.getX());
1638 const double fStartInY(bVerticalWriting
&& !bTopToBottom
? aAdjustTranslate
.getY() + aOutlinerScale
.getY() : aAdjustTranslate
.getY());
1639 aNewTransformA
.translate(fStartInX
, fStartInY
);
1641 // mirroring. We are now in aAnchorTextRange sizes. When mirroring in X and Y,
1642 // move the null point which was top left to bottom right.
1643 const bool bMirrorX(basegfx::fTools::less(aScale
.getX(), 0.0));
1644 const bool bMirrorY(basegfx::fTools::less(aScale
.getY(), 0.0));
1645 aNewTransformB
.scale(bMirrorX
? -1.0 : 1.0, bMirrorY
? -1.0 : 1.0);
1647 // in-between the translations of the single primitives will take place. Afterwards,
1648 // the object's transformations need to be applied
1649 aNewTransformB
.shearX(fShearX
);
1650 aNewTransformB
.rotate(fRotate
);
1651 aNewTransformB
.translate(aTranslate
.getX(), aTranslate
.getY());
1653 basegfx::B2DRange aClipRange
;
1655 // now break up text primitives.
1656 impTextBreakupHandler
aConverter(rOutliner
);
1657 aConverter
.decomposeBlockTextPrimitive(aNewTransformA
, aNewTransformB
, aClipRange
);
1661 rOutliner
.setVisualizedPage(nullptr);
1662 rOutliner
.SetControlWord(nOriginalControlWord
);
1664 rTarget
= aConverter
.getPrimitive2DSequence();
1667 // Direct decomposer for text visualization when you already have a prepared
1668 // Outliner containing all the needed information
1669 void SdrTextObj::impDecomposeBlockTextPrimitiveDirect(
1670 drawinglayer::primitive2d::Primitive2DContainer
& rTarget
,
1671 SdrOutliner
& rOutliner
,
1672 const basegfx::B2DHomMatrix
& rNewTransformA
,
1673 const basegfx::B2DHomMatrix
& rNewTransformB
,
1674 const basegfx::B2DRange
& rClipRange
)
1676 impTextBreakupHandler
aConverter(rOutliner
);
1677 aConverter
.decomposeBlockTextPrimitive(rNewTransformA
, rNewTransformB
, rClipRange
);
1678 rTarget
.append(aConverter
.getPrimitive2DSequence());
1681 double SdrTextObj::GetCameraZRotation() const
1683 const css::uno::Any
* pAny
;
1684 double fTextCameraZRotateAngle
= 0.0;
1685 const SfxItemSet
& rSet
= GetObjectItemSet();
1686 const SdrCustomShapeGeometryItem
& rGeometryItem(rSet
.Get(SDRATTR_CUSTOMSHAPE_GEOMETRY
));
1688 pAny
= rGeometryItem
.GetPropertyValueByName("TextCameraZRotateAngle");
1691 *pAny
>>= fTextCameraZRotateAngle
;
1693 return fTextCameraZRotateAngle
;
1696 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */