update dev300-m58
[ooovba.git] / drawinglayer / source / primitive2d / textdecoratedprimitive2d.cxx
blob6a2d66a5d359920c176c6a44e12510b525461b68
1 /*************************************************************************
3 * OpenOffice.org - a multi-platform office productivity suite
5 * $RCSfile: textdecoratedprimitive2d.cxx,v $
7 * $Revision: 1.12 $
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,
32 * MA 02111-1307 USA
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
56 namespace primitive2d
58 void TextDecoratedPortionPrimitive2D::impCreateTextLine(
59 std::vector< Primitive2DReference >& rTarget,
60 basegfx::DecomposedB2DHomMatrixContainer& rDecTrans,
61 const basegfx::B2DHomMatrix &rUnscaledTransform,
62 FontUnderline eLineStyle,
63 double fLineOffset,
64 double fLineHeight,
65 double fLineWidth,
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
80 switch(eLineStyle)
82 default: // case FONT_UNDERLINE_SINGLE:
84 break;
86 case FONT_UNDERLINE_DOUBLE:
88 bDoubleLine = true;
89 break;
91 case FONT_UNDERLINE_DOTTED:
93 pDotDashArray = aDottedArray;
94 break;
96 case FONT_UNDERLINE_DASH:
98 pDotDashArray = aDashedArray;
99 break;
101 case FONT_UNDERLINE_LONGDASH:
103 pDotDashArray = aLongDashArray;
104 break;
106 case FONT_UNDERLINE_DASHDOT:
108 pDotDashArray = aDotDashArray;
109 break;
111 case FONT_UNDERLINE_DASHDOTDOT:
113 pDotDashArray = aDashDotDotArray;
114 break;
116 case FONT_UNDERLINE_SMALLWAVE:
118 bWaveLine = true;
119 break;
121 case FONT_UNDERLINE_WAVE:
123 bWaveLine = true;
124 break;
126 case FONT_UNDERLINE_DOUBLEWAVE:
128 bDoubleLine = true;
129 bWaveLine = true;
130 break;
132 case FONT_UNDERLINE_BOLD:
134 bBoldLine = true;
135 break;
137 case FONT_UNDERLINE_BOLDDOTTED:
139 bBoldLine = true;
140 pDotDashArray = aDottedArray;
141 break;
143 case FONT_UNDERLINE_BOLDDASH:
145 bBoldLine = true;
146 pDotDashArray = aDashedArray;
147 break;
149 case FONT_UNDERLINE_BOLDLONGDASH:
151 bBoldLine = true;
152 pDotDashArray = aLongDashArray;
153 break;
155 case FONT_UNDERLINE_BOLDDASHDOT:
157 bBoldLine = true;
158 pDotDashArray = aDotDashArray;
159 break;
161 case FONT_UNDERLINE_BOLDDASHDOTDOT:
163 bBoldLine = true;
164 pDotDashArray = aDashDotDotArray;
165 break;
167 case FONT_UNDERLINE_BOLDWAVE:
169 bWaveLine = true;
170 bBoldLine = true;
171 break;
175 if(bBoldLine)
177 fLineHeight *= 2.0;
180 if(bDoubleLine)
182 fLineOffset -= 0.50 * fLineHeight;
183 fLineHeight *= 0.64;
186 if(bWaveLine)
188 eLineJoin = basegfx::B2DLINEJOIN_ROUND;
189 fLineHeight *= 0.25;
192 // prepare Line and Stroke Attributes
193 const attribute::LineAttribute aLineAttribute(rLineColor, fLineHeight, eLineJoin);
194 attribute::StrokeAttribute aStrokeAttribute;
196 if(pDotDashArray)
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);
216 if(bWaveLine)
218 double fWaveWidth(10.6 * fLineHeight);
220 if(FONT_UNDERLINE_SMALLWAVE == eLineStyle)
222 fWaveWidth *= 0.7;
224 else if(FONT_UNDERLINE_WAVE == eLineStyle)
226 // extra multiply to get the same WaveWidth as with the bold version
227 fWaveWidth *= 2.0;
230 aNewPrimitive = Primitive2DReference(new PolygonWavePrimitive2D(aLine, aLineAttribute, aStrokeAttribute, fWaveWidth, fWaveWidth * 0.5));
232 else
234 aNewPrimitive = Primitive2DReference(new PolygonStrokePrimitive2D(aLine, aLineAttribute, aStrokeAttribute));
237 // add primitive
238 rTarget.push_back(aNewPrimitive);
240 if(bDoubleLine)
242 // double line, create 2nd primitive with offset using TransformPrimitive based on
243 // already created NewPrimitive
244 double fLineDist(2.3 * fLineHeight);
246 if(bWaveLine)
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,
273 const String& rText,
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(),
282 rText,
283 aTextPosition,
284 aTextLength,
285 rDXArray,
286 rFontAttributes,
287 getLocale(),
288 getFontColor())));
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());
310 // get text width
311 double fTextWidth(0.0);
313 if(rDXArray.empty())
315 fTextWidth = aTextLayouter.getTextWidth(rText, aTextPosition, aTextLength);
317 else
319 fTextWidth = rDXArray.back() * rDecTrans.getScale().getX();
322 if(bOverlineUsed)
324 // create primitive geometry for overline
325 impCreateTextLine(rTarget, rDecTrans, aUnscaledTransform, getFontOverline(), aTextLayouter.getOverlineOffset(),
326 aTextLayouter.getOverlineHeight(), fTextWidth, getOverlineColor());
329 if(bUnderlineUsed)
331 // create primitive geometry for underline
332 impCreateTextLine(rTarget, rDecTrans, aUnscaledTransform, getFontUnderline(), aTextLayouter.getUnderlineOffset(),
333 aTextLayouter.getUnderlineHeight(), fTextWidth, getTextlineColor());
336 if(bStrikeoutUsed)
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(),
361 aStrikeoutString,
363 aStrikeoutString.Len(),
364 aDXArray,
365 rFontAttributes,
366 getLocale(),
367 getFontColor())));
369 else
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:
381 break;
383 case primitive2d::FONT_STRIKEOUT_DOUBLE:
385 bDoubleLine = true;
386 break;
388 case primitive2d::FONT_STRIKEOUT_BOLD:
390 fStrikeoutHeight *= 2.0;
391 break;
395 if(bDoubleLine)
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));
411 // add primitive
412 rTarget.push_back(aNewPrimitive);
414 if(bDoubleLine)
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)
494 // #i96474#
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);
520 else
522 // prepare TextLayouter
523 const bool bNoDXArray(getDXArray().empty());
524 TextLayouterDevice aTextLayouter;
526 if(bNoDXArray)
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());
544 if(!bNoDXArray)
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
555 double fOffset(0.0);
557 if(bNoDXArray)
559 // evaluate using TextLayouter
560 fOffset = aTextLayouter.getTextWidth(getText(), getTextPosition(), nNewTextStart);
562 else
564 // get from DXArray
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);
572 if(!bNoDXArray)
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,
612 // Strikeout, etc...
613 if(getWordLineMode())
615 // support for single word mode
616 impSplitSingleWords(aNewPrimitives, aDecTrans);
618 else
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());
639 if(nMemberCount)
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;
661 if(bHasShadow)
663 // create shadow with current content (in aRetval). Text shadow
664 // is constant, relative to font size, rotated with the text and has a
665 // constant color.
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(
677 aShadowTransform,
678 aShadowColor,
679 aRetval));
682 if(bHasFontRelief)
684 // create emboss using an own helper primitive since this will
685 // be view-dependent
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;
696 else
698 aTextEffectStyle2D = TEXTEFFECTSTYLE2D_RELIEF_EMBOSSED_DEFAULT;
701 else
703 if(FONT_RELIEF_ENGRAVED == getFontRelief())
705 aTextEffectStyle2D = TEXTEFFECTSTYLE2D_RELIEF_ENGRAVED;
707 else
709 aTextEffectStyle2D = TEXTEFFECTSTYLE2D_RELIEF_EMBOSSED;
713 Primitive2DReference aNewTextEffect(new TextEffectPrimitive2D(
714 aRetval,
715 aDecTrans.getTranslate(),
716 aDecTrans.getRotate(),
717 aTextEffectStyle2D));
718 aRetval = Primitive2DSequence(&aNewTextEffect, 1);
720 else if(bHasOutline)
722 // create outline using an own helper primitive since this will
723 // be view-dependent
724 Primitive2DReference aNewTextEffect(new TextEffectPrimitive2D(
725 aRetval,
726 aDecTrans.getTranslate(),
727 aDecTrans.getRotate(),
728 TEXTEFFECTSTYLE2D_OUTLINE));
729 aRetval = Primitive2DSequence(&aNewTextEffect, 1);
732 if(aShadow.is())
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);
743 return aRetval;
746 TextDecoratedPortionPrimitive2D::TextDecoratedPortionPrimitive2D(
748 // TextSimplePortionPrimitive2D parameters
749 const basegfx::B2DHomMatrix& rNewTransform,
750 const String& rText,
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,
758 // local parameters
759 const basegfx::BColor& rOverlineColor,
760 const basegfx::BColor& rTextlineColor,
761 FontUnderline eFontOverline,
762 FontUnderline eFontUnderline,
763 bool bUnderlineAbove,
764 FontStrikeout eFontStrikeout,
765 bool bWordLineMode,
766 FontEmphasisMark eFontEmphasisMark,
767 bool bEmphasisMarkAbove,
768 bool bEmphasisMarkBelow,
769 FontRelief eFontRelief,
770 bool bShadow)
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),
783 mbShadow(bShadow)
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());
807 return false;
810 // #i96475#
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()
821 || getShadow());
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
827 // geometric objects
828 return BasePrimitive2D::getB2DRange(rViewInformation);
830 else
832 // no relevant decoration used, fallback to TextSimplePortionPrimitive2D::getB2DRange
833 return TextSimplePortionPrimitive2D::getB2DRange(rViewInformation);
837 // provide unique ID
838 ImplPrimitrive2DIDBlock(TextDecoratedPortionPrimitive2D, PRIMITIVE2D_ID_TEXTDECORATEDPORTIONPRIMITIVE2D)
840 } // end of namespace primitive2d
841 } // end of namespace drawinglayer
843 //////////////////////////////////////////////////////////////////////////////
844 // eof