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/processor2d/vclprocessor2d.hxx> 28 #include <drawinglayer/primitive2d/textprimitive2d.hxx> 29 #include <drawinglayer/primitive2d/textdecoratedprimitive2d.hxx> 30 #include <tools/debug.hxx> 31 #include <vcl/outdev.hxx> 32 #include <drawinglayer/primitive2d/polygonprimitive2d.hxx> 33 #include <drawinglayer/primitive2d/bitmapprimitive2d.hxx> 34 #include <vclhelperbitmaptransform.hxx> 35 #include <basegfx/polygon/b2dpolygontools.hxx> 36 #include <vclhelperbitmaprender.hxx> 37 #include <drawinglayer/attribute/sdrfillgraphicattribute.hxx> 38 #include <drawinglayer/primitive2d/fillgraphicprimitive2d.hxx> 39 #include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx> 40 #include <vclhelpergradient.hxx> 41 #include <drawinglayer/primitive2d/metafileprimitive2d.hxx> 42 #include <drawinglayer/primitive2d/maskprimitive2d.hxx> 43 #include <basegfx/polygon/b2dpolypolygontools.hxx> 44 #include <vclhelperbufferdevice.hxx> 45 #include <drawinglayer/primitive2d/modifiedcolorprimitive2d.hxx> 46 #include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx> 47 #include <drawinglayer/primitive2d/transparenceprimitive2d.hxx> 48 #include <drawinglayer/primitive2d/transformprimitive2d.hxx> 49 #include <drawinglayer/primitive2d/markerarrayprimitive2d.hxx> 50 #include <drawinglayer/primitive2d/pointarrayprimitive2d.hxx> 51 #include <drawinglayer/primitive2d/wrongspellprimitive2d.hxx> 52 #include <svl/ctloptions.hxx> 53 #include <vcl/svapp.hxx> 54 #include <drawinglayer/primitive2d/pagepreviewprimitive2d.hxx> 55 #include <tools/diagnose_ex.h> 56 #include <vcl/metric.hxx> 57 #include <drawinglayer/primitive2d/textenumsprimitive2d.hxx> 58 #include <drawinglayer/primitive2d/epsprimitive2d.hxx> 59 #include <drawinglayer/primitive2d/svggradientprimitive2d.hxx> 60 #include <basegfx/color/bcolor.hxx> 61 #include <basegfx/matrix/b2dhommatrixtools.hxx> 62 #include <vcl/graph.hxx> 63 64 ////////////////////////////////////////////////////////////////////////////// 65 // control support 66 67 #include <com/sun/star/awt/XWindow2.hpp> 68 #include <com/sun/star/awt/PosSize.hpp> 69 #include <com/sun/star/awt/XView.hpp> 70 #include <drawinglayer/primitive2d/controlprimitive2d.hxx> 71 #include <drawinglayer/primitive2d/textlayoutdevice.hxx> 72 73 ////////////////////////////////////////////////////////////////////////////// 74 // for test, can be removed again 75 76 #include <basegfx/polygon/b2dpolygonclipper.hxx> 77 #include <basegfx/polygon/b2dtrapezoid.hxx> 78 79 ////////////////////////////////////////////////////////////////////////////// 80 81 using namespace com::sun::star; 82 83 ////////////////////////////////////////////////////////////////////////////// 84 85 namespace 86 { 87 sal_uInt32 calculateStepsForSvgGradient(const basegfx::BColor& rColorA, const basegfx::BColor& rColorB, double fDelta, double fDiscreteUnit) 88 { 89 // use color distance, assume to do every color step 90 sal_uInt32 nSteps(basegfx::fround(rColorA.getDistance(rColorB) * 255.0)); 91 92 if(nSteps) 93 { 94 // calc discrete length to change color each disctete unit (pixel) 95 const sal_uInt32 nDistSteps(basegfx::fround(fDelta / fDiscreteUnit)); 96 97 nSteps = std::min(nSteps, nDistSteps); 98 } 99 100 // reduce quality to 3 discrete units or every 3rd color step for rendering 101 nSteps /= 2; 102 103 // roughly cut when too big or too small (not full quality, reduce complexity) 104 nSteps = std::min(nSteps, sal_uInt32(255)); 105 nSteps = std::max(nSteps, sal_uInt32(1)); 106 107 return nSteps; 108 } 109 } // end of anonymous namespace 110 111 ////////////////////////////////////////////////////////////////////////////// 112 113 namespace drawinglayer 114 { 115 namespace processor2d 116 { 117 ////////////////////////////////////////////////////////////////////////////// 118 // UNO class usages 119 using ::com::sun::star::uno::Reference; 120 using ::com::sun::star::uno::UNO_QUERY; 121 using ::com::sun::star::uno::UNO_QUERY_THROW; 122 using ::com::sun::star::uno::Exception; 123 using ::com::sun::star::awt::XView; 124 using ::com::sun::star::awt::XGraphics; 125 using ::com::sun::star::awt::XWindow; 126 using ::com::sun::star::awt::PosSize::POSSIZE; 127 128 ////////////////////////////////////////////////////////////////////////////// 129 // rendering support 130 131 // directdraw of text simple portion or decorated portion primitive. When decorated, all the extra 132 // information is translated to VCL parameters and set at the font. 133 // Acceptance is restricted to no shearing and positive scaling in X and Y (no font mirroring 134 // for VCL) 135 void VclProcessor2D::RenderTextSimpleOrDecoratedPortionPrimitive2D(const primitive2d::TextSimplePortionPrimitive2D& rTextCandidate) 136 { 137 // decompose matrix to have position and size of text 138 basegfx::B2DHomMatrix aLocalTransform(maCurrentTransformation * rTextCandidate.getTextTransform()); 139 basegfx::B2DVector aFontScaling, aTranslate; 140 double fRotate, fShearX; 141 aLocalTransform.decompose(aFontScaling, aTranslate, fRotate, fShearX); 142 bool bPrimitiveAccepted(false); 143 144 if(basegfx::fTools::equalZero(fShearX)) 145 { 146 if(basegfx::fTools::less(aFontScaling.getX(), 0.0) && basegfx::fTools::less(aFontScaling.getY(), 0.0)) 147 { 148 // handle special case: If scale is negative in (x,y) (3rd quadrant), it can 149 // be expressed as rotation by PI. Use this since the Font rendering will not 150 // apply the negative scales in any form 151 aFontScaling = basegfx::absolute(aFontScaling); 152 fRotate += F_PI; 153 } 154 155 if(basegfx::fTools::more(aFontScaling.getX(), 0.0) && basegfx::fTools::more(aFontScaling.getY(), 0.0)) 156 { 157 // Get the VCL font (use FontHeight as FontWidth) 158 Font aFont(primitive2d::getVclFontFromFontAttribute( 159 rTextCandidate.getFontAttribute(), 160 aFontScaling.getX(), 161 aFontScaling.getY(), 162 fRotate, 163 rTextCandidate.getLocale())); 164 165 // handle additional font attributes 166 const primitive2d::TextDecoratedPortionPrimitive2D* pTCPP = 167 dynamic_cast<const primitive2d::TextDecoratedPortionPrimitive2D*>( &rTextCandidate ); 168 169 if( pTCPP != NULL ) 170 { 171 172 // set the color of text decorations 173 const basegfx::BColor aTextlineColor = maBColorModifierStack.getModifiedColor(pTCPP->getTextlineColor()); 174 mpOutputDevice->SetTextLineColor( Color(aTextlineColor) ); 175 176 // set Overline attribute 177 const FontUnderline eFontOverline(primitive2d::mapTextLineToFontUnderline( pTCPP->getFontOverline() )); 178 if( eFontOverline != UNDERLINE_NONE ) 179 { 180 aFont.SetOverline( eFontOverline ); 181 const basegfx::BColor aOverlineColor = maBColorModifierStack.getModifiedColor(pTCPP->getOverlineColor()); 182 mpOutputDevice->SetOverlineColor( Color(aOverlineColor) ); 183 if( pTCPP->getWordLineMode() ) 184 aFont.SetWordLineMode( true ); 185 } 186 187 // set Underline attribute 188 const FontUnderline eFontUnderline(primitive2d::mapTextLineToFontUnderline( pTCPP->getFontUnderline() )); 189 if( eFontUnderline != UNDERLINE_NONE ) 190 { 191 aFont.SetUnderline( eFontUnderline ); 192 if( pTCPP->getWordLineMode() ) 193 aFont.SetWordLineMode( true ); 194 //TODO: ??? if( pTCPP->getUnderlineAbove() ) 195 // aFont.SetUnderlineAbove( true ); 196 } 197 198 // set Strikeout attribute 199 const FontStrikeout eFontStrikeout(primitive2d::mapTextStrikeoutToFontStrikeout(pTCPP->getTextStrikeout())); 200 201 if( eFontStrikeout != STRIKEOUT_NONE ) 202 aFont.SetStrikeout( eFontStrikeout ); 203 204 // set EmphasisMark attribute 205 FontEmphasisMark eFontEmphasisMark = EMPHASISMARK_NONE; 206 switch( pTCPP->getTextEmphasisMark() ) 207 { 208 default: 209 DBG_WARNING1( "DrawingLayer: Unknown EmphasisMark style (%d)!", pTCPP->getTextEmphasisMark() ); 210 // fall through 211 case primitive2d::TEXT_EMPHASISMARK_NONE: eFontEmphasisMark = EMPHASISMARK_NONE; break; 212 case primitive2d::TEXT_EMPHASISMARK_DOT: eFontEmphasisMark = EMPHASISMARK_DOT; break; 213 case primitive2d::TEXT_EMPHASISMARK_CIRCLE: eFontEmphasisMark = EMPHASISMARK_CIRCLE; break; 214 case primitive2d::TEXT_EMPHASISMARK_DISC: eFontEmphasisMark = EMPHASISMARK_DISC; break; 215 case primitive2d::TEXT_EMPHASISMARK_ACCENT: eFontEmphasisMark = EMPHASISMARK_ACCENT; break; 216 } 217 218 if( eFontEmphasisMark != EMPHASISMARK_NONE ) 219 { 220 DBG_ASSERT( (pTCPP->getEmphasisMarkAbove() != pTCPP->getEmphasisMarkBelow()), 221 "DrawingLayer: Bad EmphasisMark position!" ); 222 if( pTCPP->getEmphasisMarkAbove() ) 223 eFontEmphasisMark |= EMPHASISMARK_POS_ABOVE; 224 else 225 eFontEmphasisMark |= EMPHASISMARK_POS_BELOW; 226 aFont.SetEmphasisMark( eFontEmphasisMark ); 227 } 228 229 // set Relief attribute 230 FontRelief eFontRelief = RELIEF_NONE; 231 switch( pTCPP->getTextRelief() ) 232 { 233 default: 234 DBG_WARNING1( "DrawingLayer: Unknown Relief style (%d)!", pTCPP->getTextRelief() ); 235 // fall through 236 case primitive2d::TEXT_RELIEF_NONE: eFontRelief = RELIEF_NONE; break; 237 case primitive2d::TEXT_RELIEF_EMBOSSED: eFontRelief = RELIEF_EMBOSSED; break; 238 case primitive2d::TEXT_RELIEF_ENGRAVED: eFontRelief = RELIEF_ENGRAVED; break; 239 } 240 241 if( eFontRelief != RELIEF_NONE ) 242 aFont.SetRelief( eFontRelief ); 243 244 // set Shadow attribute 245 if( pTCPP->getShadow() ) 246 aFont.SetShadow( true ); 247 } 248 249 // create transformed integer DXArray in view coordinate system 250 ::std::vector< sal_Int32 > aTransformedDXArray; 251 252 if(rTextCandidate.getDXArray().size()) 253 { 254 aTransformedDXArray.reserve(rTextCandidate.getDXArray().size()); 255 const basegfx::B2DVector aPixelVector(maCurrentTransformation * basegfx::B2DVector(1.0, 0.0)); 256 const double fPixelVectorFactor(aPixelVector.getLength()); 257 258 for(::std::vector< double >::const_iterator aStart(rTextCandidate.getDXArray().begin()); 259 aStart != rTextCandidate.getDXArray().end(); aStart++) 260 { 261 aTransformedDXArray.push_back(basegfx::fround((*aStart) * fPixelVectorFactor)); 262 } 263 } 264 265 // set parameters and paint text snippet 266 const basegfx::BColor aRGBFontColor(maBColorModifierStack.getModifiedColor(rTextCandidate.getFontColor())); 267 const basegfx::B2DPoint aPoint(aLocalTransform * basegfx::B2DPoint(0.0, 0.0)); 268 const Point aStartPoint(basegfx::fround(aPoint.getX()), basegfx::fround(aPoint.getY())); 269 const sal_uInt32 nOldLayoutMode(mpOutputDevice->GetLayoutMode()); 270 271 if(rTextCandidate.getFontAttribute().getRTL()) 272 { 273 sal_uInt32 nRTLLayoutMode(nOldLayoutMode & ~(TEXT_LAYOUT_COMPLEX_DISABLED|TEXT_LAYOUT_BIDI_STRONG)); 274 nRTLLayoutMode |= TEXT_LAYOUT_BIDI_RTL|TEXT_LAYOUT_TEXTORIGIN_LEFT; 275 mpOutputDevice->SetLayoutMode(nRTLLayoutMode); 276 } 277 278 mpOutputDevice->SetFont(aFont); 279 mpOutputDevice->SetTextColor(Color(aRGBFontColor)); 280 281 if(aTransformedDXArray.size()) 282 { 283 mpOutputDevice->DrawTextArray( 284 aStartPoint, 285 rTextCandidate.getText(), 286 &(aTransformedDXArray[0]), 287 rTextCandidate.getTextPosition(), 288 rTextCandidate.getTextLength()); 289 } 290 else 291 { 292 mpOutputDevice->DrawText( 293 aStartPoint, 294 rTextCandidate.getText(), 295 rTextCandidate.getTextPosition(), 296 rTextCandidate.getTextLength()); 297 } 298 299 if(rTextCandidate.getFontAttribute().getRTL()) 300 { 301 mpOutputDevice->SetLayoutMode(nOldLayoutMode); 302 } 303 304 bPrimitiveAccepted = true; 305 } 306 } 307 308 if(!bPrimitiveAccepted) 309 { 310 // let break down 311 process(rTextCandidate.get2DDecomposition(getViewInformation2D())); 312 } 313 } 314 315 // direct draw of hairline 316 void VclProcessor2D::RenderPolygonHairlinePrimitive2D(const primitive2d::PolygonHairlinePrimitive2D& rPolygonCandidate, bool bPixelBased) 317 { 318 const basegfx::BColor aHairlineColor(maBColorModifierStack.getModifiedColor(rPolygonCandidate.getBColor())); 319 mpOutputDevice->SetLineColor(Color(aHairlineColor)); 320 mpOutputDevice->SetFillColor(); 321 322 basegfx::B2DPolygon aLocalPolygon(rPolygonCandidate.getB2DPolygon()); 323 aLocalPolygon.transform(maCurrentTransformation); 324 325 static bool bCheckTrapezoidDecomposition(false); 326 static bool bShowOutlinesThere(false); 327 if(bCheckTrapezoidDecomposition) 328 { 329 // clip against discrete ViewPort 330 const basegfx::B2DRange& rDiscreteViewport = getViewInformation2D().getDiscreteViewport(); 331 basegfx::B2DPolyPolygon aLocalPolyPolygon(basegfx::tools::clipPolygonOnRange( 332 aLocalPolygon, rDiscreteViewport, true, false)); 333 334 if(aLocalPolyPolygon.count()) 335 { 336 // subdivide 337 aLocalPolyPolygon = basegfx::tools::adaptiveSubdivideByDistance( 338 aLocalPolyPolygon, 0.5); 339 340 // trapezoidize 341 static double fLineWidth(2.0); 342 basegfx::B2DTrapezoidVector aB2DTrapezoidVector; 343 basegfx::tools::createLineTrapezoidFromB2DPolyPolygon(aB2DTrapezoidVector, aLocalPolyPolygon, fLineWidth); 344 345 const sal_uInt32 nCount(aB2DTrapezoidVector.size()); 346 347 if(nCount) 348 { 349 basegfx::BColor aInvPolygonColor(aHairlineColor); 350 aInvPolygonColor.invert(); 351 352 for(sal_uInt32 a(0); a < nCount; a++) 353 { 354 const basegfx::B2DPolygon aTempPolygon(aB2DTrapezoidVector[a].getB2DPolygon()); 355 356 if(bShowOutlinesThere) 357 { 358 mpOutputDevice->SetFillColor(Color(aHairlineColor)); 359 mpOutputDevice->SetLineColor(); 360 } 361 362 mpOutputDevice->DrawPolygon(aTempPolygon); 363 364 if(bShowOutlinesThere) 365 { 366 mpOutputDevice->SetFillColor(); 367 mpOutputDevice->SetLineColor(Color(aInvPolygonColor)); 368 mpOutputDevice->DrawPolyLine(aTempPolygon, 0.0); 369 } 370 } 371 } 372 } 373 } 374 else 375 { 376 if(bPixelBased && getOptionsDrawinglayer().IsAntiAliasing() && getOptionsDrawinglayer().IsSnapHorVerLinesToDiscrete()) 377 { 378 // #i98289# 379 // when a Hairline is painted and AntiAliasing is on the option SnapHorVerLinesToDiscrete 380 // allows to suppress AntiAliasing for pure horizontal or vertical lines. This is done since 381 // not-AntiAliased such lines look more pleasing to the eye (e.g. 2D chart content). This 382 // NEEDS to be done in discrete coordinates, so only useful for pixel based rendering. 383 aLocalPolygon = basegfx::tools::snapPointsOfHorizontalOrVerticalEdges(aLocalPolygon); 384 } 385 386 mpOutputDevice->DrawPolyLine(aLocalPolygon, 0.0); 387 } 388 } 389 390 // direct draw of transformed BitmapEx primitive 391 void VclProcessor2D::RenderBitmapPrimitive2D(const primitive2d::BitmapPrimitive2D& rBitmapCandidate) 392 { 393 // create local transform 394 basegfx::B2DHomMatrix aLocalTransform(maCurrentTransformation * rBitmapCandidate.getTransform()); 395 BitmapEx aBitmapEx(rBitmapCandidate.getBitmapEx()); 396 bool bPainted(false); 397 398 if(maBColorModifierStack.count()) 399 { 400 aBitmapEx = impModifyBitmapEx(maBColorModifierStack, aBitmapEx); 401 402 if(aBitmapEx.IsEmpty()) 403 { 404 // color gets completely replaced, get it 405 const basegfx::BColor aModifiedColor(maBColorModifierStack.getModifiedColor(basegfx::BColor())); 406 basegfx::B2DPolygon aPolygon(basegfx::tools::createUnitPolygon()); 407 aPolygon.transform(aLocalTransform); 408 409 mpOutputDevice->SetFillColor(Color(aModifiedColor)); 410 mpOutputDevice->SetLineColor(); 411 mpOutputDevice->DrawPolygon(aPolygon); 412 413 bPainted = true; 414 } 415 } 416 417 if(!bPainted) 418 { 419 static bool bForceUseOfOwnTransformer(false); 420 static bool bUseGraphicManager(true); 421 422 // decompose matrix to check for shear, rotate and mirroring 423 basegfx::B2DVector aScale, aTranslate; 424 double fRotate, fShearX; 425 aLocalTransform.decompose(aScale, aTranslate, fRotate, fShearX); 426 427 if(!bForceUseOfOwnTransformer && basegfx::fTools::equalZero(fShearX)) 428 { 429 if(!bUseGraphicManager && basegfx::fTools::equalZero(fRotate)) 430 { 431 RenderBitmapPrimitive2D_BitmapEx(*mpOutputDevice, aBitmapEx, aLocalTransform); 432 } 433 else 434 { 435 RenderBitmapPrimitive2D_GraphicManager(*mpOutputDevice, aBitmapEx, aLocalTransform); 436 } 437 } 438 else 439 { 440 if(!aBitmapEx.IsTransparent() && (!basegfx::fTools::equalZero(fShearX) || !basegfx::fTools::equalZero(fRotate))) 441 { 442 // parts will be uncovered, extend aBitmapEx with a mask bitmap 443 const Bitmap aContent(aBitmapEx.GetBitmap()); 444 aBitmapEx = BitmapEx(aContent, Bitmap(aContent.GetSizePixel(), 1)); 445 } 446 447 RenderBitmapPrimitive2D_self(*mpOutputDevice, aBitmapEx, aLocalTransform); 448 } 449 } 450 } 451 452 void VclProcessor2D::RenderFillGraphicPrimitive2D(const primitive2d::FillGraphicPrimitive2D& rFillBitmapCandidate) 453 { 454 const attribute::FillGraphicAttribute& rFillGraphicAttribute(rFillBitmapCandidate.getFillGraphic()); 455 bool bPrimitiveAccepted(false); 456 static bool bTryTilingDirect = true; 457 458 // #121194# when tiling is used and content is bitmap-based, do direct tiling in the 459 // renderer on pixel base to ensure tight fitting. Do not do this when 460 // the fill is rotated or sheared. 461 462 // ovveride static bool (for debug) and tiling is active 463 if(bTryTilingDirect && rFillGraphicAttribute.getTiling()) 464 { 465 // content is bitmap(ex) 466 // 467 // for SVG support, force decomposition when SVG is present. This will lead to use 468 // the primitive representation of the svg directly. 469 // 470 // when graphic is animated, force decomposition to use the correct graphic, else 471 // fill style will not be animated 472 if(GRAPHIC_BITMAP == rFillGraphicAttribute.getGraphic().GetType() 473 && !rFillGraphicAttribute.getGraphic().getSvgData().get() 474 && !rFillGraphicAttribute.getGraphic().IsAnimated()) 475 { 476 // decompose matrix to check for shear, rotate and mirroring 477 basegfx::B2DHomMatrix aLocalTransform(maCurrentTransformation * rFillBitmapCandidate.getTransformation()); 478 basegfx::B2DVector aScale, aTranslate; 479 double fRotate, fShearX; 480 aLocalTransform.decompose(aScale, aTranslate, fRotate, fShearX); 481 482 // when nopt rotated/sheared 483 if(basegfx::fTools::equalZero(fRotate) && basegfx::fTools::equalZero(fShearX)) 484 { 485 // no shear or rotate, draw direct in pixel coordinates 486 bPrimitiveAccepted = true; 487 488 // transform object range to device coordinates (pixels). Use 489 // the device transformation for better accuracy 490 basegfx::B2DRange aObjectRange(aTranslate, aTranslate + aScale); 491 aObjectRange.transform(mpOutputDevice->GetViewTransformation()); 492 493 // extract discrete size of object 494 const sal_Int32 nOWidth(basegfx::fround(aObjectRange.getWidth())); 495 const sal_Int32 nOHeight(basegfx::fround(aObjectRange.getHeight())); 496 497 // only do something when object has a size in discrete units 498 if(nOWidth > 0 && nOHeight > 0) 499 { 500 // transform graphic range to device coordinates (pixels). Use 501 // the device transformation for better accuracy 502 basegfx::B2DRange aGraphicRange(rFillGraphicAttribute.getGraphicRange()); 503 aGraphicRange.transform(mpOutputDevice->GetViewTransformation() * aLocalTransform); 504 505 // extract discrete size of graphic 506 const sal_Int32 nBWidth(basegfx::fround(aGraphicRange.getWidth())); 507 const sal_Int32 nBHeight(basegfx::fround(aGraphicRange.getHeight())); 508 509 // only do something when bitmap fill has a size in discrete units 510 if(nBWidth > 0 && nBHeight > 0) 511 { 512 // nBWidth, nBHeight is the pixel size of the neede bitmap. To not need to scale it 513 // in vcl many times, create a size-optimized version 514 const Size aNeededBitmapSizePixel(nBWidth, nBHeight); 515 BitmapEx aBitmapEx(rFillGraphicAttribute.getGraphic().GetBitmapEx( 516 GraphicConversionParameters( 517 aNeededBitmapSizePixel, // get the correct size immediately 518 false, // no unlimited size 519 false, // Use AntiAliasing 520 false, //SnapHorVerLines 521 true // ScaleHighQuality 522 ))); 523 bool bPainted(false); 524 525 if(maBColorModifierStack.count()) 526 { 527 // when color modifier, apply to bitmap 528 aBitmapEx = impModifyBitmapEx(maBColorModifierStack, aBitmapEx); 529 530 // impModifyBitmapEx uses empty bitmap as sign to return that 531 // the content will be completely replaced to mono color, use shortcut 532 if(aBitmapEx.IsEmpty()) 533 { 534 // color gets completely replaced, get it 535 const basegfx::BColor aModifiedColor(maBColorModifierStack.getModifiedColor(basegfx::BColor())); 536 basegfx::B2DPolygon aPolygon(basegfx::tools::createUnitPolygon()); 537 aPolygon.transform(aLocalTransform); 538 539 mpOutputDevice->SetFillColor(Color(aModifiedColor)); 540 mpOutputDevice->SetLineColor(); 541 mpOutputDevice->DrawPolygon(aPolygon); 542 543 bPainted = true; 544 } 545 } 546 547 if(!bPainted) 548 { 549 sal_Int32 nBLeft(basegfx::fround(aGraphicRange.getMinX())); 550 sal_Int32 nBTop(basegfx::fround(aGraphicRange.getMinY())); 551 const sal_Int32 nOLeft(basegfx::fround(aObjectRange.getMinX())); 552 const sal_Int32 nOTop(basegfx::fround(aObjectRange.getMinY())); 553 sal_Int32 nPosX(0); 554 sal_Int32 nPosY(0); 555 556 if(nBLeft > nOLeft) 557 { 558 const sal_Int32 nDiff((nBLeft / nBWidth) + 1); 559 560 nPosX -= nDiff; 561 nBLeft -= nDiff * nBWidth; 562 } 563 564 if(nBLeft + nBWidth <= nOLeft) 565 { 566 const sal_Int32 nDiff(-nBLeft / nBWidth); 567 568 nPosX += nDiff; 569 nBLeft += nDiff * nBWidth; 570 } 571 572 if(nBTop > nOTop) 573 { 574 const sal_Int32 nDiff((nBTop / nBHeight) + 1); 575 576 nPosY -= nDiff; 577 nBTop -= nDiff * nBHeight; 578 } 579 580 if(nBTop + nBHeight <= nOTop) 581 { 582 const sal_Int32 nDiff(-nBTop / nBHeight); 583 584 nPosY += nDiff; 585 nBTop += nDiff * nBHeight; 586 } 587 588 // prepare OutDev 589 const Point aEmptyPoint(0, 0); 590 const Rectangle aVisiblePixel(aEmptyPoint, mpOutputDevice->GetOutputSizePixel()); 591 const bool bWasEnabled(mpOutputDevice->IsMapModeEnabled()); 592 mpOutputDevice->EnableMapMode(false); 593 594 // check if offset is used 595 const sal_Int32 nOffsetX(basegfx::fround(rFillGraphicAttribute.getOffsetX() * nBWidth)); 596 597 if(nOffsetX) 598 { 599 // offset in X, so iterate over Y first and draw lines 600 for(sal_Int32 nYPos(nBTop); nYPos < nOTop + nOHeight; nYPos += nBHeight, nPosY++) 601 { 602 for(sal_Int32 nXPos(nPosY % 2 ? nBLeft - nBWidth + nOffsetX : nBLeft); 603 nXPos < nOLeft + nOWidth; nXPos += nBWidth) 604 { 605 const Rectangle aOutRectPixel(Point(nXPos, nYPos), aNeededBitmapSizePixel); 606 607 if(aOutRectPixel.IsOver(aVisiblePixel)) 608 { 609 mpOutputDevice->DrawBitmapEx(aOutRectPixel.TopLeft(), aBitmapEx); 610 } 611 } 612 } 613 } 614 else 615 { 616 // check if offset is used 617 const sal_Int32 nOffsetY(basegfx::fround(rFillGraphicAttribute.getOffsetY() * nBHeight)); 618 619 // possible offset in Y, so iterate over X first and draw columns 620 for(sal_Int32 nXPos(nBLeft); nXPos < nOLeft + nOWidth; nXPos += nBWidth, nPosX++) 621 { 622 for(sal_Int32 nYPos(nPosX % 2 ? nBTop - nBHeight + nOffsetY : nBTop); 623 nYPos < nOTop + nOHeight; nYPos += nBHeight) 624 { 625 const Rectangle aOutRectPixel(Point(nXPos, nYPos), aNeededBitmapSizePixel); 626 627 if(aOutRectPixel.IsOver(aVisiblePixel)) 628 { 629 mpOutputDevice->DrawBitmapEx(aOutRectPixel.TopLeft(), aBitmapEx); 630 } 631 } 632 } 633 } 634 635 // restore OutDev 636 mpOutputDevice->EnableMapMode(bWasEnabled); 637 } 638 } 639 } 640 } 641 } 642 } 643 644 if(!bPrimitiveAccepted) 645 { 646 // do not accept, use decomposition 647 process(rFillBitmapCandidate.get2DDecomposition(getViewInformation2D())); 648 } 649 } 650 651 // direct draw of gradient 652 void VclProcessor2D::RenderPolyPolygonGradientPrimitive2D(const primitive2d::PolyPolygonGradientPrimitive2D& rPolygonCandidate) 653 { 654 const attribute::FillGradientAttribute& rGradient(rPolygonCandidate.getFillGradient()); 655 basegfx::BColor aStartColor(maBColorModifierStack.getModifiedColor(rGradient.getStartColor())); 656 basegfx::BColor aEndColor(maBColorModifierStack.getModifiedColor(rGradient.getEndColor())); 657 basegfx::B2DPolyPolygon aLocalPolyPolygon(rPolygonCandidate.getB2DPolyPolygon()); 658 659 if(aLocalPolyPolygon.count()) 660 { 661 aLocalPolyPolygon.transform(maCurrentTransformation); 662 663 if(aStartColor == aEndColor) 664 { 665 // no gradient at all, draw as polygon in AA and non-AA case 666 mpOutputDevice->SetLineColor(); 667 mpOutputDevice->SetFillColor(Color(aStartColor)); 668 mpOutputDevice->DrawPolyPolygon(aLocalPolyPolygon); 669 } 670 else if(getOptionsDrawinglayer().IsAntiAliasing()) 671 { 672 // For AA, direct render has to be avoided since it uses XOR maskings which will not 673 // work with AA. Instead, the decompose which uses MaskPrimitive2D with fillings is 674 // used 675 process(rPolygonCandidate.get2DDecomposition(getViewInformation2D())); 676 } 677 else 678 { 679 static bool bSimple = false; // allow testing simple paint in debugger 680 681 impDrawGradientToOutDev( 682 *mpOutputDevice, aLocalPolyPolygon, rGradient.getStyle(), rGradient.getSteps(), 683 aStartColor, aEndColor, rGradient.getBorder(), 684 rGradient.getAngle(), rGradient.getOffsetX(), rGradient.getOffsetY(), bSimple); 685 } 686 } 687 } 688 689 // direct draw of Graphic 690 void VclProcessor2D::RenderPolyPolygonGraphicPrimitive2D(const primitive2d::PolyPolygonGraphicPrimitive2D& rPolygonCandidate) 691 { 692 bool bDone(false); 693 const basegfx::B2DPolyPolygon& rPolyPolygon = rPolygonCandidate.getB2DPolyPolygon(); 694 695 // #121194# Todo: check if this works 696 if(!rPolyPolygon.count()) 697 { 698 // empty polyPolygon, done 699 bDone = true; 700 } 701 else 702 { 703 const attribute::FillGraphicAttribute& rFillGraphicAttribute = rPolygonCandidate.getFillGraphic(); 704 705 // try to catch cases where the graphic will be color-modified to a single 706 // color (e.g. shadow) 707 switch(rFillGraphicAttribute.getGraphic().GetType()) 708 { 709 case GRAPHIC_GDIMETAFILE: 710 { 711 // metafiles are potentially transparent, cannot optimize�, not done 712 break; 713 } 714 case GRAPHIC_BITMAP: 715 { 716 if(!rFillGraphicAttribute.getGraphic().IsTransparent() && !rFillGraphicAttribute.getGraphic().IsAlpha()) 717 { 718 // bitmap is not transparent and has no alpha 719 const sal_uInt32 nBColorModifierStackCount(maBColorModifierStack.count()); 720 721 if(nBColorModifierStackCount) 722 { 723 const basegfx::BColorModifier& rTopmostModifier = maBColorModifierStack.getBColorModifier(nBColorModifierStackCount - 1); 724 725 if(basegfx::BCOLORMODIFYMODE_REPLACE == rTopmostModifier.getMode()) 726 { 727 // the bitmap fill is in unified color, so we can replace it with 728 // a single polygon fill. The form of the fill depends on tiling 729 if(rFillGraphicAttribute.getTiling()) 730 { 731 // with tiling, fill the whole PolyPolygon with the modifier color 732 basegfx::B2DPolyPolygon aLocalPolyPolygon(rPolyPolygon); 733 734 aLocalPolyPolygon.transform(maCurrentTransformation); 735 mpOutputDevice->SetLineColor(); 736 mpOutputDevice->SetFillColor(Color(rTopmostModifier.getBColor())); 737 mpOutputDevice->DrawPolyPolygon(aLocalPolyPolygon); 738 } 739 else 740 { 741 // without tiling, only the area common to the bitmap tile and the 742 // PolyPolygon is filled. Create the bitmap tile area in object 743 // coordinates. For this, the object transformation needs to be created 744 // from the already scaled PolyPolygon. The tile area in object 745 // coordinates wil always be non-rotated, so it's not necessary to 746 // work with a polygon here 747 basegfx::B2DRange aTileRange(rFillGraphicAttribute.getGraphicRange()); 748 const basegfx::B2DRange aPolyPolygonRange(rPolyPolygon.getB2DRange()); 749 const basegfx::B2DHomMatrix aNewObjectTransform( 750 basegfx::tools::createScaleTranslateB2DHomMatrix( 751 aPolyPolygonRange.getRange(), 752 aPolyPolygonRange.getMinimum())); 753 754 aTileRange.transform(aNewObjectTransform); 755 756 // now clip the object polyPolygon against the tile range 757 // to get the common area 758 basegfx::B2DPolyPolygon aTarget = basegfx::tools::clipPolyPolygonOnRange( 759 rPolyPolygon, 760 aTileRange, 761 true, 762 false); 763 764 if(aTarget.count()) 765 { 766 aTarget.transform(maCurrentTransformation); 767 mpOutputDevice->SetLineColor(); 768 mpOutputDevice->SetFillColor(Color(rTopmostModifier.getBColor())); 769 mpOutputDevice->DrawPolyPolygon(aTarget); 770 } 771 } 772 773 // simplified output executed, we are done 774 bDone = true; 775 } 776 } 777 } 778 break; 779 } 780 default: //GRAPHIC_NONE, GRAPHIC_DEFAULT 781 { 782 // empty graphic, we are done 783 bDone = true; 784 break; 785 } 786 } 787 } 788 789 if(!bDone) 790 { 791 // use default decomposition 792 process(rPolygonCandidate.get2DDecomposition(getViewInformation2D())); 793 } 794 } 795 796 // direct draw of PolyPolygon with color 797 void VclProcessor2D::RenderPolyPolygonColorPrimitive2D(const primitive2d::PolyPolygonColorPrimitive2D& rPolygonCandidate) 798 { 799 const basegfx::BColor aPolygonColor(maBColorModifierStack.getModifiedColor(rPolygonCandidate.getBColor())); 800 mpOutputDevice->SetFillColor(Color(aPolygonColor)); 801 mpOutputDevice->SetLineColor(); 802 803 basegfx::B2DPolyPolygon aLocalPolyPolygon(rPolygonCandidate.getB2DPolyPolygon()); 804 aLocalPolyPolygon.transform(maCurrentTransformation); 805 806 static bool bCheckTrapezoidDecomposition(false); 807 static bool bShowOutlinesThere(false); 808 if(bCheckTrapezoidDecomposition) 809 { 810 // clip against discrete ViewPort 811 const basegfx::B2DRange& rDiscreteViewport = getViewInformation2D().getDiscreteViewport(); 812 aLocalPolyPolygon = basegfx::tools::clipPolyPolygonOnRange( 813 aLocalPolyPolygon, rDiscreteViewport, true, false); 814 815 if(aLocalPolyPolygon.count()) 816 { 817 // subdivide 818 aLocalPolyPolygon = basegfx::tools::adaptiveSubdivideByDistance( 819 aLocalPolyPolygon, 0.5); 820 821 // trapezoidize 822 basegfx::B2DTrapezoidVector aB2DTrapezoidVector; 823 basegfx::tools::trapezoidSubdivide(aB2DTrapezoidVector, aLocalPolyPolygon); 824 825 const sal_uInt32 nCount(aB2DTrapezoidVector.size()); 826 827 if(nCount) 828 { 829 basegfx::BColor aInvPolygonColor(aPolygonColor); 830 aInvPolygonColor.invert(); 831 832 for(sal_uInt32 a(0); a < nCount; a++) 833 { 834 const basegfx::B2DPolygon aTempPolygon(aB2DTrapezoidVector[a].getB2DPolygon()); 835 836 if(bShowOutlinesThere) 837 { 838 mpOutputDevice->SetFillColor(Color(aPolygonColor)); 839 mpOutputDevice->SetLineColor(); 840 } 841 842 mpOutputDevice->DrawPolygon(aTempPolygon); 843 844 if(bShowOutlinesThere) 845 { 846 mpOutputDevice->SetFillColor(); 847 mpOutputDevice->SetLineColor(Color(aInvPolygonColor)); 848 mpOutputDevice->DrawPolyLine(aTempPolygon, 0.0); 849 } 850 } 851 } 852 } 853 } 854 else 855 { 856 mpOutputDevice->DrawPolyPolygon(aLocalPolyPolygon); 857 858 if(mnPolygonStrokePrimitive2D 859 && getOptionsDrawinglayer().IsAntiAliasing() 860 && (mpOutputDevice->GetAntialiasing() & ANTIALIASING_ENABLE_B2DDRAW)) 861 { 862 // when AA is on and this filled polygons are the result of stroked line geometry, 863 // draw the geometry once extra as lines to avoid AA 'gaps' between partial polygons 864 mpOutputDevice->SetFillColor(); 865 mpOutputDevice->SetLineColor(Color(aPolygonColor)); 866 const sal_uInt32 nCount(aLocalPolyPolygon.count()); 867 868 for(sal_uInt32 a(0); a < nCount; a++) 869 { 870 mpOutputDevice->DrawPolyLine(aLocalPolyPolygon.getB2DPolygon(a), 0.0); 871 } 872 } 873 } 874 } 875 876 // direct draw of MetaFile 877 void VclProcessor2D::RenderMetafilePrimitive2D(const primitive2d::MetafilePrimitive2D& rMetaCandidate) 878 { 879 // decompose matrix to check for shear, rotate and mirroring 880 basegfx::B2DHomMatrix aLocalTransform(maCurrentTransformation * rMetaCandidate.getTransform()); 881 basegfx::B2DVector aScale, aTranslate; 882 double fRotate, fShearX; 883 aLocalTransform.decompose(aScale, aTranslate, fRotate, fShearX); 884 885 if(basegfx::fTools::less(aScale.getX(), 0.0) && basegfx::fTools::less(aScale.getY(), 0.0)) 886 { 887 // #i102175# handle special case: If scale is negative in (x,y) (3rd quadrant), it can 888 // be expressed as rotation by PI. This needs to be done for Metafiles since 889 // these can be rotated, but not really mirrored 890 aScale = basegfx::absolute(aScale); 891 fRotate += F_PI; 892 } 893 894 // get BoundRect 895 basegfx::B2DRange aOutlineRange(rMetaCandidate.getB2DRange(getViewInformation2D())); 896 aOutlineRange.transform(maCurrentTransformation); 897 898 // Due to the integer MapModes used from VCL aind inside MetaFiles errors of up to three 899 // pixels in size may happen. As long as there is no better way (e.g. convert the MetaFile 900 // to primitives) it is necessary to reduce maximum pixel size by 1 in X and Y and to use 901 // the inner pixel bounds accordingly (ceil resp. floor). This will also be done for logic 902 // units e.g. when creating a new MetaFile, but since much huger value ranges are used 903 // there typically will be okay for this compromize. 904 Rectangle aDestRectView( 905 // !!CAUTION!! Here, ceil and floor are exchanged BY PURPOSE, do NOT copy when 906 // looking for a standard conversion to rectangle (!) 907 (sal_Int32)ceil(aOutlineRange.getMinX()), (sal_Int32)ceil(aOutlineRange.getMinY()), 908 (sal_Int32)floor(aOutlineRange.getMaxX()), (sal_Int32)floor(aOutlineRange.getMaxY())); 909 910 // get metafile (copy it) 911 GDIMetaFile aMetaFile; 912 913 if(maBColorModifierStack.count()) 914 { 915 const basegfx::BColor aRGBBaseColor(0, 0, 0); 916 const basegfx::BColor aRGBColor(maBColorModifierStack.getModifiedColor(aRGBBaseColor)); 917 aMetaFile = rMetaCandidate.getMetaFile().GetMonochromeMtf(Color(aRGBColor)); 918 } 919 else 920 { 921 aMetaFile = rMetaCandidate.getMetaFile(); 922 } 923 924 // rotation 925 if(!basegfx::fTools::equalZero(fRotate)) 926 { 927 // #i103530# 928 // MetaFile::Rotate has no input parameter check, so the parameter needs to be 929 // well-aligned to the old range [0..3600] 10th degrees with inverse orientation 930 sal_Int16 nRotation((sal_Int16)((fRotate / F_PI180) * -10.0)); 931 932 while(nRotation < 0) 933 nRotation += 3600; 934 935 while(nRotation >= 3600) 936 nRotation -= 3600; 937 938 aMetaFile.Rotate(nRotation); 939 } 940 941 // Prepare target output size 942 Size aDestSize(aDestRectView.GetSize()); 943 944 if(aDestSize.getWidth() && aDestSize.getHeight()) 945 { 946 // Get preferred Metafile output size. When it's very equal to the output size, it's probably 947 // a rounding error somewhere, so correct it to get a 1:1 output without single pixel scalings 948 // of the Metafile (esp. for contaned Bitmaps, e.g 3D charts) 949 const Size aPrefSize(mpOutputDevice->LogicToPixel(aMetaFile.GetPrefSize(), aMetaFile.GetPrefMapMode())); 950 951 if(aPrefSize.getWidth() && (aPrefSize.getWidth() - 1 == aDestSize.getWidth() || aPrefSize.getWidth() + 1 == aDestSize.getWidth())) 952 { 953 aDestSize.setWidth(aPrefSize.getWidth()); 954 } 955 956 if(aPrefSize.getHeight() && (aPrefSize.getHeight() - 1 == aDestSize.getHeight() || aPrefSize.getHeight() + 1 == aDestSize.getHeight())) 957 { 958 aDestSize.setHeight(aPrefSize.getHeight()); 959 } 960 961 // paint it 962 aMetaFile.WindStart(); 963 aMetaFile.Play(mpOutputDevice, aDestRectView.TopLeft(), aDestSize); 964 } 965 } 966 967 // mask group. Force output to VDev and create mask from given mask 968 void VclProcessor2D::RenderMaskPrimitive2DPixel(const primitive2d::MaskPrimitive2D& rMaskCandidate) 969 { 970 if(rMaskCandidate.getChildren().hasElements()) 971 { 972 basegfx::B2DPolyPolygon aMask(rMaskCandidate.getMask()); 973 974 if(aMask.count()) 975 { 976 aMask.transform(maCurrentTransformation); 977 const basegfx::B2DRange aRange(basegfx::tools::getRange(aMask)); 978 impBufferDevice aBufferDevice(*mpOutputDevice, aRange, true); 979 980 if(aBufferDevice.isVisible()) 981 { 982 // remember last OutDev and set to content 983 OutputDevice* pLastOutputDevice = mpOutputDevice; 984 mpOutputDevice = &aBufferDevice.getContent(); 985 986 // paint to it 987 process(rMaskCandidate.getChildren()); 988 989 // back to old OutDev 990 mpOutputDevice = pLastOutputDevice; 991 992 // draw mask 993 if(getOptionsDrawinglayer().IsAntiAliasing()) 994 { 995 // with AA, use 8bit AlphaMask to get nice borders 996 VirtualDevice& rTransparence = aBufferDevice.getTransparence(); 997 rTransparence.SetLineColor(); 998 rTransparence.SetFillColor(COL_BLACK); 999 rTransparence.DrawPolyPolygon(aMask); 1000 1001 // dump buffer to outdev 1002 aBufferDevice.paint(); 1003 } 1004 else 1005 { 1006 // No AA, use 1bit mask 1007 VirtualDevice& rMask = aBufferDevice.getMask(); 1008 rMask.SetLineColor(); 1009 rMask.SetFillColor(COL_BLACK); 1010 rMask.DrawPolyPolygon(aMask); 1011 1012 // dump buffer to outdev 1013 aBufferDevice.paint(); 1014 } 1015 } 1016 } 1017 } 1018 } 1019 1020 // modified color group. Force output to unified color. 1021 void VclProcessor2D::RenderModifiedColorPrimitive2D(const primitive2d::ModifiedColorPrimitive2D& rModifiedCandidate) 1022 { 1023 if(rModifiedCandidate.getChildren().hasElements()) 1024 { 1025 maBColorModifierStack.push(rModifiedCandidate.getColorModifier()); 1026 process(rModifiedCandidate.getChildren()); 1027 maBColorModifierStack.pop(); 1028 } 1029 } 1030 1031 // unified sub-transparence. Draw to VDev first. 1032 void VclProcessor2D::RenderUnifiedTransparencePrimitive2D(const primitive2d::UnifiedTransparencePrimitive2D& rTransCandidate) 1033 { 1034 static bool bForceToDecomposition(false); 1035 1036 if(rTransCandidate.getChildren().hasElements()) 1037 { 1038 if(bForceToDecomposition) 1039 { 1040 // use decomposition 1041 process(rTransCandidate.get2DDecomposition(getViewInformation2D())); 1042 } 1043 else 1044 { 1045 if(0.0 == rTransCandidate.getTransparence()) 1046 { 1047 // no transparence used, so just use the content 1048 process(rTransCandidate.getChildren()); 1049 } 1050 else if(rTransCandidate.getTransparence() > 0.0 && rTransCandidate.getTransparence() < 1.0) 1051 { 1052 // transparence is in visible range 1053 basegfx::B2DRange aRange(primitive2d::getB2DRangeFromPrimitive2DSequence(rTransCandidate.getChildren(), getViewInformation2D())); 1054 aRange.transform(maCurrentTransformation); 1055 impBufferDevice aBufferDevice(*mpOutputDevice, aRange, true); 1056 1057 if(aBufferDevice.isVisible()) 1058 { 1059 // remember last OutDev and set to content 1060 OutputDevice* pLastOutputDevice = mpOutputDevice; 1061 mpOutputDevice = &aBufferDevice.getContent(); 1062 1063 // paint content to it 1064 process(rTransCandidate.getChildren()); 1065 1066 // back to old OutDev 1067 mpOutputDevice = pLastOutputDevice; 1068 1069 // dump buffer to outdev using given transparence 1070 aBufferDevice.paint(rTransCandidate.getTransparence()); 1071 } 1072 } 1073 } 1074 } 1075 } 1076 1077 // sub-transparence group. Draw to VDev first. 1078 void VclProcessor2D::RenderTransparencePrimitive2D(const primitive2d::TransparencePrimitive2D& rTransCandidate) 1079 { 1080 if(rTransCandidate.getChildren().hasElements()) 1081 { 1082 basegfx::B2DRange aRange(primitive2d::getB2DRangeFromPrimitive2DSequence(rTransCandidate.getChildren(), getViewInformation2D())); 1083 aRange.transform(maCurrentTransformation); 1084 impBufferDevice aBufferDevice(*mpOutputDevice, aRange, true); 1085 1086 if(aBufferDevice.isVisible()) 1087 { 1088 // remember last OutDev and set to content 1089 OutputDevice* pLastOutputDevice = mpOutputDevice; 1090 mpOutputDevice = &aBufferDevice.getContent(); 1091 1092 // paint content to it 1093 process(rTransCandidate.getChildren()); 1094 1095 // set to mask 1096 mpOutputDevice = &aBufferDevice.getTransparence(); 1097 1098 // when painting transparence masks, reset the color stack 1099 basegfx::BColorModifierStack aLastBColorModifierStack(maBColorModifierStack); 1100 maBColorModifierStack = basegfx::BColorModifierStack(); 1101 1102 // paint mask to it (always with transparence intensities, evtl. with AA) 1103 process(rTransCandidate.getTransparence()); 1104 1105 // back to old color stack 1106 maBColorModifierStack = aLastBColorModifierStack; 1107 1108 // back to old OutDev 1109 mpOutputDevice = pLastOutputDevice; 1110 1111 // dump buffer to outdev 1112 aBufferDevice.paint(); 1113 } 1114 } 1115 } 1116 1117 // transform group. 1118 void VclProcessor2D::RenderTransformPrimitive2D(const primitive2d::TransformPrimitive2D& rTransformCandidate) 1119 { 1120 // remember current transformation and ViewInformation 1121 const basegfx::B2DHomMatrix aLastCurrentTransformation(maCurrentTransformation); 1122 const geometry::ViewInformation2D aLastViewInformation2D(getViewInformation2D()); 1123 1124 // create new transformations for CurrentTransformation 1125 // and for local ViewInformation2D 1126 maCurrentTransformation = maCurrentTransformation * rTransformCandidate.getTransformation(); 1127 const geometry::ViewInformation2D aViewInformation2D( 1128 getViewInformation2D().getObjectTransformation() * rTransformCandidate.getTransformation(), 1129 getViewInformation2D().getViewTransformation(), 1130 getViewInformation2D().getViewport(), 1131 getViewInformation2D().getVisualizedPage(), 1132 getViewInformation2D().getViewTime(), 1133 getViewInformation2D().getExtendedInformationSequence()); 1134 updateViewInformation(aViewInformation2D); 1135 1136 // proccess content 1137 process(rTransformCandidate.getChildren()); 1138 1139 // restore transformations 1140 maCurrentTransformation = aLastCurrentTransformation; 1141 updateViewInformation(aLastViewInformation2D); 1142 } 1143 1144 // new XDrawPage for ViewInformation2D 1145 void VclProcessor2D::RenderPagePreviewPrimitive2D(const primitive2d::PagePreviewPrimitive2D& rPagePreviewCandidate) 1146 { 1147 // remember current transformation and ViewInformation 1148 const geometry::ViewInformation2D aLastViewInformation2D(getViewInformation2D()); 1149 1150 // create new local ViewInformation2D 1151 const geometry::ViewInformation2D aViewInformation2D( 1152 getViewInformation2D().getObjectTransformation(), 1153 getViewInformation2D().getViewTransformation(), 1154 getViewInformation2D().getViewport(), 1155 rPagePreviewCandidate.getXDrawPage(), 1156 getViewInformation2D().getViewTime(), 1157 getViewInformation2D().getExtendedInformationSequence()); 1158 updateViewInformation(aViewInformation2D); 1159 1160 // proccess decomposed content 1161 process(rPagePreviewCandidate.get2DDecomposition(getViewInformation2D())); 1162 1163 // restore transformations 1164 updateViewInformation(aLastViewInformation2D); 1165 } 1166 1167 // marker 1168 void VclProcessor2D::RenderMarkerArrayPrimitive2D(const primitive2d::MarkerArrayPrimitive2D& rMarkArrayCandidate) 1169 { 1170 static bool bCheckCompleteMarkerDecompose(false); 1171 if(bCheckCompleteMarkerDecompose) 1172 { 1173 process(rMarkArrayCandidate.get2DDecomposition(getViewInformation2D())); 1174 return; 1175 } 1176 1177 // get data 1178 const std::vector< basegfx::B2DPoint >& rPositions = rMarkArrayCandidate.getPositions(); 1179 const sal_uInt32 nCount(rPositions.size()); 1180 1181 if(nCount && !rMarkArrayCandidate.getMarker().IsEmpty()) 1182 { 1183 // get pixel size 1184 const BitmapEx& rMarker(rMarkArrayCandidate.getMarker()); 1185 const Size aBitmapSize(rMarker.GetSizePixel()); 1186 1187 if(aBitmapSize.Width() && aBitmapSize.Height()) 1188 { 1189 // get discrete half size 1190 const basegfx::B2DVector aDiscreteHalfSize( 1191 (aBitmapSize.getWidth() - 1.0) * 0.5, 1192 (aBitmapSize.getHeight() - 1.0) * 0.5); 1193 const bool bWasEnabled(mpOutputDevice->IsMapModeEnabled()); 1194 1195 // do not forget evtl. moved origin in target device MapMode when 1196 // switching it off; it would be missing and lead to wrong positions. 1197 // All his could be done using logic sizes and coordinates, too, but 1198 // we want a 1:1 bitmap rendering here, so it's more safe and faster 1199 // to work with switching off MapMode usage completely. 1200 const Point aOrigin(mpOutputDevice->GetMapMode().GetOrigin()); 1201 1202 mpOutputDevice->EnableMapMode(false); 1203 1204 for(std::vector< basegfx::B2DPoint >::const_iterator aIter(rPositions.begin()); aIter != rPositions.end(); aIter++) 1205 { 1206 const basegfx::B2DPoint aDiscreteTopLeft((maCurrentTransformation * (*aIter)) - aDiscreteHalfSize); 1207 const Point aDiscretePoint(basegfx::fround(aDiscreteTopLeft.getX()), basegfx::fround(aDiscreteTopLeft.getY())); 1208 1209 mpOutputDevice->DrawBitmapEx(aDiscretePoint + aOrigin, rMarker); 1210 } 1211 1212 mpOutputDevice->EnableMapMode(bWasEnabled); 1213 } 1214 } 1215 } 1216 1217 // point 1218 void VclProcessor2D::RenderPointArrayPrimitive2D(const primitive2d::PointArrayPrimitive2D& rPointArrayCandidate) 1219 { 1220 const std::vector< basegfx::B2DPoint >& rPositions = rPointArrayCandidate.getPositions(); 1221 const basegfx::BColor aRGBColor(maBColorModifierStack.getModifiedColor(rPointArrayCandidate.getRGBColor())); 1222 const Color aVCLColor(aRGBColor); 1223 1224 for(std::vector< basegfx::B2DPoint >::const_iterator aIter(rPositions.begin()); aIter != rPositions.end(); aIter++) 1225 { 1226 const basegfx::B2DPoint aViewPosition(maCurrentTransformation * (*aIter)); 1227 const Point aPos(basegfx::fround(aViewPosition.getX()), basegfx::fround(aViewPosition.getY())); 1228 1229 mpOutputDevice->DrawPixel(aPos, aVCLColor); 1230 } 1231 } 1232 1233 void VclProcessor2D::RenderPolygonStrokePrimitive2D(const primitive2d::PolygonStrokePrimitive2D& rPolygonStrokeCandidate) 1234 { 1235 // #i101491# method restructured to clearly use the DrawPolyLine 1236 // calls starting from a deined line width 1237 const attribute::LineAttribute& rLineAttribute = rPolygonStrokeCandidate.getLineAttribute(); 1238 const double fLineWidth(rLineAttribute.getWidth()); 1239 bool bDone(false); 1240 1241 if(basegfx::fTools::more(fLineWidth, 0.0)) 1242 { 1243 const basegfx::B2DVector aDiscreteUnit(maCurrentTransformation * basegfx::B2DVector(fLineWidth, 0.0)); 1244 const double fDiscreteLineWidth(aDiscreteUnit.getLength()); 1245 const attribute::StrokeAttribute& rStrokeAttribute = rPolygonStrokeCandidate.getStrokeAttribute(); 1246 const basegfx::BColor aHairlineColor(maBColorModifierStack.getModifiedColor(rLineAttribute.getColor())); 1247 basegfx::B2DPolyPolygon aHairlinePolyPolygon; 1248 1249 mpOutputDevice->SetLineColor(Color(aHairlineColor)); 1250 mpOutputDevice->SetFillColor(); 1251 1252 if(0.0 == rStrokeAttribute.getFullDotDashLen()) 1253 { 1254 // no line dashing, just copy 1255 aHairlinePolyPolygon.append(rPolygonStrokeCandidate.getB2DPolygon()); 1256 } 1257 else 1258 { 1259 // else apply LineStyle 1260 basegfx::tools::applyLineDashing(rPolygonStrokeCandidate.getB2DPolygon(), 1261 rStrokeAttribute.getDotDashArray(), 1262 &aHairlinePolyPolygon, 0, rStrokeAttribute.getFullDotDashLen()); 1263 } 1264 1265 const sal_uInt32 nCount(aHairlinePolyPolygon.count()); 1266 1267 if(nCount) 1268 { 1269 const bool bAntiAliased(getOptionsDrawinglayer().IsAntiAliasing()); 1270 aHairlinePolyPolygon.transform(maCurrentTransformation); 1271 1272 if(bAntiAliased) 1273 { 1274 if(basegfx::fTools::lessOrEqual(fDiscreteLineWidth, 1.0)) 1275 { 1276 // line in range ]0.0 .. 1.0[ 1277 // paint as simple hairline 1278 for(sal_uInt32 a(0); a < nCount; a++) 1279 { 1280 mpOutputDevice->DrawPolyLine(aHairlinePolyPolygon.getB2DPolygon(a), 0.0); 1281 } 1282 1283 bDone = true; 1284 } 1285 else if(basegfx::fTools::lessOrEqual(fDiscreteLineWidth, 2.0)) 1286 { 1287 // line in range [1.0 .. 2.0[ 1288 // paint as 2x2 with dynamic line distance 1289 basegfx::B2DHomMatrix aMat; 1290 const double fDistance(fDiscreteLineWidth - 1.0); 1291 const double fHalfDistance(fDistance * 0.5); 1292 1293 for(sal_uInt32 a(0); a < nCount; a++) 1294 { 1295 basegfx::B2DPolygon aCandidate(aHairlinePolyPolygon.getB2DPolygon(a)); 1296 1297 aMat.set(0, 2, -fHalfDistance); 1298 aMat.set(1, 2, -fHalfDistance); 1299 aCandidate.transform(aMat); 1300 mpOutputDevice->DrawPolyLine(aCandidate, 0.0); 1301 1302 aMat.set(0, 2, fDistance); 1303 aMat.set(1, 2, 0.0); 1304 aCandidate.transform(aMat); 1305 mpOutputDevice->DrawPolyLine(aCandidate, 0.0); 1306 1307 aMat.set(0, 2, 0.0); 1308 aMat.set(1, 2, fDistance); 1309 aCandidate.transform(aMat); 1310 mpOutputDevice->DrawPolyLine(aCandidate, 0.0); 1311 1312 aMat.set(0, 2, -fDistance); 1313 aMat.set(1, 2, 0.0); 1314 aCandidate.transform(aMat); 1315 mpOutputDevice->DrawPolyLine(aCandidate, 0.0); 1316 } 1317 1318 bDone = true; 1319 } 1320 else if(basegfx::fTools::lessOrEqual(fDiscreteLineWidth, 3.0)) 1321 { 1322 // line in range [2.0 .. 3.0] 1323 // paint as cross in a 3x3 with dynamic line distance 1324 basegfx::B2DHomMatrix aMat; 1325 const double fDistance((fDiscreteLineWidth - 1.0) * 0.5); 1326 1327 for(sal_uInt32 a(0); a < nCount; a++) 1328 { 1329 basegfx::B2DPolygon aCandidate(aHairlinePolyPolygon.getB2DPolygon(a)); 1330 1331 mpOutputDevice->DrawPolyLine(aCandidate, 0.0); 1332 1333 aMat.set(0, 2, -fDistance); 1334 aMat.set(1, 2, 0.0); 1335 aCandidate.transform(aMat); 1336 mpOutputDevice->DrawPolyLine(aCandidate, 0.0); 1337 1338 aMat.set(0, 2, fDistance); 1339 aMat.set(1, 2, -fDistance); 1340 aCandidate.transform(aMat); 1341 mpOutputDevice->DrawPolyLine(aCandidate, 0.0); 1342 1343 aMat.set(0, 2, fDistance); 1344 aMat.set(1, 2, fDistance); 1345 aCandidate.transform(aMat); 1346 mpOutputDevice->DrawPolyLine(aCandidate, 0.0); 1347 1348 aMat.set(0, 2, -fDistance); 1349 aMat.set(1, 2, fDistance); 1350 aCandidate.transform(aMat); 1351 mpOutputDevice->DrawPolyLine(aCandidate, 0.0); 1352 } 1353 1354 bDone = true; 1355 } 1356 else 1357 { 1358 // #i101491# line width above 3.0 1359 } 1360 } 1361 else 1362 { 1363 if(basegfx::fTools::lessOrEqual(fDiscreteLineWidth, 1.5)) 1364 { 1365 // line width below 1.5, draw the basic hairline polygon 1366 for(sal_uInt32 a(0); a < nCount; a++) 1367 { 1368 mpOutputDevice->DrawPolyLine(aHairlinePolyPolygon.getB2DPolygon(a), 0.0); 1369 } 1370 1371 bDone = true; 1372 } 1373 else if(basegfx::fTools::lessOrEqual(fDiscreteLineWidth, 2.5)) 1374 { 1375 // line width is in range ]1.5 .. 2.5], use four hairlines 1376 // drawn in a square 1377 for(sal_uInt32 a(0); a < nCount; a++) 1378 { 1379 basegfx::B2DPolygon aCandidate(aHairlinePolyPolygon.getB2DPolygon(a)); 1380 basegfx::B2DHomMatrix aMat; 1381 1382 mpOutputDevice->DrawPolyLine(aCandidate, 0.0); 1383 1384 aMat.set(0, 2, 1.0); 1385 aMat.set(1, 2, 0.0); 1386 aCandidate.transform(aMat); 1387 1388 mpOutputDevice->DrawPolyLine(aCandidate, 0.0); 1389 1390 aMat.set(0, 2, 0.0); 1391 aMat.set(1, 2, 1.0); 1392 aCandidate.transform(aMat); 1393 1394 mpOutputDevice->DrawPolyLine(aCandidate, 0.0); 1395 1396 aMat.set(0, 2, -1.0); 1397 aMat.set(1, 2, 0.0); 1398 aCandidate.transform(aMat); 1399 1400 mpOutputDevice->DrawPolyLine(aCandidate, 0.0); 1401 } 1402 1403 bDone = true; 1404 } 1405 else 1406 { 1407 // #i101491# line width is above 2.5 1408 } 1409 } 1410 1411 if(!bDone && rPolygonStrokeCandidate.getB2DPolygon().count() > 1000) 1412 { 1413 // #i101491# If the polygon complexity uses more than a given amount, do 1414 // use OuputDevice::DrawPolyLine directly; this will avoid buffering all 1415 // decompositions in primtives (memory) and fallback to old line painting 1416 // for very complex polygons, too 1417 for(sal_uInt32 a(0); a < nCount; a++) 1418 { 1419 mpOutputDevice->DrawPolyLine( 1420 aHairlinePolyPolygon.getB2DPolygon(a), 1421 fDiscreteLineWidth, 1422 rLineAttribute.getLineJoin(), 1423 rLineAttribute.getLineCap()); 1424 } 1425 1426 bDone = true; 1427 } 1428 } 1429 } 1430 1431 if(!bDone) 1432 { 1433 // remeber that we enter a PolygonStrokePrimitive2D decomposition, 1434 // used for AA thick line drawing 1435 mnPolygonStrokePrimitive2D++; 1436 1437 // line width is big enough for standard filled polygon visualisation or zero 1438 process(rPolygonStrokeCandidate.get2DDecomposition(getViewInformation2D())); 1439 1440 // leave PolygonStrokePrimitive2D 1441 mnPolygonStrokePrimitive2D--; 1442 } 1443 } 1444 1445 void VclProcessor2D::RenderEpsPrimitive2D(const primitive2d::EpsPrimitive2D& rEpsPrimitive2D) 1446 { 1447 // The new decomposition of Metafiles made it necessary to add an Eps 1448 // primitive to handle embedded Eps data. On some devices, this can be 1449 // painted directly (mac, printer). 1450 // To be able to handle the replacement correctly, i need to handle it myself 1451 // since DrawEPS will not be able e.g. to rotate the replacement. To be able 1452 // to do that, i added a boolean return to OutputDevice::DrawEPS(..) 1453 // to know when EPS was handled directly already. 1454 basegfx::B2DRange aRange(0.0, 0.0, 1.0, 1.0); 1455 aRange.transform(maCurrentTransformation * rEpsPrimitive2D.getEpsTransform()); 1456 1457 if(!aRange.isEmpty()) 1458 { 1459 const Rectangle aRectangle( 1460 (sal_Int32)floor(aRange.getMinX()), (sal_Int32)floor(aRange.getMinY()), 1461 (sal_Int32)ceil(aRange.getMaxX()), (sal_Int32)ceil(aRange.getMaxY())); 1462 1463 if(!aRectangle.IsEmpty()) 1464 { 1465 // try to paint EPS directly without fallback visualisation 1466 const bool bEPSPaintedDirectly(mpOutputDevice->DrawEPS( 1467 aRectangle.TopLeft(), 1468 aRectangle.GetSize(), 1469 rEpsPrimitive2D.getGfxLink(), 1470 0)); 1471 1472 if(!bEPSPaintedDirectly) 1473 { 1474 // use the decomposition which will correctly handle the 1475 // fallback visualisation using full transformation (e.g. rotation) 1476 process(rEpsPrimitive2D.get2DDecomposition(getViewInformation2D())); 1477 } 1478 } 1479 } 1480 } 1481 1482 void VclProcessor2D::RenderSvgLinearAtomPrimitive2D(const primitive2d::SvgLinearAtomPrimitive2D& rCandidate) 1483 { 1484 const double fDelta(rCandidate.getOffsetB() - rCandidate.getOffsetA()); 1485 1486 if(basegfx::fTools::more(fDelta, 0.0)) 1487 { 1488 const basegfx::BColor aColorA(maBColorModifierStack.getModifiedColor(rCandidate.getColorA())); 1489 const basegfx::BColor aColorB(maBColorModifierStack.getModifiedColor(rCandidate.getColorB())); 1490 const double fDiscreteUnit((getViewInformation2D().getInverseObjectToViewTransformation() * basegfx::B2DVector(1.0, 0.0)).getLength()); 1491 1492 // use color distance and discrete lengths to calculate step count 1493 const sal_uInt32 nSteps(calculateStepsForSvgGradient(aColorA, aColorB, fDelta, fDiscreteUnit)); 1494 1495 // switch off line painting 1496 mpOutputDevice->SetLineColor(); 1497 1498 // prepare polygon in needed width at start position (with discrete overlap) 1499 const basegfx::B2DPolygon aPolygon( 1500 basegfx::tools::createPolygonFromRect( 1501 basegfx::B2DRange( 1502 rCandidate.getOffsetA() - fDiscreteUnit, 1503 0.0, 1504 rCandidate.getOffsetA() + (fDelta / nSteps) + fDiscreteUnit, 1505 1.0))); 1506 1507 1508 // prepare loop ([0.0 .. 1.0[) 1509 double fUnitScale(0.0); 1510 const double fUnitStep(1.0 / nSteps); 1511 1512 // loop and paint 1513 for(sal_uInt32 a(0); a < nSteps; a++, fUnitScale += fUnitStep) 1514 { 1515 basegfx::B2DPolygon aNew(aPolygon); 1516 1517 aNew.transform(maCurrentTransformation * basegfx::tools::createTranslateB2DHomMatrix(fDelta * fUnitScale, 0.0)); 1518 mpOutputDevice->SetFillColor(Color(basegfx::interpolate(aColorA, aColorB, fUnitScale))); 1519 mpOutputDevice->DrawPolyPolygon(basegfx::B2DPolyPolygon(aNew)); 1520 } 1521 } 1522 } 1523 1524 void VclProcessor2D::RenderSvgRadialAtomPrimitive2D(const primitive2d::SvgRadialAtomPrimitive2D& rCandidate) 1525 { 1526 const double fDeltaScale(rCandidate.getScaleB() - rCandidate.getScaleA()); 1527 1528 if(basegfx::fTools::more(fDeltaScale, 0.0)) 1529 { 1530 const basegfx::BColor aColorA(maBColorModifierStack.getModifiedColor(rCandidate.getColorA())); 1531 const basegfx::BColor aColorB(maBColorModifierStack.getModifiedColor(rCandidate.getColorB())); 1532 const double fDiscreteUnit((getViewInformation2D().getInverseObjectToViewTransformation() * basegfx::B2DVector(1.0, 0.0)).getLength()); 1533 1534 // use color distance and discrete lengths to calculate step count 1535 const sal_uInt32 nSteps(calculateStepsForSvgGradient(aColorA, aColorB, fDeltaScale, fDiscreteUnit)); 1536 1537 // switch off line painting 1538 mpOutputDevice->SetLineColor(); 1539 1540 // prepare loop ([0.0 .. 1.0[, full polygons, no polypolygons with holes) 1541 double fUnitScale(0.0); 1542 const double fUnitStep(1.0 / nSteps); 1543 1544 for(sal_uInt32 a(0); a < nSteps; a++, fUnitScale += fUnitStep) 1545 { 1546 basegfx::B2DHomMatrix aTransform; 1547 const double fEndScale(rCandidate.getScaleB() - (fDeltaScale * fUnitScale)); 1548 1549 if(rCandidate.isTranslateSet()) 1550 { 1551 const basegfx::B2DVector aTranslate( 1552 basegfx::interpolate( 1553 rCandidate.getTranslateB(), 1554 rCandidate.getTranslateA(), 1555 fUnitScale)); 1556 1557 aTransform = basegfx::tools::createScaleTranslateB2DHomMatrix( 1558 fEndScale, 1559 fEndScale, 1560 aTranslate.getX(), 1561 aTranslate.getY()); 1562 } 1563 else 1564 { 1565 aTransform = basegfx::tools::createScaleB2DHomMatrix( 1566 fEndScale, 1567 fEndScale); 1568 } 1569 1570 basegfx::B2DPolygon aNew(basegfx::tools::createPolygonFromUnitCircle()); 1571 1572 aNew.transform(maCurrentTransformation * aTransform); 1573 mpOutputDevice->SetFillColor(Color(basegfx::interpolate(aColorB, aColorA, fUnitScale))); 1574 mpOutputDevice->DrawPolyPolygon(basegfx::B2DPolyPolygon(aNew)); 1575 } 1576 } 1577 } 1578 1579 void VclProcessor2D::adaptLineToFillDrawMode() const 1580 { 1581 const sal_uInt32 nOriginalDrawMode(mpOutputDevice->GetDrawMode()); 1582 1583 if(nOriginalDrawMode & (DRAWMODE_BLACKLINE|DRAWMODE_GRAYLINE|DRAWMODE_GHOSTEDLINE|DRAWMODE_WHITELINE|DRAWMODE_SETTINGSLINE)) 1584 { 1585 sal_uInt32 nAdaptedDrawMode(nOriginalDrawMode); 1586 1587 if(nOriginalDrawMode & DRAWMODE_BLACKLINE) 1588 { 1589 nAdaptedDrawMode |= DRAWMODE_BLACKFILL; 1590 } 1591 else 1592 { 1593 nAdaptedDrawMode &= ~DRAWMODE_BLACKFILL; 1594 } 1595 1596 if(nOriginalDrawMode & DRAWMODE_GRAYLINE) 1597 { 1598 nAdaptedDrawMode |= DRAWMODE_GRAYFILL; 1599 } 1600 else 1601 { 1602 nAdaptedDrawMode &= ~DRAWMODE_GRAYFILL; 1603 } 1604 1605 if(nOriginalDrawMode & DRAWMODE_GHOSTEDLINE) 1606 { 1607 nAdaptedDrawMode |= DRAWMODE_GHOSTEDFILL; 1608 } 1609 else 1610 { 1611 nAdaptedDrawMode &= ~DRAWMODE_GHOSTEDFILL; 1612 } 1613 1614 if(nOriginalDrawMode & DRAWMODE_WHITELINE) 1615 { 1616 nAdaptedDrawMode |= DRAWMODE_WHITEFILL; 1617 } 1618 else 1619 { 1620 nAdaptedDrawMode &= ~DRAWMODE_WHITEFILL; 1621 } 1622 1623 if(nOriginalDrawMode & DRAWMODE_SETTINGSLINE) 1624 { 1625 nAdaptedDrawMode |= DRAWMODE_SETTINGSFILL; 1626 } 1627 else 1628 { 1629 nAdaptedDrawMode &= ~DRAWMODE_SETTINGSFILL; 1630 } 1631 1632 mpOutputDevice->SetDrawMode(nAdaptedDrawMode); 1633 } 1634 } 1635 1636 void VclProcessor2D::adaptTextToFillDrawMode() const 1637 { 1638 const sal_uInt32 nOriginalDrawMode(mpOutputDevice->GetDrawMode()); 1639 if(nOriginalDrawMode & (DRAWMODE_BLACKTEXT|DRAWMODE_GRAYTEXT|DRAWMODE_GHOSTEDTEXT|DRAWMODE_WHITETEXT|DRAWMODE_SETTINGSTEXT)) 1640 { 1641 sal_uInt32 nAdaptedDrawMode(nOriginalDrawMode); 1642 1643 if(nOriginalDrawMode & DRAWMODE_BLACKTEXT) 1644 { 1645 nAdaptedDrawMode |= DRAWMODE_BLACKFILL; 1646 } 1647 else 1648 { 1649 nAdaptedDrawMode &= ~DRAWMODE_BLACKFILL; 1650 } 1651 1652 if(nOriginalDrawMode & DRAWMODE_GRAYTEXT) 1653 { 1654 nAdaptedDrawMode |= DRAWMODE_GRAYFILL; 1655 } 1656 else 1657 { 1658 nAdaptedDrawMode &= ~DRAWMODE_GRAYFILL; 1659 } 1660 1661 if(nOriginalDrawMode & DRAWMODE_GHOSTEDTEXT) 1662 { 1663 nAdaptedDrawMode |= DRAWMODE_GHOSTEDFILL; 1664 } 1665 else 1666 { 1667 nAdaptedDrawMode &= ~DRAWMODE_GHOSTEDFILL; 1668 } 1669 1670 if(nOriginalDrawMode & DRAWMODE_WHITETEXT) 1671 { 1672 nAdaptedDrawMode |= DRAWMODE_WHITEFILL; 1673 } 1674 else 1675 { 1676 nAdaptedDrawMode &= ~DRAWMODE_WHITEFILL; 1677 } 1678 1679 if(nOriginalDrawMode & DRAWMODE_SETTINGSTEXT) 1680 { 1681 nAdaptedDrawMode |= DRAWMODE_SETTINGSFILL; 1682 } 1683 else 1684 { 1685 nAdaptedDrawMode &= ~DRAWMODE_SETTINGSFILL; 1686 } 1687 1688 mpOutputDevice->SetDrawMode(nAdaptedDrawMode); 1689 } 1690 } 1691 1692 ////////////////////////////////////////////////////////////////////////////// 1693 // process support 1694 1695 VclProcessor2D::VclProcessor2D( 1696 const geometry::ViewInformation2D& rViewInformation, 1697 OutputDevice& rOutDev) 1698 : BaseProcessor2D(rViewInformation), 1699 mpOutputDevice(&rOutDev), 1700 maBColorModifierStack(), 1701 maCurrentTransformation(), 1702 maDrawinglayerOpt(), 1703 mnPolygonStrokePrimitive2D(0) 1704 { 1705 // set digit language, derived from SvtCTLOptions to have the correct 1706 // number display for arabic/hindi numerals 1707 const SvtCTLOptions aSvtCTLOptions; 1708 LanguageType eLang(LANGUAGE_SYSTEM); 1709 1710 if(SvtCTLOptions::NUMERALS_HINDI == aSvtCTLOptions.GetCTLTextNumerals()) 1711 { 1712 eLang = LANGUAGE_ARABIC_SAUDI_ARABIA; 1713 } 1714 else if(SvtCTLOptions::NUMERALS_ARABIC == aSvtCTLOptions.GetCTLTextNumerals()) 1715 { 1716 eLang = LANGUAGE_ENGLISH; 1717 } 1718 else 1719 { 1720 eLang = (LanguageType)Application::GetSettings().GetLanguage(); 1721 } 1722 1723 rOutDev.SetDigitLanguage(eLang); 1724 } 1725 1726 VclProcessor2D::~VclProcessor2D() 1727 { 1728 } 1729 } // end of namespace processor2d 1730 } // end of namespace drawinglayer 1731 1732 ////////////////////////////////////////////////////////////////////////////// 1733 // eof 1734