Update ooo320-m1
[ooovba.git] / svx / source / svdraw / svdotextpathdecomposition.cxx
blob077ddce02ecb2b9fbf986054bc91a043d9dd0982
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: svdotextpathdecomposition.cxx,v $
11 * $Revision: 1.2 $
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>
44 #include <algorithm>
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>
71 #include <unoapi.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
84 namespace
86 class impPathTextPortion
88 basegfx::B2DVector maOffset;
89 String maText;
90 xub_StrLen mnTextStart;
91 xub_StrLen mnTextLength;
92 sal_uInt16 mnParagraph;
93 xub_StrLen mnIndex;
94 SvxFont maFont;
95 ::std::vector< double > maDblDXArray; // double DXArray, font size independent -> unit coordinate system
96 ::com::sun::star::lang::Locale maLocale;
98 // bitfield
99 unsigned mbRTL : 1;
101 public:
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),
110 maDblDXArray(),
111 maLocale(rInfo.mpLocale ? *rInfo.mpLocale : ::com::sun::star::lang::Locale()),
112 mbRTL(rInfo.mrFont.IsVertical() ? false : rInfo.IsRTL())
114 if(mnTextLength)
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);
127 // for ::std::sort
128 bool operator<(const impPathTextPortion& rComp) const
130 if(mnParagraph < rComp.mnParagraph)
132 return true;
135 if(maOffset.getX() < rComp.maOffset.getX())
137 return true;
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
156 if(mbRTL)
158 return (mnTextStart + (mnTextLength - (nIndex + nLength)));
160 else
162 return (mnTextStart + nIndex);
166 double getDisplayLength(xub_StrLen nIndex, xub_StrLen nLength) const
168 drawinglayer::primitive2d::TextLayouterDevice aTextLayouter;
169 double fRetval(0.0);
171 if(maFont.IsVertical())
173 fRetval = aTextLayouter.getTextHeight() * (double)nLength;
175 else
177 fRetval = aTextLayouter.getTextWidth(maText, getPortionIndex(nIndex, nLength), nLength);
180 return fRetval;
183 } // end of anonymous namespace
185 //////////////////////////////////////////////////////////////////////////////
186 // TextBreakup helper
188 namespace
190 class impTextBreakupHandler
192 SdrOutliner& mrOutliner;
193 ::std::vector< impPathTextPortion > maPathTextPortions;
195 DECL_LINK(decompositionPathTextPrimitive, DrawPortionInfo* );
197 public:
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));
222 return 0;
224 } // end of anonymous namespace
226 //////////////////////////////////////////////////////////////////////////////
227 // TextBreakup one poly and one paragraph helper
229 namespace
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;
241 double fRetval(0.0);
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());
254 return fRetval;
257 xub_StrLen getNextGlyphLen(const impPathTextPortion* pCandidate, xub_StrLen nPosition, const ::com::sun::star::lang::Locale& rFontLocale)
259 xub_StrLen nNextGlyphLen(1);
261 if(mxBreak.is())
263 sal_Int32 nDone(0L);
264 nNextGlyphLen = (xub_StrLen)mxBreak->nextCharacters(pCandidate->getText(), nPosition,
265 rFontLocale, CharacterIteratorMode::SKIPCELL, 1, nDone) - nPosition;
268 return nNextGlyphLen;
271 public:
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"));
284 if(xInterface.is())
286 Any x = xInterface->queryInterface(::getCppuType((const Reference< XBreakIterator >*)0));
287 x >>= mxBreak;
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;
318 else
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())
340 if(!bTextTooLong)
342 // if right aligned, add difference to polygon start
343 fPolyStart += ((fPolyEnd - fPolyStart) - fParagraphTextLength);
346 else if(XFT_CENTER == mrSdrFormTextAttribute.getFormTextAdjust())
348 if(!bTextTooLong)
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(
371 aFontScaling,
372 pCandidate->getFont(),
373 pCandidate->isRTL(),
374 false));
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);
400 // add font scaling
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());
413 if(bShadow)
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())
434 case XFT_ROTATE :
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());
441 break;
443 case XFT_UPRIGHT :
445 aNewTransformB.translate(aStartPos.getX() - (fPortionLength / 2.0), aStartPos.getY());
447 break;
449 case XFT_SLANTX :
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());
465 break;
467 case XFT_SLANTY :
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());
484 break;
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
505 if(bShadow)
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(),
520 nPortionIndex,
521 nNextGlyphLen,
522 aNewDXArray,
523 aCandidateFontAttributes,
524 pCandidate->getLocale(),
525 aRGBShadowColor);
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(),
545 nPortionIndex,
546 nNextGlyphLen,
547 aNewDXArray,
548 aCandidateFontAttributes,
549 pCandidate->getLocale(),
550 aRGBColor);
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
570 namespace
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]);
606 if(pTextCandidate)
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(
619 aB2DPolyPolyVector,
620 aPolygonTransform,
621 rOutlineAttribute.getLineAttribute(),
622 rOutlineAttribute.getStrokeAttribute(),
623 aStrokePrimitives);
624 const sal_uInt32 nStrokeCount(aStrokePrimitives.size());
626 if(nStrokeCount)
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);
644 else
646 // add polygons to rDecomposition as polygonStrokePrimitives
647 aNewPrimitives.insert(aNewPrimitives.end(), aStrokePrimitives.begin(), aStrokePrimitives.end());
654 const sal_uInt32 nNewCount(aNewPrimitives.size());
656 if(nNewCount)
658 drawinglayer::primitive2d::Primitive2DSequence aRetval(nNewCount);
660 for(sal_uInt32 a(0L); a < nNewCount; a++)
662 aRetval[a] = drawinglayer::primitive2d::Primitive2DReference(aNewPrimitives[a]);
665 return aRetval;
667 else
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;
685 // prepare outliner
686 SdrOutliner& rOutliner = ImpGetDrawOutliner();
687 rOutliner.SetUpdateMode(true);
688 rOutliner.Clear();
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());
705 // get loop count
706 sal_uInt32 nLoopCount(rPathPolyPolygon.count());
708 if(rOutliner.GetParagraphCount() < nLoopCount)
710 nLoopCount = rOutliner.GetParagraphCount();
713 if(nLoopCount)
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);
720 sal_uInt32 a;
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());
747 if(nShadowCount)
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);
766 if(nRegularCount)
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);
787 // cleanup outliner
788 rOutliner.SetDrawPortionHdl(Link());
789 rOutliner.Clear();
790 rOutliner.setVisualizedPage(0);
792 // concatenate all results
793 drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget, aRetvalA);
794 drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget, aRetvalB);
797 //////////////////////////////////////////////////////////////////////////////
798 // eof