1 /*************************************************************************
3 * OpenOffice.org - a multi-platform office productivity suite
5 * $RCSfile: textdecoratedprimitive2d.cxx,v $
9 * last change: $Author: aw $ $Date: 2008-05-27 14:11:20 $
11 * The Contents of this file are made available subject to
12 * the terms of GNU Lesser General Public License Version 2.1.
15 * GNU Lesser General Public License Version 2.1
16 * =============================================
17 * Copyright 2005 by Sun Microsystems, Inc.
18 * 901 San Antonio Road, Palo Alto, CA 94303, USA
20 * This library is free software; you can redistribute it and/or
21 * modify it under the terms of the GNU Lesser General Public
22 * License version 2.1, as published by the Free Software Foundation.
24 * This library is distributed in the hope that it will be useful,
25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
27 * Lesser General Public License for more details.
29 * You should have received a copy of the GNU Lesser General Public
30 * License along with this library; if not, write to the Free Software
31 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
34 ************************************************************************/
36 // MARKER(update_precomp.py): autogen include statement, do not remove
37 #include "precompiled_drawinglayer.hxx"
39 #include <drawinglayer/primitive2d/textdecoratedprimitive2d.hxx>
40 #include <drawinglayer/primitive2d/textlayoutdevice.hxx>
41 #include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
42 #include <drawinglayer/attribute/strokeattribute.hxx>
43 #include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
44 #include <basegfx/matrix/b2dhommatrixtools.hxx>
45 #include <comphelper/processfactory.hxx>
46 #include <com/sun/star/i18n/WordType.hpp>
47 #include <drawinglayer/primitive2d/texteffectprimitive2d.hxx>
48 #include <drawinglayer/primitive2d/shadowprimitive2d.hxx>
49 #include <com/sun/star/i18n/XBreakIterator.hpp>
50 #include <drawinglayer/primitive2d/transformprimitive2d.hxx>
52 //////////////////////////////////////////////////////////////////////////////
54 namespace drawinglayer
58 void TextDecoratedPortionPrimitive2D::impCreateTextLine(
59 std::vector
< Primitive2DReference
>& rTarget
,
60 basegfx::DecomposedB2DHomMatrixContainer
& rDecTrans
,
61 const basegfx::B2DHomMatrix
&rUnscaledTransform
,
62 FontUnderline eLineStyle
,
66 const basegfx::BColor
& rLineColor
) const
68 bool bDoubleLine(false);
69 bool bWaveLine(false);
70 bool bBoldLine(false);
71 const int* pDotDashArray(0);
72 basegfx::B2DLineJoin
eLineJoin(basegfx::B2DLINEJOIN_NONE
);
74 static const int aDottedArray
[] = { 1, 1, 0}; // DOTTED LINE
75 static const int aDotDashArray
[] = { 1, 1, 4, 1, 0}; // DASHDOT
76 static const int aDashDotDotArray
[] = { 1, 1, 1, 1, 4, 1, 0}; // DASHDOTDOT
77 static const int aDashedArray
[] = { 5, 2, 0}; // DASHED LINE
78 static const int aLongDashArray
[] = { 7, 2, 0}; // LONGDASH
82 default: // case FONT_UNDERLINE_SINGLE:
86 case FONT_UNDERLINE_DOUBLE
:
91 case FONT_UNDERLINE_DOTTED
:
93 pDotDashArray
= aDottedArray
;
96 case FONT_UNDERLINE_DASH
:
98 pDotDashArray
= aDashedArray
;
101 case FONT_UNDERLINE_LONGDASH
:
103 pDotDashArray
= aLongDashArray
;
106 case FONT_UNDERLINE_DASHDOT
:
108 pDotDashArray
= aDotDashArray
;
111 case FONT_UNDERLINE_DASHDOTDOT
:
113 pDotDashArray
= aDashDotDotArray
;
116 case FONT_UNDERLINE_SMALLWAVE
:
121 case FONT_UNDERLINE_WAVE
:
126 case FONT_UNDERLINE_DOUBLEWAVE
:
132 case FONT_UNDERLINE_BOLD
:
137 case FONT_UNDERLINE_BOLDDOTTED
:
140 pDotDashArray
= aDottedArray
;
143 case FONT_UNDERLINE_BOLDDASH
:
146 pDotDashArray
= aDashedArray
;
149 case FONT_UNDERLINE_BOLDLONGDASH
:
152 pDotDashArray
= aLongDashArray
;
155 case FONT_UNDERLINE_BOLDDASHDOT
:
158 pDotDashArray
= aDotDashArray
;
161 case FONT_UNDERLINE_BOLDDASHDOTDOT
:
164 pDotDashArray
= aDashDotDotArray
;
167 case FONT_UNDERLINE_BOLDWAVE
:
182 fLineOffset
-= 0.50 * fLineHeight
;
188 eLineJoin
= basegfx::B2DLINEJOIN_ROUND
;
192 // prepare Line and Stroke Attributes
193 const attribute::LineAttribute
aLineAttribute(rLineColor
, fLineHeight
, eLineJoin
);
194 attribute::StrokeAttribute aStrokeAttribute
;
198 ::std::vector
< double > aDoubleArray
;
200 for(const int* p
= pDotDashArray
; *p
; ++p
)
202 aDoubleArray
.push_back((double)(*p
) * fLineHeight
);
205 aStrokeAttribute
= attribute::StrokeAttribute(aDoubleArray
);
208 // create base polygon and new primitive
209 basegfx::B2DPolygon aLine
;
210 Primitive2DReference aNewPrimitive
;
212 aLine
.append(basegfx::B2DPoint(0.0, fLineOffset
));
213 aLine
.append(basegfx::B2DPoint(fLineWidth
, fLineOffset
));
214 aLine
.transform(rUnscaledTransform
);
218 double fWaveWidth(10.6 * fLineHeight
);
220 if(FONT_UNDERLINE_SMALLWAVE
== eLineStyle
)
224 else if(FONT_UNDERLINE_WAVE
== eLineStyle
)
226 // extra multiply to get the same WaveWidth as with the bold version
230 aNewPrimitive
= Primitive2DReference(new PolygonWavePrimitive2D(aLine
, aLineAttribute
, aStrokeAttribute
, fWaveWidth
, fWaveWidth
* 0.5));
234 aNewPrimitive
= Primitive2DReference(new PolygonStrokePrimitive2D(aLine
, aLineAttribute
, aStrokeAttribute
));
238 rTarget
.push_back(aNewPrimitive
);
242 // double line, create 2nd primitive with offset using TransformPrimitive based on
243 // already created NewPrimitive
244 double fLineDist(2.3 * fLineHeight
);
248 fLineDist
= 6.3 * fLineHeight
;
251 basegfx::B2DHomMatrix aTransform
;
253 // move base point of text to 0.0 and de-rotate
254 aTransform
.translate(-rDecTrans
.getTranslate().getX(), -rDecTrans
.getTranslate().getY());
255 aTransform
.rotate(-rDecTrans
.getRotate());
257 // translate in Y by offset
258 aTransform
.translate(0.0, fLineDist
);
260 // move back and rotate
261 aTransform
.rotate(rDecTrans
.getRotate());
262 aTransform
.translate(rDecTrans
.getTranslate().getX(), rDecTrans
.getTranslate().getY());
264 // add transform primitive
265 const Primitive2DSequence
aContent(&aNewPrimitive
, 1);
266 rTarget
.push_back(Primitive2DReference(new TransformPrimitive2D(aTransform
, aContent
)));
270 void TextDecoratedPortionPrimitive2D::impCreateGeometryContent(
271 std::vector
< Primitive2DReference
>& rTarget
,
272 basegfx::DecomposedB2DHomMatrixContainer
& rDecTrans
,
274 xub_StrLen aTextPosition
,
275 xub_StrLen aTextLength
,
276 const ::std::vector
< double >& rDXArray
,
277 const FontAttributes
& rFontAttributes
) const
279 // create the SimpleTextPrimitive needed in any case
280 rTarget
.push_back(Primitive2DReference(new TextSimplePortionPrimitive2D(
281 rDecTrans
.getB2DHomMatrix(),
290 // see if something else needs to be done
291 const bool bOverlineUsed(FONT_UNDERLINE_NONE
!= getFontOverline());
292 const bool bUnderlineUsed(FONT_UNDERLINE_NONE
!= getFontUnderline());
293 const bool bStrikeoutUsed(FONT_STRIKEOUT_NONE
!= getFontStrikeout());
295 if(bUnderlineUsed
|| bStrikeoutUsed
|| bOverlineUsed
)
297 // common preparations
298 basegfx::B2DHomMatrix aUnscaledTransform
;
299 TextLayouterDevice aTextLayouter
;
301 // unscaled is needed since scale contains already the font size
302 aUnscaledTransform
.shearX(rDecTrans
.getShearX());
303 aUnscaledTransform
.rotate(rDecTrans
.getRotate());
304 aUnscaledTransform
.translate(rDecTrans
.getTranslate().getX(), rDecTrans
.getTranslate().getY());
306 // TextLayouterDevice is needed to get metrics for text decorations like
307 // underline/strikeout/emphasis marks from it. For setup, the font size is needed
308 aTextLayouter
.setFontAttributes(getFontAttributes(), rDecTrans
.getScale().getX(), rDecTrans
.getScale().getY(), getLocale());
311 double fTextWidth(0.0);
315 fTextWidth
= aTextLayouter
.getTextWidth(rText
, aTextPosition
, aTextLength
);
319 fTextWidth
= rDXArray
.back() * rDecTrans
.getScale().getX();
324 // create primitive geometry for overline
325 impCreateTextLine(rTarget
, rDecTrans
, aUnscaledTransform
, getFontOverline(), aTextLayouter
.getOverlineOffset(),
326 aTextLayouter
.getOverlineHeight(), fTextWidth
, getOverlineColor());
331 // create primitive geometry for underline
332 impCreateTextLine(rTarget
, rDecTrans
, aUnscaledTransform
, getFontUnderline(), aTextLayouter
.getUnderlineOffset(),
333 aTextLayouter
.getUnderlineHeight(), fTextWidth
, getTextlineColor());
338 // create primitive geometry for strikeout
339 if(FONT_STRIKEOUT_SLASH
== getFontStrikeout() || FONT_STRIKEOUT_X
== getFontStrikeout())
341 // strikeout with character
342 const sal_Unicode
aStrikeoutChar(FONT_STRIKEOUT_SLASH
== getFontStrikeout() ? '/' : 'X');
343 const String
aSingleCharString(aStrikeoutChar
);
344 const double fStrikeCharWidth(aTextLayouter
.getTextWidth(aSingleCharString
, 0, 1));
345 const double fStrikeCharCount(fabs(fTextWidth
/fStrikeCharWidth
));
346 const sal_uInt32
nStrikeCharCount(static_cast< sal_uInt32
>(fStrikeCharCount
+ 0.9));
347 const double fScaleX(rDecTrans
.getScale().getX());
348 const double fStrikeCharWidthUnscaled(basegfx::fTools::equalZero(fScaleX
) ? fStrikeCharWidth
: fStrikeCharWidth
/fScaleX
);
350 std::vector
<double> aDXArray(nStrikeCharCount
);
351 String aStrikeoutString
;
353 for(sal_uInt32
a(0); a
< nStrikeCharCount
; a
++)
355 aStrikeoutString
+= aSingleCharString
;
356 aDXArray
[a
] = (a
+ 1) * fStrikeCharWidthUnscaled
;
359 rTarget
.push_back(Primitive2DReference(new TextSimplePortionPrimitive2D(
360 rDecTrans
.getB2DHomMatrix(),
363 aStrikeoutString
.Len(),
371 // strikeout with geometry
372 double fStrikeoutHeight(aTextLayouter
.getUnderlineHeight());
373 double fStrikeoutOffset(aTextLayouter
.getStrikeoutOffset());
374 bool bDoubleLine(false);
376 // set line attribute
377 switch(getFontStrikeout())
379 default : // case primitive2d::FONT_STRIKEOUT_SINGLE:
383 case primitive2d::FONT_STRIKEOUT_DOUBLE
:
388 case primitive2d::FONT_STRIKEOUT_BOLD
:
390 fStrikeoutHeight
*= 2.0;
397 fStrikeoutOffset
-= 0.50 * fStrikeoutHeight
;
398 fStrikeoutHeight
*= 0.64;
401 // create base polygon and new primitive
402 basegfx::B2DPolygon aStrikeoutLine
;
404 aStrikeoutLine
.append(basegfx::B2DPoint(0.0, -fStrikeoutOffset
));
405 aStrikeoutLine
.append(basegfx::B2DPoint(fTextWidth
, -fStrikeoutOffset
));
406 aStrikeoutLine
.transform(aUnscaledTransform
);
408 const attribute::LineAttribute
aLineAttribute(getFontColor(), fStrikeoutHeight
, basegfx::B2DLINEJOIN_NONE
);
409 Primitive2DReference
aNewPrimitive(new PolygonStrokePrimitive2D(aStrikeoutLine
, aLineAttribute
));
412 rTarget
.push_back(aNewPrimitive
);
416 // double line, create 2nd primitive with offset using TransformPrimitive based on
417 // already created NewPrimitive
418 const double fLineDist(2.0 * fStrikeoutHeight
);
419 basegfx::B2DHomMatrix aTransform
;
421 // move base point of text to 0.0 and de-rotate
422 aTransform
.translate(-rDecTrans
.getTranslate().getX(), -rDecTrans
.getTranslate().getY());
423 aTransform
.rotate(-rDecTrans
.getRotate());
425 // translate in Y by offset
426 aTransform
.translate(0.0, -fLineDist
);
428 // move back and rotate
429 aTransform
.rotate(rDecTrans
.getRotate());
430 aTransform
.translate(rDecTrans
.getTranslate().getX(), rDecTrans
.getTranslate().getY());
432 // add transform primitive
433 const Primitive2DSequence
aContent(&aNewPrimitive
, 1);
434 rTarget
.push_back(Primitive2DReference(new TransformPrimitive2D(aTransform
, aContent
)));
440 // TODO: Handle Font Emphasis Above/Below
443 void TextDecoratedPortionPrimitive2D::impCorrectTextBoundary(::com::sun::star::i18n::Boundary
& rNextWordBoundary
) const
445 // truncate aNextWordBoundary to min/max possible values. This is necessary since the word start may be
446 // before/after getTextPosition() when a long string is the content and getTextPosition()
447 // is right inside a word. Same for end.
448 const sal_Int32
aMinPos(static_cast< sal_Int32
>(getTextPosition()));
449 const sal_Int32
aMaxPos(aMinPos
+ static_cast< sal_Int32
>(getTextLength()));
451 if(rNextWordBoundary
.startPos
< aMinPos
)
453 rNextWordBoundary
.startPos
= aMinPos
;
455 else if(rNextWordBoundary
.startPos
> aMaxPos
)
457 rNextWordBoundary
.startPos
= aMaxPos
;
460 if(rNextWordBoundary
.endPos
< aMinPos
)
462 rNextWordBoundary
.endPos
= aMinPos
;
464 else if(rNextWordBoundary
.endPos
> aMaxPos
)
466 rNextWordBoundary
.endPos
= aMaxPos
;
470 void TextDecoratedPortionPrimitive2D::impSplitSingleWords(
471 std::vector
< Primitive2DReference
>& rTarget
,
472 basegfx::DecomposedB2DHomMatrixContainer
& rDecTrans
) const
474 // break iterator support
475 // made static so it only needs to be fetched once, even with many single
476 // constructed VclMetafileProcessor2D. It's still incarnated on demand,
477 // but exists for OOo runtime now by purpose.
478 static ::com::sun::star::uno::Reference
< ::com::sun::star::i18n::XBreakIterator
> xLocalBreakIterator
;
480 if(!xLocalBreakIterator
.is())
482 ::com::sun::star::uno::Reference
< ::com::sun::star::lang::XMultiServiceFactory
> xMSF(::comphelper::getProcessServiceFactory());
483 xLocalBreakIterator
.set(xMSF
->createInstance(rtl::OUString::createFromAscii("com.sun.star.i18n.BreakIterator")), ::com::sun::star::uno::UNO_QUERY
);
486 if(xLocalBreakIterator
.is())
488 // init word iterator, get first word and truncate to possibilities
489 ::com::sun::star::i18n::Boundary
aNextWordBoundary(xLocalBreakIterator
->getWordBoundary(
490 getText(), getTextPosition(), getLocale(), ::com::sun::star::i18n::WordType::ANYWORD_IGNOREWHITESPACES
, sal_True
));
492 if(aNextWordBoundary
.endPos
== getTextPosition() && getTextLength() > 0)
495 // a word before was found (this can happen when search starts on a whitespace and a word
496 // in front of it exists), force to look one position further
497 aNextWordBoundary
= xLocalBreakIterator
->getWordBoundary(
498 getText(), getTextPosition() + 1, getLocale(), ::com::sun::star::i18n::WordType::ANYWORD_IGNOREWHITESPACES
, sal_True
);
501 impCorrectTextBoundary(aNextWordBoundary
);
503 // prepare new font attributes WITHOUT outline
504 const FontAttributes
aNewFontAttributes(
505 getFontAttributes().getFamilyName(),
506 getFontAttributes().getStyleName(),
507 getFontAttributes().getWeight(),
508 getFontAttributes().getSymbol(),
509 getFontAttributes().getVertical(),
510 getFontAttributes().getItalic(),
511 false, // no outline anymore, handled locally
512 getFontAttributes().getRTL(),
513 getFontAttributes().getBiDiStrong());
515 if(aNextWordBoundary
.startPos
== getTextPosition() && aNextWordBoundary
.endPos
== getTextLength())
517 // it IS only a single word, handle as one word
518 impCreateGeometryContent(rTarget
, rDecTrans
, getText(), getTextPosition(), getTextLength(), getDXArray(), aNewFontAttributes
);
522 // prepare TextLayouter
523 const bool bNoDXArray(getDXArray().empty());
524 TextLayouterDevice aTextLayouter
;
528 // ..but only completely when no DXArray
529 aTextLayouter
.setFontAttributes(getFontAttributes(), rDecTrans
.getScale().getX(), rDecTrans
.getScale().getY(),getLocale());
532 // do iterate over single words
533 while(aNextWordBoundary
.startPos
!= aNextWordBoundary
.endPos
)
535 // prepare values for new portion
536 const xub_StrLen
nNewTextStart(static_cast< xub_StrLen
>(aNextWordBoundary
.startPos
));
537 const xub_StrLen
nNewTextEnd(static_cast< xub_StrLen
>(aNextWordBoundary
.endPos
));
539 // prepare transform for the single word
540 basegfx::B2DHomMatrix aNewTransform
;
541 ::std::vector
< double > aNewDXArray
;
542 const bool bNewStartIsNotOldStart(nNewTextStart
> getTextPosition());
546 // prepare new DXArray for the single word
547 aNewDXArray
= ::std::vector
< double >(
548 getDXArray().begin() + static_cast< sal_uInt32
>(nNewTextStart
- getTextPosition()),
549 getDXArray().begin() + static_cast< sal_uInt32
>(nNewTextEnd
- getTextPosition()));
552 if(bNewStartIsNotOldStart
)
554 // needs to be moved to a new start position
559 // evaluate using TextLayouter
560 fOffset
= aTextLayouter
.getTextWidth(getText(), getTextPosition(), nNewTextStart
);
565 const sal_uInt32
nIndex(static_cast< sal_uInt32
>(nNewTextStart
- getTextPosition()));
566 fOffset
= getDXArray()[nIndex
- 1];
569 // apply needed offset to transformation
570 aNewTransform
.translate(fOffset
, 0.0);
574 // DXArray values need to be corrected with the offset, too
575 const sal_uInt32
nArraySize(aNewDXArray
.size());
577 for(sal_uInt32
a(0); a
< nArraySize
; a
++)
579 aNewDXArray
[a
] -= fOffset
;
584 // add text transformation to new transformation
585 aNewTransform
*= rDecTrans
.getB2DHomMatrix();
587 // create geometry content for the single word. Do not forget
588 // to use the new transformation
589 basegfx::DecomposedB2DHomMatrixContainer
aDecTrans(aNewTransform
);
591 impCreateGeometryContent(rTarget
, aDecTrans
, getText(), nNewTextStart
,
592 nNewTextEnd
- nNewTextStart
, aNewDXArray
, aNewFontAttributes
);
594 // prepare next word and truncate to possibilities
595 aNextWordBoundary
= xLocalBreakIterator
->nextWord(
596 getText(), aNextWordBoundary
.endPos
, getLocale(),
597 ::com::sun::star::i18n::WordType::ANYWORD_IGNOREWHITESPACES
);
599 impCorrectTextBoundary(aNextWordBoundary
);
605 Primitive2DSequence
TextDecoratedPortionPrimitive2D::createLocalDecomposition(const geometry::ViewInformation2D
& /*rViewInformation*/) const
607 std::vector
< Primitive2DReference
> aNewPrimitives
;
608 basegfx::DecomposedB2DHomMatrixContainer
aDecTrans(getTextTransform());
609 Primitive2DSequence aRetval
;
611 // create basic geometry such as SimpleTextPrimitive, Overline, Underline,
613 if(getWordLineMode())
615 // support for single word mode
616 impSplitSingleWords(aNewPrimitives
, aDecTrans
);
620 // prepare new font attributes WITHOUT outline
621 const FontAttributes
aNewFontAttributes(
622 getFontAttributes().getFamilyName(),
623 getFontAttributes().getStyleName(),
624 getFontAttributes().getWeight(),
625 getFontAttributes().getSymbol(),
626 getFontAttributes().getVertical(),
627 getFontAttributes().getItalic(),
628 false, // no outline anymore, handled locally
629 getFontAttributes().getRTL(),
630 getFontAttributes().getBiDiStrong());
632 // handle as one word
633 impCreateGeometryContent(aNewPrimitives
, aDecTrans
, getText(), getTextPosition(), getTextLength(), getDXArray(), aNewFontAttributes
);
636 // convert to Primitive2DSequence
637 const sal_uInt32
nMemberCount(aNewPrimitives
.size());
641 aRetval
.realloc(nMemberCount
);
643 for(sal_uInt32
a(0); a
< nMemberCount
; a
++)
645 aRetval
[a
] = aNewPrimitives
[a
];
649 // Handle Shadow, Outline and FontRelief
650 if(aRetval
.hasElements())
652 // outline AND shadow depend on NO FontRelief (see dialog)
653 const bool bHasFontRelief(FONT_RELIEF_NONE
!= getFontRelief());
654 const bool bHasShadow(!bHasFontRelief
&& getShadow());
655 const bool bHasOutline(!bHasFontRelief
&& getFontAttributes().getOutline());
657 if(bHasShadow
|| bHasFontRelief
|| bHasOutline
)
659 Primitive2DReference aShadow
;
663 // create shadow with current content (in aRetval). Text shadow
664 // is constant, relative to font size, rotated with the text and has a
666 // shadow parameter values
667 static double fFactor(1.0 / 24.0);
668 const double fTextShadowOffset(aDecTrans
.getScale().getY() * fFactor
);
669 static basegfx::BColor
aShadowColor(0.3, 0.3, 0.3);
671 // preapare shadow transform matrix
672 basegfx::B2DHomMatrix aShadowTransform
;
673 aShadowTransform
.translate(fTextShadowOffset
, fTextShadowOffset
);
675 // create shadow primitive
676 aShadow
= Primitive2DReference(new ShadowPrimitive2D(
684 // create emboss using an own helper primitive since this will
686 const basegfx::BColor
aBBlack(0.0, 0.0, 0.0);
687 const bool bDefaultTextColor(aBBlack
== getFontColor());
688 TextEffectStyle2D
aTextEffectStyle2D(TEXTEFFECTSTYLE2D_RELIEF_EMBOSSED
);
690 if(bDefaultTextColor
)
692 if(FONT_RELIEF_ENGRAVED
== getFontRelief())
694 aTextEffectStyle2D
= TEXTEFFECTSTYLE2D_RELIEF_ENGRAVED_DEFAULT
;
698 aTextEffectStyle2D
= TEXTEFFECTSTYLE2D_RELIEF_EMBOSSED_DEFAULT
;
703 if(FONT_RELIEF_ENGRAVED
== getFontRelief())
705 aTextEffectStyle2D
= TEXTEFFECTSTYLE2D_RELIEF_ENGRAVED
;
709 aTextEffectStyle2D
= TEXTEFFECTSTYLE2D_RELIEF_EMBOSSED
;
713 Primitive2DReference
aNewTextEffect(new TextEffectPrimitive2D(
715 aDecTrans
.getTranslate(),
716 aDecTrans
.getRotate(),
717 aTextEffectStyle2D
));
718 aRetval
= Primitive2DSequence(&aNewTextEffect
, 1);
722 // create outline using an own helper primitive since this will
724 Primitive2DReference
aNewTextEffect(new TextEffectPrimitive2D(
726 aDecTrans
.getTranslate(),
727 aDecTrans
.getRotate(),
728 TEXTEFFECTSTYLE2D_OUTLINE
));
729 aRetval
= Primitive2DSequence(&aNewTextEffect
, 1);
734 // put shadow in front if there is one to paint timely before
735 // but placed behind content
736 const Primitive2DSequence
aContent(aRetval
);
737 aRetval
= Primitive2DSequence(&aShadow
, 1);
738 appendPrimitive2DSequenceToPrimitive2DSequence(aRetval
, aContent
);
746 TextDecoratedPortionPrimitive2D::TextDecoratedPortionPrimitive2D(
748 // TextSimplePortionPrimitive2D parameters
749 const basegfx::B2DHomMatrix
& rNewTransform
,
751 xub_StrLen aTextPosition
,
752 xub_StrLen aTextLength
,
753 const ::std::vector
< double >& rDXArray
,
754 const FontAttributes
& rFontAttributes
,
755 const ::com::sun::star::lang::Locale
& rLocale
,
756 const basegfx::BColor
& rFontColor
,
759 const basegfx::BColor
& rOverlineColor
,
760 const basegfx::BColor
& rTextlineColor
,
761 FontUnderline eFontOverline
,
762 FontUnderline eFontUnderline
,
763 bool bUnderlineAbove
,
764 FontStrikeout eFontStrikeout
,
766 FontEmphasisMark eFontEmphasisMark
,
767 bool bEmphasisMarkAbove
,
768 bool bEmphasisMarkBelow
,
769 FontRelief eFontRelief
,
771 : TextSimplePortionPrimitive2D(rNewTransform
, rText
, aTextPosition
, aTextLength
, rDXArray
, rFontAttributes
, rLocale
, rFontColor
),
772 maOverlineColor(rOverlineColor
),
773 maTextlineColor(rTextlineColor
),
774 meFontOverline(eFontOverline
),
775 meFontUnderline(eFontUnderline
),
776 meFontStrikeout(eFontStrikeout
),
777 meFontEmphasisMark(eFontEmphasisMark
),
778 meFontRelief(eFontRelief
),
779 mbUnderlineAbove(bUnderlineAbove
),
780 mbWordLineMode(bWordLineMode
),
781 mbEmphasisMarkAbove(bEmphasisMarkAbove
),
782 mbEmphasisMarkBelow(bEmphasisMarkBelow
),
787 bool TextDecoratedPortionPrimitive2D::operator==(const BasePrimitive2D
& rPrimitive
) const
789 if(TextSimplePortionPrimitive2D::operator==(rPrimitive
))
791 const TextDecoratedPortionPrimitive2D
& rCompare
= (TextDecoratedPortionPrimitive2D
&)rPrimitive
;
793 return (getOverlineColor() == rCompare
.getOverlineColor()
794 && getTextlineColor() == rCompare
.getTextlineColor()
795 && getFontOverline() == rCompare
.getFontOverline()
796 && getFontUnderline() == rCompare
.getFontUnderline()
797 && getFontStrikeout() == rCompare
.getFontStrikeout()
798 && getFontEmphasisMark() == rCompare
.getFontEmphasisMark()
799 && getFontRelief() == rCompare
.getFontRelief()
800 && getUnderlineAbove() == rCompare
.getUnderlineAbove()
801 && getWordLineMode() == rCompare
.getWordLineMode()
802 && getEmphasisMarkAbove() == rCompare
.getEmphasisMarkAbove()
803 && getEmphasisMarkBelow() == rCompare
.getEmphasisMarkBelow()
804 && getShadow() == rCompare
.getShadow());
811 // Added missing implementation. Decorations may (will) stick out of the text's
812 // inking area, so add them if needed
813 basegfx::B2DRange
TextDecoratedPortionPrimitive2D::getB2DRange(const geometry::ViewInformation2D
& rViewInformation
) const
815 const bool bDecoratedIsNeeded(
816 FONT_UNDERLINE_NONE
!= getFontOverline()
817 || FONT_UNDERLINE_NONE
!= getFontUnderline()
818 || FONT_STRIKEOUT_NONE
!= getFontStrikeout()
819 || FONT_EMPHASISMARK_NONE
!= getFontEmphasisMark()
820 || FONT_RELIEF_NONE
!= getFontRelief()
823 if(bDecoratedIsNeeded
)
825 // decoration is used, fallback to BasePrimitive2D::getB2DRange which uses
826 // the own local decomposition for computation and thus creates all necessary
828 return BasePrimitive2D::getB2DRange(rViewInformation
);
832 // no relevant decoration used, fallback to TextSimplePortionPrimitive2D::getB2DRange
833 return TextSimplePortionPrimitive2D::getB2DRange(rViewInformation
);
838 ImplPrimitrive2DIDBlock(TextDecoratedPortionPrimitive2D
, PRIMITIVE2D_ID_TEXTDECORATEDPORTIONPRIMITIVE2D
)
840 } // end of namespace primitive2d
841 } // end of namespace drawinglayer
843 //////////////////////////////////////////////////////////////////////////////