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 aSize
;
369 const drawinglayer::primitive2d::FontAttributes
aCandidateFontAttributes(drawinglayer::primitive2d::getFontAttributesFromVclFont(
371 pCandidate
->getFont(),
375 if(pCandidate
&& pCandidate
->getTextLength())
377 drawinglayer::primitive2d::TextLayouterDevice aTextLayouter
;
378 aTextLayouter
.setFont(pCandidate
->getFont());
379 xub_StrLen
nUsedTextLength(0);
381 while(nUsedTextLength
< pCandidate
->getTextLength() && fPolyStart
< fPolyEnd
)
383 xub_StrLen
nNextGlyphLen(getNextGlyphLen(pCandidate
, pCandidate
->getTextStart() + nUsedTextLength
, pCandidate
->getLocale()));
385 // prepare portion length. Takes RTL sections into account.
386 double fPortionLength(pCandidate
->getDisplayLength(nUsedTextLength
, nNextGlyphLen
));
388 if(XFT_AUTOSIZE
== mrSdrFormTextAttribute
.getFormTextAdjust())
390 // when scaling, expand portion length
391 fPortionLength
*= fScaleFactor
;
394 // create transformation
395 basegfx::B2DHomMatrix aNewTransformA
, aNewTransformB
, aNewShadowTransform
;
396 basegfx::B2DPoint
aStartPos(basegfx::tools::getPositionAbsolute(aPolygonCandidate
, fPolyStart
, fPolyLength
));
397 basegfx::B2DPoint
aEndPos(aStartPos
);
400 aNewTransformA
.scale(aSize
.getX(), aSize
.getY());
402 // prepare scaling of text primitive
403 if(XFT_AUTOSIZE
== mrSdrFormTextAttribute
.getFormTextAdjust())
405 // when scaling, expand text primitive scaling
406 aNewTransformA
.scale(fScaleFactor
, fScaleFactor
);
409 // eventually create shadow primitives from aDecomposition and add to rDecomposition
410 const bool bShadow(XFTSHADOW_NONE
!= mrSdrFormTextAttribute
.getFormTextShadow());
414 if(XFTSHADOW_NORMAL
== mrSdrFormTextAttribute
.getFormTextShadow())
416 aNewShadowTransform
.translate(
417 mrSdrFormTextAttribute
.getFormTextShdwXVal(),
418 -mrSdrFormTextAttribute
.getFormTextShdwYVal());
420 else // XFTSHADOW_SLANT
422 double fScaleValue(mrSdrFormTextAttribute
.getFormTextShdwYVal() / 100.0);
423 double fShearValue(-mrSdrFormTextAttribute
.getFormTextShdwXVal() * F_PI1800
);
425 aNewShadowTransform
.scale(1.0, fScaleValue
);
426 aNewShadowTransform
.shearX(sin(fShearValue
));
427 aNewShadowTransform
.scale(1.0, cos(fShearValue
));
431 switch(mrSdrFormTextAttribute
.getFormTextStyle())
435 aEndPos
= basegfx::tools::getPositionAbsolute(aPolygonCandidate
, fPolyStart
+ fPortionLength
, fPolyLength
);
436 const basegfx::B2DVector
aDirection(aEndPos
- aStartPos
);
437 aNewTransformB
.rotate(atan2(aDirection
.getY(), aDirection
.getX()));
438 aNewTransformB
.translate(aStartPos
.getX(), aStartPos
.getY());
444 aNewTransformB
.translate(aStartPos
.getX() - (fPortionLength
/ 2.0), aStartPos
.getY());
450 aEndPos
= basegfx::tools::getPositionAbsolute(aPolygonCandidate
, fPolyStart
+ fPortionLength
, fPolyLength
);
451 const basegfx::B2DVector
aDirection(aEndPos
- aStartPos
);
452 const double fShearValue(atan2(aDirection
.getY(), aDirection
.getX()));
453 const double fSin(sin(fShearValue
));
454 const double fCos(cos(fShearValue
));
456 aNewTransformB
.shearX(-fSin
);
458 // Scale may lead to objects without height since fCos == 0.0 is possible.
459 // Renderers need to handle that, it's not a forbidden value and does not
460 // need to be avoided
461 aNewTransformB
.scale(1.0, fCos
);
462 aNewTransformB
.translate(aStartPos
.getX() - (fPortionLength
/ 2.0), aStartPos
.getY());
468 aEndPos
= basegfx::tools::getPositionAbsolute(aPolygonCandidate
, fPolyStart
+ fPortionLength
, fPolyLength
);
469 const basegfx::B2DVector
aDirection(aEndPos
- aStartPos
);
470 const double fShearValue(atan2(aDirection
.getY(), aDirection
.getX()));
471 const double fCos(cos(fShearValue
));
472 const double fTan(tan(fShearValue
));
474 // shear to 'stand' on the curve
475 aNewTransformB
.shearY(fTan
);
477 // scale in X to make as tight as needed. As with XFT_SLANT_X, this may
478 // lead to primitives without width which the renderers will handle
479 aNewTransformA
.scale(fCos
, 1.0);
481 aNewTransformB
.translate(aStartPos
.getX(), aStartPos
.getY());
485 default : break; // XFT_NONE
488 // distance from path?
489 if(mrSdrFormTextAttribute
.getFormTextDistance())
491 if(aEndPos
.equal(aStartPos
))
493 aEndPos
= basegfx::tools::getPositionAbsolute(aPolygonCandidate
, fPolyStart
+ fPortionLength
, fPolyLength
);
496 // use back vector (aStartPos - aEndPos) here to get mirrored perpendicular as in old stuff
497 const basegfx::B2DVector
aPerpendicular(
498 basegfx::getNormalizedPerpendicular(aStartPos
- aEndPos
) *
499 mrSdrFormTextAttribute
.getFormTextDistance());
500 aNewTransformB
.translate(aPerpendicular
.getX(), aPerpendicular
.getY());
503 // shadow primitive creation
506 if(pCandidate
->getText().Len() && nNextGlyphLen
)
508 const Color
aShadowColor(mrSdrFormTextAttribute
.getFormTextShdwColor());
509 const basegfx::BColor
aRGBShadowColor(aShadowColor
.getBColor());
510 const xub_StrLen
nPortionIndex(pCandidate
->getPortionIndex(nUsedTextLength
, nNextGlyphLen
));
511 const ::std::vector
< double > aNewDXArray(
512 pCandidate
->getDoubleDXArray().begin() + nPortionIndex
,
513 pCandidate
->getDoubleDXArray().begin() + nPortionIndex
+ nNextGlyphLen
);
515 drawinglayer::primitive2d::TextSimplePortionPrimitive2D
* pNew
= new drawinglayer::primitive2d::TextSimplePortionPrimitive2D(
516 aNewTransformB
* aNewShadowTransform
* aNewTransformA
,
517 pCandidate
->getText(),
521 aCandidateFontAttributes
,
522 pCandidate
->getLocale(),
525 mrShadowDecomposition
.push_back(pNew
);
529 // primitive creation
530 if(pCandidate
->getText().Len() && nNextGlyphLen
)
532 const Color
aColor(pCandidate
->getFont().GetColor());
533 const basegfx::BColor
aRGBColor(aColor
.getBColor());
534 const xub_StrLen
nPortionIndex(pCandidate
->getPortionIndex(nUsedTextLength
, nNextGlyphLen
));
535 const ::std::vector
< double > aNewDXArray(
536 pCandidate
->getDoubleDXArray().begin() + nPortionIndex
,
537 pCandidate
->getDoubleDXArray().begin() + nPortionIndex
+ nNextGlyphLen
);
539 drawinglayer::primitive2d::TextSimplePortionPrimitive2D
* pNew
= new drawinglayer::primitive2d::TextSimplePortionPrimitive2D(
540 aNewTransformB
* aNewTransformA
,
541 pCandidate
->getText(),
545 aCandidateFontAttributes
,
546 pCandidate
->getLocale(),
549 mrDecomposition
.push_back(pNew
);
552 // consume from portion // no += here, xub_StrLen is USHORT and the compiler will gererate a warning here
553 nUsedTextLength
= nUsedTextLength
+ nNextGlyphLen
;
555 // consume from polygon
556 fPolyStart
+= fPortionLength
;
562 } // end of anonymous namespace
564 //////////////////////////////////////////////////////////////////////////////
565 // primitive decomposition helpers
569 void impAddPolygonStrokePrimitives(
570 const basegfx::B2DPolyPolygonVector
& rB2DPolyPolyVector
,
571 const basegfx::B2DHomMatrix
& rTransform
,
572 const drawinglayer::attribute::LineAttribute
& rLineAttribute
,
573 const drawinglayer::attribute::StrokeAttribute
& rStrokeAttribute
,
574 std::vector
< drawinglayer::primitive2d::BasePrimitive2D
* >& rTarget
)
576 for(basegfx::B2DPolyPolygonVector::const_iterator
aPolygon(rB2DPolyPolyVector
.begin()); aPolygon
!= rB2DPolyPolyVector
.end(); aPolygon
++)
578 // prepare PolyPolygons
579 basegfx::B2DPolyPolygon aB2DPolyPolygon
= *aPolygon
;
580 aB2DPolyPolygon
.transform(rTransform
);
582 for(sal_uInt32
a(0L); a
< aB2DPolyPolygon
.count(); a
++)
584 // create one primitive per polygon
585 drawinglayer::primitive2d::PolygonStrokePrimitive2D
* pNew
=
586 new drawinglayer::primitive2d::PolygonStrokePrimitive2D(
587 aB2DPolyPolygon
.getB2DPolygon(a
), rLineAttribute
, rStrokeAttribute
);
588 rTarget
.push_back(pNew
);
593 drawinglayer::primitive2d::Primitive2DSequence
impAddPathTextOutlines(
594 const std::vector
< drawinglayer::primitive2d::BasePrimitive2D
* >& rSource
,
595 const drawinglayer::attribute::SdrFormTextOutlineAttribute
& rOutlineAttribute
)
597 std::vector
< drawinglayer::primitive2d::BasePrimitive2D
* > aNewPrimitives
;
599 for(sal_uInt32
a(0L); a
< rSource
.size(); a
++)
601 const drawinglayer::primitive2d::TextSimplePortionPrimitive2D
* pTextCandidate
= dynamic_cast< const drawinglayer::primitive2d::TextSimplePortionPrimitive2D
* >(rSource
[a
]);
605 basegfx::B2DPolyPolygonVector aB2DPolyPolyVector
;
606 basegfx::B2DHomMatrix aPolygonTransform
;
608 // get text outlines and their object transformation
609 pTextCandidate
->getTextOutlinesAndTransformation(aB2DPolyPolyVector
, aPolygonTransform
);
611 if(aB2DPolyPolyVector
.size())
613 // create stroke primitives
614 std::vector
< drawinglayer::primitive2d::BasePrimitive2D
* > aStrokePrimitives
;
615 impAddPolygonStrokePrimitives(
618 rOutlineAttribute
.getLineAttribute(),
619 rOutlineAttribute
.getStrokeAttribute(),
621 const sal_uInt32
nStrokeCount(aStrokePrimitives
.size());
625 if(rOutlineAttribute
.getTransparence())
627 // create UnifiedAlphaPrimitive2D
628 drawinglayer::primitive2d::Primitive2DSequence
aStrokePrimitiveSequence(nStrokeCount
);
630 for(sal_uInt32
b(0L); b
< nStrokeCount
; b
++)
632 aStrokePrimitiveSequence
[b
] = drawinglayer::primitive2d::Primitive2DReference(aStrokePrimitives
[b
]);
635 drawinglayer::primitive2d::UnifiedAlphaPrimitive2D
* pNew2
=
636 new drawinglayer::primitive2d::UnifiedAlphaPrimitive2D(
637 aStrokePrimitiveSequence
,
638 (double)rOutlineAttribute
.getTransparence() / 100.0);
639 aNewPrimitives
.push_back(pNew2
);
643 // add polygons to rDecomposition as polygonStrokePrimitives
644 aNewPrimitives
.insert(aNewPrimitives
.end(), aStrokePrimitives
.begin(), aStrokePrimitives
.end());
651 const sal_uInt32
nNewCount(aNewPrimitives
.size());
655 drawinglayer::primitive2d::Primitive2DSequence
aRetval(nNewCount
);
657 for(sal_uInt32
a(0L); a
< nNewCount
; a
++)
659 aRetval
[a
] = drawinglayer::primitive2d::Primitive2DReference(aNewPrimitives
[a
]);
666 return drawinglayer::primitive2d::Primitive2DSequence();
669 } // end of anonymous namespace
671 //////////////////////////////////////////////////////////////////////////////
672 // primitive decomposition
674 bool SdrTextObj::impDecomposePathTextPrimitive(
675 drawinglayer::primitive2d::Primitive2DSequence
& rTarget
,
676 const drawinglayer::primitive2d::SdrPathTextPrimitive2D
& rSdrPathTextPrimitive
,
677 const drawinglayer::geometry::ViewInformation2D
& aViewInformation
) const
679 drawinglayer::primitive2d::Primitive2DSequence aRetvalA
;
680 drawinglayer::primitive2d::Primitive2DSequence aRetvalB
;
683 SdrOutliner
& rOutliner
= ImpGetDrawOutliner();
684 rOutliner
.SetUpdateMode(true);
686 rOutliner
.SetPaperSize(Size(LONG_MAX
,LONG_MAX
));
687 rOutliner
.SetText(rSdrPathTextPrimitive
.getOutlinerParaObject());
689 // set visualizing page at Outliner; needed e.g. for PageNumberField decomposition
690 rOutliner
.setVisualizedPage(GetSdrPageFromXDrawPage(aViewInformation
.getVisualizedPage()));
692 // now break up to text portions
693 impTextBreakupHandler
aConverter(rOutliner
);
694 const ::std::vector
< impPathTextPortion
> rPathTextPortions
= aConverter
.decompositionPathTextPrimitive();
696 if(rPathTextPortions
.size())
698 // get FormText and polygon values
699 const drawinglayer::attribute::SdrFormTextAttribute
& rFormTextAttribute
= rSdrPathTextPrimitive
.getSdrFormTextAttribute();
700 const basegfx::B2DPolyPolygon
& rPathPolyPolygon(rSdrPathTextPrimitive
.getPathPolyPolygon());
703 sal_uInt32
nLoopCount(rPathPolyPolygon
.count());
705 if(rOutliner
.GetParagraphCount() < nLoopCount
)
707 nLoopCount
= rOutliner
.GetParagraphCount();
712 // prepare common decomposition stuff
713 std::vector
< drawinglayer::primitive2d::BasePrimitive2D
* > aRegularDecomposition
;
714 std::vector
< drawinglayer::primitive2d::BasePrimitive2D
* > aShadowDecomposition
;
715 impPolygonParagraphHandler
aPolygonParagraphHandler(
716 rFormTextAttribute
, aRegularDecomposition
, aShadowDecomposition
);
719 for(a
= 0L; a
< nLoopCount
; a
++)
721 // filter text portions for this paragraph
722 ::std::vector
< const impPathTextPortion
* > aParagraphTextPortions
;
724 for(sal_uInt32
b(0L); b
< rPathTextPortions
.size(); b
++)
726 const impPathTextPortion
& rCandidate
= rPathTextPortions
[b
];
728 if(rCandidate
.getParagraph() == a
)
730 aParagraphTextPortions
.push_back(&rCandidate
);
734 // handle data pair polygon/ParagraphTextPortions
735 if(aParagraphTextPortions
.size())
737 aPolygonParagraphHandler
.HandlePair(rPathPolyPolygon
.getB2DPolygon(a
), aParagraphTextPortions
);
741 const sal_uInt32
nShadowCount(aShadowDecomposition
.size());
742 const sal_uInt32
nRegularCount(aRegularDecomposition
.size());
746 // add shadow primitives to decomposition
747 aRetvalA
.realloc(nShadowCount
);
749 for(a
= 0L; a
< nShadowCount
; a
++)
751 aRetvalA
[a
] = drawinglayer::primitive2d::Primitive2DReference(aShadowDecomposition
[a
]);
754 // evtl. add shadow outlines
755 if(rFormTextAttribute
.getFormTextOutline() && rFormTextAttribute
.getShadowOutline())
757 const drawinglayer::primitive2d::Primitive2DSequence
aOutlines(
758 impAddPathTextOutlines(aShadowDecomposition
, *rFormTextAttribute
.getShadowOutline()));
759 drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(aRetvalA
, aOutlines
);
765 // add normal primitives to decomposition
766 aRetvalB
.realloc(nRegularCount
);
768 for(a
= 0L; a
< nRegularCount
; a
++)
770 aRetvalB
[a
] = drawinglayer::primitive2d::Primitive2DReference(aRegularDecomposition
[a
]);
773 // evtl. add outlines
774 if(rFormTextAttribute
.getFormTextOutline() && rFormTextAttribute
.getOutline())
776 const drawinglayer::primitive2d::Primitive2DSequence
aOutlines(
777 impAddPathTextOutlines(aRegularDecomposition
, *rFormTextAttribute
.getOutline()));
778 drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(aRetvalB
, aOutlines
);
785 rOutliner
.SetDrawPortionHdl(Link());
787 rOutliner
.setVisualizedPage(0);
789 // concatenate all results
790 drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget
, aRetvalA
);
791 drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget
, aRetvalB
);
796 //////////////////////////////////////////////////////////////////////////////