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