bump product version to 4.1.6.2
[LibreOffice.git] / svx / source / svdraw / svdotextpathdecomposition.cxx
blob097b4763917710afc2de0391b241a9616ff6b602
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <svx/svdotext.hxx>
22 #include <svx/svdoutl.hxx>
23 #include <basegfx/vector/b2dvector.hxx>
24 #include <svx/sdr/primitive2d/sdrtextprimitive2d.hxx>
25 #include <basegfx/range/b2drange.hxx>
26 #include <svl/itemset.hxx>
27 #include <basegfx/polygon/b2dpolygontools.hxx>
28 #include <basegfx/polygon/b2dpolygon.hxx>
29 #include <algorithm>
30 #include <svx/xtextit.hxx>
31 #include <svx/xftshtit.hxx>
32 #include <vcl/virdev.hxx>
33 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
34 #include <com/sun/star/i18n/ScriptType.hpp>
35 #include <com/sun/star/i18n/BreakIterator.hpp>
36 #include <comphelper/processfactory.hxx>
37 #include <com/sun/star/i18n/CharacterIteratorMode.hpp>
38 #include <editeng/unolingu.hxx>
39 #include <drawinglayer/primitive2d/textlayoutdevice.hxx>
40 #include <drawinglayer/primitive2d/textprimitive2d.hxx>
41 #include <basegfx/color/bcolor.hxx>
43 //////////////////////////////////////////////////////////////////////////////
44 // primitive decomposition helpers
46 #include <basegfx/polygon/b2dlinegeometry.hxx>
47 #include <drawinglayer/attribute/strokeattribute.hxx>
48 #include <svx/xlnclit.hxx>
49 #include <svx/xlntrit.hxx>
50 #include <svx/xlnwtit.hxx>
51 #include <svx/xlinjoit.hxx>
52 #include <svx/xlndsit.hxx>
53 #include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
54 #include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx>
55 #include <editeng/editstat.hxx>
56 #include <svx/unoapi.hxx>
57 #include <drawinglayer/geometry/viewinformation2d.hxx>
58 #include <svx/sdr/attribute/sdrformtextoutlineattribute.hxx>
60 //////////////////////////////////////////////////////////////////////////////
62 using namespace ::com::sun::star::uno;
63 using namespace ::com::sun::star::lang;
64 using namespace ::com::sun::star::i18n;
66 //////////////////////////////////////////////////////////////////////////////
67 // PathTextPortion helper
69 namespace
71 class impPathTextPortion
73 basegfx::B2DVector maOffset;
74 String maText;
75 xub_StrLen mnTextStart;
76 xub_StrLen mnTextLength;
77 sal_Int32 mnParagraph;
78 xub_StrLen mnIndex;
79 SvxFont maFont;
80 ::std::vector< double > maDblDXArray; // double DXArray, font size independent -> unit coordinate system
81 ::com::sun::star::lang::Locale maLocale;
83 // bitfield
84 unsigned mbRTL : 1;
86 public:
87 impPathTextPortion(DrawPortionInfo& rInfo)
88 : maOffset(rInfo.mrStartPos.X(), rInfo.mrStartPos.Y()),
89 maText(rInfo.mrText),
90 mnTextStart(rInfo.mnTextStart),
91 mnTextLength(rInfo.mnTextLen),
92 mnParagraph(rInfo.mnPara),
93 mnIndex(rInfo.mnIndex),
94 maFont(rInfo.mrFont),
95 maDblDXArray(),
96 maLocale(rInfo.mpLocale ? *rInfo.mpLocale : ::com::sun::star::lang::Locale()),
97 mbRTL(rInfo.mrFont.IsVertical() ? false : rInfo.IsRTL())
99 if(mnTextLength && rInfo.mpDXArray)
101 maDblDXArray.reserve(mnTextLength);
103 for(xub_StrLen a(0); a < mnTextLength; a++)
105 maDblDXArray.push_back((double)rInfo.mpDXArray[a]);
110 // for ::std::sort
111 bool operator<(const impPathTextPortion& rComp) const
113 if(mnParagraph < rComp.mnParagraph)
115 return true;
118 if(maOffset.getX() < rComp.maOffset.getX())
120 return true;
123 return (maOffset.getY() < rComp.maOffset.getY());
126 const basegfx::B2DVector& getOffset() const { return maOffset; }
127 const String& getText() const { return maText; }
128 xub_StrLen getTextStart() const { return mnTextStart; }
129 xub_StrLen getTextLength() const { return mnTextLength; }
130 sal_Int32 getParagraph() const { return mnParagraph; }
131 xub_StrLen getIndex() const { return mnIndex; }
132 const SvxFont& getFont() const { return maFont; }
133 bool isRTL() const { return mbRTL; }
134 const ::std::vector< double >& getDoubleDXArray() const { return maDblDXArray; }
135 const ::com::sun::star::lang::Locale& getLocale() const { return maLocale; }
137 xub_StrLen getPortionIndex(xub_StrLen nIndex, xub_StrLen nLength) const
139 if(mbRTL)
141 return (mnTextStart + (mnTextLength - (nIndex + nLength)));
143 else
145 return (mnTextStart + nIndex);
149 double getDisplayLength(xub_StrLen nIndex, xub_StrLen nLength) const
151 drawinglayer::primitive2d::TextLayouterDevice aTextLayouter;
152 double fRetval(0.0);
154 if(maFont.IsVertical())
156 fRetval = aTextLayouter.getTextHeight() * (double)nLength;
158 else
160 fRetval = aTextLayouter.getTextWidth(maText, getPortionIndex(nIndex, nLength), nLength);
163 return fRetval;
166 } // end of anonymous namespace
168 //////////////////////////////////////////////////////////////////////////////
169 // TextBreakup helper
171 namespace
173 class impTextBreakupHandler
175 SdrOutliner& mrOutliner;
176 ::std::vector< impPathTextPortion > maPathTextPortions;
178 DECL_LINK(decompositionPathTextPrimitive, DrawPortionInfo* );
180 public:
181 impTextBreakupHandler(SdrOutliner& rOutliner)
182 : mrOutliner(rOutliner)
186 const ::std::vector< impPathTextPortion >& decompositionPathTextPrimitive()
188 // strip portions to maPathTextPortions
189 mrOutliner.SetDrawPortionHdl(LINK(this, impTextBreakupHandler, decompositionPathTextPrimitive));
190 mrOutliner.StripPortions();
192 if(!maPathTextPortions.empty())
194 // sort portions by paragraph, x and y
195 ::std::sort(maPathTextPortions.begin(), maPathTextPortions.end());
198 return maPathTextPortions;
202 IMPL_LINK(impTextBreakupHandler, decompositionPathTextPrimitive, DrawPortionInfo*, pInfo)
204 maPathTextPortions.push_back(impPathTextPortion(*pInfo));
205 return 0;
207 } // end of anonymous namespace
209 //////////////////////////////////////////////////////////////////////////////
210 // TextBreakup one poly and one paragraph helper
212 namespace
214 class impPolygonParagraphHandler
216 const drawinglayer::attribute::SdrFormTextAttribute maSdrFormTextAttribute; // FormText parameters
217 std::vector< drawinglayer::primitive2d::BasePrimitive2D* >& mrDecomposition; // destination primitive list
218 std::vector< drawinglayer::primitive2d::BasePrimitive2D* >& mrShadowDecomposition; // destination primitive list for shadow
219 Reference < com::sun::star::i18n::XBreakIterator > mxBreak; // break iterator
221 double getParagraphTextLength(const ::std::vector< const impPathTextPortion* >& rTextPortions)
223 drawinglayer::primitive2d::TextLayouterDevice aTextLayouter;
224 double fRetval(0.0);
226 for(sal_uInt32 a(0L); a < rTextPortions.size(); a++)
228 const impPathTextPortion* pCandidate = rTextPortions[a];
230 if(pCandidate && pCandidate->getTextLength())
232 aTextLayouter.setFont(pCandidate->getFont());
233 fRetval += pCandidate->getDisplayLength(0L, pCandidate->getTextLength());
237 return fRetval;
240 xub_StrLen getNextGlyphLen(const impPathTextPortion* pCandidate, xub_StrLen nPosition, const ::com::sun::star::lang::Locale& rFontLocale)
242 xub_StrLen nNextGlyphLen(1);
244 if(mxBreak.is())
246 sal_Int32 nDone(0L);
247 nNextGlyphLen = (xub_StrLen)mxBreak->nextCharacters(pCandidate->getText(), nPosition,
248 rFontLocale, CharacterIteratorMode::SKIPCELL, 1, nDone) - nPosition;
251 return nNextGlyphLen;
254 public:
255 impPolygonParagraphHandler(
256 const drawinglayer::attribute::SdrFormTextAttribute& rSdrFormTextAttribute,
257 std::vector< drawinglayer::primitive2d::BasePrimitive2D* >& rDecomposition,
258 std::vector< drawinglayer::primitive2d::BasePrimitive2D* >& rShadowDecomposition)
259 : maSdrFormTextAttribute(rSdrFormTextAttribute),
260 mrDecomposition(rDecomposition),
261 mrShadowDecomposition(rShadowDecomposition)
263 // prepare BreakIterator
264 Reference < XComponentContext > xContext = ::comphelper::getProcessComponentContext();
265 mxBreak = com::sun::star::i18n::BreakIterator::create(xContext);
268 void HandlePair(const basegfx::B2DPolygon rPolygonCandidate, const ::std::vector< const impPathTextPortion* >& rTextPortions)
270 // prepare polygon geometry, take into account as many parameters as possible
271 basegfx::B2DPolygon aPolygonCandidate(rPolygonCandidate);
272 const double fPolyLength(basegfx::tools::getLength(aPolygonCandidate));
273 double fPolyEnd(fPolyLength);
274 double fPolyStart(0.0);
275 double fAutosizeScaleFactor(1.0);
276 bool bAutosizeScale(false);
278 if(maSdrFormTextAttribute.getFormTextMirror())
280 aPolygonCandidate.flip();
283 if(maSdrFormTextAttribute.getFormTextStart()
284 && (XFT_LEFT == maSdrFormTextAttribute.getFormTextAdjust()
285 || XFT_RIGHT == maSdrFormTextAttribute.getFormTextAdjust()))
287 if(XFT_LEFT == maSdrFormTextAttribute.getFormTextAdjust())
289 fPolyStart += maSdrFormTextAttribute.getFormTextStart();
291 if(fPolyStart > fPolyEnd)
293 fPolyStart = fPolyEnd;
296 else
298 fPolyEnd -= maSdrFormTextAttribute.getFormTextStart();
300 if(fPolyEnd < fPolyStart)
302 fPolyEnd = fPolyStart;
307 if(XFT_LEFT != maSdrFormTextAttribute.getFormTextAdjust())
309 // calculate total text length of this paragraph, some layout needs to be done
310 const double fParagraphTextLength(getParagraphTextLength(rTextPortions));
312 // check if text is too long for paragraph. If yes, handle as if left aligned (default),
313 // but still take care of XFT_AUTOSIZE in that case
314 const bool bTextTooLong(fParagraphTextLength > (fPolyEnd - fPolyStart));
316 if(XFT_RIGHT == maSdrFormTextAttribute.getFormTextAdjust())
318 if(!bTextTooLong)
320 // if right aligned, add difference to polygon start
321 fPolyStart += ((fPolyEnd - fPolyStart) - fParagraphTextLength);
324 else if(XFT_CENTER == maSdrFormTextAttribute.getFormTextAdjust())
326 if(!bTextTooLong)
328 // if centered, add half of difference to polygon start
329 fPolyStart += ((fPolyEnd - fPolyStart) - fParagraphTextLength) / 2.0;
332 else if(XFT_AUTOSIZE == maSdrFormTextAttribute.getFormTextAdjust())
334 // if scale, prepare scale factor between curve length and text length
335 if(0.0 != fParagraphTextLength)
337 fAutosizeScaleFactor = (fPolyEnd - fPolyStart) / fParagraphTextLength;
338 bAutosizeScale = true;
343 // handle text portions for this paragraph
344 for(sal_uInt32 a(0L); a < rTextPortions.size() && fPolyStart < fPolyEnd; a++)
346 const impPathTextPortion* pCandidate = rTextPortions[a];
347 basegfx::B2DVector aFontScaling;
349 if(pCandidate && pCandidate->getTextLength())
351 const drawinglayer::attribute::FontAttribute aCandidateFontAttribute(
352 drawinglayer::primitive2d::getFontAttributeFromVclFont(
353 aFontScaling,
354 pCandidate->getFont(),
355 pCandidate->isRTL(),
356 false));
358 drawinglayer::primitive2d::TextLayouterDevice aTextLayouter;
359 aTextLayouter.setFont(pCandidate->getFont());
360 xub_StrLen nUsedTextLength(0);
362 while(nUsedTextLength < pCandidate->getTextLength() && fPolyStart < fPolyEnd)
364 xub_StrLen nNextGlyphLen(getNextGlyphLen(pCandidate, pCandidate->getTextStart() + nUsedTextLength, pCandidate->getLocale()));
366 // prepare portion length. Takes RTL sections into account.
367 double fPortionLength(pCandidate->getDisplayLength(nUsedTextLength, nNextGlyphLen));
369 if(bAutosizeScale)
371 // when autosize scaling, expand portion length
372 fPortionLength *= fAutosizeScaleFactor;
375 // create transformation
376 basegfx::B2DHomMatrix aNewTransformA, aNewTransformB, aNewShadowTransform;
377 basegfx::B2DPoint aStartPos(basegfx::tools::getPositionAbsolute(aPolygonCandidate, fPolyStart, fPolyLength));
378 basegfx::B2DPoint aEndPos(aStartPos);
380 // add font scaling
381 aNewTransformA.scale(aFontScaling.getX(), aFontScaling.getY());
383 // prepare scaling of text primitive
384 if(bAutosizeScale)
386 // when autosize scaling, expand text primitive scaling to it
387 aNewTransformA.scale(fAutosizeScaleFactor, fAutosizeScaleFactor);
390 // eventually create shadow primitives from aDecomposition and add to rDecomposition
391 const bool bShadow(XFTSHADOW_NONE != maSdrFormTextAttribute.getFormTextShadow());
393 if(bShadow)
395 if(XFTSHADOW_NORMAL == maSdrFormTextAttribute.getFormTextShadow())
397 aNewShadowTransform.translate(
398 maSdrFormTextAttribute.getFormTextShdwXVal(),
399 -maSdrFormTextAttribute.getFormTextShdwYVal());
401 else // XFTSHADOW_SLANT
403 double fScaleValue(maSdrFormTextAttribute.getFormTextShdwYVal() / 100.0);
404 double fShearValue(-maSdrFormTextAttribute.getFormTextShdwXVal() * F_PI1800);
406 aNewShadowTransform.scale(1.0, fScaleValue);
407 aNewShadowTransform.shearX(sin(fShearValue));
408 aNewShadowTransform.scale(1.0, cos(fShearValue));
412 switch(maSdrFormTextAttribute.getFormTextStyle())
414 case XFT_ROTATE :
416 aEndPos = basegfx::tools::getPositionAbsolute(aPolygonCandidate, fPolyStart + fPortionLength, fPolyLength);
417 const basegfx::B2DVector aDirection(aEndPos - aStartPos);
418 aNewTransformB.rotate(atan2(aDirection.getY(), aDirection.getX()));
419 aNewTransformB.translate(aStartPos.getX(), aStartPos.getY());
421 break;
423 case XFT_UPRIGHT :
425 aNewTransformB.translate(aStartPos.getX() - (fPortionLength / 2.0), aStartPos.getY());
427 break;
429 case XFT_SLANTX :
431 aEndPos = basegfx::tools::getPositionAbsolute(aPolygonCandidate, fPolyStart + fPortionLength, fPolyLength);
432 const basegfx::B2DVector aDirection(aEndPos - aStartPos);
433 const double fShearValue(atan2(aDirection.getY(), aDirection.getX()));
434 const double fSin(sin(fShearValue));
435 const double fCos(cos(fShearValue));
437 aNewTransformB.shearX(-fSin);
439 // Scale may lead to objects without height since fCos == 0.0 is possible.
440 // Renderers need to handle that, it's not a forbidden value and does not
441 // need to be avoided
442 aNewTransformB.scale(1.0, fCos);
443 aNewTransformB.translate(aStartPos.getX() - (fPortionLength / 2.0), aStartPos.getY());
445 break;
447 case XFT_SLANTY :
449 aEndPos = basegfx::tools::getPositionAbsolute(aPolygonCandidate, fPolyStart + fPortionLength, fPolyLength);
450 const basegfx::B2DVector aDirection(aEndPos - aStartPos);
451 const double fShearValue(atan2(aDirection.getY(), aDirection.getX()));
452 const double fCos(cos(fShearValue));
453 const double fTan(tan(fShearValue));
455 // shear to 'stand' on the curve
456 aNewTransformB.shearY(fTan);
458 // scale in X to make as tight as needed. As with XFT_SLANT_X, this may
459 // lead to primitives without width which the renderers will handle
460 aNewTransformA.scale(fCos, 1.0);
462 aNewTransformB.translate(aStartPos.getX(), aStartPos.getY());
464 break;
466 default : break; // XFT_NONE
469 // distance from path?
470 if(maSdrFormTextAttribute.getFormTextDistance())
472 if(aEndPos.equal(aStartPos))
474 aEndPos = basegfx::tools::getPositionAbsolute(aPolygonCandidate, fPolyStart + fPortionLength, fPolyLength);
477 // use back vector (aStartPos - aEndPos) here to get mirrored perpendicular as in old stuff
478 const basegfx::B2DVector aPerpendicular(
479 basegfx::getNormalizedPerpendicular(aStartPos - aEndPos) *
480 maSdrFormTextAttribute.getFormTextDistance());
481 aNewTransformB.translate(aPerpendicular.getX(), aPerpendicular.getY());
484 if(pCandidate->getText().Len() && nNextGlyphLen)
486 const xub_StrLen nPortionIndex(pCandidate->getPortionIndex(nUsedTextLength, nNextGlyphLen));
487 ::std::vector< double > aNewDXArray;
489 if(nNextGlyphLen > 1 && pCandidate->getDoubleDXArray().size())
491 // copy DXArray for portion
492 aNewDXArray.insert(
493 aNewDXArray.begin(),
494 pCandidate->getDoubleDXArray().begin() + nPortionIndex,
495 pCandidate->getDoubleDXArray().begin() + (nPortionIndex + nNextGlyphLen));
497 if(nPortionIndex > 0)
499 // adapt to portion start
500 double fDXOffset= *(pCandidate->getDoubleDXArray().begin() + (nPortionIndex - 1));
501 ::std::transform(
502 aNewDXArray.begin(), aNewDXArray.end(),
503 aNewDXArray.begin(), ::std::bind2nd(::std::minus<double>(), fDXOffset));
506 if(bAutosizeScale)
508 // when autosize scaling, adapt to DXArray, too
509 ::std::transform(
510 aNewDXArray.begin(), aNewDXArray.end(),
511 aNewDXArray.begin(), ::std::bind2nd(::std::multiplies<double>(), fAutosizeScaleFactor));
515 if(bShadow)
517 // shadow primitive creation
518 const Color aShadowColor(maSdrFormTextAttribute.getFormTextShdwColor());
519 const basegfx::BColor aRGBShadowColor(aShadowColor.getBColor());
521 drawinglayer::primitive2d::TextSimplePortionPrimitive2D* pNew =
522 new drawinglayer::primitive2d::TextSimplePortionPrimitive2D(
523 aNewTransformB * aNewShadowTransform * aNewTransformA,
524 pCandidate->getText(),
525 nPortionIndex,
526 nNextGlyphLen,
527 aNewDXArray,
528 aCandidateFontAttribute,
529 pCandidate->getLocale(),
530 aRGBShadowColor);
532 mrShadowDecomposition.push_back(pNew);
536 // primitive creation
537 const Color aColor(pCandidate->getFont().GetColor());
538 const basegfx::BColor aRGBColor(aColor.getBColor());
540 drawinglayer::primitive2d::TextSimplePortionPrimitive2D* pNew =
541 new drawinglayer::primitive2d::TextSimplePortionPrimitive2D(
542 aNewTransformB * aNewTransformA,
543 pCandidate->getText(),
544 nPortionIndex,
545 nNextGlyphLen,
546 aNewDXArray,
547 aCandidateFontAttribute,
548 pCandidate->getLocale(),
549 aRGBColor);
551 mrDecomposition.push_back(pNew);
555 // consume from portion // no += here, xub_StrLen is sal_uInt16 and the compiler will generate 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.empty())
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 UnifiedTransparencePrimitive2D
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::UnifiedTransparencePrimitive2D* pNew2 =
639 new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D(
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.empty())
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(static_cast<sal_uInt32>(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,
720 aRegularDecomposition,
721 aShadowDecomposition);
722 sal_uInt32 a;
724 for(a = 0L; a < nLoopCount; a++)
726 // filter text portions for this paragraph
727 ::std::vector< const impPathTextPortion* > aParagraphTextPortions;
729 for(sal_uInt32 b(0L); b < rPathTextPortions.size(); b++)
731 const impPathTextPortion& rCandidate = rPathTextPortions[b];
733 if(static_cast<sal_uInt32>(rCandidate.getParagraph()) == a)
735 aParagraphTextPortions.push_back(&rCandidate);
739 // handle data pair polygon/ParagraphTextPortions
740 if(!aParagraphTextPortions.empty())
742 aPolygonParagraphHandler.HandlePair(rPathPolyPolygon.getB2DPolygon(a), aParagraphTextPortions);
746 const sal_uInt32 nShadowCount(aShadowDecomposition.size());
747 const sal_uInt32 nRegularCount(aRegularDecomposition.size());
749 if(nShadowCount)
751 // add shadow primitives to decomposition
752 aRetvalA.realloc(nShadowCount);
754 for(a = 0L; a < nShadowCount; a++)
756 aRetvalA[a] = drawinglayer::primitive2d::Primitive2DReference(aShadowDecomposition[a]);
759 // if necessary, add shadow outlines
760 if(rFormTextAttribute.getFormTextOutline()
761 && !rFormTextAttribute.getShadowOutline().isDefault())
763 const drawinglayer::primitive2d::Primitive2DSequence aOutlines(
764 impAddPathTextOutlines(
765 aShadowDecomposition,
766 rFormTextAttribute.getShadowOutline()));
768 drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(aRetvalA, aOutlines);
772 if(nRegularCount)
774 // add normal primitives to decomposition
775 aRetvalB.realloc(nRegularCount);
777 for(a = 0L; a < nRegularCount; a++)
779 aRetvalB[a] = drawinglayer::primitive2d::Primitive2DReference(aRegularDecomposition[a]);
782 // if necessary, add outlines
783 if(rFormTextAttribute.getFormTextOutline()
784 && !rFormTextAttribute.getOutline().isDefault())
786 const drawinglayer::primitive2d::Primitive2DSequence aOutlines(
787 impAddPathTextOutlines(
788 aRegularDecomposition,
789 rFormTextAttribute.getOutline()));
791 drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(aRetvalB, aOutlines);
797 // clean up outliner
798 rOutliner.SetDrawPortionHdl(Link());
799 rOutliner.Clear();
800 rOutliner.setVisualizedPage(0);
802 // concatenate all results
803 drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget, aRetvalA);
804 drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget, aRetvalB);
808 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */