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 // #121387# when mirrored and rotated, avoid the GraphicManager output which has low quality 428 const bool bRotated(!basegfx::fTools::equalZero(fRotate)); 429 const bool bSheared(!basegfx::fTools::equalZero(fShearX)); 430 const bool bMirrored(aScale.getX() < 0.0 || aScale.getY() < 0.0); 431 const bool bMirroredAndRotated(bRotated && bMirrored); 432 433 if(!bForceUseOfOwnTransformer && !bSheared && !bMirroredAndRotated) 434 { 435 if(!bUseGraphicManager && !bRotated) 436 { 437 RenderBitmapPrimitive2D_BitmapEx(*mpOutputDevice, aBitmapEx, aLocalTransform); 438 } 439 else 440 { 441 RenderBitmapPrimitive2D_GraphicManager(*mpOutputDevice, aBitmapEx, aLocalTransform); 442 } 443 } 444 else 445 { 446 if(!aBitmapEx.IsTransparent() && (bSheared || bRotated)) 447 { 448 // parts will be uncovered, extend aBitmapEx with a mask bitmap 449 const Bitmap aContent(aBitmapEx.GetBitmap()); 450 aBitmapEx = BitmapEx(aContent, Bitmap(aContent.GetSizePixel(), 1)); 451 } 452 453 RenderBitmapPrimitive2D_self(*mpOutputDevice, aBitmapEx, aLocalTransform); 454 } 455 } 456 } 457 458 void VclProcessor2D::RenderFillGraphicPrimitive2D(const primitive2d::FillGraphicPrimitive2D& rFillBitmapCandidate) 459 { 460 const attribute::FillGraphicAttribute& rFillGraphicAttribute(rFillBitmapCandidate.getFillGraphic()); 461 bool bPrimitiveAccepted(false); 462 static bool bTryTilingDirect = true; 463 464 // #121194# when tiling is used and content is bitmap-based, do direct tiling in the 465 // renderer on pixel base to ensure tight fitting. Do not do this when 466 // the fill is rotated or sheared. 467 468 // ovveride static bool (for debug) and tiling is active 469 if(bTryTilingDirect && rFillGraphicAttribute.getTiling()) 470 { 471 // content is bitmap(ex) 472 // 473 // for SVG support, force decomposition when SVG is present. This will lead to use 474 // the primitive representation of the svg directly. 475 // 476 // when graphic is animated, force decomposition to use the correct graphic, else 477 // fill style will not be animated 478 if(GRAPHIC_BITMAP == rFillGraphicAttribute.getGraphic().GetType() 479 && !rFillGraphicAttribute.getGraphic().getSvgData().get() 480 && !rFillGraphicAttribute.getGraphic().IsAnimated()) 481 { 482 // decompose matrix to check for shear, rotate and mirroring 483 basegfx::B2DHomMatrix aLocalTransform(maCurrentTransformation * rFillBitmapCandidate.getTransformation()); 484 basegfx::B2DVector aScale, aTranslate; 485 double fRotate, fShearX; 486 aLocalTransform.decompose(aScale, aTranslate, fRotate, fShearX); 487 488 // when nopt rotated/sheared 489 if(basegfx::fTools::equalZero(fRotate) && basegfx::fTools::equalZero(fShearX)) 490 { 491 // no shear or rotate, draw direct in pixel coordinates 492 bPrimitiveAccepted = true; 493 494 // transform object range to device coordinates (pixels). Use 495 // the device transformation for better accuracy 496 basegfx::B2DRange aObjectRange(aTranslate, aTranslate + aScale); 497 aObjectRange.transform(mpOutputDevice->GetViewTransformation()); 498 499 // extract discrete size of object 500 const sal_Int32 nOWidth(basegfx::fround(aObjectRange.getWidth())); 501 const sal_Int32 nOHeight(basegfx::fround(aObjectRange.getHeight())); 502 503 // only do something when object has a size in discrete units 504 if(nOWidth > 0 && nOHeight > 0) 505 { 506 // transform graphic range to device coordinates (pixels). Use 507 // the device transformation for better accuracy 508 basegfx::B2DRange aGraphicRange(rFillGraphicAttribute.getGraphicRange()); 509 aGraphicRange.transform(mpOutputDevice->GetViewTransformation() * aLocalTransform); 510 511 // extract discrete size of graphic 512 const sal_Int32 nBWidth(basegfx::fround(aGraphicRange.getWidth())); 513 const sal_Int32 nBHeight(basegfx::fround(aGraphicRange.getHeight())); 514 515 // only do something when bitmap fill has a size in discrete units 516 if(nBWidth > 0 && nBHeight > 0) 517 { 518 // nBWidth, nBHeight is the pixel size of the neede bitmap. To not need to scale it 519 // in vcl many times, create a size-optimized version 520 const Size aNeededBitmapSizePixel(nBWidth, nBHeight); 521 BitmapEx aBitmapEx(rFillGraphicAttribute.getGraphic().GetBitmapEx()); 522 static bool bEnablePreScaling(true); 523 const bool bPreScaled(bEnablePreScaling && nBWidth * nBHeight < (250 * 250)); 524 525 if(bPreScaled) 526 { 527 // ... but only up to a maximum size, else it gets too expensive 528 aBitmapEx.Scale(aNeededBitmapSizePixel, BMP_SCALE_INTERPOLATE); 529 } 530 531 bool bPainted(false); 532 533 if(maBColorModifierStack.count()) 534 { 535 // when color modifier, apply to bitmap 536 aBitmapEx = impModifyBitmapEx(maBColorModifierStack, aBitmapEx); 537 538 // impModifyBitmapEx uses empty bitmap as sign to return that 539 // the content will be completely replaced to mono color, use shortcut 540 if(aBitmapEx.IsEmpty()) 541 { 542 // color gets completely replaced, get it 543 const basegfx::BColor aModifiedColor(maBColorModifierStack.getModifiedColor(basegfx::BColor())); 544 basegfx::B2DPolygon aPolygon(basegfx::tools::createUnitPolygon()); 545 aPolygon.transform(aLocalTransform); 546 547 mpOutputDevice->SetFillColor(Color(aModifiedColor)); 548 mpOutputDevice->SetLineColor(); 549 mpOutputDevice->DrawPolygon(aPolygon); 550 551 bPainted = true; 552 } 553 } 554 555 if(!bPainted) 556 { 557 sal_Int32 nBLeft(basegfx::fround(aGraphicRange.getMinX())); 558 sal_Int32 nBTop(basegfx::fround(aGraphicRange.getMinY())); 559 const sal_Int32 nOLeft(basegfx::fround(aObjectRange.getMinX())); 560 const sal_Int32 nOTop(basegfx::fround(aObjectRange.getMinY())); 561 sal_Int32 nPosX(0); 562 sal_Int32 nPosY(0); 563 564 if(nBLeft > nOLeft) 565 { 566 const sal_Int32 nDiff((nBLeft / nBWidth) + 1); 567 568 nPosX -= nDiff; 569 nBLeft -= nDiff * nBWidth; 570 } 571 572 if(nBLeft + nBWidth <= nOLeft) 573 { 574 const sal_Int32 nDiff(-nBLeft / nBWidth); 575 576 nPosX += nDiff; 577 nBLeft += nDiff * nBWidth; 578 } 579 580 if(nBTop > nOTop) 581 { 582 const sal_Int32 nDiff((nBTop / nBHeight) + 1); 583 584 nPosY -= nDiff; 585 nBTop -= nDiff * nBHeight; 586 } 587 588 if(nBTop + nBHeight <= nOTop) 589 { 590 const sal_Int32 nDiff(-nBTop / nBHeight); 591 592 nPosY += nDiff; 593 nBTop += nDiff * nBHeight; 594 } 595 596 // prepare OutDev 597 const Point aEmptyPoint(0, 0); 598 const Rectangle aVisiblePixel(aEmptyPoint, mpOutputDevice->GetOutputSizePixel()); 599 const bool bWasEnabled(mpOutputDevice->IsMapModeEnabled()); 600 mpOutputDevice->EnableMapMode(false); 601 602 // check if offset is used 603 const sal_Int32 nOffsetX(basegfx::fround(rFillGraphicAttribute.getOffsetX() * nBWidth)); 604 605 if(nOffsetX) 606 { 607 // offset in X, so iterate over Y first and draw lines 608 for(sal_Int32 nYPos(nBTop); nYPos < nOTop + nOHeight; nYPos += nBHeight, nPosY++) 609 { 610 for(sal_Int32 nXPos(nPosY % 2 ? nBLeft - nBWidth + nOffsetX : nBLeft); 611 nXPos < nOLeft + nOWidth; nXPos += nBWidth) 612 { 613 const Rectangle aOutRectPixel(Point(nXPos, nYPos), aNeededBitmapSizePixel); 614 615 if(aOutRectPixel.IsOver(aVisiblePixel)) 616 { 617 if(bPreScaled) 618 { 619 mpOutputDevice->DrawBitmapEx(aOutRectPixel.TopLeft(), aBitmapEx); 620 } 621 else 622 { 623 mpOutputDevice->DrawBitmapEx(aOutRectPixel.TopLeft(), aNeededBitmapSizePixel, aBitmapEx); 624 } 625 } 626 } 627 } 628 } 629 else 630 { 631 // check if offset is used 632 const sal_Int32 nOffsetY(basegfx::fround(rFillGraphicAttribute.getOffsetY() * nBHeight)); 633 634 // possible offset in Y, so iterate over X first and draw columns 635 for(sal_Int32 nXPos(nBLeft); nXPos < nOLeft + nOWidth; nXPos += nBWidth, nPosX++) 636 { 637 for(sal_Int32 nYPos(nPosX % 2 ? nBTop - nBHeight + nOffsetY : nBTop); 638 nYPos < nOTop + nOHeight; nYPos += nBHeight) 639 { 640 const Rectangle aOutRectPixel(Point(nXPos, nYPos), aNeededBitmapSizePixel); 641 642 if(aOutRectPixel.IsOver(aVisiblePixel)) 643 { 644 if(bPreScaled) 645 { 646 mpOutputDevice->DrawBitmapEx(aOutRectPixel.TopLeft(), aBitmapEx); 647 } 648 else 649 { 650 mpOutputDevice->DrawBitmapEx(aOutRectPixel.TopLeft(), aNeededBitmapSizePixel, aBitmapEx); 651 } 652 } 653 } 654 } 655 } 656 657 // restore OutDev 658 mpOutputDevice->EnableMapMode(bWasEnabled); 659 } 660 } 661 } 662 } 663 } 664 } 665 666 if(!bPrimitiveAccepted) 667 { 668 // do not accept, use decomposition 669 process(rFillBitmapCandidate.get2DDecomposition(getViewInformation2D())); 670 } 671 } 672 673 // direct draw of gradient 674 void VclProcessor2D::RenderPolyPolygonGradientPrimitive2D(const primitive2d::PolyPolygonGradientPrimitive2D& rPolygonCandidate) 675 { 676 const attribute::FillGradientAttribute& rGradient(rPolygonCandidate.getFillGradient()); 677 basegfx::BColor aStartColor(maBColorModifierStack.getModifiedColor(rGradient.getStartColor())); 678 basegfx::BColor aEndColor(maBColorModifierStack.getModifiedColor(rGradient.getEndColor())); 679 basegfx::B2DPolyPolygon aLocalPolyPolygon(rPolygonCandidate.getB2DPolyPolygon()); 680 681 if(aLocalPolyPolygon.count()) 682 { 683 aLocalPolyPolygon.transform(maCurrentTransformation); 684 685 if(aStartColor == aEndColor) 686 { 687 // no gradient at all, draw as polygon in AA and non-AA case 688 mpOutputDevice->SetLineColor(); 689 mpOutputDevice->SetFillColor(Color(aStartColor)); 690 mpOutputDevice->DrawPolyPolygon(aLocalPolyPolygon); 691 } 692 else if(getOptionsDrawinglayer().IsAntiAliasing()) 693 { 694 // For AA, direct render has to be avoided since it uses XOR maskings which will not 695 // work with AA. Instead, the decompose which uses MaskPrimitive2D with fillings is 696 // used 697 process(rPolygonCandidate.get2DDecomposition(getViewInformation2D())); 698 } 699 else 700 { 701 static bool bSimple = false; // allow testing simple paint in debugger 702 703 impDrawGradientToOutDev( 704 *mpOutputDevice, aLocalPolyPolygon, rGradient.getStyle(), rGradient.getSteps(), 705 aStartColor, aEndColor, rGradient.getBorder(), 706 rGradient.getAngle(), rGradient.getOffsetX(), rGradient.getOffsetY(), bSimple); 707 } 708 } 709 } 710 711 // direct draw of Graphic 712 void VclProcessor2D::RenderPolyPolygonGraphicPrimitive2D(const primitive2d::PolyPolygonGraphicPrimitive2D& rPolygonCandidate) 713 { 714 bool bDone(false); 715 const basegfx::B2DPolyPolygon& rPolyPolygon = rPolygonCandidate.getB2DPolyPolygon(); 716 717 // #121194# Todo: check if this works 718 if(!rPolyPolygon.count()) 719 { 720 // empty polyPolygon, done 721 bDone = true; 722 } 723 else 724 { 725 const attribute::FillGraphicAttribute& rFillGraphicAttribute = rPolygonCandidate.getFillGraphic(); 726 727 // try to catch cases where the graphic will be color-modified to a single 728 // color (e.g. shadow) 729 switch(rFillGraphicAttribute.getGraphic().GetType()) 730 { 731 case GRAPHIC_GDIMETAFILE: 732 { 733 // metafiles are potentially transparent, cannot optimize�, not done 734 break; 735 } 736 case GRAPHIC_BITMAP: 737 { 738 if(!rFillGraphicAttribute.getGraphic().IsTransparent() && !rFillGraphicAttribute.getGraphic().IsAlpha()) 739 { 740 // bitmap is not transparent and has no alpha 741 const sal_uInt32 nBColorModifierStackCount(maBColorModifierStack.count()); 742 743 if(nBColorModifierStackCount) 744 { 745 const basegfx::BColorModifier& rTopmostModifier = maBColorModifierStack.getBColorModifier(nBColorModifierStackCount - 1); 746 747 if(basegfx::BCOLORMODIFYMODE_REPLACE == rTopmostModifier.getMode()) 748 { 749 // the bitmap fill is in unified color, so we can replace it with 750 // a single polygon fill. The form of the fill depends on tiling 751 if(rFillGraphicAttribute.getTiling()) 752 { 753 // with tiling, fill the whole PolyPolygon with the modifier color 754 basegfx::B2DPolyPolygon aLocalPolyPolygon(rPolyPolygon); 755 756 aLocalPolyPolygon.transform(maCurrentTransformation); 757 mpOutputDevice->SetLineColor(); 758 mpOutputDevice->SetFillColor(Color(rTopmostModifier.getBColor())); 759 mpOutputDevice->DrawPolyPolygon(aLocalPolyPolygon); 760 } 761 else 762 { 763 // without tiling, only the area common to the bitmap tile and the 764 // PolyPolygon is filled. Create the bitmap tile area in object 765 // coordinates. For this, the object transformation needs to be created 766 // from the already scaled PolyPolygon. The tile area in object 767 // coordinates wil always be non-rotated, so it's not necessary to 768 // work with a polygon here 769 basegfx::B2DRange aTileRange(rFillGraphicAttribute.getGraphicRange()); 770 const basegfx::B2DRange aPolyPolygonRange(rPolyPolygon.getB2DRange()); 771 const basegfx::B2DHomMatrix aNewObjectTransform( 772 basegfx::tools::createScaleTranslateB2DHomMatrix( 773 aPolyPolygonRange.getRange(), 774 aPolyPolygonRange.getMinimum())); 775 776 aTileRange.transform(aNewObjectTransform); 777 778 // now clip the object polyPolygon against the tile range 779 // to get the common area 780 basegfx::B2DPolyPolygon aTarget = basegfx::tools::clipPolyPolygonOnRange( 781 rPolyPolygon, 782 aTileRange, 783 true, 784 false); 785 786 if(aTarget.count()) 787 { 788 aTarget.transform(maCurrentTransformation); 789 mpOutputDevice->SetLineColor(); 790 mpOutputDevice->SetFillColor(Color(rTopmostModifier.getBColor())); 791 mpOutputDevice->DrawPolyPolygon(aTarget); 792 } 793 } 794 795 // simplified output executed, we are done 796 bDone = true; 797 } 798 } 799 } 800 break; 801 } 802 default: //GRAPHIC_NONE, GRAPHIC_DEFAULT 803 { 804 // empty graphic, we are done 805 bDone = true; 806 break; 807 } 808 } 809 } 810 811 if(!bDone) 812 { 813 // use default decomposition 814 process(rPolygonCandidate.get2DDecomposition(getViewInformation2D())); 815 } 816 } 817 818 // direct draw of PolyPolygon with color 819 void VclProcessor2D::RenderPolyPolygonColorPrimitive2D(const primitive2d::PolyPolygonColorPrimitive2D& rPolygonCandidate) 820 { 821 const basegfx::BColor aPolygonColor(maBColorModifierStack.getModifiedColor(rPolygonCandidate.getBColor())); 822 mpOutputDevice->SetFillColor(Color(aPolygonColor)); 823 mpOutputDevice->SetLineColor(); 824 825 basegfx::B2DPolyPolygon aLocalPolyPolygon(rPolygonCandidate.getB2DPolyPolygon()); 826 aLocalPolyPolygon.transform(maCurrentTransformation); 827 828 static bool bCheckTrapezoidDecomposition(false); 829 static bool bShowOutlinesThere(false); 830 if(bCheckTrapezoidDecomposition) 831 { 832 // clip against discrete ViewPort 833 const basegfx::B2DRange& rDiscreteViewport = getViewInformation2D().getDiscreteViewport(); 834 aLocalPolyPolygon = basegfx::tools::clipPolyPolygonOnRange( 835 aLocalPolyPolygon, rDiscreteViewport, true, false); 836 837 if(aLocalPolyPolygon.count()) 838 { 839 // subdivide 840 aLocalPolyPolygon = basegfx::tools::adaptiveSubdivideByDistance( 841 aLocalPolyPolygon, 0.5); 842 843 // trapezoidize 844 basegfx::B2DTrapezoidVector aB2DTrapezoidVector; 845 basegfx::tools::trapezoidSubdivide(aB2DTrapezoidVector, aLocalPolyPolygon); 846 847 const sal_uInt32 nCount(aB2DTrapezoidVector.size()); 848 849 if(nCount) 850 { 851 basegfx::BColor aInvPolygonColor(aPolygonColor); 852 aInvPolygonColor.invert(); 853 854 for(sal_uInt32 a(0); a < nCount; a++) 855 { 856 const basegfx::B2DPolygon aTempPolygon(aB2DTrapezoidVector[a].getB2DPolygon()); 857 858 if(bShowOutlinesThere) 859 { 860 mpOutputDevice->SetFillColor(Color(aPolygonColor)); 861 mpOutputDevice->SetLineColor(); 862 } 863 864 mpOutputDevice->DrawPolygon(aTempPolygon); 865 866 if(bShowOutlinesThere) 867 { 868 mpOutputDevice->SetFillColor(); 869 mpOutputDevice->SetLineColor(Color(aInvPolygonColor)); 870 mpOutputDevice->DrawPolyLine(aTempPolygon, 0.0); 871 } 872 } 873 } 874 } 875 } 876 else 877 { 878 mpOutputDevice->DrawPolyPolygon(aLocalPolyPolygon); 879 880 if(mnPolygonStrokePrimitive2D 881 && getOptionsDrawinglayer().IsAntiAliasing() 882 && (mpOutputDevice->GetAntialiasing() & ANTIALIASING_ENABLE_B2DDRAW)) 883 { 884 // when AA is on and this filled polygons are the result of stroked line geometry, 885 // draw the geometry once extra as lines to avoid AA 'gaps' between partial polygons 886 mpOutputDevice->SetFillColor(); 887 mpOutputDevice->SetLineColor(Color(aPolygonColor)); 888 const sal_uInt32 nCount(aLocalPolyPolygon.count()); 889 890 for(sal_uInt32 a(0); a < nCount; a++) 891 { 892 mpOutputDevice->DrawPolyLine(aLocalPolyPolygon.getB2DPolygon(a), 0.0); 893 } 894 } 895 } 896 } 897 898 // direct draw of MetaFile 899 void VclProcessor2D::RenderMetafilePrimitive2D(const primitive2d::MetafilePrimitive2D& rMetaCandidate) 900 { 901 // decompose matrix to check for shear, rotate and mirroring 902 basegfx::B2DHomMatrix aLocalTransform(maCurrentTransformation * rMetaCandidate.getTransform()); 903 basegfx::B2DVector aScale, aTranslate; 904 double fRotate, fShearX; 905 aLocalTransform.decompose(aScale, aTranslate, fRotate, fShearX); 906 907 if(basegfx::fTools::less(aScale.getX(), 0.0) && basegfx::fTools::less(aScale.getY(), 0.0)) 908 { 909 // #i102175# handle special case: If scale is negative in (x,y) (3rd quadrant), it can 910 // be expressed as rotation by PI. This needs to be done for Metafiles since 911 // these can be rotated, but not really mirrored 912 aScale = basegfx::absolute(aScale); 913 fRotate += F_PI; 914 } 915 916 // get BoundRect 917 basegfx::B2DRange aOutlineRange(rMetaCandidate.getB2DRange(getViewInformation2D())); 918 aOutlineRange.transform(maCurrentTransformation); 919 920 // Due to the integer MapModes used from VCL aind inside MetaFiles errors of up to three 921 // pixels in size may happen. As long as there is no better way (e.g. convert the MetaFile 922 // to primitives) it is necessary to reduce maximum pixel size by 1 in X and Y and to use 923 // the inner pixel bounds accordingly (ceil resp. floor). This will also be done for logic 924 // units e.g. when creating a new MetaFile, but since much huger value ranges are used 925 // there typically will be okay for this compromize. 926 Rectangle aDestRectView( 927 // !!CAUTION!! Here, ceil and floor are exchanged BY PURPOSE, do NOT copy when 928 // looking for a standard conversion to rectangle (!) 929 (sal_Int32)ceil(aOutlineRange.getMinX()), (sal_Int32)ceil(aOutlineRange.getMinY()), 930 (sal_Int32)floor(aOutlineRange.getMaxX()), (sal_Int32)floor(aOutlineRange.getMaxY())); 931 932 // get metafile (copy it) 933 GDIMetaFile aMetaFile; 934 935 if(maBColorModifierStack.count()) 936 { 937 const basegfx::BColor aRGBBaseColor(0, 0, 0); 938 const basegfx::BColor aRGBColor(maBColorModifierStack.getModifiedColor(aRGBBaseColor)); 939 aMetaFile = rMetaCandidate.getMetaFile().GetMonochromeMtf(Color(aRGBColor)); 940 } 941 else 942 { 943 aMetaFile = rMetaCandidate.getMetaFile(); 944 } 945 946 // rotation 947 if(!basegfx::fTools::equalZero(fRotate)) 948 { 949 // #i103530# 950 // MetaFile::Rotate has no input parameter check, so the parameter needs to be 951 // well-aligned to the old range [0..3600] 10th degrees with inverse orientation 952 sal_Int16 nRotation((sal_Int16)((fRotate / F_PI180) * -10.0)); 953 954 while(nRotation < 0) 955 nRotation += 3600; 956 957 while(nRotation >= 3600) 958 nRotation -= 3600; 959 960 aMetaFile.Rotate(nRotation); 961 } 962 963 // Prepare target output size 964 Size aDestSize(aDestRectView.GetSize()); 965 966 if(aDestSize.getWidth() && aDestSize.getHeight()) 967 { 968 // Get preferred Metafile output size. When it's very equal to the output size, it's probably 969 // a rounding error somewhere, so correct it to get a 1:1 output without single pixel scalings 970 // of the Metafile (esp. for contaned Bitmaps, e.g 3D charts) 971 const Size aPrefSize(mpOutputDevice->LogicToPixel(aMetaFile.GetPrefSize(), aMetaFile.GetPrefMapMode())); 972 973 if(aPrefSize.getWidth() && (aPrefSize.getWidth() - 1 == aDestSize.getWidth() || aPrefSize.getWidth() + 1 == aDestSize.getWidth())) 974 { 975 aDestSize.setWidth(aPrefSize.getWidth()); 976 } 977 978 if(aPrefSize.getHeight() && (aPrefSize.getHeight() - 1 == aDestSize.getHeight() || aPrefSize.getHeight() + 1 == aDestSize.getHeight())) 979 { 980 aDestSize.setHeight(aPrefSize.getHeight()); 981 } 982 983 // paint it 984 aMetaFile.WindStart(); 985 aMetaFile.Play(mpOutputDevice, aDestRectView.TopLeft(), aDestSize); 986 } 987 } 988 989 // mask group. Force output to VDev and create mask from given mask 990 void VclProcessor2D::RenderMaskPrimitive2DPixel(const primitive2d::MaskPrimitive2D& rMaskCandidate) 991 { 992 if(rMaskCandidate.getChildren().hasElements()) 993 { 994 basegfx::B2DPolyPolygon aMask(rMaskCandidate.getMask()); 995 996 if(aMask.count()) 997 { 998 aMask.transform(maCurrentTransformation); 999 const basegfx::B2DRange aRange(basegfx::tools::getRange(aMask)); 1000 impBufferDevice aBufferDevice(*mpOutputDevice, aRange, true); 1001 1002 if(aBufferDevice.isVisible()) 1003 { 1004 // remember last OutDev and set to content 1005 OutputDevice* pLastOutputDevice = mpOutputDevice; 1006 mpOutputDevice = &aBufferDevice.getContent(); 1007 1008 // paint to it 1009 process(rMaskCandidate.getChildren()); 1010 1011 // back to old OutDev 1012 mpOutputDevice = pLastOutputDevice; 1013 1014 // draw mask 1015 if(getOptionsDrawinglayer().IsAntiAliasing()) 1016 { 1017 // with AA, use 8bit AlphaMask to get nice borders 1018 VirtualDevice& rTransparence = aBufferDevice.getTransparence(); 1019 rTransparence.SetLineColor(); 1020 rTransparence.SetFillColor(COL_BLACK); 1021 rTransparence.DrawPolyPolygon(aMask); 1022 1023 // dump buffer to outdev 1024 aBufferDevice.paint(); 1025 } 1026 else 1027 { 1028 // No AA, use 1bit mask 1029 VirtualDevice& rMask = aBufferDevice.getMask(); 1030 rMask.SetLineColor(); 1031 rMask.SetFillColor(COL_BLACK); 1032 rMask.DrawPolyPolygon(aMask); 1033 1034 // dump buffer to outdev 1035 aBufferDevice.paint(); 1036 } 1037 } 1038 } 1039 } 1040 } 1041 1042 // modified color group. Force output to unified color. 1043 void VclProcessor2D::RenderModifiedColorPrimitive2D(const primitive2d::ModifiedColorPrimitive2D& rModifiedCandidate) 1044 { 1045 if(rModifiedCandidate.getChildren().hasElements()) 1046 { 1047 maBColorModifierStack.push(rModifiedCandidate.getColorModifier()); 1048 process(rModifiedCandidate.getChildren()); 1049 maBColorModifierStack.pop(); 1050 } 1051 } 1052 1053 // unified sub-transparence. Draw to VDev first. 1054 void VclProcessor2D::RenderUnifiedTransparencePrimitive2D(const primitive2d::UnifiedTransparencePrimitive2D& rTransCandidate) 1055 { 1056 static bool bForceToDecomposition(false); 1057 1058 if(rTransCandidate.getChildren().hasElements()) 1059 { 1060 if(bForceToDecomposition) 1061 { 1062 // use decomposition 1063 process(rTransCandidate.get2DDecomposition(getViewInformation2D())); 1064 } 1065 else 1066 { 1067 if(0.0 == rTransCandidate.getTransparence()) 1068 { 1069 // no transparence used, so just use the content 1070 process(rTransCandidate.getChildren()); 1071 } 1072 else if(rTransCandidate.getTransparence() > 0.0 && rTransCandidate.getTransparence() < 1.0) 1073 { 1074 // transparence is in visible range 1075 basegfx::B2DRange aRange(primitive2d::getB2DRangeFromPrimitive2DSequence(rTransCandidate.getChildren(), getViewInformation2D())); 1076 aRange.transform(maCurrentTransformation); 1077 impBufferDevice aBufferDevice(*mpOutputDevice, aRange, true); 1078 1079 if(aBufferDevice.isVisible()) 1080 { 1081 // remember last OutDev and set to content 1082 OutputDevice* pLastOutputDevice = mpOutputDevice; 1083 mpOutputDevice = &aBufferDevice.getContent(); 1084 1085 // paint content to it 1086 process(rTransCandidate.getChildren()); 1087 1088 // back to old OutDev 1089 mpOutputDevice = pLastOutputDevice; 1090 1091 // dump buffer to outdev using given transparence 1092 aBufferDevice.paint(rTransCandidate.getTransparence()); 1093 } 1094 } 1095 } 1096 } 1097 } 1098 1099 // sub-transparence group. Draw to VDev first. 1100 void VclProcessor2D::RenderTransparencePrimitive2D(const primitive2d::TransparencePrimitive2D& rTransCandidate) 1101 { 1102 if(rTransCandidate.getChildren().hasElements()) 1103 { 1104 basegfx::B2DRange aRange(primitive2d::getB2DRangeFromPrimitive2DSequence(rTransCandidate.getChildren(), getViewInformation2D())); 1105 aRange.transform(maCurrentTransformation); 1106 impBufferDevice aBufferDevice(*mpOutputDevice, aRange, true); 1107 1108 if(aBufferDevice.isVisible()) 1109 { 1110 // remember last OutDev and set to content 1111 OutputDevice* pLastOutputDevice = mpOutputDevice; 1112 mpOutputDevice = &aBufferDevice.getContent(); 1113 1114 // paint content to it 1115 process(rTransCandidate.getChildren()); 1116 1117 // set to mask 1118 mpOutputDevice = &aBufferDevice.getTransparence(); 1119 1120 // when painting transparence masks, reset the color stack 1121 basegfx::BColorModifierStack aLastBColorModifierStack(maBColorModifierStack); 1122 maBColorModifierStack = basegfx::BColorModifierStack(); 1123 1124 // paint mask to it (always with transparence intensities, evtl. with AA) 1125 process(rTransCandidate.getTransparence()); 1126 1127 // back to old color stack 1128 maBColorModifierStack = aLastBColorModifierStack; 1129 1130 // back to old OutDev 1131 mpOutputDevice = pLastOutputDevice; 1132 1133 // dump buffer to outdev 1134 aBufferDevice.paint(); 1135 } 1136 } 1137 } 1138 1139 // transform group. 1140 void VclProcessor2D::RenderTransformPrimitive2D(const primitive2d::TransformPrimitive2D& rTransformCandidate) 1141 { 1142 // remember current transformation and ViewInformation 1143 const basegfx::B2DHomMatrix aLastCurrentTransformation(maCurrentTransformation); 1144 const geometry::ViewInformation2D aLastViewInformation2D(getViewInformation2D()); 1145 1146 // create new transformations for CurrentTransformation 1147 // and for local ViewInformation2D 1148 maCurrentTransformation = maCurrentTransformation * rTransformCandidate.getTransformation(); 1149 const geometry::ViewInformation2D aViewInformation2D( 1150 getViewInformation2D().getObjectTransformation() * rTransformCandidate.getTransformation(), 1151 getViewInformation2D().getViewTransformation(), 1152 getViewInformation2D().getViewport(), 1153 getViewInformation2D().getVisualizedPage(), 1154 getViewInformation2D().getViewTime(), 1155 getViewInformation2D().getExtendedInformationSequence()); 1156 updateViewInformation(aViewInformation2D); 1157 1158 // proccess content 1159 process(rTransformCandidate.getChildren()); 1160 1161 // restore transformations 1162 maCurrentTransformation = aLastCurrentTransformation; 1163 updateViewInformation(aLastViewInformation2D); 1164 } 1165 1166 // new XDrawPage for ViewInformation2D 1167 void VclProcessor2D::RenderPagePreviewPrimitive2D(const primitive2d::PagePreviewPrimitive2D& rPagePreviewCandidate) 1168 { 1169 // remember current transformation and ViewInformation 1170 const geometry::ViewInformation2D aLastViewInformation2D(getViewInformation2D()); 1171 1172 // create new local ViewInformation2D 1173 const geometry::ViewInformation2D aViewInformation2D( 1174 getViewInformation2D().getObjectTransformation(), 1175 getViewInformation2D().getViewTransformation(), 1176 getViewInformation2D().getViewport(), 1177 rPagePreviewCandidate.getXDrawPage(), 1178 getViewInformation2D().getViewTime(), 1179 getViewInformation2D().getExtendedInformationSequence()); 1180 updateViewInformation(aViewInformation2D); 1181 1182 // proccess decomposed content 1183 process(rPagePreviewCandidate.get2DDecomposition(getViewInformation2D())); 1184 1185 // restore transformations 1186 updateViewInformation(aLastViewInformation2D); 1187 } 1188 1189 // marker 1190 void VclProcessor2D::RenderMarkerArrayPrimitive2D(const primitive2d::MarkerArrayPrimitive2D& rMarkArrayCandidate) 1191 { 1192 static bool bCheckCompleteMarkerDecompose(false); 1193 if(bCheckCompleteMarkerDecompose) 1194 { 1195 process(rMarkArrayCandidate.get2DDecomposition(getViewInformation2D())); 1196 return; 1197 } 1198 1199 // get data 1200 const std::vector< basegfx::B2DPoint >& rPositions = rMarkArrayCandidate.getPositions(); 1201 const sal_uInt32 nCount(rPositions.size()); 1202 1203 if(nCount && !rMarkArrayCandidate.getMarker().IsEmpty()) 1204 { 1205 // get pixel size 1206 const BitmapEx& rMarker(rMarkArrayCandidate.getMarker()); 1207 const Size aBitmapSize(rMarker.GetSizePixel()); 1208 1209 if(aBitmapSize.Width() && aBitmapSize.Height()) 1210 { 1211 // get discrete half size 1212 const basegfx::B2DVector aDiscreteHalfSize( 1213 (aBitmapSize.getWidth() - 1.0) * 0.5, 1214 (aBitmapSize.getHeight() - 1.0) * 0.5); 1215 const bool bWasEnabled(mpOutputDevice->IsMapModeEnabled()); 1216 1217 // do not forget evtl. moved origin in target device MapMode when 1218 // switching it off; it would be missing and lead to wrong positions. 1219 // All his could be done using logic sizes and coordinates, too, but 1220 // we want a 1:1 bitmap rendering here, so it's more safe and faster 1221 // to work with switching off MapMode usage completely. 1222 const Point aOrigin(mpOutputDevice->GetMapMode().GetOrigin()); 1223 1224 mpOutputDevice->EnableMapMode(false); 1225 1226 for(std::vector< basegfx::B2DPoint >::const_iterator aIter(rPositions.begin()); aIter != rPositions.end(); aIter++) 1227 { 1228 const basegfx::B2DPoint aDiscreteTopLeft((maCurrentTransformation * (*aIter)) - aDiscreteHalfSize); 1229 const Point aDiscretePoint(basegfx::fround(aDiscreteTopLeft.getX()), basegfx::fround(aDiscreteTopLeft.getY())); 1230 1231 mpOutputDevice->DrawBitmapEx(aDiscretePoint + aOrigin, rMarker); 1232 } 1233 1234 mpOutputDevice->EnableMapMode(bWasEnabled); 1235 } 1236 } 1237 } 1238 1239 // point 1240 void VclProcessor2D::RenderPointArrayPrimitive2D(const primitive2d::PointArrayPrimitive2D& rPointArrayCandidate) 1241 { 1242 const std::vector< basegfx::B2DPoint >& rPositions = rPointArrayCandidate.getPositions(); 1243 const basegfx::BColor aRGBColor(maBColorModifierStack.getModifiedColor(rPointArrayCandidate.getRGBColor())); 1244 const Color aVCLColor(aRGBColor); 1245 1246 for(std::vector< basegfx::B2DPoint >::const_iterator aIter(rPositions.begin()); aIter != rPositions.end(); aIter++) 1247 { 1248 const basegfx::B2DPoint aViewPosition(maCurrentTransformation * (*aIter)); 1249 const Point aPos(basegfx::fround(aViewPosition.getX()), basegfx::fround(aViewPosition.getY())); 1250 1251 mpOutputDevice->DrawPixel(aPos, aVCLColor); 1252 } 1253 } 1254 1255 void VclProcessor2D::RenderPolygonStrokePrimitive2D(const primitive2d::PolygonStrokePrimitive2D& rPolygonStrokeCandidate) 1256 { 1257 // #i101491# method restructured to clearly use the DrawPolyLine 1258 // calls starting from a deined line width 1259 const attribute::LineAttribute& rLineAttribute = rPolygonStrokeCandidate.getLineAttribute(); 1260 const double fLineWidth(rLineAttribute.getWidth()); 1261 bool bDone(false); 1262 1263 if(basegfx::fTools::more(fLineWidth, 0.0)) 1264 { 1265 const basegfx::B2DVector aDiscreteUnit(maCurrentTransformation * basegfx::B2DVector(fLineWidth, 0.0)); 1266 const double fDiscreteLineWidth(aDiscreteUnit.getLength()); 1267 const attribute::StrokeAttribute& rStrokeAttribute = rPolygonStrokeCandidate.getStrokeAttribute(); 1268 const basegfx::BColor aHairlineColor(maBColorModifierStack.getModifiedColor(rLineAttribute.getColor())); 1269 basegfx::B2DPolyPolygon aHairlinePolyPolygon; 1270 1271 mpOutputDevice->SetLineColor(Color(aHairlineColor)); 1272 mpOutputDevice->SetFillColor(); 1273 1274 if(0.0 == rStrokeAttribute.getFullDotDashLen()) 1275 { 1276 // no line dashing, just copy 1277 aHairlinePolyPolygon.append(rPolygonStrokeCandidate.getB2DPolygon()); 1278 } 1279 else 1280 { 1281 // else apply LineStyle 1282 basegfx::tools::applyLineDashing(rPolygonStrokeCandidate.getB2DPolygon(), 1283 rStrokeAttribute.getDotDashArray(), 1284 &aHairlinePolyPolygon, 0, rStrokeAttribute.getFullDotDashLen()); 1285 } 1286 1287 const sal_uInt32 nCount(aHairlinePolyPolygon.count()); 1288 1289 if(nCount) 1290 { 1291 const bool bAntiAliased(getOptionsDrawinglayer().IsAntiAliasing()); 1292 aHairlinePolyPolygon.transform(maCurrentTransformation); 1293 1294 if(bAntiAliased) 1295 { 1296 if(basegfx::fTools::lessOrEqual(fDiscreteLineWidth, 1.0)) 1297 { 1298 // line in range ]0.0 .. 1.0[ 1299 // paint as simple hairline 1300 for(sal_uInt32 a(0); a < nCount; a++) 1301 { 1302 mpOutputDevice->DrawPolyLine(aHairlinePolyPolygon.getB2DPolygon(a), 0.0); 1303 } 1304 1305 bDone = true; 1306 } 1307 else if(basegfx::fTools::lessOrEqual(fDiscreteLineWidth, 2.0)) 1308 { 1309 // line in range [1.0 .. 2.0[ 1310 // paint as 2x2 with dynamic line distance 1311 basegfx::B2DHomMatrix aMat; 1312 const double fDistance(fDiscreteLineWidth - 1.0); 1313 const double fHalfDistance(fDistance * 0.5); 1314 1315 for(sal_uInt32 a(0); a < nCount; a++) 1316 { 1317 basegfx::B2DPolygon aCandidate(aHairlinePolyPolygon.getB2DPolygon(a)); 1318 1319 aMat.set(0, 2, -fHalfDistance); 1320 aMat.set(1, 2, -fHalfDistance); 1321 aCandidate.transform(aMat); 1322 mpOutputDevice->DrawPolyLine(aCandidate, 0.0); 1323 1324 aMat.set(0, 2, fDistance); 1325 aMat.set(1, 2, 0.0); 1326 aCandidate.transform(aMat); 1327 mpOutputDevice->DrawPolyLine(aCandidate, 0.0); 1328 1329 aMat.set(0, 2, 0.0); 1330 aMat.set(1, 2, fDistance); 1331 aCandidate.transform(aMat); 1332 mpOutputDevice->DrawPolyLine(aCandidate, 0.0); 1333 1334 aMat.set(0, 2, -fDistance); 1335 aMat.set(1, 2, 0.0); 1336 aCandidate.transform(aMat); 1337 mpOutputDevice->DrawPolyLine(aCandidate, 0.0); 1338 } 1339 1340 bDone = true; 1341 } 1342 else if(basegfx::fTools::lessOrEqual(fDiscreteLineWidth, 3.0)) 1343 { 1344 // line in range [2.0 .. 3.0] 1345 // paint as cross in a 3x3 with dynamic line distance 1346 basegfx::B2DHomMatrix aMat; 1347 const double fDistance((fDiscreteLineWidth - 1.0) * 0.5); 1348 1349 for(sal_uInt32 a(0); a < nCount; a++) 1350 { 1351 basegfx::B2DPolygon aCandidate(aHairlinePolyPolygon.getB2DPolygon(a)); 1352 1353 mpOutputDevice->DrawPolyLine(aCandidate, 0.0); 1354 1355 aMat.set(0, 2, -fDistance); 1356 aMat.set(1, 2, 0.0); 1357 aCandidate.transform(aMat); 1358 mpOutputDevice->DrawPolyLine(aCandidate, 0.0); 1359 1360 aMat.set(0, 2, fDistance); 1361 aMat.set(1, 2, -fDistance); 1362 aCandidate.transform(aMat); 1363 mpOutputDevice->DrawPolyLine(aCandidate, 0.0); 1364 1365 aMat.set(0, 2, fDistance); 1366 aMat.set(1, 2, fDistance); 1367 aCandidate.transform(aMat); 1368 mpOutputDevice->DrawPolyLine(aCandidate, 0.0); 1369 1370 aMat.set(0, 2, -fDistance); 1371 aMat.set(1, 2, fDistance); 1372 aCandidate.transform(aMat); 1373 mpOutputDevice->DrawPolyLine(aCandidate, 0.0); 1374 } 1375 1376 bDone = true; 1377 } 1378 else 1379 { 1380 // #i101491# line width above 3.0 1381 } 1382 } 1383 else 1384 { 1385 if(basegfx::fTools::lessOrEqual(fDiscreteLineWidth, 1.5)) 1386 { 1387 // line width below 1.5, draw the basic hairline polygon 1388 for(sal_uInt32 a(0); a < nCount; a++) 1389 { 1390 mpOutputDevice->DrawPolyLine(aHairlinePolyPolygon.getB2DPolygon(a), 0.0); 1391 } 1392 1393 bDone = true; 1394 } 1395 else if(basegfx::fTools::lessOrEqual(fDiscreteLineWidth, 2.5)) 1396 { 1397 // line width is in range ]1.5 .. 2.5], use four hairlines 1398 // drawn in a square 1399 for(sal_uInt32 a(0); a < nCount; a++) 1400 { 1401 basegfx::B2DPolygon aCandidate(aHairlinePolyPolygon.getB2DPolygon(a)); 1402 basegfx::B2DHomMatrix aMat; 1403 1404 mpOutputDevice->DrawPolyLine(aCandidate, 0.0); 1405 1406 aMat.set(0, 2, 1.0); 1407 aMat.set(1, 2, 0.0); 1408 aCandidate.transform(aMat); 1409 1410 mpOutputDevice->DrawPolyLine(aCandidate, 0.0); 1411 1412 aMat.set(0, 2, 0.0); 1413 aMat.set(1, 2, 1.0); 1414 aCandidate.transform(aMat); 1415 1416 mpOutputDevice->DrawPolyLine(aCandidate, 0.0); 1417 1418 aMat.set(0, 2, -1.0); 1419 aMat.set(1, 2, 0.0); 1420 aCandidate.transform(aMat); 1421 1422 mpOutputDevice->DrawPolyLine(aCandidate, 0.0); 1423 } 1424 1425 bDone = true; 1426 } 1427 else 1428 { 1429 // #i101491# line width is above 2.5 1430 } 1431 } 1432 1433 if(!bDone && rPolygonStrokeCandidate.getB2DPolygon().count() > 1000) 1434 { 1435 // #i101491# If the polygon complexity uses more than a given amount, do 1436 // use OuputDevice::DrawPolyLine directly; this will avoid buffering all 1437 // decompositions in primtives (memory) and fallback to old line painting 1438 // for very complex polygons, too 1439 for(sal_uInt32 a(0); a < nCount; a++) 1440 { 1441 mpOutputDevice->DrawPolyLine( 1442 aHairlinePolyPolygon.getB2DPolygon(a), 1443 fDiscreteLineWidth, 1444 rLineAttribute.getLineJoin(), 1445 rLineAttribute.getLineCap()); 1446 } 1447 1448 bDone = true; 1449 } 1450 } 1451 } 1452 1453 if(!bDone) 1454 { 1455 // remeber that we enter a PolygonStrokePrimitive2D decomposition, 1456 // used for AA thick line drawing 1457 mnPolygonStrokePrimitive2D++; 1458 1459 // line width is big enough for standard filled polygon visualisation or zero 1460 process(rPolygonStrokeCandidate.get2DDecomposition(getViewInformation2D())); 1461 1462 // leave PolygonStrokePrimitive2D 1463 mnPolygonStrokePrimitive2D--; 1464 } 1465 } 1466 1467 void VclProcessor2D::RenderEpsPrimitive2D(const primitive2d::EpsPrimitive2D& rEpsPrimitive2D) 1468 { 1469 // The new decomposition of Metafiles made it necessary to add an Eps 1470 // primitive to handle embedded Eps data. On some devices, this can be 1471 // painted directly (mac, printer). 1472 // To be able to handle the replacement correctly, i need to handle it myself 1473 // since DrawEPS will not be able e.g. to rotate the replacement. To be able 1474 // to do that, i added a boolean return to OutputDevice::DrawEPS(..) 1475 // to know when EPS was handled directly already. 1476 basegfx::B2DRange aRange(0.0, 0.0, 1.0, 1.0); 1477 aRange.transform(maCurrentTransformation * rEpsPrimitive2D.getEpsTransform()); 1478 1479 if(!aRange.isEmpty()) 1480 { 1481 const Rectangle aRectangle( 1482 (sal_Int32)floor(aRange.getMinX()), (sal_Int32)floor(aRange.getMinY()), 1483 (sal_Int32)ceil(aRange.getMaxX()), (sal_Int32)ceil(aRange.getMaxY())); 1484 1485 if(!aRectangle.IsEmpty()) 1486 { 1487 // try to paint EPS directly without fallback visualisation 1488 const bool bEPSPaintedDirectly(mpOutputDevice->DrawEPS( 1489 aRectangle.TopLeft(), 1490 aRectangle.GetSize(), 1491 rEpsPrimitive2D.getGfxLink(), 1492 0)); 1493 1494 if(!bEPSPaintedDirectly) 1495 { 1496 // use the decomposition which will correctly handle the 1497 // fallback visualisation using full transformation (e.g. rotation) 1498 process(rEpsPrimitive2D.get2DDecomposition(getViewInformation2D())); 1499 } 1500 } 1501 } 1502 } 1503 1504 void VclProcessor2D::RenderSvgLinearAtomPrimitive2D(const primitive2d::SvgLinearAtomPrimitive2D& rCandidate) 1505 { 1506 const double fDelta(rCandidate.getOffsetB() - rCandidate.getOffsetA()); 1507 1508 if(basegfx::fTools::more(fDelta, 0.0)) 1509 { 1510 const basegfx::BColor aColorA(maBColorModifierStack.getModifiedColor(rCandidate.getColorA())); 1511 const basegfx::BColor aColorB(maBColorModifierStack.getModifiedColor(rCandidate.getColorB())); 1512 const double fDiscreteUnit((getViewInformation2D().getInverseObjectToViewTransformation() * basegfx::B2DVector(1.0, 0.0)).getLength()); 1513 1514 // use color distance and discrete lengths to calculate step count 1515 const sal_uInt32 nSteps(calculateStepsForSvgGradient(aColorA, aColorB, fDelta, fDiscreteUnit)); 1516 1517 // switch off line painting 1518 mpOutputDevice->SetLineColor(); 1519 1520 // prepare polygon in needed width at start position (with discrete overlap) 1521 const basegfx::B2DPolygon aPolygon( 1522 basegfx::tools::createPolygonFromRect( 1523 basegfx::B2DRange( 1524 rCandidate.getOffsetA() - fDiscreteUnit, 1525 0.0, 1526 rCandidate.getOffsetA() + (fDelta / nSteps) + fDiscreteUnit, 1527 1.0))); 1528 1529 1530 // prepare loop ([0.0 .. 1.0[) 1531 double fUnitScale(0.0); 1532 const double fUnitStep(1.0 / nSteps); 1533 1534 // loop and paint 1535 for(sal_uInt32 a(0); a < nSteps; a++, fUnitScale += fUnitStep) 1536 { 1537 basegfx::B2DPolygon aNew(aPolygon); 1538 1539 aNew.transform(maCurrentTransformation * basegfx::tools::createTranslateB2DHomMatrix(fDelta * fUnitScale, 0.0)); 1540 mpOutputDevice->SetFillColor(Color(basegfx::interpolate(aColorA, aColorB, fUnitScale))); 1541 mpOutputDevice->DrawPolyPolygon(basegfx::B2DPolyPolygon(aNew)); 1542 } 1543 } 1544 } 1545 1546 void VclProcessor2D::RenderSvgRadialAtomPrimitive2D(const primitive2d::SvgRadialAtomPrimitive2D& rCandidate) 1547 { 1548 const double fDeltaScale(rCandidate.getScaleB() - rCandidate.getScaleA()); 1549 1550 if(basegfx::fTools::more(fDeltaScale, 0.0)) 1551 { 1552 const basegfx::BColor aColorA(maBColorModifierStack.getModifiedColor(rCandidate.getColorA())); 1553 const basegfx::BColor aColorB(maBColorModifierStack.getModifiedColor(rCandidate.getColorB())); 1554 const double fDiscreteUnit((getViewInformation2D().getInverseObjectToViewTransformation() * basegfx::B2DVector(1.0, 0.0)).getLength()); 1555 1556 // use color distance and discrete lengths to calculate step count 1557 const sal_uInt32 nSteps(calculateStepsForSvgGradient(aColorA, aColorB, fDeltaScale, fDiscreteUnit)); 1558 1559 // switch off line painting 1560 mpOutputDevice->SetLineColor(); 1561 1562 // prepare loop ([0.0 .. 1.0[, full polygons, no polypolygons with holes) 1563 double fUnitScale(0.0); 1564 const double fUnitStep(1.0 / nSteps); 1565 1566 for(sal_uInt32 a(0); a < nSteps; a++, fUnitScale += fUnitStep) 1567 { 1568 basegfx::B2DHomMatrix aTransform; 1569 const double fEndScale(rCandidate.getScaleB() - (fDeltaScale * fUnitScale)); 1570 1571 if(rCandidate.isTranslateSet()) 1572 { 1573 const basegfx::B2DVector aTranslate( 1574 basegfx::interpolate( 1575 rCandidate.getTranslateB(), 1576 rCandidate.getTranslateA(), 1577 fUnitScale)); 1578 1579 aTransform = basegfx::tools::createScaleTranslateB2DHomMatrix( 1580 fEndScale, 1581 fEndScale, 1582 aTranslate.getX(), 1583 aTranslate.getY()); 1584 } 1585 else 1586 { 1587 aTransform = basegfx::tools::createScaleB2DHomMatrix( 1588 fEndScale, 1589 fEndScale); 1590 } 1591 1592 basegfx::B2DPolygon aNew(basegfx::tools::createPolygonFromUnitCircle()); 1593 1594 aNew.transform(maCurrentTransformation * aTransform); 1595 mpOutputDevice->SetFillColor(Color(basegfx::interpolate(aColorB, aColorA, fUnitScale))); 1596 mpOutputDevice->DrawPolyPolygon(basegfx::B2DPolyPolygon(aNew)); 1597 } 1598 } 1599 } 1600 1601 void VclProcessor2D::adaptLineToFillDrawMode() const 1602 { 1603 const sal_uInt32 nOriginalDrawMode(mpOutputDevice->GetDrawMode()); 1604 1605 if(nOriginalDrawMode & (DRAWMODE_BLACKLINE|DRAWMODE_GRAYLINE|DRAWMODE_GHOSTEDLINE|DRAWMODE_WHITELINE|DRAWMODE_SETTINGSLINE)) 1606 { 1607 sal_uInt32 nAdaptedDrawMode(nOriginalDrawMode); 1608 1609 if(nOriginalDrawMode & DRAWMODE_BLACKLINE) 1610 { 1611 nAdaptedDrawMode |= DRAWMODE_BLACKFILL; 1612 } 1613 else 1614 { 1615 nAdaptedDrawMode &= ~DRAWMODE_BLACKFILL; 1616 } 1617 1618 if(nOriginalDrawMode & DRAWMODE_GRAYLINE) 1619 { 1620 nAdaptedDrawMode |= DRAWMODE_GRAYFILL; 1621 } 1622 else 1623 { 1624 nAdaptedDrawMode &= ~DRAWMODE_GRAYFILL; 1625 } 1626 1627 if(nOriginalDrawMode & DRAWMODE_GHOSTEDLINE) 1628 { 1629 nAdaptedDrawMode |= DRAWMODE_GHOSTEDFILL; 1630 } 1631 else 1632 { 1633 nAdaptedDrawMode &= ~DRAWMODE_GHOSTEDFILL; 1634 } 1635 1636 if(nOriginalDrawMode & DRAWMODE_WHITELINE) 1637 { 1638 nAdaptedDrawMode |= DRAWMODE_WHITEFILL; 1639 } 1640 else 1641 { 1642 nAdaptedDrawMode &= ~DRAWMODE_WHITEFILL; 1643 } 1644 1645 if(nOriginalDrawMode & DRAWMODE_SETTINGSLINE) 1646 { 1647 nAdaptedDrawMode |= DRAWMODE_SETTINGSFILL; 1648 } 1649 else 1650 { 1651 nAdaptedDrawMode &= ~DRAWMODE_SETTINGSFILL; 1652 } 1653 1654 mpOutputDevice->SetDrawMode(nAdaptedDrawMode); 1655 } 1656 } 1657 1658 void VclProcessor2D::adaptTextToFillDrawMode() const 1659 { 1660 const sal_uInt32 nOriginalDrawMode(mpOutputDevice->GetDrawMode()); 1661 if(nOriginalDrawMode & (DRAWMODE_BLACKTEXT|DRAWMODE_GRAYTEXT|DRAWMODE_GHOSTEDTEXT|DRAWMODE_WHITETEXT|DRAWMODE_SETTINGSTEXT)) 1662 { 1663 sal_uInt32 nAdaptedDrawMode(nOriginalDrawMode); 1664 1665 if(nOriginalDrawMode & DRAWMODE_BLACKTEXT) 1666 { 1667 nAdaptedDrawMode |= DRAWMODE_BLACKFILL; 1668 } 1669 else 1670 { 1671 nAdaptedDrawMode &= ~DRAWMODE_BLACKFILL; 1672 } 1673 1674 if(nOriginalDrawMode & DRAWMODE_GRAYTEXT) 1675 { 1676 nAdaptedDrawMode |= DRAWMODE_GRAYFILL; 1677 } 1678 else 1679 { 1680 nAdaptedDrawMode &= ~DRAWMODE_GRAYFILL; 1681 } 1682 1683 if(nOriginalDrawMode & DRAWMODE_GHOSTEDTEXT) 1684 { 1685 nAdaptedDrawMode |= DRAWMODE_GHOSTEDFILL; 1686 } 1687 else 1688 { 1689 nAdaptedDrawMode &= ~DRAWMODE_GHOSTEDFILL; 1690 } 1691 1692 if(nOriginalDrawMode & DRAWMODE_WHITETEXT) 1693 { 1694 nAdaptedDrawMode |= DRAWMODE_WHITEFILL; 1695 } 1696 else 1697 { 1698 nAdaptedDrawMode &= ~DRAWMODE_WHITEFILL; 1699 } 1700 1701 if(nOriginalDrawMode & DRAWMODE_SETTINGSTEXT) 1702 { 1703 nAdaptedDrawMode |= DRAWMODE_SETTINGSFILL; 1704 } 1705 else 1706 { 1707 nAdaptedDrawMode &= ~DRAWMODE_SETTINGSFILL; 1708 } 1709 1710 mpOutputDevice->SetDrawMode(nAdaptedDrawMode); 1711 } 1712 } 1713 1714 ////////////////////////////////////////////////////////////////////////////// 1715 // process support 1716 1717 VclProcessor2D::VclProcessor2D( 1718 const geometry::ViewInformation2D& rViewInformation, 1719 OutputDevice& rOutDev) 1720 : BaseProcessor2D(rViewInformation), 1721 mpOutputDevice(&rOutDev), 1722 maBColorModifierStack(), 1723 maCurrentTransformation(), 1724 maDrawinglayerOpt(), 1725 mnPolygonStrokePrimitive2D(0) 1726 { 1727 // set digit language, derived from SvtCTLOptions to have the correct 1728 // number display for arabic/hindi numerals 1729 const SvtCTLOptions aSvtCTLOptions; 1730 LanguageType eLang(LANGUAGE_SYSTEM); 1731 1732 if(SvtCTLOptions::NUMERALS_HINDI == aSvtCTLOptions.GetCTLTextNumerals()) 1733 { 1734 eLang = LANGUAGE_ARABIC_SAUDI_ARABIA; 1735 } 1736 else if(SvtCTLOptions::NUMERALS_ARABIC == aSvtCTLOptions.GetCTLTextNumerals()) 1737 { 1738 eLang = LANGUAGE_ENGLISH; 1739 } 1740 else 1741 { 1742 eLang = (LanguageType)Application::GetSettings().GetLanguage(); 1743 } 1744 1745 rOutDev.SetDigitLanguage(eLang); 1746 } 1747 1748 VclProcessor2D::~VclProcessor2D() 1749 { 1750 } 1751 } // end of namespace processor2d 1752 } // end of namespace drawinglayer 1753 1754 ////////////////////////////////////////////////////////////////////////////// 1755 // eof 1756