1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: svdotextpathdecomposition.cxx,v $
13 * This file is part of OpenOffice.org.
15 * OpenOffice.org is free software: you can redistribute it and/or modify
16 * it under the terms of the GNU Lesser General Public License version 3
17 * only, as published by the Free Software Foundation.
19 * OpenOffice.org is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU Lesser General Public License version 3 for more details
23 * (a copy is included in the LICENSE file that accompanied this code).
25 * You should have received a copy of the GNU Lesser General Public License
26 * version 3 along with OpenOffice.org. If not, see
27 * <http://www.openoffice.org/license.html>
28 * for a copy of the LGPLv3 License.
30 ************************************************************************/
32 // MARKER(update_precomp.py): autogen include statement, do not remove
33 #include "precompiled_svx.hxx"
35 #include <svx/svdotext.hxx>
36 #include <svx/svdoutl.hxx>
37 #include <basegfx/vector/b2dvector.hxx>
38 #include <svx/sdr/primitive2d/sdrtextprimitive2d.hxx>
39 #include <basegfx/range/b2drange.hxx>
40 #include <vcl/salbtype.hxx>
41 #include <svtools/itemset.hxx>
42 #include <basegfx/polygon/b2dpolygontools.hxx>
43 #include <basegfx/polygon/b2dpolygon.hxx>
45 #include <svx/xtextit.hxx>
46 #include <svx/xftshtit.hxx>
47 #include <vcl/virdev.hxx>
48 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
49 #include <com/sun/star/i18n/ScriptType.hdl>
50 #include <com/sun/star/i18n/XBreakIterator.hpp>
51 #include <comphelper/processfactory.hxx>
52 #include <com/sun/star/i18n/CharacterIteratorMode.hdl>
53 #include <unolingu.hxx>
54 #include <drawinglayer/primitive2d/textlayoutdevice.hxx>
55 #include <drawinglayer/primitive2d/textprimitive2d.hxx>
56 #include <basegfx/color/bcolor.hxx>
58 //////////////////////////////////////////////////////////////////////////////
59 // primitive decomposition helpers
61 #include <basegfx/polygon/b2dlinegeometry.hxx>
62 #include <drawinglayer/attribute/strokeattribute.hxx>
63 #include <svx/xlnclit.hxx>
64 #include <svx/xlntrit.hxx>
65 #include <svx/xlnwtit.hxx>
66 #include <xlinjoit.hxx>
67 #include <svx/xlndsit.hxx>
68 #include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
69 #include <drawinglayer/primitive2d/unifiedalphaprimitive2d.hxx>
70 #include <editstat.hxx>
72 #include <drawinglayer/geometry/viewinformation2d.hxx>
73 #include <svx/sdr/attribute/sdrformtextoutlineattribute.hxx>
75 //////////////////////////////////////////////////////////////////////////////
77 using namespace ::com::sun::star::uno
;
78 using namespace ::com::sun::star::lang
;
79 using namespace ::com::sun::star::i18n
;
81 //////////////////////////////////////////////////////////////////////////////
82 // PathTextPortion helper
86 class impPathTextPortion
88 basegfx::B2DVector maOffset
;
90 xub_StrLen mnTextStart
;
91 xub_StrLen mnTextLength
;
92 sal_uInt16 mnParagraph
;
95 ::std::vector
< double > maDblDXArray
; // double DXArray, font size independent -> unit coordinate system
96 ::com::sun::star::lang::Locale maLocale
;
102 impPathTextPortion(DrawPortionInfo
& rInfo
)
103 : maOffset(rInfo
.mrStartPos
.X(), rInfo
.mrStartPos
.Y()),
104 maText(rInfo
.mrText
),
105 mnTextStart(rInfo
.mnTextStart
),
106 mnTextLength(rInfo
.mnTextLen
),
107 mnParagraph(rInfo
.mnPara
),
108 mnIndex(rInfo
.mnIndex
),
109 maFont(rInfo
.mrFont
),
111 maLocale(rInfo
.mpLocale
? *rInfo
.mpLocale
: ::com::sun::star::lang::Locale()),
112 mbRTL(rInfo
.mrFont
.IsVertical() ? false : rInfo
.IsRTL())
116 maDblDXArray
.reserve(mnTextLength
);
117 const sal_Int32
nFontWidth(0L == maFont
.GetWidth() ? maFont
.GetHeight() : maFont
.GetWidth());
118 const double fScaleFactor(0L != nFontWidth
? 1.0 / (double)nFontWidth
: 1.0);
120 for(xub_StrLen
a(0); a
< mnTextLength
; a
++)
122 maDblDXArray
.push_back((double)rInfo
.mpDXArray
[a
] * fScaleFactor
);
128 bool operator<(const impPathTextPortion
& rComp
) const
130 if(mnParagraph
< rComp
.mnParagraph
)
135 if(maOffset
.getX() < rComp
.maOffset
.getX())
140 return (maOffset
.getY() < rComp
.maOffset
.getY());
143 const basegfx::B2DVector
& getOffset() const { return maOffset
; }
144 const String
& getText() const { return maText
; }
145 xub_StrLen
getTextStart() const { return mnTextStart
; }
146 xub_StrLen
getTextLength() const { return mnTextLength
; }
147 sal_uInt16
getParagraph() const { return mnParagraph
; }
148 xub_StrLen
getIndex() const { return mnIndex
; }
149 const SvxFont
& getFont() const { return maFont
; }
150 bool isRTL() const { return mbRTL
; }
151 const ::std::vector
< double >& getDoubleDXArray() const { return maDblDXArray
; }
152 const ::com::sun::star::lang::Locale
& getLocale() const { return maLocale
; }
154 xub_StrLen
getPortionIndex(xub_StrLen nIndex
, xub_StrLen nLength
) const
158 return (mnTextStart
+ (mnTextLength
- (nIndex
+ nLength
)));
162 return (mnTextStart
+ nIndex
);
166 double getDisplayLength(xub_StrLen nIndex
, xub_StrLen nLength
) const
168 drawinglayer::primitive2d::TextLayouterDevice aTextLayouter
;
171 if(maFont
.IsVertical())
173 fRetval
= aTextLayouter
.getTextHeight() * (double)nLength
;
177 fRetval
= aTextLayouter
.getTextWidth(maText
, getPortionIndex(nIndex
, nLength
), nLength
);
183 } // end of anonymous namespace
185 //////////////////////////////////////////////////////////////////////////////
186 // TextBreakup helper
190 class impTextBreakupHandler
192 SdrOutliner
& mrOutliner
;
193 ::std::vector
< impPathTextPortion
> maPathTextPortions
;
195 DECL_LINK(decompositionPathTextPrimitive
, DrawPortionInfo
* );
198 impTextBreakupHandler(SdrOutliner
& rOutliner
)
199 : mrOutliner(rOutliner
)
203 const ::std::vector
< impPathTextPortion
>& decompositionPathTextPrimitive()
205 // strip portions to maPathTextPortions
206 mrOutliner
.SetDrawPortionHdl(LINK(this, impTextBreakupHandler
, decompositionPathTextPrimitive
));
207 mrOutliner
.StripPortions();
209 if(maPathTextPortions
.size())
211 // sort portions by paragraph, x and y
212 ::std::sort(maPathTextPortions
.begin(), maPathTextPortions
.end());
215 return maPathTextPortions
;
219 IMPL_LINK(impTextBreakupHandler
, decompositionPathTextPrimitive
, DrawPortionInfo
*, pInfo
)
221 maPathTextPortions
.push_back(impPathTextPortion(*pInfo
));
224 } // end of anonymous namespace
226 //////////////////////////////////////////////////////////////////////////////
227 // TextBreakup one poly and one paragraph helper
231 class impPolygonParagraphHandler
233 const drawinglayer::attribute::SdrFormTextAttribute
& mrSdrFormTextAttribute
; // FormText parameters
234 std::vector
< drawinglayer::primitive2d::BasePrimitive2D
* >& mrDecomposition
; // destination primitive list
235 std::vector
< drawinglayer::primitive2d::BasePrimitive2D
* >& mrShadowDecomposition
; // destination primitive list for shadow
236 Reference
< com::sun::star::i18n::XBreakIterator
> mxBreak
; // break iterator
238 double getParagraphTextLength(const ::std::vector
< const impPathTextPortion
* >& rTextPortions
)
240 drawinglayer::primitive2d::TextLayouterDevice aTextLayouter
;
243 for(sal_uInt32
a(0L); a
< rTextPortions
.size(); a
++)
245 const impPathTextPortion
* pCandidate
= rTextPortions
[a
];
247 if(pCandidate
&& pCandidate
->getTextLength())
249 aTextLayouter
.setFont(pCandidate
->getFont());
250 fRetval
+= pCandidate
->getDisplayLength(0L, pCandidate
->getTextLength());
257 xub_StrLen
getNextGlyphLen(const impPathTextPortion
* pCandidate
, xub_StrLen nPosition
, const ::com::sun::star::lang::Locale
& rFontLocale
)
259 xub_StrLen
nNextGlyphLen(1);
264 nNextGlyphLen
= (xub_StrLen
)mxBreak
->nextCharacters(pCandidate
->getText(), nPosition
,
265 rFontLocale
, CharacterIteratorMode::SKIPCELL
, 1, nDone
) - nPosition
;
268 return nNextGlyphLen
;
272 impPolygonParagraphHandler(
273 const drawinglayer::attribute::SdrFormTextAttribute
& rSdrFormTextAttribute
,
274 std::vector
< drawinglayer::primitive2d::BasePrimitive2D
* >& rDecomposition
,
275 std::vector
< drawinglayer::primitive2d::BasePrimitive2D
* >& rShadowDecomposition
)
276 : mrSdrFormTextAttribute(rSdrFormTextAttribute
),
277 mrDecomposition(rDecomposition
),
278 mrShadowDecomposition(rShadowDecomposition
)
280 // prepare BreakIterator
281 Reference
< XMultiServiceFactory
> xMSF
= ::comphelper::getProcessServiceFactory();
282 Reference
< XInterface
> xInterface
= xMSF
->createInstance(::rtl::OUString::createFromAscii("com.sun.star.i18n.BreakIterator"));
286 Any x
= xInterface
->queryInterface(::getCppuType((const Reference
< XBreakIterator
>*)0));
291 void HandlePair(const basegfx::B2DPolygon rPolygonCandidate
, const ::std::vector
< const impPathTextPortion
* >& rTextPortions
)
293 // prepare polygon geometry, take into account as many parameters as possible
294 basegfx::B2DPolygon
aPolygonCandidate(rPolygonCandidate
);
295 const double fPolyLength(basegfx::tools::getLength(aPolygonCandidate
));
296 double fPolyEnd(fPolyLength
);
297 double fPolyStart(0.0);
298 double fScaleFactor(1.0);
300 if(mrSdrFormTextAttribute
.getFormTextMirror())
302 aPolygonCandidate
.flip();
305 if(mrSdrFormTextAttribute
.getFormTextStart()
306 && (XFT_LEFT
== mrSdrFormTextAttribute
.getFormTextAdjust()
307 || XFT_RIGHT
== mrSdrFormTextAttribute
.getFormTextAdjust()))
309 if(XFT_LEFT
== mrSdrFormTextAttribute
.getFormTextAdjust())
311 fPolyStart
+= mrSdrFormTextAttribute
.getFormTextStart();
313 if(fPolyStart
> fPolyEnd
)
315 fPolyStart
= fPolyEnd
;
320 fPolyEnd
-= mrSdrFormTextAttribute
.getFormTextStart();
322 if(fPolyEnd
< fPolyStart
)
324 fPolyEnd
= fPolyStart
;
329 if(XFT_LEFT
!= mrSdrFormTextAttribute
.getFormTextAdjust())
331 // calculate total text length of this paragraph, some layout needs to be done
332 const double fParagraphTextLength(getParagraphTextLength(rTextPortions
));
334 // check if text is too long for paragraph. If yes, handle as if left aligned (default),
335 // but still take care of XFT_AUTOSIZE in that case
336 const bool bTextTooLong(fParagraphTextLength
> (fPolyEnd
- fPolyStart
));
338 if(XFT_RIGHT
== mrSdrFormTextAttribute
.getFormTextAdjust())
342 // if right aligned, add difference to polygon start
343 fPolyStart
+= ((fPolyEnd
- fPolyStart
) - fParagraphTextLength
);
346 else if(XFT_CENTER
== mrSdrFormTextAttribute
.getFormTextAdjust())
350 // if centered, add half of difference to polygon start
351 fPolyStart
+= ((fPolyEnd
- fPolyStart
) - fParagraphTextLength
) / 2.0;
354 else if(XFT_AUTOSIZE
== mrSdrFormTextAttribute
.getFormTextAdjust())
356 // if scale, prepare scale factor between curve length and text length
357 if(0.0 != fParagraphTextLength
)
359 fScaleFactor
= (fPolyEnd
- fPolyStart
) / fParagraphTextLength
;
364 // handle text portions for this paragraph
365 for(sal_uInt32
a(0L); a
< rTextPortions
.size() && fPolyStart
< fPolyEnd
; a
++)
367 const impPathTextPortion
* pCandidate
= rTextPortions
[a
];
368 basegfx::B2DVector aFontScaling
;
369 const drawinglayer::primitive2d::FontAttributes
aCandidateFontAttributes(
370 drawinglayer::primitive2d::getFontAttributesFromVclFont(
372 pCandidate
->getFont(),
376 if(pCandidate
&& pCandidate
->getTextLength())
378 drawinglayer::primitive2d::TextLayouterDevice aTextLayouter
;
379 aTextLayouter
.setFont(pCandidate
->getFont());
380 xub_StrLen
nUsedTextLength(0);
382 while(nUsedTextLength
< pCandidate
->getTextLength() && fPolyStart
< fPolyEnd
)
384 xub_StrLen
nNextGlyphLen(getNextGlyphLen(pCandidate
, pCandidate
->getTextStart() + nUsedTextLength
, pCandidate
->getLocale()));
386 // prepare portion length. Takes RTL sections into account.
387 double fPortionLength(pCandidate
->getDisplayLength(nUsedTextLength
, nNextGlyphLen
));
389 if(XFT_AUTOSIZE
== mrSdrFormTextAttribute
.getFormTextAdjust())
391 // when scaling, expand portion length
392 fPortionLength
*= fScaleFactor
;
395 // create transformation
396 basegfx::B2DHomMatrix aNewTransformA
, aNewTransformB
, aNewShadowTransform
;
397 basegfx::B2DPoint
aStartPos(basegfx::tools::getPositionAbsolute(aPolygonCandidate
, fPolyStart
, fPolyLength
));
398 basegfx::B2DPoint
aEndPos(aStartPos
);
401 aNewTransformA
.scale(aFontScaling
.getX(), aFontScaling
.getY());
403 // prepare scaling of text primitive
404 if(XFT_AUTOSIZE
== mrSdrFormTextAttribute
.getFormTextAdjust())
406 // when scaling, expand text primitive scaling
407 aNewTransformA
.scale(fScaleFactor
, fScaleFactor
);
410 // eventually create shadow primitives from aDecomposition and add to rDecomposition
411 const bool bShadow(XFTSHADOW_NONE
!= mrSdrFormTextAttribute
.getFormTextShadow());
415 if(XFTSHADOW_NORMAL
== mrSdrFormTextAttribute
.getFormTextShadow())
417 aNewShadowTransform
.translate(
418 mrSdrFormTextAttribute
.getFormTextShdwXVal(),
419 -mrSdrFormTextAttribute
.getFormTextShdwYVal());
421 else // XFTSHADOW_SLANT
423 double fScaleValue(mrSdrFormTextAttribute
.getFormTextShdwYVal() / 100.0);
424 double fShearValue(-mrSdrFormTextAttribute
.getFormTextShdwXVal() * F_PI1800
);
426 aNewShadowTransform
.scale(1.0, fScaleValue
);
427 aNewShadowTransform
.shearX(sin(fShearValue
));
428 aNewShadowTransform
.scale(1.0, cos(fShearValue
));
432 switch(mrSdrFormTextAttribute
.getFormTextStyle())
436 aEndPos
= basegfx::tools::getPositionAbsolute(aPolygonCandidate
, fPolyStart
+ fPortionLength
, fPolyLength
);
437 const basegfx::B2DVector
aDirection(aEndPos
- aStartPos
);
438 aNewTransformB
.rotate(atan2(aDirection
.getY(), aDirection
.getX()));
439 aNewTransformB
.translate(aStartPos
.getX(), aStartPos
.getY());
445 aNewTransformB
.translate(aStartPos
.getX() - (fPortionLength
/ 2.0), aStartPos
.getY());
451 aEndPos
= basegfx::tools::getPositionAbsolute(aPolygonCandidate
, fPolyStart
+ fPortionLength
, fPolyLength
);
452 const basegfx::B2DVector
aDirection(aEndPos
- aStartPos
);
453 const double fShearValue(atan2(aDirection
.getY(), aDirection
.getX()));
454 const double fSin(sin(fShearValue
));
455 const double fCos(cos(fShearValue
));
457 aNewTransformB
.shearX(-fSin
);
459 // Scale may lead to objects without height since fCos == 0.0 is possible.
460 // Renderers need to handle that, it's not a forbidden value and does not
461 // need to be avoided
462 aNewTransformB
.scale(1.0, fCos
);
463 aNewTransformB
.translate(aStartPos
.getX() - (fPortionLength
/ 2.0), aStartPos
.getY());
469 aEndPos
= basegfx::tools::getPositionAbsolute(aPolygonCandidate
, fPolyStart
+ fPortionLength
, fPolyLength
);
470 const basegfx::B2DVector
aDirection(aEndPos
- aStartPos
);
471 const double fShearValue(atan2(aDirection
.getY(), aDirection
.getX()));
472 const double fCos(cos(fShearValue
));
473 const double fTan(tan(fShearValue
));
475 // shear to 'stand' on the curve
476 aNewTransformB
.shearY(fTan
);
478 // scale in X to make as tight as needed. As with XFT_SLANT_X, this may
479 // lead to primitives without width which the renderers will handle
480 aNewTransformA
.scale(fCos
, 1.0);
482 aNewTransformB
.translate(aStartPos
.getX(), aStartPos
.getY());
486 default : break; // XFT_NONE
489 // distance from path?
490 if(mrSdrFormTextAttribute
.getFormTextDistance())
492 if(aEndPos
.equal(aStartPos
))
494 aEndPos
= basegfx::tools::getPositionAbsolute(aPolygonCandidate
, fPolyStart
+ fPortionLength
, fPolyLength
);
497 // use back vector (aStartPos - aEndPos) here to get mirrored perpendicular as in old stuff
498 const basegfx::B2DVector
aPerpendicular(
499 basegfx::getNormalizedPerpendicular(aStartPos
- aEndPos
) *
500 mrSdrFormTextAttribute
.getFormTextDistance());
501 aNewTransformB
.translate(aPerpendicular
.getX(), aPerpendicular
.getY());
504 // shadow primitive creation
507 if(pCandidate
->getText().Len() && nNextGlyphLen
)
509 const Color
aShadowColor(mrSdrFormTextAttribute
.getFormTextShdwColor());
510 const basegfx::BColor
aRGBShadowColor(aShadowColor
.getBColor());
511 const xub_StrLen
nPortionIndex(pCandidate
->getPortionIndex(nUsedTextLength
, nNextGlyphLen
));
512 const ::std::vector
< double > aNewDXArray(
513 pCandidate
->getDoubleDXArray().begin() + nPortionIndex
,
514 pCandidate
->getDoubleDXArray().begin() + nPortionIndex
+ nNextGlyphLen
);
516 drawinglayer::primitive2d::TextSimplePortionPrimitive2D
* pNew
=
517 new drawinglayer::primitive2d::TextSimplePortionPrimitive2D(
518 aNewTransformB
* aNewShadowTransform
* aNewTransformA
,
519 pCandidate
->getText(),
523 aCandidateFontAttributes
,
524 pCandidate
->getLocale(),
527 mrShadowDecomposition
.push_back(pNew
);
531 // primitive creation
532 if(pCandidate
->getText().Len() && nNextGlyphLen
)
534 const Color
aColor(pCandidate
->getFont().GetColor());
535 const basegfx::BColor
aRGBColor(aColor
.getBColor());
536 const xub_StrLen
nPortionIndex(pCandidate
->getPortionIndex(nUsedTextLength
, nNextGlyphLen
));
537 const ::std::vector
< double > aNewDXArray(
538 pCandidate
->getDoubleDXArray().begin() + nPortionIndex
,
539 pCandidate
->getDoubleDXArray().begin() + nPortionIndex
+ nNextGlyphLen
);
541 drawinglayer::primitive2d::TextSimplePortionPrimitive2D
* pNew
=
542 new drawinglayer::primitive2d::TextSimplePortionPrimitive2D(
543 aNewTransformB
* aNewTransformA
,
544 pCandidate
->getText(),
548 aCandidateFontAttributes
,
549 pCandidate
->getLocale(),
552 mrDecomposition
.push_back(pNew
);
555 // consume from portion // no += here, xub_StrLen is USHORT and the compiler will gererate 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
.size())
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 UnifiedAlphaPrimitive2D
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::UnifiedAlphaPrimitive2D
* pNew2
=
639 new drawinglayer::primitive2d::UnifiedAlphaPrimitive2D(
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
.size())
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(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(
719 rFormTextAttribute
, aRegularDecomposition
, aShadowDecomposition
);
722 for(a
= 0L; a
< nLoopCount
; a
++)
724 // filter text portions for this paragraph
725 ::std::vector
< const impPathTextPortion
* > aParagraphTextPortions
;
727 for(sal_uInt32
b(0L); b
< rPathTextPortions
.size(); b
++)
729 const impPathTextPortion
& rCandidate
= rPathTextPortions
[b
];
731 if(rCandidate
.getParagraph() == a
)
733 aParagraphTextPortions
.push_back(&rCandidate
);
737 // handle data pair polygon/ParagraphTextPortions
738 if(aParagraphTextPortions
.size())
740 aPolygonParagraphHandler
.HandlePair(rPathPolyPolygon
.getB2DPolygon(a
), aParagraphTextPortions
);
744 const sal_uInt32
nShadowCount(aShadowDecomposition
.size());
745 const sal_uInt32
nRegularCount(aRegularDecomposition
.size());
749 // add shadow primitives to decomposition
750 aRetvalA
.realloc(nShadowCount
);
752 for(a
= 0L; a
< nShadowCount
; a
++)
754 aRetvalA
[a
] = drawinglayer::primitive2d::Primitive2DReference(aShadowDecomposition
[a
]);
757 // evtl. add shadow outlines
758 if(rFormTextAttribute
.getFormTextOutline() && rFormTextAttribute
.getShadowOutline())
760 const drawinglayer::primitive2d::Primitive2DSequence
aOutlines(
761 impAddPathTextOutlines(aShadowDecomposition
, *rFormTextAttribute
.getShadowOutline()));
762 drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(aRetvalA
, aOutlines
);
768 // add normal primitives to decomposition
769 aRetvalB
.realloc(nRegularCount
);
771 for(a
= 0L; a
< nRegularCount
; a
++)
773 aRetvalB
[a
] = drawinglayer::primitive2d::Primitive2DReference(aRegularDecomposition
[a
]);
776 // evtl. add outlines
777 if(rFormTextAttribute
.getFormTextOutline() && rFormTextAttribute
.getOutline())
779 const drawinglayer::primitive2d::Primitive2DSequence
aOutlines(
780 impAddPathTextOutlines(aRegularDecomposition
, *rFormTextAttribute
.getOutline()));
781 drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(aRetvalB
, aOutlines
);
788 rOutliner
.SetDrawPortionHdl(Link());
790 rOutliner
.setVisualizedPage(0);
792 // concatenate all results
793 drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget
, aRetvalA
);
794 drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget
, aRetvalB
);
797 //////////////////////////////////////////////////////////////////////////////