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(
281 new TextSimplePortionPrimitive2D(
282 rDecTrans
.getB2DHomMatrix(),
291 // see if something else needs to be done
292 const bool bOverlineUsed(FONT_UNDERLINE_NONE
!= getFontOverline());
293 const bool bUnderlineUsed(FONT_UNDERLINE_NONE
!= getFontUnderline());
294 const bool bStrikeoutUsed(FONT_STRIKEOUT_NONE
!= getFontStrikeout());
296 if(bUnderlineUsed
|| bStrikeoutUsed
|| bOverlineUsed
)
298 // common preparations
299 basegfx::B2DHomMatrix aUnscaledTransform
;
300 TextLayouterDevice aTextLayouter
;
302 // unscaled is needed since scale contains already the font size
303 aUnscaledTransform
.shearX(rDecTrans
.getShearX());
304 aUnscaledTransform
.rotate(rDecTrans
.getRotate());
305 aUnscaledTransform
.translate(rDecTrans
.getTranslate().getX(), rDecTrans
.getTranslate().getY());
307 // TextLayouterDevice is needed to get metrics for text decorations like
308 // underline/strikeout/emphasis marks from it. For setup, the font size is needed
309 aTextLayouter
.setFontAttributes(
311 rDecTrans
.getScale().getX(),
312 rDecTrans
.getScale().getY(),
316 double fTextWidth(0.0);
320 fTextWidth
= aTextLayouter
.getTextWidth(rText
, aTextPosition
, aTextLength
);
324 fTextWidth
= rDXArray
.back() * rDecTrans
.getScale().getX();
325 const double fFontScaleX(rDecTrans
.getScale().getX());
327 if(!basegfx::fTools::equal(fFontScaleX
, 1.0)
328 && !basegfx::fTools::equalZero(fFontScaleX
))
330 // need to take FontScaling out of the DXArray
331 fTextWidth
/= fFontScaleX
;
337 // create primitive geometry for overline
338 impCreateTextLine(rTarget
, rDecTrans
, aUnscaledTransform
, getFontOverline(), aTextLayouter
.getOverlineOffset(),
339 aTextLayouter
.getOverlineHeight(), fTextWidth
, getOverlineColor());
344 // create primitive geometry for underline
345 impCreateTextLine(rTarget
, rDecTrans
, aUnscaledTransform
, getFontUnderline(), aTextLayouter
.getUnderlineOffset(),
346 aTextLayouter
.getUnderlineHeight(), fTextWidth
, getTextlineColor());
351 // create primitive geometry for strikeout
352 if(FONT_STRIKEOUT_SLASH
== getFontStrikeout() || FONT_STRIKEOUT_X
== getFontStrikeout())
354 // strikeout with character
355 const sal_Unicode
aStrikeoutChar(FONT_STRIKEOUT_SLASH
== getFontStrikeout() ? '/' : 'X');
356 const String
aSingleCharString(aStrikeoutChar
);
357 const double fStrikeCharWidth(aTextLayouter
.getTextWidth(aSingleCharString
, 0, 1));
358 const double fStrikeCharCount(fabs(fTextWidth
/fStrikeCharWidth
));
359 const sal_uInt32
nStrikeCharCount(static_cast< sal_uInt32
>(fStrikeCharCount
+ 0.5));
360 std::vector
<double> aDXArray(nStrikeCharCount
);
361 String aStrikeoutString
;
363 for(sal_uInt32
a(0); a
< nStrikeCharCount
; a
++)
365 aStrikeoutString
+= aSingleCharString
;
366 aDXArray
[a
] = (a
+ 1) * fStrikeCharWidth
;
369 rTarget
.push_back(Primitive2DReference(
370 new TextSimplePortionPrimitive2D(
371 rDecTrans
.getB2DHomMatrix(),
374 aStrikeoutString
.Len(),
382 // strikeout with geometry
383 double fStrikeoutHeight(aTextLayouter
.getUnderlineHeight());
384 double fStrikeoutOffset(aTextLayouter
.getStrikeoutOffset());
385 bool bDoubleLine(false);
387 // set line attribute
388 switch(getFontStrikeout())
390 default : // case primitive2d::FONT_STRIKEOUT_SINGLE:
394 case primitive2d::FONT_STRIKEOUT_DOUBLE
:
399 case primitive2d::FONT_STRIKEOUT_BOLD
:
401 fStrikeoutHeight
*= 2.0;
408 fStrikeoutOffset
-= 0.50 * fStrikeoutHeight
;
409 fStrikeoutHeight
*= 0.64;
412 // create base polygon and new primitive
413 basegfx::B2DPolygon aStrikeoutLine
;
415 aStrikeoutLine
.append(basegfx::B2DPoint(0.0, -fStrikeoutOffset
));
416 aStrikeoutLine
.append(basegfx::B2DPoint(fTextWidth
, -fStrikeoutOffset
));
417 aStrikeoutLine
.transform(aUnscaledTransform
);
419 const attribute::LineAttribute
aLineAttribute(getFontColor(), fStrikeoutHeight
, basegfx::B2DLINEJOIN_NONE
);
420 Primitive2DReference
aNewPrimitive(new PolygonStrokePrimitive2D(aStrikeoutLine
, aLineAttribute
));
423 rTarget
.push_back(aNewPrimitive
);
427 // double line, create 2nd primitive with offset using TransformPrimitive based on
428 // already created NewPrimitive
429 const double fLineDist(2.0 * fStrikeoutHeight
);
430 basegfx::B2DHomMatrix aTransform
;
432 // move base point of text to 0.0 and de-rotate
433 aTransform
.translate(-rDecTrans
.getTranslate().getX(), -rDecTrans
.getTranslate().getY());
434 aTransform
.rotate(-rDecTrans
.getRotate());
436 // translate in Y by offset
437 aTransform
.translate(0.0, -fLineDist
);
439 // move back and rotate
440 aTransform
.rotate(rDecTrans
.getRotate());
441 aTransform
.translate(rDecTrans
.getTranslate().getX(), rDecTrans
.getTranslate().getY());
443 // add transform primitive
444 const Primitive2DSequence
aContent(&aNewPrimitive
, 1);
445 rTarget
.push_back(Primitive2DReference(new TransformPrimitive2D(aTransform
, aContent
)));
451 // TODO: Handle Font Emphasis Above/Below
454 void TextDecoratedPortionPrimitive2D::impCorrectTextBoundary(::com::sun::star::i18n::Boundary
& rNextWordBoundary
) const
456 // truncate aNextWordBoundary to min/max possible values. This is necessary since the word start may be
457 // before/after getTextPosition() when a long string is the content and getTextPosition()
458 // is right inside a word. Same for end.
459 const sal_Int32
aMinPos(static_cast< sal_Int32
>(getTextPosition()));
460 const sal_Int32
aMaxPos(aMinPos
+ static_cast< sal_Int32
>(getTextLength()));
462 if(rNextWordBoundary
.startPos
< aMinPos
)
464 rNextWordBoundary
.startPos
= aMinPos
;
466 else if(rNextWordBoundary
.startPos
> aMaxPos
)
468 rNextWordBoundary
.startPos
= aMaxPos
;
471 if(rNextWordBoundary
.endPos
< aMinPos
)
473 rNextWordBoundary
.endPos
= aMinPos
;
475 else if(rNextWordBoundary
.endPos
> aMaxPos
)
477 rNextWordBoundary
.endPos
= aMaxPos
;
481 void TextDecoratedPortionPrimitive2D::impSplitSingleWords(
482 std::vector
< Primitive2DReference
>& rTarget
,
483 basegfx::DecomposedB2DHomMatrixContainer
& rDecTrans
) const
485 // break iterator support
486 // made static so it only needs to be fetched once, even with many single
487 // constructed VclMetafileProcessor2D. It's still incarnated on demand,
488 // but exists for OOo runtime now by purpose.
489 static ::com::sun::star::uno::Reference
< ::com::sun::star::i18n::XBreakIterator
> xLocalBreakIterator
;
491 if(!xLocalBreakIterator
.is())
493 ::com::sun::star::uno::Reference
< ::com::sun::star::lang::XMultiServiceFactory
> xMSF(::comphelper::getProcessServiceFactory());
494 xLocalBreakIterator
.set(xMSF
->createInstance(rtl::OUString::createFromAscii("com.sun.star.i18n.BreakIterator")), ::com::sun::star::uno::UNO_QUERY
);
497 if(xLocalBreakIterator
.is() && getTextLength())
499 // init word iterator, get first word and truncate to possibilities
500 ::com::sun::star::i18n::Boundary
aNextWordBoundary(xLocalBreakIterator
->getWordBoundary(
501 getText(), getTextPosition(), getLocale(), ::com::sun::star::i18n::WordType::ANYWORD_IGNOREWHITESPACES
, sal_True
));
503 if(aNextWordBoundary
.endPos
== getTextPosition())
505 // backward hit, force next word
506 aNextWordBoundary
= xLocalBreakIterator
->getWordBoundary(
507 getText(), getTextPosition() + 1, getLocale(), ::com::sun::star::i18n::WordType::ANYWORD_IGNOREWHITESPACES
, sal_True
);
510 impCorrectTextBoundary(aNextWordBoundary
);
512 // prepare new font attributes WITHOUT outline
513 const FontAttributes
aNewFontAttributes(
514 getFontAttributes().getFamilyName(),
515 getFontAttributes().getStyleName(),
516 getFontAttributes().getWeight(),
517 getFontAttributes().getSymbol(),
518 getFontAttributes().getVertical(),
519 getFontAttributes().getItalic(),
520 false, // no outline anymore, handled locally
521 getFontAttributes().getRTL(),
522 getFontAttributes().getBiDiStrong());
524 if(aNextWordBoundary
.startPos
== getTextPosition() && aNextWordBoundary
.endPos
== getTextLength())
526 // it IS only a single word, handle as one word
527 impCreateGeometryContent(rTarget
, rDecTrans
, getText(), getTextPosition(), getTextLength(), getDXArray(), aNewFontAttributes
);
531 // prepare TextLayouter
532 const bool bNoDXArray(getDXArray().empty());
533 TextLayouterDevice aTextLayouter
;
537 // ..but only completely when no DXArray
538 aTextLayouter
.setFontAttributes(
540 rDecTrans
.getScale().getX(),
541 rDecTrans
.getScale().getY(),
545 // do iterate over single words
546 while(aNextWordBoundary
.startPos
!= aNextWordBoundary
.endPos
)
548 // prepare values for new portion
549 const xub_StrLen
nNewTextStart(static_cast< xub_StrLen
>(aNextWordBoundary
.startPos
));
550 const xub_StrLen
nNewTextEnd(static_cast< xub_StrLen
>(aNextWordBoundary
.endPos
));
552 // prepare transform for the single word
553 basegfx::B2DHomMatrix aNewTransform
;
554 ::std::vector
< double > aNewDXArray
;
555 const bool bNewStartIsNotOldStart(nNewTextStart
> getTextPosition());
559 // prepare new DXArray for the single word
560 aNewDXArray
= ::std::vector
< double >(
561 getDXArray().begin() + static_cast< sal_uInt32
>(nNewTextStart
- getTextPosition()),
562 getDXArray().begin() + static_cast< sal_uInt32
>(nNewTextEnd
- getTextPosition()));
565 if(bNewStartIsNotOldStart
)
567 // needs to be moved to a new start position
572 // evaluate using TextLayouter
573 fOffset
= aTextLayouter
.getTextWidth(getText(), getTextPosition(), nNewTextStart
);
578 const sal_uInt32
nIndex(static_cast< sal_uInt32
>(nNewTextStart
- getTextPosition()));
579 fOffset
= getDXArray()[nIndex
- 1];
582 // need offset without FontScale for building the new transformation. The
583 // new transformation will be multiplied with the current text transformation
584 // so FontScale would be double
585 double fOffsetNoScale(fOffset
);
586 const double fFontScaleX(rDecTrans
.getScale().getX());
588 if(!basegfx::fTools::equal(fFontScaleX
, 1.0)
589 && !basegfx::fTools::equalZero(fFontScaleX
))
591 fOffsetNoScale
/= fFontScaleX
;
594 // apply needed offset to transformation
595 aNewTransform
.translate(fOffsetNoScale
, 0.0);
599 // DXArray values need to be corrected with the offset, too. Here,
600 // take the scaled offset since the DXArray is scaled
601 const sal_uInt32
nArraySize(aNewDXArray
.size());
603 for(sal_uInt32
a(0); a
< nArraySize
; a
++)
605 aNewDXArray
[a
] -= fOffset
;
610 // add text transformation to new transformation
611 aNewTransform
*= rDecTrans
.getB2DHomMatrix();
613 // create geometry content for the single word. Do not forget
614 // to use the new transformation
615 basegfx::DecomposedB2DHomMatrixContainer
aDecTrans(aNewTransform
);
617 impCreateGeometryContent(rTarget
, aDecTrans
, getText(), nNewTextStart
,
618 nNewTextEnd
- nNewTextStart
, aNewDXArray
, aNewFontAttributes
);
620 if(aNextWordBoundary
.endPos
>= getTextPosition() + getTextLength())
623 aNextWordBoundary
.startPos
= aNextWordBoundary
.endPos
;
627 // get new word portion
628 const sal_Int32
nLastEndPos(aNextWordBoundary
.endPos
);
630 aNextWordBoundary
= xLocalBreakIterator
->getWordBoundary(
631 getText(), aNextWordBoundary
.endPos
, getLocale(),
632 ::com::sun::star::i18n::WordType::ANYWORD_IGNOREWHITESPACES
, sal_True
);
634 if(nLastEndPos
== aNextWordBoundary
.endPos
)
636 // backward hit, force next word
637 aNextWordBoundary
= xLocalBreakIterator
->getWordBoundary(
638 getText(), nLastEndPos
+ 1, getLocale(),
639 ::com::sun::star::i18n::WordType::ANYWORD_IGNOREWHITESPACES
, sal_True
);
642 impCorrectTextBoundary(aNextWordBoundary
);
649 Primitive2DSequence
TextDecoratedPortionPrimitive2D::createLocalDecomposition(const geometry::ViewInformation2D
& /*rViewInformation*/) const
651 std::vector
< Primitive2DReference
> aNewPrimitives
;
652 basegfx::DecomposedB2DHomMatrixContainer
aDecTrans(getTextTransform());
653 Primitive2DSequence aRetval
;
655 // create basic geometry such as SimpleTextPrimitive, Overline, Underline,
657 if(getWordLineMode())
659 // support for single word mode
660 impSplitSingleWords(aNewPrimitives
, aDecTrans
);
664 // prepare new font attributes WITHOUT outline
665 const FontAttributes
aNewFontAttributes(
666 getFontAttributes().getFamilyName(),
667 getFontAttributes().getStyleName(),
668 getFontAttributes().getWeight(),
669 getFontAttributes().getSymbol(),
670 getFontAttributes().getVertical(),
671 getFontAttributes().getItalic(),
672 false, // no outline anymore, handled locally
673 getFontAttributes().getRTL(),
674 getFontAttributes().getBiDiStrong());
676 // handle as one word
677 impCreateGeometryContent(aNewPrimitives
, aDecTrans
, getText(), getTextPosition(), getTextLength(), getDXArray(), aNewFontAttributes
);
680 // convert to Primitive2DSequence
681 const sal_uInt32
nMemberCount(aNewPrimitives
.size());
685 aRetval
.realloc(nMemberCount
);
687 for(sal_uInt32
a(0); a
< nMemberCount
; a
++)
689 aRetval
[a
] = aNewPrimitives
[a
];
693 // Handle Shadow, Outline and FontRelief
694 if(aRetval
.hasElements())
696 // outline AND shadow depend on NO FontRelief (see dialog)
697 const bool bHasFontRelief(FONT_RELIEF_NONE
!= getFontRelief());
698 const bool bHasShadow(!bHasFontRelief
&& getShadow());
699 const bool bHasOutline(!bHasFontRelief
&& getFontAttributes().getOutline());
701 if(bHasShadow
|| bHasFontRelief
|| bHasOutline
)
703 Primitive2DReference aShadow
;
707 // create shadow with current content (in aRetval). Text shadow
708 // is constant, relative to font size, rotated with the text and has a
710 // shadow parameter values
711 static double fFactor(1.0 / 24.0);
712 const double fTextShadowOffset(aDecTrans
.getScale().getY() * fFactor
);
713 static basegfx::BColor
aShadowColor(0.3, 0.3, 0.3);
715 // preapare shadow transform matrix
716 basegfx::B2DHomMatrix aShadowTransform
;
717 aShadowTransform
.translate(fTextShadowOffset
, fTextShadowOffset
);
719 // create shadow primitive
720 aShadow
= Primitive2DReference(new ShadowPrimitive2D(
728 // create emboss using an own helper primitive since this will
730 const basegfx::BColor
aBBlack(0.0, 0.0, 0.0);
731 const bool bDefaultTextColor(aBBlack
== getFontColor());
732 TextEffectStyle2D
aTextEffectStyle2D(TEXTEFFECTSTYLE2D_RELIEF_EMBOSSED
);
734 if(bDefaultTextColor
)
736 if(FONT_RELIEF_ENGRAVED
== getFontRelief())
738 aTextEffectStyle2D
= TEXTEFFECTSTYLE2D_RELIEF_ENGRAVED_DEFAULT
;
742 aTextEffectStyle2D
= TEXTEFFECTSTYLE2D_RELIEF_EMBOSSED_DEFAULT
;
747 if(FONT_RELIEF_ENGRAVED
== getFontRelief())
749 aTextEffectStyle2D
= TEXTEFFECTSTYLE2D_RELIEF_ENGRAVED
;
753 aTextEffectStyle2D
= TEXTEFFECTSTYLE2D_RELIEF_EMBOSSED
;
757 Primitive2DReference
aNewTextEffect(new TextEffectPrimitive2D(
759 aDecTrans
.getTranslate(),
760 aDecTrans
.getRotate(),
761 aTextEffectStyle2D
));
762 aRetval
= Primitive2DSequence(&aNewTextEffect
, 1);
766 // create outline using an own helper primitive since this will
768 Primitive2DReference
aNewTextEffect(new TextEffectPrimitive2D(
770 aDecTrans
.getTranslate(),
771 aDecTrans
.getRotate(),
772 TEXTEFFECTSTYLE2D_OUTLINE
));
773 aRetval
= Primitive2DSequence(&aNewTextEffect
, 1);
778 // put shadow in front if there is one to paint timely before
779 // but placed behind content
780 const Primitive2DSequence
aContent(aRetval
);
781 aRetval
= Primitive2DSequence(&aShadow
, 1);
782 appendPrimitive2DSequenceToPrimitive2DSequence(aRetval
, aContent
);
790 TextDecoratedPortionPrimitive2D::TextDecoratedPortionPrimitive2D(
792 // TextSimplePortionPrimitive2D parameters
793 const basegfx::B2DHomMatrix
& rNewTransform
,
795 xub_StrLen aTextPosition
,
796 xub_StrLen aTextLength
,
797 const ::std::vector
< double >& rDXArray
,
798 const FontAttributes
& rFontAttributes
,
799 const ::com::sun::star::lang::Locale
& rLocale
,
800 const basegfx::BColor
& rFontColor
,
803 const basegfx::BColor
& rOverlineColor
,
804 const basegfx::BColor
& rTextlineColor
,
805 FontUnderline eFontOverline
,
806 FontUnderline eFontUnderline
,
807 bool bUnderlineAbove
,
808 FontStrikeout eFontStrikeout
,
810 FontEmphasisMark eFontEmphasisMark
,
811 bool bEmphasisMarkAbove
,
812 bool bEmphasisMarkBelow
,
813 FontRelief eFontRelief
,
815 : TextSimplePortionPrimitive2D(rNewTransform
, rText
, aTextPosition
, aTextLength
, rDXArray
, rFontAttributes
, rLocale
, rFontColor
),
816 maOverlineColor(rOverlineColor
),
817 maTextlineColor(rTextlineColor
),
818 meFontOverline(eFontOverline
),
819 meFontUnderline(eFontUnderline
),
820 meFontStrikeout(eFontStrikeout
),
821 meFontEmphasisMark(eFontEmphasisMark
),
822 meFontRelief(eFontRelief
),
823 mbUnderlineAbove(bUnderlineAbove
),
824 mbWordLineMode(bWordLineMode
),
825 mbEmphasisMarkAbove(bEmphasisMarkAbove
),
826 mbEmphasisMarkBelow(bEmphasisMarkBelow
),
831 bool TextDecoratedPortionPrimitive2D::operator==(const BasePrimitive2D
& rPrimitive
) const
833 if(TextSimplePortionPrimitive2D::operator==(rPrimitive
))
835 const TextDecoratedPortionPrimitive2D
& rCompare
= (TextDecoratedPortionPrimitive2D
&)rPrimitive
;
837 return (getOverlineColor() == rCompare
.getOverlineColor()
838 && getTextlineColor() == rCompare
.getTextlineColor()
839 && getFontOverline() == rCompare
.getFontOverline()
840 && getFontUnderline() == rCompare
.getFontUnderline()
841 && getFontStrikeout() == rCompare
.getFontStrikeout()
842 && getFontEmphasisMark() == rCompare
.getFontEmphasisMark()
843 && getFontRelief() == rCompare
.getFontRelief()
844 && getUnderlineAbove() == rCompare
.getUnderlineAbove()
845 && getWordLineMode() == rCompare
.getWordLineMode()
846 && getEmphasisMarkAbove() == rCompare
.getEmphasisMarkAbove()
847 && getEmphasisMarkBelow() == rCompare
.getEmphasisMarkBelow()
848 && getShadow() == rCompare
.getShadow());
855 // Added missing implementation. Decorations may (will) stick out of the text's
856 // inking area, so add them if needed
857 basegfx::B2DRange
TextDecoratedPortionPrimitive2D::getB2DRange(const geometry::ViewInformation2D
& rViewInformation
) const
859 const bool bDecoratedIsNeeded(
860 FONT_UNDERLINE_NONE
!= getFontOverline()
861 || FONT_UNDERLINE_NONE
!= getFontUnderline()
862 || FONT_STRIKEOUT_NONE
!= getFontStrikeout()
863 || FONT_EMPHASISMARK_NONE
!= getFontEmphasisMark()
864 || FONT_RELIEF_NONE
!= getFontRelief()
867 if(bDecoratedIsNeeded
)
869 // decoration is used, fallback to BasePrimitive2D::getB2DRange which uses
870 // the own local decomposition for computation and thus creates all necessary
872 return BasePrimitive2D::getB2DRange(rViewInformation
);
876 // no relevant decoration used, fallback to TextSimplePortionPrimitive2D::getB2DRange
877 return TextSimplePortionPrimitive2D::getB2DRange(rViewInformation
);
882 ImplPrimitrive2DIDBlock(TextDecoratedPortionPrimitive2D
, PRIMITIVE2D_ID_TEXTDECORATEDPORTIONPRIMITIVE2D
)
884 } // end of namespace primitive2d
885 } // end of namespace drawinglayer
887 //////////////////////////////////////////////////////////////////////////////