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/svdotext.hxx>
22 #include <svx/svdoutl.hxx>
23 #include <basegfx/vector/b2dvector.hxx>
24 #include <svx/sdr/primitive2d/sdrtextprimitive2d.hxx>
25 #include <basegfx/range/b2drange.hxx>
26 #include <svl/itemset.hxx>
27 #include <basegfx/polygon/b2dpolygontools.hxx>
28 #include <basegfx/polygon/b2dpolygon.hxx>
30 #include <svx/xtextit.hxx>
31 #include <svx/xftshtit.hxx>
32 #include <vcl/virdev.hxx>
33 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
34 #include <com/sun/star/i18n/ScriptType.hpp>
35 #include <com/sun/star/i18n/BreakIterator.hpp>
36 #include <comphelper/processfactory.hxx>
37 #include <com/sun/star/i18n/CharacterIteratorMode.hpp>
38 #include <editeng/unolingu.hxx>
39 #include <drawinglayer/primitive2d/textlayoutdevice.hxx>
40 #include <drawinglayer/primitive2d/textprimitive2d.hxx>
41 #include <basegfx/color/bcolor.hxx>
43 //////////////////////////////////////////////////////////////////////////////
44 // primitive decomposition helpers
46 #include <basegfx/polygon/b2dlinegeometry.hxx>
47 #include <drawinglayer/attribute/strokeattribute.hxx>
48 #include <svx/xlnclit.hxx>
49 #include <svx/xlntrit.hxx>
50 #include <svx/xlnwtit.hxx>
51 #include <svx/xlinjoit.hxx>
52 #include <svx/xlndsit.hxx>
53 #include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
54 #include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx>
55 #include <editeng/editstat.hxx>
56 #include <svx/unoapi.hxx>
57 #include <drawinglayer/geometry/viewinformation2d.hxx>
58 #include <svx/sdr/attribute/sdrformtextoutlineattribute.hxx>
60 //////////////////////////////////////////////////////////////////////////////
62 using namespace ::com::sun::star::uno
;
63 using namespace ::com::sun::star::lang
;
64 using namespace ::com::sun::star::i18n
;
66 //////////////////////////////////////////////////////////////////////////////
67 // PathTextPortion helper
71 class impPathTextPortion
73 basegfx::B2DVector maOffset
;
75 xub_StrLen mnTextStart
;
76 xub_StrLen mnTextLength
;
77 sal_Int32 mnParagraph
;
80 ::std::vector
< double > maDblDXArray
; // double DXArray, font size independent -> unit coordinate system
81 ::com::sun::star::lang::Locale maLocale
;
87 impPathTextPortion(DrawPortionInfo
& rInfo
)
88 : maOffset(rInfo
.mrStartPos
.X(), rInfo
.mrStartPos
.Y()),
90 mnTextStart(rInfo
.mnTextStart
),
91 mnTextLength(rInfo
.mnTextLen
),
92 mnParagraph(rInfo
.mnPara
),
93 mnIndex(rInfo
.mnIndex
),
96 maLocale(rInfo
.mpLocale
? *rInfo
.mpLocale
: ::com::sun::star::lang::Locale()),
97 mbRTL(rInfo
.mrFont
.IsVertical() ? false : rInfo
.IsRTL())
99 if(mnTextLength
&& rInfo
.mpDXArray
)
101 maDblDXArray
.reserve(mnTextLength
);
103 for(xub_StrLen
a(0); a
< mnTextLength
; a
++)
105 maDblDXArray
.push_back((double)rInfo
.mpDXArray
[a
]);
111 bool operator<(const impPathTextPortion
& rComp
) const
113 if(mnParagraph
< rComp
.mnParagraph
)
118 if(maOffset
.getX() < rComp
.maOffset
.getX())
123 return (maOffset
.getY() < rComp
.maOffset
.getY());
126 const basegfx::B2DVector
& getOffset() const { return maOffset
; }
127 const String
& getText() const { return maText
; }
128 xub_StrLen
getTextStart() const { return mnTextStart
; }
129 xub_StrLen
getTextLength() const { return mnTextLength
; }
130 sal_Int32
getParagraph() const { return mnParagraph
; }
131 xub_StrLen
getIndex() const { return mnIndex
; }
132 const SvxFont
& getFont() const { return maFont
; }
133 bool isRTL() const { return mbRTL
; }
134 const ::std::vector
< double >& getDoubleDXArray() const { return maDblDXArray
; }
135 const ::com::sun::star::lang::Locale
& getLocale() const { return maLocale
; }
137 xub_StrLen
getPortionIndex(xub_StrLen nIndex
, xub_StrLen nLength
) const
141 return (mnTextStart
+ (mnTextLength
- (nIndex
+ nLength
)));
145 return (mnTextStart
+ nIndex
);
149 double getDisplayLength(xub_StrLen nIndex
, xub_StrLen nLength
) const
151 drawinglayer::primitive2d::TextLayouterDevice aTextLayouter
;
154 if(maFont
.IsVertical())
156 fRetval
= aTextLayouter
.getTextHeight() * (double)nLength
;
160 fRetval
= aTextLayouter
.getTextWidth(maText
, getPortionIndex(nIndex
, nLength
), nLength
);
166 } // end of anonymous namespace
168 //////////////////////////////////////////////////////////////////////////////
169 // TextBreakup helper
173 class impTextBreakupHandler
175 SdrOutliner
& mrOutliner
;
176 ::std::vector
< impPathTextPortion
> maPathTextPortions
;
178 DECL_LINK(decompositionPathTextPrimitive
, DrawPortionInfo
* );
181 impTextBreakupHandler(SdrOutliner
& rOutliner
)
182 : mrOutliner(rOutliner
)
186 const ::std::vector
< impPathTextPortion
>& decompositionPathTextPrimitive()
188 // strip portions to maPathTextPortions
189 mrOutliner
.SetDrawPortionHdl(LINK(this, impTextBreakupHandler
, decompositionPathTextPrimitive
));
190 mrOutliner
.StripPortions();
192 if(!maPathTextPortions
.empty())
194 // sort portions by paragraph, x and y
195 ::std::sort(maPathTextPortions
.begin(), maPathTextPortions
.end());
198 return maPathTextPortions
;
202 IMPL_LINK(impTextBreakupHandler
, decompositionPathTextPrimitive
, DrawPortionInfo
*, pInfo
)
204 maPathTextPortions
.push_back(impPathTextPortion(*pInfo
));
207 } // end of anonymous namespace
209 //////////////////////////////////////////////////////////////////////////////
210 // TextBreakup one poly and one paragraph helper
214 class impPolygonParagraphHandler
216 const drawinglayer::attribute::SdrFormTextAttribute maSdrFormTextAttribute
; // FormText parameters
217 std::vector
< drawinglayer::primitive2d::BasePrimitive2D
* >& mrDecomposition
; // destination primitive list
218 std::vector
< drawinglayer::primitive2d::BasePrimitive2D
* >& mrShadowDecomposition
; // destination primitive list for shadow
219 Reference
< com::sun::star::i18n::XBreakIterator
> mxBreak
; // break iterator
221 double getParagraphTextLength(const ::std::vector
< const impPathTextPortion
* >& rTextPortions
)
223 drawinglayer::primitive2d::TextLayouterDevice aTextLayouter
;
226 for(sal_uInt32
a(0L); a
< rTextPortions
.size(); a
++)
228 const impPathTextPortion
* pCandidate
= rTextPortions
[a
];
230 if(pCandidate
&& pCandidate
->getTextLength())
232 aTextLayouter
.setFont(pCandidate
->getFont());
233 fRetval
+= pCandidate
->getDisplayLength(0L, pCandidate
->getTextLength());
240 xub_StrLen
getNextGlyphLen(const impPathTextPortion
* pCandidate
, xub_StrLen nPosition
, const ::com::sun::star::lang::Locale
& rFontLocale
)
242 xub_StrLen
nNextGlyphLen(1);
247 nNextGlyphLen
= (xub_StrLen
)mxBreak
->nextCharacters(pCandidate
->getText(), nPosition
,
248 rFontLocale
, CharacterIteratorMode::SKIPCELL
, 1, nDone
) - nPosition
;
251 return nNextGlyphLen
;
255 impPolygonParagraphHandler(
256 const drawinglayer::attribute::SdrFormTextAttribute
& rSdrFormTextAttribute
,
257 std::vector
< drawinglayer::primitive2d::BasePrimitive2D
* >& rDecomposition
,
258 std::vector
< drawinglayer::primitive2d::BasePrimitive2D
* >& rShadowDecomposition
)
259 : maSdrFormTextAttribute(rSdrFormTextAttribute
),
260 mrDecomposition(rDecomposition
),
261 mrShadowDecomposition(rShadowDecomposition
)
263 // prepare BreakIterator
264 Reference
< XComponentContext
> xContext
= ::comphelper::getProcessComponentContext();
265 mxBreak
= com::sun::star::i18n::BreakIterator::create(xContext
);
268 void HandlePair(const basegfx::B2DPolygon rPolygonCandidate
, const ::std::vector
< const impPathTextPortion
* >& rTextPortions
)
270 // prepare polygon geometry, take into account as many parameters as possible
271 basegfx::B2DPolygon
aPolygonCandidate(rPolygonCandidate
);
272 const double fPolyLength(basegfx::tools::getLength(aPolygonCandidate
));
273 double fPolyEnd(fPolyLength
);
274 double fPolyStart(0.0);
275 double fAutosizeScaleFactor(1.0);
276 bool bAutosizeScale(false);
278 if(maSdrFormTextAttribute
.getFormTextMirror())
280 aPolygonCandidate
.flip();
283 if(maSdrFormTextAttribute
.getFormTextStart()
284 && (XFT_LEFT
== maSdrFormTextAttribute
.getFormTextAdjust()
285 || XFT_RIGHT
== maSdrFormTextAttribute
.getFormTextAdjust()))
287 if(XFT_LEFT
== maSdrFormTextAttribute
.getFormTextAdjust())
289 fPolyStart
+= maSdrFormTextAttribute
.getFormTextStart();
291 if(fPolyStart
> fPolyEnd
)
293 fPolyStart
= fPolyEnd
;
298 fPolyEnd
-= maSdrFormTextAttribute
.getFormTextStart();
300 if(fPolyEnd
< fPolyStart
)
302 fPolyEnd
= fPolyStart
;
307 if(XFT_LEFT
!= maSdrFormTextAttribute
.getFormTextAdjust())
309 // calculate total text length of this paragraph, some layout needs to be done
310 const double fParagraphTextLength(getParagraphTextLength(rTextPortions
));
312 // check if text is too long for paragraph. If yes, handle as if left aligned (default),
313 // but still take care of XFT_AUTOSIZE in that case
314 const bool bTextTooLong(fParagraphTextLength
> (fPolyEnd
- fPolyStart
));
316 if(XFT_RIGHT
== maSdrFormTextAttribute
.getFormTextAdjust())
320 // if right aligned, add difference to polygon start
321 fPolyStart
+= ((fPolyEnd
- fPolyStart
) - fParagraphTextLength
);
324 else if(XFT_CENTER
== maSdrFormTextAttribute
.getFormTextAdjust())
328 // if centered, add half of difference to polygon start
329 fPolyStart
+= ((fPolyEnd
- fPolyStart
) - fParagraphTextLength
) / 2.0;
332 else if(XFT_AUTOSIZE
== maSdrFormTextAttribute
.getFormTextAdjust())
334 // if scale, prepare scale factor between curve length and text length
335 if(0.0 != fParagraphTextLength
)
337 fAutosizeScaleFactor
= (fPolyEnd
- fPolyStart
) / fParagraphTextLength
;
338 bAutosizeScale
= true;
343 // handle text portions for this paragraph
344 for(sal_uInt32
a(0L); a
< rTextPortions
.size() && fPolyStart
< fPolyEnd
; a
++)
346 const impPathTextPortion
* pCandidate
= rTextPortions
[a
];
347 basegfx::B2DVector aFontScaling
;
349 if(pCandidate
&& pCandidate
->getTextLength())
351 const drawinglayer::attribute::FontAttribute
aCandidateFontAttribute(
352 drawinglayer::primitive2d::getFontAttributeFromVclFont(
354 pCandidate
->getFont(),
358 drawinglayer::primitive2d::TextLayouterDevice aTextLayouter
;
359 aTextLayouter
.setFont(pCandidate
->getFont());
360 xub_StrLen
nUsedTextLength(0);
362 while(nUsedTextLength
< pCandidate
->getTextLength() && fPolyStart
< fPolyEnd
)
364 xub_StrLen
nNextGlyphLen(getNextGlyphLen(pCandidate
, pCandidate
->getTextStart() + nUsedTextLength
, pCandidate
->getLocale()));
366 // prepare portion length. Takes RTL sections into account.
367 double fPortionLength(pCandidate
->getDisplayLength(nUsedTextLength
, nNextGlyphLen
));
371 // when autosize scaling, expand portion length
372 fPortionLength
*= fAutosizeScaleFactor
;
375 // create transformation
376 basegfx::B2DHomMatrix aNewTransformA
, aNewTransformB
, aNewShadowTransform
;
377 basegfx::B2DPoint
aStartPos(basegfx::tools::getPositionAbsolute(aPolygonCandidate
, fPolyStart
, fPolyLength
));
378 basegfx::B2DPoint
aEndPos(aStartPos
);
381 aNewTransformA
.scale(aFontScaling
.getX(), aFontScaling
.getY());
383 // prepare scaling of text primitive
386 // when autosize scaling, expand text primitive scaling to it
387 aNewTransformA
.scale(fAutosizeScaleFactor
, fAutosizeScaleFactor
);
390 // eventually create shadow primitives from aDecomposition and add to rDecomposition
391 const bool bShadow(XFTSHADOW_NONE
!= maSdrFormTextAttribute
.getFormTextShadow());
395 if(XFTSHADOW_NORMAL
== maSdrFormTextAttribute
.getFormTextShadow())
397 aNewShadowTransform
.translate(
398 maSdrFormTextAttribute
.getFormTextShdwXVal(),
399 -maSdrFormTextAttribute
.getFormTextShdwYVal());
401 else // XFTSHADOW_SLANT
403 double fScaleValue(maSdrFormTextAttribute
.getFormTextShdwYVal() / 100.0);
404 double fShearValue(-maSdrFormTextAttribute
.getFormTextShdwXVal() * F_PI1800
);
406 aNewShadowTransform
.scale(1.0, fScaleValue
);
407 aNewShadowTransform
.shearX(sin(fShearValue
));
408 aNewShadowTransform
.scale(1.0, cos(fShearValue
));
412 switch(maSdrFormTextAttribute
.getFormTextStyle())
416 aEndPos
= basegfx::tools::getPositionAbsolute(aPolygonCandidate
, fPolyStart
+ fPortionLength
, fPolyLength
);
417 const basegfx::B2DVector
aDirection(aEndPos
- aStartPos
);
418 aNewTransformB
.rotate(atan2(aDirection
.getY(), aDirection
.getX()));
419 aNewTransformB
.translate(aStartPos
.getX(), aStartPos
.getY());
425 aNewTransformB
.translate(aStartPos
.getX() - (fPortionLength
/ 2.0), aStartPos
.getY());
431 aEndPos
= basegfx::tools::getPositionAbsolute(aPolygonCandidate
, fPolyStart
+ fPortionLength
, fPolyLength
);
432 const basegfx::B2DVector
aDirection(aEndPos
- aStartPos
);
433 const double fShearValue(atan2(aDirection
.getY(), aDirection
.getX()));
434 const double fSin(sin(fShearValue
));
435 const double fCos(cos(fShearValue
));
437 aNewTransformB
.shearX(-fSin
);
439 // Scale may lead to objects without height since fCos == 0.0 is possible.
440 // Renderers need to handle that, it's not a forbidden value and does not
441 // need to be avoided
442 aNewTransformB
.scale(1.0, fCos
);
443 aNewTransformB
.translate(aStartPos
.getX() - (fPortionLength
/ 2.0), aStartPos
.getY());
449 aEndPos
= basegfx::tools::getPositionAbsolute(aPolygonCandidate
, fPolyStart
+ fPortionLength
, fPolyLength
);
450 const basegfx::B2DVector
aDirection(aEndPos
- aStartPos
);
451 const double fShearValue(atan2(aDirection
.getY(), aDirection
.getX()));
452 const double fCos(cos(fShearValue
));
453 const double fTan(tan(fShearValue
));
455 // shear to 'stand' on the curve
456 aNewTransformB
.shearY(fTan
);
458 // scale in X to make as tight as needed. As with XFT_SLANT_X, this may
459 // lead to primitives without width which the renderers will handle
460 aNewTransformA
.scale(fCos
, 1.0);
462 aNewTransformB
.translate(aStartPos
.getX(), aStartPos
.getY());
466 default : break; // XFT_NONE
469 // distance from path?
470 if(maSdrFormTextAttribute
.getFormTextDistance())
472 if(aEndPos
.equal(aStartPos
))
474 aEndPos
= basegfx::tools::getPositionAbsolute(aPolygonCandidate
, fPolyStart
+ fPortionLength
, fPolyLength
);
477 // use back vector (aStartPos - aEndPos) here to get mirrored perpendicular as in old stuff
478 const basegfx::B2DVector
aPerpendicular(
479 basegfx::getNormalizedPerpendicular(aStartPos
- aEndPos
) *
480 maSdrFormTextAttribute
.getFormTextDistance());
481 aNewTransformB
.translate(aPerpendicular
.getX(), aPerpendicular
.getY());
484 if(pCandidate
->getText().Len() && nNextGlyphLen
)
486 const xub_StrLen
nPortionIndex(pCandidate
->getPortionIndex(nUsedTextLength
, nNextGlyphLen
));
487 ::std::vector
< double > aNewDXArray
;
489 if(nNextGlyphLen
> 1 && pCandidate
->getDoubleDXArray().size())
491 // copy DXArray for portion
494 pCandidate
->getDoubleDXArray().begin() + nPortionIndex
,
495 pCandidate
->getDoubleDXArray().begin() + (nPortionIndex
+ nNextGlyphLen
));
497 if(nPortionIndex
> 0)
499 // adapt to portion start
500 double fDXOffset
= *(pCandidate
->getDoubleDXArray().begin() + (nPortionIndex
- 1));
502 aNewDXArray
.begin(), aNewDXArray
.end(),
503 aNewDXArray
.begin(), ::std::bind2nd(::std::minus
<double>(), fDXOffset
));
508 // when autosize scaling, adapt to DXArray, too
510 aNewDXArray
.begin(), aNewDXArray
.end(),
511 aNewDXArray
.begin(), ::std::bind2nd(::std::multiplies
<double>(), fAutosizeScaleFactor
));
517 // shadow primitive creation
518 const Color
aShadowColor(maSdrFormTextAttribute
.getFormTextShdwColor());
519 const basegfx::BColor
aRGBShadowColor(aShadowColor
.getBColor());
521 drawinglayer::primitive2d::TextSimplePortionPrimitive2D
* pNew
=
522 new drawinglayer::primitive2d::TextSimplePortionPrimitive2D(
523 aNewTransformB
* aNewShadowTransform
* aNewTransformA
,
524 pCandidate
->getText(),
528 aCandidateFontAttribute
,
529 pCandidate
->getLocale(),
532 mrShadowDecomposition
.push_back(pNew
);
536 // primitive creation
537 const Color
aColor(pCandidate
->getFont().GetColor());
538 const basegfx::BColor
aRGBColor(aColor
.getBColor());
540 drawinglayer::primitive2d::TextSimplePortionPrimitive2D
* pNew
=
541 new drawinglayer::primitive2d::TextSimplePortionPrimitive2D(
542 aNewTransformB
* aNewTransformA
,
543 pCandidate
->getText(),
547 aCandidateFontAttribute
,
548 pCandidate
->getLocale(),
551 mrDecomposition
.push_back(pNew
);
555 // consume from portion // no += here, xub_StrLen is sal_uInt16 and the compiler will generate a warning here
556 nUsedTextLength
= nUsedTextLength
+ nNextGlyphLen
;
558 // consume from polygon
559 fPolyStart
+= fPortionLength
;
565 } // end of anonymous namespace
567 //////////////////////////////////////////////////////////////////////////////
568 // primitive decomposition helpers
572 void impAddPolygonStrokePrimitives(
573 const basegfx::B2DPolyPolygonVector
& rB2DPolyPolyVector
,
574 const basegfx::B2DHomMatrix
& rTransform
,
575 const drawinglayer::attribute::LineAttribute
& rLineAttribute
,
576 const drawinglayer::attribute::StrokeAttribute
& rStrokeAttribute
,
577 std::vector
< drawinglayer::primitive2d::BasePrimitive2D
* >& rTarget
)
579 for(basegfx::B2DPolyPolygonVector::const_iterator
aPolygon(rB2DPolyPolyVector
.begin()); aPolygon
!= rB2DPolyPolyVector
.end(); ++aPolygon
)
581 // prepare PolyPolygons
582 basegfx::B2DPolyPolygon aB2DPolyPolygon
= *aPolygon
;
583 aB2DPolyPolygon
.transform(rTransform
);
585 for(sal_uInt32
a(0L); a
< aB2DPolyPolygon
.count(); a
++)
587 // create one primitive per polygon
588 drawinglayer::primitive2d::PolygonStrokePrimitive2D
* pNew
=
589 new drawinglayer::primitive2d::PolygonStrokePrimitive2D(
590 aB2DPolyPolygon
.getB2DPolygon(a
), rLineAttribute
, rStrokeAttribute
);
591 rTarget
.push_back(pNew
);
596 drawinglayer::primitive2d::Primitive2DSequence
impAddPathTextOutlines(
597 const std::vector
< drawinglayer::primitive2d::BasePrimitive2D
* >& rSource
,
598 const drawinglayer::attribute::SdrFormTextOutlineAttribute
& rOutlineAttribute
)
600 std::vector
< drawinglayer::primitive2d::BasePrimitive2D
* > aNewPrimitives
;
602 for(sal_uInt32
a(0L); a
< rSource
.size(); a
++)
604 const drawinglayer::primitive2d::TextSimplePortionPrimitive2D
* pTextCandidate
= dynamic_cast< const drawinglayer::primitive2d::TextSimplePortionPrimitive2D
* >(rSource
[a
]);
608 basegfx::B2DPolyPolygonVector aB2DPolyPolyVector
;
609 basegfx::B2DHomMatrix aPolygonTransform
;
611 // get text outlines and their object transformation
612 pTextCandidate
->getTextOutlinesAndTransformation(aB2DPolyPolyVector
, aPolygonTransform
);
614 if(!aB2DPolyPolyVector
.empty())
616 // create stroke primitives
617 std::vector
< drawinglayer::primitive2d::BasePrimitive2D
* > aStrokePrimitives
;
618 impAddPolygonStrokePrimitives(
621 rOutlineAttribute
.getLineAttribute(),
622 rOutlineAttribute
.getStrokeAttribute(),
624 const sal_uInt32
nStrokeCount(aStrokePrimitives
.size());
628 if(rOutlineAttribute
.getTransparence())
630 // create UnifiedTransparencePrimitive2D
631 drawinglayer::primitive2d::Primitive2DSequence
aStrokePrimitiveSequence(nStrokeCount
);
633 for(sal_uInt32
b(0L); b
< nStrokeCount
; b
++)
635 aStrokePrimitiveSequence
[b
] = drawinglayer::primitive2d::Primitive2DReference(aStrokePrimitives
[b
]);
638 drawinglayer::primitive2d::UnifiedTransparencePrimitive2D
* pNew2
=
639 new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D(
640 aStrokePrimitiveSequence
,
641 (double)rOutlineAttribute
.getTransparence() / 100.0);
642 aNewPrimitives
.push_back(pNew2
);
646 // add polygons to rDecomposition as polygonStrokePrimitives
647 aNewPrimitives
.insert(aNewPrimitives
.end(), aStrokePrimitives
.begin(), aStrokePrimitives
.end());
654 const sal_uInt32
nNewCount(aNewPrimitives
.size());
658 drawinglayer::primitive2d::Primitive2DSequence
aRetval(nNewCount
);
660 for(sal_uInt32
a(0L); a
< nNewCount
; a
++)
662 aRetval
[a
] = drawinglayer::primitive2d::Primitive2DReference(aNewPrimitives
[a
]);
669 return drawinglayer::primitive2d::Primitive2DSequence();
672 } // end of anonymous namespace
674 //////////////////////////////////////////////////////////////////////////////
675 // primitive decomposition
677 void SdrTextObj::impDecomposePathTextPrimitive(
678 drawinglayer::primitive2d::Primitive2DSequence
& rTarget
,
679 const drawinglayer::primitive2d::SdrPathTextPrimitive2D
& rSdrPathTextPrimitive
,
680 const drawinglayer::geometry::ViewInformation2D
& aViewInformation
) const
682 drawinglayer::primitive2d::Primitive2DSequence aRetvalA
;
683 drawinglayer::primitive2d::Primitive2DSequence aRetvalB
;
686 SdrOutliner
& rOutliner
= ImpGetDrawOutliner();
687 rOutliner
.SetUpdateMode(true);
689 rOutliner
.SetPaperSize(Size(LONG_MAX
,LONG_MAX
));
690 rOutliner
.SetText(rSdrPathTextPrimitive
.getOutlinerParaObject());
692 // set visualizing page at Outliner; needed e.g. for PageNumberField decomposition
693 rOutliner
.setVisualizedPage(GetSdrPageFromXDrawPage(aViewInformation
.getVisualizedPage()));
695 // now break up to text portions
696 impTextBreakupHandler
aConverter(rOutliner
);
697 const ::std::vector
< impPathTextPortion
> rPathTextPortions
= aConverter
.decompositionPathTextPrimitive();
699 if(!rPathTextPortions
.empty())
701 // get FormText and polygon values
702 const drawinglayer::attribute::SdrFormTextAttribute
& rFormTextAttribute
= rSdrPathTextPrimitive
.getSdrFormTextAttribute();
703 const basegfx::B2DPolyPolygon
& rPathPolyPolygon(rSdrPathTextPrimitive
.getPathPolyPolygon());
706 sal_uInt32
nLoopCount(rPathPolyPolygon
.count());
708 if(static_cast<sal_uInt32
>(rOutliner
.GetParagraphCount()) < nLoopCount
)
710 nLoopCount
= rOutliner
.GetParagraphCount();
715 // prepare common decomposition stuff
716 std::vector
< drawinglayer::primitive2d::BasePrimitive2D
* > aRegularDecomposition
;
717 std::vector
< drawinglayer::primitive2d::BasePrimitive2D
* > aShadowDecomposition
;
718 impPolygonParagraphHandler
aPolygonParagraphHandler(
720 aRegularDecomposition
,
721 aShadowDecomposition
);
724 for(a
= 0L; a
< nLoopCount
; a
++)
726 // filter text portions for this paragraph
727 ::std::vector
< const impPathTextPortion
* > aParagraphTextPortions
;
729 for(sal_uInt32
b(0L); b
< rPathTextPortions
.size(); b
++)
731 const impPathTextPortion
& rCandidate
= rPathTextPortions
[b
];
733 if(static_cast<sal_uInt32
>(rCandidate
.getParagraph()) == a
)
735 aParagraphTextPortions
.push_back(&rCandidate
);
739 // handle data pair polygon/ParagraphTextPortions
740 if(!aParagraphTextPortions
.empty())
742 aPolygonParagraphHandler
.HandlePair(rPathPolyPolygon
.getB2DPolygon(a
), aParagraphTextPortions
);
746 const sal_uInt32
nShadowCount(aShadowDecomposition
.size());
747 const sal_uInt32
nRegularCount(aRegularDecomposition
.size());
751 // add shadow primitives to decomposition
752 aRetvalA
.realloc(nShadowCount
);
754 for(a
= 0L; a
< nShadowCount
; a
++)
756 aRetvalA
[a
] = drawinglayer::primitive2d::Primitive2DReference(aShadowDecomposition
[a
]);
759 // if necessary, add shadow outlines
760 if(rFormTextAttribute
.getFormTextOutline()
761 && !rFormTextAttribute
.getShadowOutline().isDefault())
763 const drawinglayer::primitive2d::Primitive2DSequence
aOutlines(
764 impAddPathTextOutlines(
765 aShadowDecomposition
,
766 rFormTextAttribute
.getShadowOutline()));
768 drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(aRetvalA
, aOutlines
);
774 // add normal primitives to decomposition
775 aRetvalB
.realloc(nRegularCount
);
777 for(a
= 0L; a
< nRegularCount
; a
++)
779 aRetvalB
[a
] = drawinglayer::primitive2d::Primitive2DReference(aRegularDecomposition
[a
]);
782 // if necessary, add outlines
783 if(rFormTextAttribute
.getFormTextOutline()
784 && !rFormTextAttribute
.getOutline().isDefault())
786 const drawinglayer::primitive2d::Primitive2DSequence
aOutlines(
787 impAddPathTextOutlines(
788 aRegularDecomposition
,
789 rFormTextAttribute
.getOutline()));
791 drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(aRetvalB
, aOutlines
);
798 rOutliner
.SetDrawPortionHdl(Link());
800 rOutliner
.setVisualizedPage(0);
802 // concatenate all results
803 drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget
, aRetvalA
);
804 drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget
, aRetvalB
);
808 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */