update dev300-m58
[ooovba.git] / svx / source / svdraw / svdotextpathdecomposition.cxx
blobaf6413bb8d536ad963cef8f3872ff6da65021122
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 aSize;
369 const drawinglayer::primitive2d::FontAttributes aCandidateFontAttributes(drawinglayer::primitive2d::getFontAttributesFromVclFont(
370 aSize,
371 pCandidate->getFont(),
372 pCandidate->isRTL(),
373 false));
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);
399 // add font scaling
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());
412 if(bShadow)
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())
433 case XFT_ROTATE :
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());
440 break;
442 case XFT_UPRIGHT :
444 aNewTransformB.translate(aStartPos.getX() - (fPortionLength / 2.0), aStartPos.getY());
446 break;
448 case XFT_SLANTX :
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());
464 break;
466 case XFT_SLANTY :
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());
483 break;
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
504 if(bShadow)
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(),
518 nPortionIndex,
519 nNextGlyphLen,
520 aNewDXArray,
521 aCandidateFontAttributes,
522 pCandidate->getLocale(),
523 aRGBShadowColor);
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(),
542 nPortionIndex,
543 nNextGlyphLen,
544 aNewDXArray,
545 aCandidateFontAttributes,
546 pCandidate->getLocale(),
547 aRGBColor);
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
567 namespace
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]);
603 if(pTextCandidate)
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(
616 aB2DPolyPolyVector,
617 aPolygonTransform,
618 rOutlineAttribute.getLineAttribute(),
619 rOutlineAttribute.getStrokeAttribute(),
620 aStrokePrimitives);
621 const sal_uInt32 nStrokeCount(aStrokePrimitives.size());
623 if(nStrokeCount)
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);
641 else
643 // add polygons to rDecomposition as polygonStrokePrimitives
644 aNewPrimitives.insert(aNewPrimitives.end(), aStrokePrimitives.begin(), aStrokePrimitives.end());
651 const sal_uInt32 nNewCount(aNewPrimitives.size());
653 if(nNewCount)
655 drawinglayer::primitive2d::Primitive2DSequence aRetval(nNewCount);
657 for(sal_uInt32 a(0L); a < nNewCount; a++)
659 aRetval[a] = drawinglayer::primitive2d::Primitive2DReference(aNewPrimitives[a]);
662 return aRetval;
664 else
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;
682 // prepare outliner
683 SdrOutliner& rOutliner = ImpGetDrawOutliner();
684 rOutliner.SetUpdateMode(true);
685 rOutliner.Clear();
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());
702 // get loop count
703 sal_uInt32 nLoopCount(rPathPolyPolygon.count());
705 if(rOutliner.GetParagraphCount() < nLoopCount)
707 nLoopCount = rOutliner.GetParagraphCount();
710 if(nLoopCount)
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);
717 sal_uInt32 a;
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());
744 if(nShadowCount)
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);
763 if(nRegularCount)
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);
784 // cleanup outliner
785 rOutliner.SetDrawPortionHdl(Link());
786 rOutliner.Clear();
787 rOutliner.setVisualizedPage(0);
789 // concatenate all results
790 drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget, aRetvalA);
791 drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget, aRetvalB);
793 return false;
796 //////////////////////////////////////////////////////////////////////////////
797 // eof