xref: /AOO41X/main/drawinglayer/source/primitive2d/textdecoratedprimitive2d.cxx (revision 8809db7a87f97847b57a57f4cd2b0104b2b83182)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_drawinglayer.hxx"
26 
27 #include <drawinglayer/primitive2d/textdecoratedprimitive2d.hxx>
28 #include <drawinglayer/primitive2d/textlayoutdevice.hxx>
29 #include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
30 #include <drawinglayer/attribute/strokeattribute.hxx>
31 #include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
32 #include <basegfx/matrix/b2dhommatrixtools.hxx>
33 #include <comphelper/processfactory.hxx>
34 #include <com/sun/star/i18n/WordType.hpp>
35 #include <drawinglayer/primitive2d/texteffectprimitive2d.hxx>
36 #include <drawinglayer/primitive2d/shadowprimitive2d.hxx>
37 #include <com/sun/star/i18n/XBreakIterator.hpp>
38 #include <drawinglayer/primitive2d/transformprimitive2d.hxx>
39 #include <drawinglayer/primitive2d/textlineprimitive2d.hxx>
40 #include <drawinglayer/primitive2d/textstrikeoutprimitive2d.hxx>
41 
42 //////////////////////////////////////////////////////////////////////////////
43 
44 namespace drawinglayer
45 {
46     namespace primitive2d
47     {
48         void TextDecoratedPortionPrimitive2D::impCreateGeometryContent(
49             std::vector< Primitive2DReference >& rTarget,
50             basegfx::tools::B2DHomMatrixBufferedOnDemandDecompose& rDecTrans,
51             const String& rText,
52             xub_StrLen aTextPosition,
53             xub_StrLen aTextLength,
54             const ::std::vector< double >& rDXArray,
55             const attribute::FontAttribute& rFontAttribute) const
56         {
57             // create the SimpleTextPrimitive needed in any case
58             rTarget.push_back(Primitive2DReference(
59                 new TextSimplePortionPrimitive2D(
60                     rDecTrans.getB2DHomMatrix(),
61                     rText,
62                     aTextPosition,
63                     aTextLength,
64                     rDXArray,
65                     rFontAttribute,
66                     getLocale(),
67                     getFontColor())));
68 
69             // see if something else needs to be done
70             const bool bOverlineUsed(TEXT_LINE_NONE != getFontOverline());
71             const bool bUnderlineUsed(TEXT_LINE_NONE != getFontUnderline());
72             const bool bStrikeoutUsed(TEXT_STRIKEOUT_NONE != getTextStrikeout());
73 
74             if(bUnderlineUsed || bStrikeoutUsed || bOverlineUsed)
75             {
76                 // common preparations
77                 TextLayouterDevice aTextLayouter;
78 
79                 // TextLayouterDevice is needed to get metrics for text decorations like
80                 // underline/strikeout/emphasis marks from it. For setup, the font size is needed
81                 aTextLayouter.setFontAttribute(
82                     getFontAttribute(),
83                     rDecTrans.getScale().getX(),
84                     rDecTrans.getScale().getY(),
85                     getLocale());
86 
87                 // get text width
88                 double fTextWidth(0.0);
89 
90                 if(rDXArray.empty())
91                 {
92                     fTextWidth = aTextLayouter.getTextWidth(rText, aTextPosition, aTextLength);
93                 }
94                 else
95                 {
96                     fTextWidth = rDXArray.back() * rDecTrans.getScale().getX();
97                     const double fFontScaleX(rDecTrans.getScale().getX());
98 
99                     if(!basegfx::fTools::equal(fFontScaleX, 1.0)
100                         && !basegfx::fTools::equalZero(fFontScaleX))
101                     {
102                         // need to take FontScaling out of the DXArray
103                         fTextWidth /= fFontScaleX;
104                     }
105                 }
106 
107                 if(bOverlineUsed)
108                 {
109                     // create primitive geometry for overline
110                     rTarget.push_back(Primitive2DReference(
111                         new TextLinePrimitive2D(
112                             rDecTrans.getB2DHomMatrix(),
113                             fTextWidth,
114                             aTextLayouter.getOverlineOffset(),
115                             aTextLayouter.getOverlineHeight(),
116                             getFontOverline(),
117                             getOverlineColor())));
118                 }
119 
120                 if(bUnderlineUsed)
121                 {
122                     // create primitive geometry for underline
123                     rTarget.push_back(Primitive2DReference(
124                         new TextLinePrimitive2D(
125                             rDecTrans.getB2DHomMatrix(),
126                             fTextWidth,
127                             aTextLayouter.getUnderlineOffset(),
128                             aTextLayouter.getUnderlineHeight(),
129                             getFontUnderline(),
130                             getTextlineColor())));
131                 }
132 
133                 if(bStrikeoutUsed)
134                 {
135                     // create primitive geometry for strikeout
136                     if(TEXT_STRIKEOUT_SLASH == getTextStrikeout() || TEXT_STRIKEOUT_X == getTextStrikeout())
137                     {
138                         // strikeout with character
139                         const sal_Unicode aStrikeoutChar(TEXT_STRIKEOUT_SLASH == getTextStrikeout() ? '/' : 'X');
140 
141                         rTarget.push_back(Primitive2DReference(
142                             new TextCharacterStrikeoutPrimitive2D(
143                                 rDecTrans.getB2DHomMatrix(),
144                                 fTextWidth,
145                                 getFontColor(),
146                                 aStrikeoutChar,
147                                 getFontAttribute(),
148                                 getLocale())));
149                     }
150                     else
151                     {
152                         // strikeout with geometry
153                         rTarget.push_back(Primitive2DReference(
154                             new TextGeometryStrikeoutPrimitive2D(
155                                 rDecTrans.getB2DHomMatrix(),
156                                 fTextWidth,
157                                 getFontColor(),
158                                 aTextLayouter.getUnderlineHeight(),
159                                 aTextLayouter.getStrikeoutOffset(),
160                                 getTextStrikeout())));
161                     }
162                 }
163             }
164 
165             // TODO: Handle Font Emphasis Above/Below
166         }
167 
168         void TextDecoratedPortionPrimitive2D::impCorrectTextBoundary(::com::sun::star::i18n::Boundary& rNextWordBoundary) const
169         {
170             // truncate aNextWordBoundary to min/max possible values. This is necessary since the word start may be
171             // before/after getTextPosition() when a long string is the content and getTextPosition()
172             // is right inside a word. Same for end.
173             const sal_Int32 aMinPos(static_cast< sal_Int32 >(getTextPosition()));
174             const sal_Int32 aMaxPos(aMinPos + static_cast< sal_Int32 >(getTextLength()));
175 
176             if(rNextWordBoundary.startPos < aMinPos)
177             {
178                 rNextWordBoundary.startPos = aMinPos;
179             }
180             else if(rNextWordBoundary.startPos > aMaxPos)
181             {
182                 rNextWordBoundary.startPos = aMaxPos;
183             }
184 
185             if(rNextWordBoundary.endPos < aMinPos)
186             {
187                 rNextWordBoundary.endPos = aMinPos;
188             }
189             else if(rNextWordBoundary.endPos > aMaxPos)
190             {
191                 rNextWordBoundary.endPos = aMaxPos;
192             }
193         }
194 
195         void TextDecoratedPortionPrimitive2D::impSplitSingleWords(
196             std::vector< Primitive2DReference >& rTarget,
197             basegfx::tools::B2DHomMatrixBufferedOnDemandDecompose& rDecTrans) const
198         {
199             // break iterator support
200             // made static so it only needs to be fetched once, even with many single
201             // constructed VclMetafileProcessor2D. It's still incarnated on demand,
202             // but exists for OOo runtime now by purpose.
203             static ::com::sun::star::uno::Reference< ::com::sun::star::i18n::XBreakIterator > xLocalBreakIterator;
204 
205             if(!xLocalBreakIterator.is())
206             {
207                 ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > xMSF(::comphelper::getProcessServiceFactory());
208                 xLocalBreakIterator.set(xMSF->createInstance(rtl::OUString::createFromAscii("com.sun.star.i18n.BreakIterator")), ::com::sun::star::uno::UNO_QUERY);
209             }
210 
211             if(xLocalBreakIterator.is() && getTextLength())
212             {
213                 // init word iterator, get first word and truncate to possibilities
214                 ::com::sun::star::i18n::Boundary aNextWordBoundary(xLocalBreakIterator->getWordBoundary(
215                     getText(), getTextPosition(), getLocale(), ::com::sun::star::i18n::WordType::ANYWORD_IGNOREWHITESPACES, sal_True));
216 
217                 if(aNextWordBoundary.endPos == getTextPosition())
218                 {
219                     // backward hit, force next word
220                     aNextWordBoundary = xLocalBreakIterator->getWordBoundary(
221                         getText(), getTextPosition() + 1, getLocale(), ::com::sun::star::i18n::WordType::ANYWORD_IGNOREWHITESPACES, sal_True);
222                 }
223 
224                 impCorrectTextBoundary(aNextWordBoundary);
225 
226                 // prepare new font attributes WITHOUT outline
227                 const attribute::FontAttribute aNewFontAttribute(
228                     getFontAttribute().getFamilyName(),
229                     getFontAttribute().getStyleName(),
230                     getFontAttribute().getWeight(),
231                     getFontAttribute().getSymbol(),
232                     getFontAttribute().getVertical(),
233                     getFontAttribute().getItalic(),
234                     false,             // no outline anymore, handled locally
235                     getFontAttribute().getRTL(),
236                     getFontAttribute().getBiDiStrong());
237 
238                 if(aNextWordBoundary.startPos == getTextPosition() && aNextWordBoundary.endPos == getTextLength())
239                 {
240                     // it IS only a single word, handle as one word
241                     impCreateGeometryContent(rTarget, rDecTrans, getText(), getTextPosition(), getTextLength(), getDXArray(), aNewFontAttribute);
242                 }
243                 else
244                 {
245                     // prepare TextLayouter
246                     const bool bNoDXArray(getDXArray().empty());
247                     TextLayouterDevice aTextLayouter;
248 
249                     if(bNoDXArray)
250                     {
251                         // ..but only completely when no DXArray
252                         aTextLayouter.setFontAttribute(
253                             getFontAttribute(),
254                             rDecTrans.getScale().getX(),
255                             rDecTrans.getScale().getY(),
256                             getLocale());
257                     }
258 
259                     // do iterate over single words
260                     while(aNextWordBoundary.startPos != aNextWordBoundary.endPos)
261                     {
262                         // prepare values for new portion
263                         const xub_StrLen nNewTextStart(static_cast< xub_StrLen >(aNextWordBoundary.startPos));
264                         const xub_StrLen nNewTextEnd(static_cast< xub_StrLen >(aNextWordBoundary.endPos));
265 
266                         // prepare transform for the single word
267                         basegfx::B2DHomMatrix aNewTransform;
268                         ::std::vector< double > aNewDXArray;
269                         const bool bNewStartIsNotOldStart(nNewTextStart > getTextPosition());
270 
271                         if(!bNoDXArray)
272                         {
273                             // prepare new DXArray for the single word
274                             aNewDXArray = ::std::vector< double >(
275                                 getDXArray().begin() + static_cast< sal_uInt32 >(nNewTextStart - getTextPosition()),
276                                 getDXArray().begin() + static_cast< sal_uInt32 >(nNewTextEnd - getTextPosition()));
277                         }
278 
279                         if(bNewStartIsNotOldStart)
280                         {
281                             // needs to be moved to a new start position
282                             double fOffset(0.0);
283 
284                             if(bNoDXArray)
285                             {
286                                 // evaluate using TextLayouter
287                                 fOffset = aTextLayouter.getTextWidth(getText(), getTextPosition(), nNewTextStart);
288                             }
289                             else
290                             {
291                                 // get from DXArray
292                                 const sal_uInt32 nIndex(static_cast< sal_uInt32 >(nNewTextStart - getTextPosition()));
293                                 fOffset = getDXArray()[nIndex - 1];
294                             }
295 
296                             // need offset without FontScale for building the new transformation. The
297                             // new transformation will be multiplied with the current text transformation
298                             // so FontScale would be double
299                             double fOffsetNoScale(fOffset);
300                             const double fFontScaleX(rDecTrans.getScale().getX());
301 
302                             if(!basegfx::fTools::equal(fFontScaleX, 1.0)
303                                 && !basegfx::fTools::equalZero(fFontScaleX))
304                             {
305                                 fOffsetNoScale /= fFontScaleX;
306                             }
307 
308                             // apply needed offset to transformation
309                             aNewTransform.translate(fOffsetNoScale, 0.0);
310 
311                             if(!bNoDXArray)
312                             {
313                                 // DXArray values need to be corrected with the offset, too. Here,
314                                 // take the scaled offset since the DXArray is scaled
315                                 const sal_uInt32 nArraySize(aNewDXArray.size());
316 
317                                 for(sal_uInt32 a(0); a < nArraySize; a++)
318                                 {
319                                     aNewDXArray[a] -= fOffset;
320                                 }
321                             }
322                         }
323 
324                         // add text transformation to new transformation
325                         aNewTransform *= rDecTrans.getB2DHomMatrix();
326 
327                         // create geometry content for the single word. Do not forget
328                         // to use the new transformation
329                         basegfx::tools::B2DHomMatrixBufferedOnDemandDecompose aDecTrans(aNewTransform);
330 
331                         impCreateGeometryContent(rTarget, aDecTrans, getText(), nNewTextStart,
332                             nNewTextEnd - nNewTextStart, aNewDXArray, aNewFontAttribute);
333 
334                         if(aNextWordBoundary.endPos >= getTextPosition() + getTextLength())
335                         {
336                             // end reached
337                             aNextWordBoundary.startPos = aNextWordBoundary.endPos;
338                         }
339                         else
340                         {
341                             // get new word portion
342                             const sal_Int32 nLastEndPos(aNextWordBoundary.endPos);
343 
344                             aNextWordBoundary = xLocalBreakIterator->getWordBoundary(
345                                 getText(), aNextWordBoundary.endPos, getLocale(),
346                                 ::com::sun::star::i18n::WordType::ANYWORD_IGNOREWHITESPACES, sal_True);
347 
348                             if(nLastEndPos == aNextWordBoundary.endPos)
349                             {
350                                 // backward hit, force next word
351                                 aNextWordBoundary = xLocalBreakIterator->getWordBoundary(
352                                     getText(), nLastEndPos + 1, getLocale(),
353                                     ::com::sun::star::i18n::WordType::ANYWORD_IGNOREWHITESPACES, sal_True);
354                             }
355 
356                             impCorrectTextBoundary(aNextWordBoundary);
357                         }
358                     }
359                 }
360             }
361         }
362 
363         Primitive2DSequence TextDecoratedPortionPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const
364         {
365             std::vector< Primitive2DReference > aNewPrimitives;
366             basegfx::tools::B2DHomMatrixBufferedOnDemandDecompose aDecTrans(getTextTransform());
367             Primitive2DSequence aRetval;
368 
369             // create basic geometry such as SimpleTextPrimitive, Overline, Underline,
370             // Strikeout, etc...
371             if(getWordLineMode())
372             {
373                 // support for single word mode
374                 impSplitSingleWords(aNewPrimitives, aDecTrans);
375             }
376             else
377             {
378                 // prepare new font attributes WITHOUT outline
379                 const attribute::FontAttribute aNewFontAttribute(
380                     getFontAttribute().getFamilyName(),
381                     getFontAttribute().getStyleName(),
382                     getFontAttribute().getWeight(),
383                     getFontAttribute().getSymbol(),
384                     getFontAttribute().getVertical(),
385                     getFontAttribute().getItalic(),
386                     false,             // no outline anymore, handled locally
387                     getFontAttribute().getRTL(),
388                     getFontAttribute().getBiDiStrong());
389 
390                 // handle as one word
391                 impCreateGeometryContent(aNewPrimitives, aDecTrans, getText(), getTextPosition(), getTextLength(), getDXArray(), aNewFontAttribute);
392             }
393 
394             // convert to Primitive2DSequence
395             const sal_uInt32 nMemberCount(aNewPrimitives.size());
396 
397             if(nMemberCount)
398             {
399                 aRetval.realloc(nMemberCount);
400 
401                 for(sal_uInt32 a(0); a < nMemberCount; a++)
402                 {
403                     aRetval[a] = aNewPrimitives[a];
404                 }
405             }
406 
407             // Handle Shadow, Outline and TextRelief
408             if(aRetval.hasElements())
409             {
410                 // outline AND shadow depend on NO TextRelief (see dialog)
411                 const bool bHasTextRelief(TEXT_RELIEF_NONE != getTextRelief());
412                 const bool bHasShadow(!bHasTextRelief && getShadow());
413                 const bool bHasOutline(!bHasTextRelief && getFontAttribute().getOutline());
414 
415                 if(bHasShadow || bHasTextRelief || bHasOutline)
416                 {
417                     Primitive2DReference aShadow;
418 
419                     if(bHasShadow)
420                     {
421                         // create shadow with current content (in aRetval). Text shadow
422                         // is constant, relative to font size, rotated with the text and has a
423                         // constant color.
424                         // shadow parameter values
425                         static double fFactor(1.0 / 24.0);
426                         const double fTextShadowOffset(aDecTrans.getScale().getY() * fFactor);
427                         static basegfx::BColor aShadowColor(0.3, 0.3, 0.3);
428 
429                         // preapare shadow transform matrix
430                         const basegfx::B2DHomMatrix aShadowTransform(basegfx::tools::createTranslateB2DHomMatrix(
431                             fTextShadowOffset, fTextShadowOffset));
432 
433                         // create shadow primitive
434                         aShadow = Primitive2DReference(new ShadowPrimitive2D(
435                             aShadowTransform,
436                             aShadowColor,
437                             aRetval));
438                     }
439 
440                     if(bHasTextRelief)
441                     {
442                         // create emboss using an own helper primitive since this will
443                         // be view-dependent
444                         const basegfx::BColor aBBlack(0.0, 0.0, 0.0);
445                         const bool bDefaultTextColor(aBBlack == getFontColor());
446                         TextEffectStyle2D aTextEffectStyle2D(TEXTEFFECTSTYLE2D_RELIEF_EMBOSSED);
447 
448                         if(bDefaultTextColor)
449                         {
450                             if(TEXT_RELIEF_ENGRAVED == getTextRelief())
451                             {
452                                 aTextEffectStyle2D = TEXTEFFECTSTYLE2D_RELIEF_ENGRAVED_DEFAULT;
453                             }
454                             else
455                             {
456                                 aTextEffectStyle2D = TEXTEFFECTSTYLE2D_RELIEF_EMBOSSED_DEFAULT;
457                             }
458                         }
459                         else
460                         {
461                             if(TEXT_RELIEF_ENGRAVED == getTextRelief())
462                             {
463                                 aTextEffectStyle2D = TEXTEFFECTSTYLE2D_RELIEF_ENGRAVED;
464                             }
465                             else
466                             {
467                                 aTextEffectStyle2D = TEXTEFFECTSTYLE2D_RELIEF_EMBOSSED;
468                             }
469                         }
470 
471                         Primitive2DReference aNewTextEffect(new TextEffectPrimitive2D(
472                             aRetval,
473                             aDecTrans.getTranslate(),
474                             aDecTrans.getRotate(),
475                             aTextEffectStyle2D));
476                         aRetval = Primitive2DSequence(&aNewTextEffect, 1);
477                     }
478                     else if(bHasOutline)
479                     {
480                         // create outline using an own helper primitive since this will
481                         // be view-dependent
482                         Primitive2DReference aNewTextEffect(new TextEffectPrimitive2D(
483                             aRetval,
484                             aDecTrans.getTranslate(),
485                             aDecTrans.getRotate(),
486                             TEXTEFFECTSTYLE2D_OUTLINE));
487                         aRetval = Primitive2DSequence(&aNewTextEffect, 1);
488                     }
489 
490                     if(aShadow.is())
491                     {
492                         // put shadow in front if there is one to paint timely before
493                         // but placed behind content
494                         const Primitive2DSequence aContent(aRetval);
495                         aRetval = Primitive2DSequence(&aShadow, 1);
496                         appendPrimitive2DSequenceToPrimitive2DSequence(aRetval, aContent);
497                     }
498                 }
499             }
500 
501             return aRetval;
502         }
503 
504         TextDecoratedPortionPrimitive2D::TextDecoratedPortionPrimitive2D(
505 
506             // TextSimplePortionPrimitive2D parameters
507             const basegfx::B2DHomMatrix& rNewTransform,
508             const String& rText,
509             xub_StrLen aTextPosition,
510             xub_StrLen aTextLength,
511             const ::std::vector< double >& rDXArray,
512             const attribute::FontAttribute& rFontAttribute,
513             const ::com::sun::star::lang::Locale& rLocale,
514             const basegfx::BColor& rFontColor,
515 
516             // local parameters
517             const basegfx::BColor& rOverlineColor,
518             const basegfx::BColor& rTextlineColor,
519             TextLine eFontOverline,
520             TextLine eFontUnderline,
521             bool bUnderlineAbove,
522             TextStrikeout eTextStrikeout,
523             bool bWordLineMode,
524             TextEmphasisMark eTextEmphasisMark,
525             bool bEmphasisMarkAbove,
526             bool bEmphasisMarkBelow,
527             TextRelief eTextRelief,
528             bool bShadow)
529         :   TextSimplePortionPrimitive2D(rNewTransform, rText, aTextPosition, aTextLength, rDXArray, rFontAttribute, rLocale, rFontColor),
530             maOverlineColor(rOverlineColor),
531             maTextlineColor(rTextlineColor),
532             meFontOverline(eFontOverline),
533             meFontUnderline(eFontUnderline),
534             meTextStrikeout(eTextStrikeout),
535             meTextEmphasisMark(eTextEmphasisMark),
536             meTextRelief(eTextRelief),
537             mbUnderlineAbove(bUnderlineAbove),
538             mbWordLineMode(bWordLineMode),
539             mbEmphasisMarkAbove(bEmphasisMarkAbove),
540             mbEmphasisMarkBelow(bEmphasisMarkBelow),
541             mbShadow(bShadow)
542         {
543         }
544 
545         bool TextDecoratedPortionPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
546         {
547             if(TextSimplePortionPrimitive2D::operator==(rPrimitive))
548             {
549                 const TextDecoratedPortionPrimitive2D& rCompare = (TextDecoratedPortionPrimitive2D&)rPrimitive;
550 
551                 return (getOverlineColor() == rCompare.getOverlineColor()
552                     && getTextlineColor() == rCompare.getTextlineColor()
553                     && getFontOverline() == rCompare.getFontOverline()
554                     && getFontUnderline() == rCompare.getFontUnderline()
555                     && getTextStrikeout() == rCompare.getTextStrikeout()
556                     && getTextEmphasisMark() == rCompare.getTextEmphasisMark()
557                     && getTextRelief() == rCompare.getTextRelief()
558                     && getUnderlineAbove() == rCompare.getUnderlineAbove()
559                     && getWordLineMode() == rCompare.getWordLineMode()
560                     && getEmphasisMarkAbove() == rCompare.getEmphasisMarkAbove()
561                     && getEmphasisMarkBelow() == rCompare.getEmphasisMarkBelow()
562                     && getShadow() == rCompare.getShadow());
563             }
564 
565             return false;
566         }
567 
568         // #i96475#
569         // Added missing implementation. Decorations may (will) stick out of the text's
570         // inking area, so add them if needed
571         basegfx::B2DRange TextDecoratedPortionPrimitive2D::getB2DRange(const geometry::ViewInformation2D& rViewInformation) const
572         {
573             const bool bDecoratedIsNeeded(
574                 TEXT_LINE_NONE != getFontOverline()
575              || TEXT_LINE_NONE != getFontUnderline()
576              || TEXT_STRIKEOUT_NONE != getTextStrikeout()
577              || TEXT_EMPHASISMARK_NONE != getTextEmphasisMark()
578              || TEXT_RELIEF_NONE != getTextRelief()
579              || getShadow());
580 
581             if(bDecoratedIsNeeded)
582             {
583                 // decoration is used, fallback to BufferedDecompositionPrimitive2D::getB2DRange which uses
584                 // the own local decomposition for computation and thus creates all necessary
585                 // geometric objects
586                 return BufferedDecompositionPrimitive2D::getB2DRange(rViewInformation);
587             }
588             else
589             {
590                 // no relevant decoration used, fallback to TextSimplePortionPrimitive2D::getB2DRange
591                 return TextSimplePortionPrimitive2D::getB2DRange(rViewInformation);
592             }
593         }
594 
595         // provide unique ID
596         ImplPrimitrive2DIDBlock(TextDecoratedPortionPrimitive2D, PRIMITIVE2D_ID_TEXTDECORATEDPORTIONPRIMITIVE2D)
597 
598     } // end of namespace primitive2d
599 } // end of namespace drawinglayer
600 
601 //////////////////////////////////////////////////////////////////////////////
602 // eof
603