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 <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>
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 <sdr/attribute/sdrformtextoutlineattribute.hxx>
62 using namespace ::com::sun::star::uno
;
63 using namespace ::com::sun::star::lang
;
64 using namespace ::com::sun::star::i18n
;
67 // PathTextPortion helper
71 class impPathTextPortion
73 basegfx::B2DVector maOffset
;
75 sal_Int32 mnTextStart
;
76 sal_Int32 mnTextLength
;
77 sal_Int32 mnParagraph
;
79 ::std::vector
< double > maDblDXArray
; // double DXArray, font size independent -> unit coordinate system
80 ::com::sun::star::lang::Locale maLocale
;
86 impPathTextPortion(DrawPortionInfo
& rInfo
)
87 : maOffset(rInfo
.mrStartPos
.X(), rInfo
.mrStartPos
.Y()),
89 mnTextStart(rInfo
.mnTextStart
),
90 mnTextLength(rInfo
.mnTextLen
),
91 mnParagraph(rInfo
.mnPara
),
94 maLocale(rInfo
.mpLocale
? *rInfo
.mpLocale
: ::com::sun::star::lang::Locale()),
95 mbRTL(rInfo
.mrFont
.IsVertical() ? sal_False
: rInfo
.IsRTL())
97 if(mnTextLength
&& rInfo
.mpDXArray
)
99 maDblDXArray
.reserve(mnTextLength
);
101 for(sal_Int32 a
=0; a
< mnTextLength
; a
++)
103 maDblDXArray
.push_back((double)rInfo
.mpDXArray
[a
]);
109 bool operator<(const impPathTextPortion
& rComp
) const
111 if(mnParagraph
< rComp
.mnParagraph
)
116 if(maOffset
.getX() < rComp
.maOffset
.getX())
121 return (maOffset
.getY() < rComp
.maOffset
.getY());
124 const OUString
& getText() const { return maText
; }
125 sal_Int32
getTextStart() const { return mnTextStart
; }
126 sal_Int32
getTextLength() const { return mnTextLength
; }
127 sal_Int32
getParagraph() const { return mnParagraph
; }
128 const SvxFont
& getFont() const { return maFont
; }
129 bool isRTL() const { return mbRTL
; }
130 const ::std::vector
< double >& getDoubleDXArray() const { return maDblDXArray
; }
131 const ::com::sun::star::lang::Locale
& getLocale() const { return maLocale
; }
133 sal_Int32
getPortionIndex(sal_Int32 nIndex
, sal_Int32 nLength
) const
137 return (mnTextStart
+ (mnTextLength
- (nIndex
+ nLength
)));
141 return (mnTextStart
+ nIndex
);
145 double getDisplayLength(sal_Int32 nIndex
, sal_Int32 nLength
) const
147 drawinglayer::primitive2d::TextLayouterDevice aTextLayouter
;
150 if(maFont
.IsVertical())
152 fRetval
= aTextLayouter
.getTextHeight() * (double)nLength
;
156 fRetval
= aTextLayouter
.getTextWidth(maText
, getPortionIndex(nIndex
, nLength
), nLength
);
162 } // end of anonymous namespace
165 // TextBreakup helper
169 class impTextBreakupHandler
171 SdrOutliner
& mrOutliner
;
172 ::std::vector
< impPathTextPortion
> maPathTextPortions
;
174 DECL_LINK(decompositionPathTextPrimitive
, DrawPortionInfo
* );
177 impTextBreakupHandler(SdrOutliner
& rOutliner
)
178 : mrOutliner(rOutliner
)
182 const ::std::vector
< impPathTextPortion
>& decompositionPathTextPrimitive()
184 // strip portions to maPathTextPortions
185 mrOutliner
.SetDrawPortionHdl(LINK(this, impTextBreakupHandler
, decompositionPathTextPrimitive
));
186 mrOutliner
.StripPortions();
188 if(!maPathTextPortions
.empty())
190 // sort portions by paragraph, x and y
191 ::std::sort(maPathTextPortions
.begin(), maPathTextPortions
.end());
194 return maPathTextPortions
;
198 IMPL_LINK(impTextBreakupHandler
, decompositionPathTextPrimitive
, DrawPortionInfo
*, pInfo
)
200 maPathTextPortions
.push_back(impPathTextPortion(*pInfo
));
203 } // end of anonymous namespace
206 // TextBreakup one poly and one paragraph helper
210 class impPolygonParagraphHandler
212 const drawinglayer::attribute::SdrFormTextAttribute maSdrFormTextAttribute
; // FormText parameters
213 std::vector
< drawinglayer::primitive2d::BasePrimitive2D
* >& mrDecomposition
; // destination primitive list
214 std::vector
< drawinglayer::primitive2d::BasePrimitive2D
* >& mrShadowDecomposition
; // destination primitive list for shadow
215 Reference
< com::sun::star::i18n::XBreakIterator
> mxBreak
; // break iterator
217 double getParagraphTextLength(const ::std::vector
< const impPathTextPortion
* >& rTextPortions
)
219 drawinglayer::primitive2d::TextLayouterDevice aTextLayouter
;
222 for(sal_uInt32
a(0L); a
< rTextPortions
.size(); a
++)
224 const impPathTextPortion
* pCandidate
= rTextPortions
[a
];
226 if(pCandidate
&& pCandidate
->getTextLength())
228 aTextLayouter
.setFont(pCandidate
->getFont());
229 fRetval
+= pCandidate
->getDisplayLength(0L, pCandidate
->getTextLength());
236 sal_Int32
getNextGlyphLen(const impPathTextPortion
* pCandidate
, sal_Int32 nPosition
, const ::com::sun::star::lang::Locale
& rFontLocale
)
238 sal_Int32
nNextGlyphLen(1);
243 nNextGlyphLen
= mxBreak
->nextCharacters(pCandidate
->getText(), nPosition
,
244 rFontLocale
, CharacterIteratorMode::SKIPCELL
, 1, nDone
) - nPosition
;
247 return nNextGlyphLen
;
251 impPolygonParagraphHandler(
252 const drawinglayer::attribute::SdrFormTextAttribute
& rSdrFormTextAttribute
,
253 std::vector
< drawinglayer::primitive2d::BasePrimitive2D
* >& rDecomposition
,
254 std::vector
< drawinglayer::primitive2d::BasePrimitive2D
* >& rShadowDecomposition
)
255 : maSdrFormTextAttribute(rSdrFormTextAttribute
),
256 mrDecomposition(rDecomposition
),
257 mrShadowDecomposition(rShadowDecomposition
)
259 // prepare BreakIterator
260 Reference
< XComponentContext
> xContext
= ::comphelper::getProcessComponentContext();
261 mxBreak
= com::sun::star::i18n::BreakIterator::create(xContext
);
264 void HandlePair(const basegfx::B2DPolygon rPolygonCandidate
, const ::std::vector
< const impPathTextPortion
* >& rTextPortions
)
266 // prepare polygon geometry, take into account as many parameters as possible
267 basegfx::B2DPolygon
aPolygonCandidate(rPolygonCandidate
);
268 const double fPolyLength(basegfx::tools::getLength(aPolygonCandidate
));
269 double fPolyEnd(fPolyLength
);
270 double fPolyStart(0.0);
271 double fAutosizeScaleFactor(1.0);
272 bool bAutosizeScale(false);
274 if(maSdrFormTextAttribute
.getFormTextMirror())
276 aPolygonCandidate
.flip();
279 if(maSdrFormTextAttribute
.getFormTextStart()
280 && (XFT_LEFT
== maSdrFormTextAttribute
.getFormTextAdjust()
281 || XFT_RIGHT
== maSdrFormTextAttribute
.getFormTextAdjust()))
283 if(XFT_LEFT
== maSdrFormTextAttribute
.getFormTextAdjust())
285 fPolyStart
+= maSdrFormTextAttribute
.getFormTextStart();
287 if(fPolyStart
> fPolyEnd
)
289 fPolyStart
= fPolyEnd
;
294 fPolyEnd
-= maSdrFormTextAttribute
.getFormTextStart();
296 if(fPolyEnd
< fPolyStart
)
298 fPolyEnd
= fPolyStart
;
303 if(XFT_LEFT
!= maSdrFormTextAttribute
.getFormTextAdjust())
305 // calculate total text length of this paragraph, some layout needs to be done
306 const double fParagraphTextLength(getParagraphTextLength(rTextPortions
));
308 // check if text is too long for paragraph. If yes, handle as if left aligned (default),
309 // but still take care of XFT_AUTOSIZE in that case
310 const bool bTextTooLong(fParagraphTextLength
> (fPolyEnd
- fPolyStart
));
312 if(XFT_RIGHT
== maSdrFormTextAttribute
.getFormTextAdjust())
316 // if right aligned, add difference to polygon start
317 fPolyStart
+= ((fPolyEnd
- fPolyStart
) - fParagraphTextLength
);
320 else if(XFT_CENTER
== maSdrFormTextAttribute
.getFormTextAdjust())
324 // if centered, add half of difference to polygon start
325 fPolyStart
+= ((fPolyEnd
- fPolyStart
) - fParagraphTextLength
) / 2.0;
328 else if(XFT_AUTOSIZE
== maSdrFormTextAttribute
.getFormTextAdjust())
330 // if scale, prepare scale factor between curve length and text length
331 if(0.0 != fParagraphTextLength
)
333 fAutosizeScaleFactor
= (fPolyEnd
- fPolyStart
) / fParagraphTextLength
;
334 bAutosizeScale
= true;
339 // handle text portions for this paragraph
340 for(sal_uInt32
a(0L); a
< rTextPortions
.size() && fPolyStart
< fPolyEnd
; a
++)
342 const impPathTextPortion
* pCandidate
= rTextPortions
[a
];
343 basegfx::B2DVector aFontScaling
;
345 if(pCandidate
&& pCandidate
->getTextLength())
347 const drawinglayer::attribute::FontAttribute
aCandidateFontAttribute(
348 drawinglayer::primitive2d::getFontAttributeFromVclFont(
350 pCandidate
->getFont(),
354 drawinglayer::primitive2d::TextLayouterDevice aTextLayouter
;
355 aTextLayouter
.setFont(pCandidate
->getFont());
356 sal_Int32
nUsedTextLength(0);
358 while(nUsedTextLength
< pCandidate
->getTextLength() && fPolyStart
< fPolyEnd
)
360 sal_Int32
nNextGlyphLen(getNextGlyphLen(pCandidate
, pCandidate
->getTextStart() + nUsedTextLength
, pCandidate
->getLocale()));
362 // prepare portion length. Takes RTL sections into account.
363 double fPortionLength(pCandidate
->getDisplayLength(nUsedTextLength
, nNextGlyphLen
));
367 // when autosize scaling, expand portion length
368 fPortionLength
*= fAutosizeScaleFactor
;
371 // create transformation
372 basegfx::B2DHomMatrix aNewTransformA
, aNewTransformB
, aNewShadowTransform
;
373 basegfx::B2DPoint
aStartPos(basegfx::tools::getPositionAbsolute(aPolygonCandidate
, fPolyStart
, fPolyLength
));
374 basegfx::B2DPoint
aEndPos(aStartPos
);
377 aNewTransformA
.scale(aFontScaling
.getX(), aFontScaling
.getY());
379 // prepare scaling of text primitive
382 // when autosize scaling, expand text primitive scaling to it
383 aNewTransformA
.scale(fAutosizeScaleFactor
, fAutosizeScaleFactor
);
386 // eventually create shadow primitives from aDecomposition and add to rDecomposition
387 const bool bShadow(XFTSHADOW_NONE
!= maSdrFormTextAttribute
.getFormTextShadow());
391 if(XFTSHADOW_NORMAL
== maSdrFormTextAttribute
.getFormTextShadow())
393 aNewShadowTransform
.translate(
394 maSdrFormTextAttribute
.getFormTextShdwXVal(),
395 -maSdrFormTextAttribute
.getFormTextShdwYVal());
397 else // XFTSHADOW_SLANT
399 double fScaleValue(maSdrFormTextAttribute
.getFormTextShdwYVal() / 100.0);
400 double fShearValue(-maSdrFormTextAttribute
.getFormTextShdwXVal() * F_PI1800
);
402 aNewShadowTransform
.scale(1.0, fScaleValue
);
403 aNewShadowTransform
.shearX(sin(fShearValue
));
404 aNewShadowTransform
.scale(1.0, cos(fShearValue
));
408 switch(maSdrFormTextAttribute
.getFormTextStyle())
412 aEndPos
= basegfx::tools::getPositionAbsolute(aPolygonCandidate
, fPolyStart
+ fPortionLength
, fPolyLength
);
413 const basegfx::B2DVector
aDirection(aEndPos
- aStartPos
);
414 aNewTransformB
.rotate(atan2(aDirection
.getY(), aDirection
.getX()));
415 aNewTransformB
.translate(aStartPos
.getX(), aStartPos
.getY());
421 aNewTransformB
.translate(aStartPos
.getX() - (fPortionLength
/ 2.0), aStartPos
.getY());
427 aEndPos
= basegfx::tools::getPositionAbsolute(aPolygonCandidate
, fPolyStart
+ fPortionLength
, fPolyLength
);
428 const basegfx::B2DVector
aDirection(aEndPos
- aStartPos
);
429 const double fShearValue(atan2(aDirection
.getY(), aDirection
.getX()));
430 const double fSin(sin(fShearValue
));
431 const double fCos(cos(fShearValue
));
433 aNewTransformB
.shearX(-fSin
);
435 // Scale may lead to objects without height since fCos == 0.0 is possible.
436 // Renderers need to handle that, it's not a forbidden value and does not
437 // need to be avoided
438 aNewTransformB
.scale(1.0, fCos
);
439 aNewTransformB
.translate(aStartPos
.getX() - (fPortionLength
/ 2.0), aStartPos
.getY());
445 aEndPos
= basegfx::tools::getPositionAbsolute(aPolygonCandidate
, fPolyStart
+ fPortionLength
, fPolyLength
);
446 const basegfx::B2DVector
aDirection(aEndPos
- aStartPos
);
447 const double fShearValue(atan2(aDirection
.getY(), aDirection
.getX()));
448 const double fCos(cos(fShearValue
));
449 const double fTan(tan(fShearValue
));
451 // shear to 'stand' on the curve
452 aNewTransformB
.shearY(fTan
);
454 // scale in X to make as tight as needed. As with XFT_SLANT_X, this may
455 // lead to primitives without width which the renderers will handle
456 aNewTransformA
.scale(fCos
, 1.0);
458 aNewTransformB
.translate(aStartPos
.getX(), aStartPos
.getY());
462 default : break; // XFT_NONE
465 // distance from path?
466 if(maSdrFormTextAttribute
.getFormTextDistance())
468 if(aEndPos
.equal(aStartPos
))
470 aEndPos
= basegfx::tools::getPositionAbsolute(aPolygonCandidate
, fPolyStart
+ fPortionLength
, fPolyLength
);
473 // use back vector (aStartPos - aEndPos) here to get mirrored perpendicular as in old stuff
474 const basegfx::B2DVector
aPerpendicular(
475 basegfx::getNormalizedPerpendicular(aStartPos
- aEndPos
) *
476 maSdrFormTextAttribute
.getFormTextDistance());
477 aNewTransformB
.translate(aPerpendicular
.getX(), aPerpendicular
.getY());
480 if(!pCandidate
->getText().isEmpty() && nNextGlyphLen
)
482 const sal_Int32
nPortionIndex(pCandidate
->getPortionIndex(nUsedTextLength
, nNextGlyphLen
));
483 ::std::vector
< double > aNewDXArray
;
485 if(nNextGlyphLen
> 1 && pCandidate
->getDoubleDXArray().size())
487 // copy DXArray for portion
490 pCandidate
->getDoubleDXArray().begin() + nPortionIndex
,
491 pCandidate
->getDoubleDXArray().begin() + (nPortionIndex
+ nNextGlyphLen
));
493 if(nPortionIndex
> 0)
495 // adapt to portion start
496 double fDXOffset
= *(pCandidate
->getDoubleDXArray().begin() + (nPortionIndex
- 1));
498 aNewDXArray
.begin(), aNewDXArray
.end(),
499 aNewDXArray
.begin(), ::std::bind2nd(::std::minus
<double>(), fDXOffset
));
504 // when autosize scaling, adapt to DXArray, too
506 aNewDXArray
.begin(), aNewDXArray
.end(),
507 aNewDXArray
.begin(), ::std::bind2nd(::std::multiplies
<double>(), fAutosizeScaleFactor
));
513 // shadow primitive creation
514 const Color
aShadowColor(maSdrFormTextAttribute
.getFormTextShdwColor());
515 const basegfx::BColor
aRGBShadowColor(aShadowColor
.getBColor());
517 drawinglayer::primitive2d::TextSimplePortionPrimitive2D
* pNew
=
518 new drawinglayer::primitive2d::TextSimplePortionPrimitive2D(
519 aNewTransformB
* aNewShadowTransform
* aNewTransformA
,
520 pCandidate
->getText(),
524 aCandidateFontAttribute
,
525 pCandidate
->getLocale(),
528 mrShadowDecomposition
.push_back(pNew
);
532 // primitive creation
533 const Color
aColor(pCandidate
->getFont().GetColor());
534 const basegfx::BColor
aRGBColor(aColor
.getBColor());
536 drawinglayer::primitive2d::TextSimplePortionPrimitive2D
* pNew
=
537 new drawinglayer::primitive2d::TextSimplePortionPrimitive2D(
538 aNewTransformB
* aNewTransformA
,
539 pCandidate
->getText(),
543 aCandidateFontAttribute
,
544 pCandidate
->getLocale(),
547 mrDecomposition
.push_back(pNew
);
551 // consume from portion
552 nUsedTextLength
+= nNextGlyphLen
;
554 // consume from polygon
555 fPolyStart
+= fPortionLength
;
561 } // end of anonymous namespace
564 // primitive decomposition helpers
568 void impAddPolygonStrokePrimitives(
569 const basegfx::B2DPolyPolygonVector
& rB2DPolyPolyVector
,
570 const basegfx::B2DHomMatrix
& rTransform
,
571 const drawinglayer::attribute::LineAttribute
& rLineAttribute
,
572 const drawinglayer::attribute::StrokeAttribute
& rStrokeAttribute
,
573 std::vector
< drawinglayer::primitive2d::BasePrimitive2D
* >& rTarget
)
575 for(basegfx::B2DPolyPolygonVector::const_iterator
aPolygon(rB2DPolyPolyVector
.begin()); aPolygon
!= rB2DPolyPolyVector
.end(); ++aPolygon
)
577 // prepare PolyPolygons
578 basegfx::B2DPolyPolygon aB2DPolyPolygon
= *aPolygon
;
579 aB2DPolyPolygon
.transform(rTransform
);
581 for(sal_uInt32
a(0L); a
< aB2DPolyPolygon
.count(); a
++)
583 // create one primitive per polygon
584 drawinglayer::primitive2d::PolygonStrokePrimitive2D
* pNew
=
585 new drawinglayer::primitive2d::PolygonStrokePrimitive2D(
586 aB2DPolyPolygon
.getB2DPolygon(a
), rLineAttribute
, rStrokeAttribute
);
587 rTarget
.push_back(pNew
);
592 drawinglayer::primitive2d::Primitive2DSequence
impAddPathTextOutlines(
593 const std::vector
< drawinglayer::primitive2d::BasePrimitive2D
* >& rSource
,
594 const drawinglayer::attribute::SdrFormTextOutlineAttribute
& rOutlineAttribute
)
596 std::vector
< drawinglayer::primitive2d::BasePrimitive2D
* > aNewPrimitives
;
598 for(sal_uInt32
a(0L); a
< rSource
.size(); a
++)
600 const drawinglayer::primitive2d::TextSimplePortionPrimitive2D
* pTextCandidate
= dynamic_cast< const drawinglayer::primitive2d::TextSimplePortionPrimitive2D
* >(rSource
[a
]);
604 basegfx::B2DPolyPolygonVector aB2DPolyPolyVector
;
605 basegfx::B2DHomMatrix aPolygonTransform
;
607 // get text outlines and their object transformation
608 pTextCandidate
->getTextOutlinesAndTransformation(aB2DPolyPolyVector
, aPolygonTransform
);
610 if(!aB2DPolyPolyVector
.empty())
612 // create stroke primitives
613 std::vector
< drawinglayer::primitive2d::BasePrimitive2D
* > aStrokePrimitives
;
614 impAddPolygonStrokePrimitives(
617 rOutlineAttribute
.getLineAttribute(),
618 rOutlineAttribute
.getStrokeAttribute(),
620 const sal_uInt32
nStrokeCount(aStrokePrimitives
.size());
624 if(rOutlineAttribute
.getTransparence())
626 // create UnifiedTransparencePrimitive2D
627 drawinglayer::primitive2d::Primitive2DSequence
aStrokePrimitiveSequence(nStrokeCount
);
629 for(sal_uInt32
b(0L); b
< nStrokeCount
; b
++)
631 aStrokePrimitiveSequence
[b
] = drawinglayer::primitive2d::Primitive2DReference(aStrokePrimitives
[b
]);
634 drawinglayer::primitive2d::UnifiedTransparencePrimitive2D
* pNew2
=
635 new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D(
636 aStrokePrimitiveSequence
,
637 (double)rOutlineAttribute
.getTransparence() / 100.0);
638 aNewPrimitives
.push_back(pNew2
);
642 // add polygons to rDecomposition as polygonStrokePrimitives
643 aNewPrimitives
.insert(aNewPrimitives
.end(), aStrokePrimitives
.begin(), aStrokePrimitives
.end());
650 const sal_uInt32
nNewCount(aNewPrimitives
.size());
654 drawinglayer::primitive2d::Primitive2DSequence
aRetval(nNewCount
);
656 for(sal_uInt32
a(0L); a
< nNewCount
; a
++)
658 aRetval
[a
] = drawinglayer::primitive2d::Primitive2DReference(aNewPrimitives
[a
]);
665 return drawinglayer::primitive2d::Primitive2DSequence();
668 } // end of anonymous namespace
671 // primitive decomposition
673 void SdrTextObj::impDecomposePathTextPrimitive(
674 drawinglayer::primitive2d::Primitive2DSequence
& rTarget
,
675 const drawinglayer::primitive2d::SdrPathTextPrimitive2D
& rSdrPathTextPrimitive
,
676 const drawinglayer::geometry::ViewInformation2D
& aViewInformation
) const
678 drawinglayer::primitive2d::Primitive2DSequence aRetvalA
;
679 drawinglayer::primitive2d::Primitive2DSequence aRetvalB
;
682 SdrOutliner
& rOutliner
= ImpGetDrawOutliner();
683 rOutliner
.SetUpdateMode(true);
685 rOutliner
.SetPaperSize(Size(LONG_MAX
,LONG_MAX
));
686 rOutliner
.SetText(rSdrPathTextPrimitive
.getOutlinerParaObject());
688 // set visualizing page at Outliner; needed e.g. for PageNumberField decomposition
689 rOutliner
.setVisualizedPage(GetSdrPageFromXDrawPage(aViewInformation
.getVisualizedPage()));
691 // now break up to text portions
692 impTextBreakupHandler
aConverter(rOutliner
);
693 const ::std::vector
< impPathTextPortion
> rPathTextPortions
= aConverter
.decompositionPathTextPrimitive();
695 if(!rPathTextPortions
.empty())
697 // get FormText and polygon values
698 const drawinglayer::attribute::SdrFormTextAttribute
& rFormTextAttribute
= rSdrPathTextPrimitive
.getSdrFormTextAttribute();
699 const basegfx::B2DPolyPolygon
& rPathPolyPolygon(rSdrPathTextPrimitive
.getPathPolyPolygon());
702 sal_uInt32
nLoopCount(rPathPolyPolygon
.count());
704 if(static_cast<sal_uInt32
>(rOutliner
.GetParagraphCount()) < nLoopCount
)
706 nLoopCount
= rOutliner
.GetParagraphCount();
711 // prepare common decomposition stuff
712 std::vector
< drawinglayer::primitive2d::BasePrimitive2D
* > aRegularDecomposition
;
713 std::vector
< drawinglayer::primitive2d::BasePrimitive2D
* > aShadowDecomposition
;
714 impPolygonParagraphHandler
aPolygonParagraphHandler(
716 aRegularDecomposition
,
717 aShadowDecomposition
);
720 for(a
= 0L; a
< nLoopCount
; a
++)
722 // filter text portions for this paragraph
723 ::std::vector
< const impPathTextPortion
* > aParagraphTextPortions
;
725 for(sal_uInt32
b(0L); b
< rPathTextPortions
.size(); b
++)
727 const impPathTextPortion
& rCandidate
= rPathTextPortions
[b
];
729 if(static_cast<sal_uInt32
>(rCandidate
.getParagraph()) == a
)
731 aParagraphTextPortions
.push_back(&rCandidate
);
735 // handle data pair polygon/ParagraphTextPortions
736 if(!aParagraphTextPortions
.empty())
738 aPolygonParagraphHandler
.HandlePair(rPathPolyPolygon
.getB2DPolygon(a
), aParagraphTextPortions
);
742 const sal_uInt32
nShadowCount(aShadowDecomposition
.size());
743 const sal_uInt32
nRegularCount(aRegularDecomposition
.size());
747 // add shadow primitives to decomposition
748 aRetvalA
.realloc(nShadowCount
);
750 for(a
= 0L; a
< nShadowCount
; a
++)
752 aRetvalA
[a
] = drawinglayer::primitive2d::Primitive2DReference(aShadowDecomposition
[a
]);
755 // if necessary, add shadow outlines
756 if(rFormTextAttribute
.getFormTextOutline()
757 && !rFormTextAttribute
.getShadowOutline().isDefault())
759 const drawinglayer::primitive2d::Primitive2DSequence
aOutlines(
760 impAddPathTextOutlines(
761 aShadowDecomposition
,
762 rFormTextAttribute
.getShadowOutline()));
764 drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(aRetvalA
, aOutlines
);
770 // add normal primitives to decomposition
771 aRetvalB
.realloc(nRegularCount
);
773 for(a
= 0L; a
< nRegularCount
; a
++)
775 aRetvalB
[a
] = drawinglayer::primitive2d::Primitive2DReference(aRegularDecomposition
[a
]);
778 // if necessary, add outlines
779 if(rFormTextAttribute
.getFormTextOutline()
780 && !rFormTextAttribute
.getOutline().isDefault())
782 const drawinglayer::primitive2d::Primitive2DSequence
aOutlines(
783 impAddPathTextOutlines(
784 aRegularDecomposition
,
785 rFormTextAttribute
.getOutline()));
787 drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(aRetvalB
, aOutlines
);
794 rOutliner
.SetDrawPortionHdl(Link());
796 rOutliner
.setVisualizedPage(0);
798 // concatenate all results
799 drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget
, aRetvalA
);
800 drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget
, aRetvalB
);
804 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */