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/vclpixelprocessor2d.hxx> 28 #include <vcl/outdev.hxx> 29 #include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx> 30 #include <drawinglayer/primitive2d/textprimitive2d.hxx> 31 #include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx> 32 #include <drawinglayer/primitive2d/polygonprimitive2d.hxx> 33 #include <drawinglayer/primitive2d/bitmapprimitive2d.hxx> 34 #include <drawinglayer/primitive2d/fillgraphicprimitive2d.hxx> 35 #include <drawinglayer/primitive2d/metafileprimitive2d.hxx> 36 #include <drawinglayer/primitive2d/maskprimitive2d.hxx> 37 #include <drawinglayer/primitive2d/modifiedcolorprimitive2d.hxx> 38 #include <drawinglayer/primitive2d/transparenceprimitive2d.hxx> 39 #include <drawinglayer/primitive2d/transformprimitive2d.hxx> 40 #include <drawinglayer/primitive2d/markerarrayprimitive2d.hxx> 41 #include <drawinglayer/primitive2d/pointarrayprimitive2d.hxx> 42 #include <drawinglayer/primitive2d/wrongspellprimitive2d.hxx> 43 #include <drawinglayer/primitive2d/controlprimitive2d.hxx> 44 #include <com/sun/star/awt/XWindow2.hpp> 45 #include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx> 46 #include <drawinglayer/primitive2d/pagepreviewprimitive2d.hxx> 47 #include <helperwrongspellrenderer.hxx> 48 #include <drawinglayer/primitive2d/fillhatchprimitive2d.hxx> 49 #include <basegfx/polygon/b2dpolygontools.hxx> 50 #include <vcl/hatch.hxx> 51 #include <tools/diagnose_ex.h> 52 #include <com/sun/star/awt/PosSize.hpp> 53 #include <drawinglayer/primitive2d/invertprimitive2d.hxx> 54 #include <cstdio> 55 #include <drawinglayer/primitive2d/backgroundcolorprimitive2d.hxx> 56 #include <basegfx/matrix/b2dhommatrixtools.hxx> 57 #include <drawinglayer/primitive2d/epsprimitive2d.hxx> 58 #include <drawinglayer/primitive2d/svggradientprimitive2d.hxx> 59 #include <toolkit/helper/vclunohelper.hxx> 60 #include <vcl/window.hxx> 61 62 ////////////////////////////////////////////////////////////////////////////// 63 64 using namespace com::sun::star; 65 66 ////////////////////////////////////////////////////////////////////////////// 67 68 namespace drawinglayer 69 { 70 namespace processor2d 71 { VclPixelProcessor2D(const geometry::ViewInformation2D & rViewInformation,OutputDevice & rOutDev)72 VclPixelProcessor2D::VclPixelProcessor2D(const geometry::ViewInformation2D& rViewInformation, OutputDevice& rOutDev) 73 : VclProcessor2D(rViewInformation, rOutDev) 74 { 75 // prepare maCurrentTransformation matrix with viewTransformation to target directly to pixels 76 maCurrentTransformation = rViewInformation.getObjectToViewTransformation(); 77 78 // prepare output directly to pixels 79 mpOutputDevice->Push(PUSH_MAPMODE); 80 mpOutputDevice->SetMapMode(); 81 82 // react on AntiAliasing settings 83 if(getOptionsDrawinglayer().IsAntiAliasing()) 84 { 85 mpOutputDevice->SetAntialiasing(mpOutputDevice->GetAntialiasing() | ANTIALIASING_ENABLE_B2DDRAW); 86 } 87 else 88 { 89 mpOutputDevice->SetAntialiasing(mpOutputDevice->GetAntialiasing() & ~ANTIALIASING_ENABLE_B2DDRAW); 90 } 91 } 92 ~VclPixelProcessor2D()93 VclPixelProcessor2D::~VclPixelProcessor2D() 94 { 95 // restore MapMode 96 mpOutputDevice->Pop(); 97 98 // restore AntiAliasing 99 mpOutputDevice->SetAntialiasing(mpOutputDevice->GetAntialiasing() & ~ANTIALIASING_ENABLE_B2DDRAW); 100 } 101 tryDrawPolyPolygonColorPrimitive2DDirect(const drawinglayer::primitive2d::PolyPolygonColorPrimitive2D & rSource,double fTransparency)102 bool VclPixelProcessor2D::tryDrawPolyPolygonColorPrimitive2DDirect(const drawinglayer::primitive2d::PolyPolygonColorPrimitive2D& rSource, double fTransparency) 103 { 104 basegfx::B2DPolyPolygon aLocalPolyPolygon(rSource.getB2DPolyPolygon()); 105 106 if(!aLocalPolyPolygon.count()) 107 { 108 // no geometry, done 109 return true; 110 } 111 112 const basegfx::BColor aPolygonColor(maBColorModifierStack.getModifiedColor(rSource.getBColor())); 113 114 mpOutputDevice->SetFillColor(Color(aPolygonColor)); 115 mpOutputDevice->SetLineColor(); 116 aLocalPolyPolygon.transform(maCurrentTransformation); 117 mpOutputDevice->DrawTransparent( 118 aLocalPolyPolygon, 119 fTransparency); 120 121 return true; 122 } 123 tryDrawPolygonHairlinePrimitive2DDirect(const drawinglayer::primitive2d::PolygonHairlinePrimitive2D & rSource,double fTransparency)124 bool VclPixelProcessor2D::tryDrawPolygonHairlinePrimitive2DDirect(const drawinglayer::primitive2d::PolygonHairlinePrimitive2D& rSource, double fTransparency) 125 { 126 basegfx::B2DPolygon aLocalPolygon(rSource.getB2DPolygon()); 127 128 if(!aLocalPolygon.count()) 129 { 130 // no geometry, done 131 return true; 132 } 133 134 const basegfx::BColor aLineColor(maBColorModifierStack.getModifiedColor(rSource.getBColor())); 135 136 mpOutputDevice->SetFillColor(); 137 mpOutputDevice->SetLineColor(Color(aLineColor)); 138 aLocalPolygon.transform(maCurrentTransformation); 139 140 // try drawing; if it did not work, use standard fallback 141 if(mpOutputDevice->TryDrawPolyLineDirect( 142 aLocalPolygon, 143 0.0, 144 fTransparency)) 145 { 146 return true; 147 } 148 149 return false; 150 } 151 tryDrawPolygonStrokePrimitive2DDirect(const drawinglayer::primitive2d::PolygonStrokePrimitive2D & rSource,double fTransparency)152 bool VclPixelProcessor2D::tryDrawPolygonStrokePrimitive2DDirect(const drawinglayer::primitive2d::PolygonStrokePrimitive2D& rSource, double fTransparency) 153 { 154 basegfx::B2DPolygon aLocalPolygon(rSource.getB2DPolygon()); 155 156 if(!aLocalPolygon.count()) 157 { 158 // no geometry, done 159 return true; 160 } 161 162 aLocalPolygon = basegfx::tools::simplifyCurveSegments(aLocalPolygon); 163 basegfx::B2DPolyPolygon aHairLinePolyPolygon; 164 165 if(rSource.getStrokeAttribute().isDefault() || 0.0 == rSource.getStrokeAttribute().getFullDotDashLen()) 166 { 167 // no line dashing, just copy 168 aHairLinePolyPolygon.append(aLocalPolygon); 169 } 170 else 171 { 172 // apply LineStyle 173 basegfx::tools::applyLineDashing( 174 aLocalPolygon, 175 rSource.getStrokeAttribute().getDotDashArray(), 176 &aHairLinePolyPolygon, 177 0, 178 rSource.getStrokeAttribute().getFullDotDashLen()); 179 } 180 181 if(!aHairLinePolyPolygon.count()) 182 { 183 // no geometry, done 184 return true; 185 } 186 187 const basegfx::BColor aLineColor( 188 maBColorModifierStack.getModifiedColor( 189 rSource.getLineAttribute().getColor())); 190 191 mpOutputDevice->SetFillColor(); 192 mpOutputDevice->SetLineColor(Color(aLineColor)); 193 aHairLinePolyPolygon.transform(maCurrentTransformation); 194 195 double fLineWidth(rSource.getLineAttribute().getWidth()); 196 197 if(basegfx::fTools::more(fLineWidth, 0.0)) 198 { 199 basegfx::B2DVector aLineWidth(fLineWidth, 0.0); 200 201 aLineWidth = maCurrentTransformation * aLineWidth; 202 fLineWidth = aLineWidth.getLength(); 203 } 204 205 bool bHasPoints(false); 206 bool bTryWorked(false); 207 208 for(sal_uInt32 a(0); a < aHairLinePolyPolygon.count(); a++) 209 { 210 const basegfx::B2DPolygon aSingle(aHairLinePolyPolygon.getB2DPolygon(a)); 211 212 if(aSingle.count()) 213 { 214 bHasPoints = true; 215 216 if(mpOutputDevice->TryDrawPolyLineDirect( 217 aSingle, 218 fLineWidth, 219 fTransparency, 220 rSource.getLineAttribute().getLineJoin(), 221 rSource.getLineAttribute().getLineCap())) 222 { 223 bTryWorked = true; 224 } 225 } 226 } 227 228 if(!bTryWorked && !bHasPoints) 229 { 230 // no geometry despite try 231 bTryWorked = true; 232 } 233 234 return bTryWorked; 235 } 236 processBasePrimitive2D(const primitive2d::BasePrimitive2D & rCandidate)237 void VclPixelProcessor2D::processBasePrimitive2D(const primitive2d::BasePrimitive2D& rCandidate) 238 { 239 switch(rCandidate.getPrimitive2DID()) 240 { 241 case PRIMITIVE2D_ID_WRONGSPELLPRIMITIVE2D : 242 { 243 // directdraw of wrong spell primitive; added test possibility to check wrong spell decompose 244 static bool bHandleWrongSpellDirectly(true); 245 246 if(bHandleWrongSpellDirectly) 247 { 248 const primitive2d::WrongSpellPrimitive2D& rWrongSpellPrimitive = static_cast< const primitive2d::WrongSpellPrimitive2D& >(rCandidate); 249 250 if(!renderWrongSpellPrimitive2D( 251 rWrongSpellPrimitive, 252 *mpOutputDevice, 253 maCurrentTransformation, 254 maBColorModifierStack)) 255 { 256 // fallback to decomposition (MetaFile) 257 process(rWrongSpellPrimitive.get2DDecomposition(getViewInformation2D())); 258 } 259 } 260 else 261 { 262 process(rCandidate.get2DDecomposition(getViewInformation2D())); 263 } 264 break; 265 } 266 case PRIMITIVE2D_ID_TEXTSIMPLEPORTIONPRIMITIVE2D : 267 { 268 // directdraw of text simple portion; added test possibility to check text decompose 269 static bool bForceSimpleTextDecomposition(false); 270 271 // Adapt evtl. used special DrawMode 272 const sal_uInt32 nOriginalDrawMode(mpOutputDevice->GetDrawMode()); 273 adaptTextToFillDrawMode(); 274 275 if(!bForceSimpleTextDecomposition && getOptionsDrawinglayer().IsRenderSimpleTextDirect()) 276 { 277 RenderTextSimpleOrDecoratedPortionPrimitive2D(static_cast< const primitive2d::TextSimplePortionPrimitive2D& >(rCandidate)); 278 } 279 else 280 { 281 process(rCandidate.get2DDecomposition(getViewInformation2D())); 282 } 283 284 // restore DrawMode 285 mpOutputDevice->SetDrawMode(nOriginalDrawMode); 286 287 break; 288 } 289 case PRIMITIVE2D_ID_TEXTDECORATEDPORTIONPRIMITIVE2D : 290 { 291 // directdraw of text simple portion; added test possibility to check text decompose 292 static bool bForceComplexTextDecomposition(false); 293 294 // Adapt evtl. used special DrawMode 295 const sal_uInt32 nOriginalDrawMode(mpOutputDevice->GetDrawMode()); 296 adaptTextToFillDrawMode(); 297 298 if(!bForceComplexTextDecomposition && getOptionsDrawinglayer().IsRenderDecoratedTextDirect()) 299 { 300 RenderTextSimpleOrDecoratedPortionPrimitive2D(static_cast< const primitive2d::TextSimplePortionPrimitive2D& >(rCandidate)); 301 } 302 else 303 { 304 process(rCandidate.get2DDecomposition(getViewInformation2D())); 305 } 306 307 // restore DrawMode 308 mpOutputDevice->SetDrawMode(nOriginalDrawMode); 309 310 break; 311 } 312 case PRIMITIVE2D_ID_POLYGONHAIRLINEPRIMITIVE2D : 313 { 314 // try to use directly 315 const primitive2d::PolygonHairlinePrimitive2D& rPolygonHairlinePrimitive2D = static_cast< const primitive2d::PolygonHairlinePrimitive2D& >(rCandidate); 316 static bool bAllowed(true); 317 318 if(bAllowed && tryDrawPolygonHairlinePrimitive2DDirect(rPolygonHairlinePrimitive2D, 0.0)) 319 { 320 break; 321 } 322 323 // direct draw of hairline 324 RenderPolygonHairlinePrimitive2D(rPolygonHairlinePrimitive2D, true); 325 break; 326 } 327 case PRIMITIVE2D_ID_BITMAPPRIMITIVE2D : 328 { 329 // direct draw of transformed BitmapEx primitive 330 const primitive2d::BitmapPrimitive2D& rBitmapCandidate = static_cast< const primitive2d::BitmapPrimitive2D& >(rCandidate); 331 332 // check if graphic content is inside discrete local ViewPort 333 const basegfx::B2DRange& rDiscreteViewPort(getViewInformation2D().getDiscreteViewport()); 334 const basegfx::B2DHomMatrix aLocalTransform(maCurrentTransformation * rBitmapCandidate.getTransform()); 335 336 if(!rDiscreteViewPort.isEmpty()) 337 { 338 basegfx::B2DRange aUnitRange(0.0, 0.0, 1.0, 1.0); 339 340 aUnitRange.transform(aLocalTransform); 341 342 if(!aUnitRange.overlaps(rDiscreteViewPort)) 343 { 344 // content is outside discrete local ViewPort 345 break; 346 } 347 } 348 349 RenderBitmapPrimitive2D(static_cast< const primitive2d::BitmapPrimitive2D& >(rCandidate)); 350 break; 351 } 352 case PRIMITIVE2D_ID_FILLGRAPHICPRIMITIVE2D : 353 { 354 // direct draw of fillBitmapPrimitive 355 RenderFillGraphicPrimitive2D(static_cast< const primitive2d::FillGraphicPrimitive2D& >(rCandidate)); 356 break; 357 } 358 case PRIMITIVE2D_ID_POLYPOLYGONGRADIENTPRIMITIVE2D : 359 { 360 // direct draw of gradient 361 const primitive2d::PolyPolygonGradientPrimitive2D& rPolygonCandidate = static_cast< const primitive2d::PolyPolygonGradientPrimitive2D& >(rCandidate); 362 const attribute::FillGradientAttribute& rGradient(rPolygonCandidate.getFillGradient()); 363 basegfx::BColor aStartColor(maBColorModifierStack.getModifiedColor(rGradient.getStartColor())); 364 basegfx::BColor aEndColor(maBColorModifierStack.getModifiedColor(rGradient.getEndColor())); 365 basegfx::B2DPolyPolygon aLocalPolyPolygon(rPolygonCandidate.getB2DPolyPolygon()); 366 367 if(aLocalPolyPolygon.count()) 368 { 369 aLocalPolyPolygon.transform(maCurrentTransformation); 370 371 if(aStartColor == aEndColor) 372 { 373 // no gradient at all, draw as polygon in AA and non-AA case 374 mpOutputDevice->SetLineColor(); 375 mpOutputDevice->SetFillColor(Color(aStartColor)); 376 mpOutputDevice->DrawPolyPolygon(aLocalPolyPolygon); 377 } 378 else 379 { 380 // use the primitive decomposition of the metafile 381 process(rPolygonCandidate.get2DDecomposition(getViewInformation2D())); 382 } 383 } 384 break; 385 } 386 case PRIMITIVE2D_ID_POLYPOLYGONGRAPHICPRIMITIVE2D : 387 { 388 // direct draw of bitmap 389 RenderPolyPolygonGraphicPrimitive2D(static_cast< const primitive2d::PolyPolygonGraphicPrimitive2D& >(rCandidate)); 390 break; 391 } 392 case PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D : 393 { 394 // try to use directly 395 const primitive2d::PolyPolygonColorPrimitive2D& rPolyPolygonColorPrimitive2D = static_cast< const primitive2d::PolyPolygonColorPrimitive2D& >(rCandidate); 396 basegfx::B2DPolyPolygon aLocalPolyPolygon; 397 static bool bAllowed(true); 398 399 if(bAllowed && tryDrawPolyPolygonColorPrimitive2DDirect(rPolyPolygonColorPrimitive2D, 0.0)) 400 { 401 // okay, done. In this case no gaps should have to be repaired, too 402 } 403 else 404 { 405 // direct draw of PolyPolygon with color 406 const basegfx::BColor aPolygonColor(maBColorModifierStack.getModifiedColor(rPolyPolygonColorPrimitive2D.getBColor())); 407 408 mpOutputDevice->SetFillColor(Color(aPolygonColor)); 409 mpOutputDevice->SetLineColor(); 410 aLocalPolyPolygon = rPolyPolygonColorPrimitive2D.getB2DPolyPolygon(); 411 aLocalPolyPolygon.transform(maCurrentTransformation); 412 mpOutputDevice->DrawPolyPolygon(aLocalPolyPolygon); 413 } 414 415 // when AA is on and this filled polygons are the result of stroked line geometry, 416 // draw the geometry once extra as lines to avoid AA 'gaps' between partial polygons 417 // Caution: This is needed in both cases (!) 418 if(mnPolygonStrokePrimitive2D 419 && getOptionsDrawinglayer().IsAntiAliasing() 420 && (mpOutputDevice->GetAntialiasing() & ANTIALIASING_ENABLE_B2DDRAW)) 421 { 422 const basegfx::BColor aPolygonColor(maBColorModifierStack.getModifiedColor(rPolyPolygonColorPrimitive2D.getBColor())); 423 sal_uInt32 nCount(aLocalPolyPolygon.count()); 424 425 if(!nCount) 426 { 427 aLocalPolyPolygon = rPolyPolygonColorPrimitive2D.getB2DPolyPolygon(); 428 aLocalPolyPolygon.transform(maCurrentTransformation); 429 nCount = aLocalPolyPolygon.count(); 430 } 431 432 mpOutputDevice->SetFillColor(); 433 mpOutputDevice->SetLineColor(Color(aPolygonColor)); 434 435 for(sal_uInt32 a(0); a < nCount; a++) 436 { 437 mpOutputDevice->DrawPolyLine(aLocalPolyPolygon.getB2DPolygon(a), 0.0); 438 } 439 } 440 441 break; 442 } 443 case PRIMITIVE2D_ID_METAFILEPRIMITIVE2D : 444 { 445 // #i98289# 446 const bool bForceLineSnap(getOptionsDrawinglayer().IsAntiAliasing() && getOptionsDrawinglayer().IsSnapHorVerLinesToDiscrete()); 447 const sal_uInt16 nOldAntiAliase(mpOutputDevice->GetAntialiasing()); 448 449 if(bForceLineSnap) 450 { 451 mpOutputDevice->SetAntialiasing(nOldAntiAliase | ANTIALIASING_PIXELSNAPHAIRLINE); 452 } 453 454 // use new Metafile decomposition 455 process(rCandidate.get2DDecomposition(getViewInformation2D())); 456 457 if(bForceLineSnap) 458 { 459 mpOutputDevice->SetAntialiasing(nOldAntiAliase); 460 } 461 462 break; 463 } 464 case PRIMITIVE2D_ID_MASKPRIMITIVE2D : 465 { 466 // mask group. 467 RenderMaskPrimitive2DPixel(static_cast< const primitive2d::MaskPrimitive2D& >(rCandidate)); 468 break; 469 } 470 case PRIMITIVE2D_ID_MODIFIEDCOLORPRIMITIVE2D : 471 { 472 // modified color group. Force output to unified color. 473 RenderModifiedColorPrimitive2D(static_cast< const primitive2d::ModifiedColorPrimitive2D& >(rCandidate)); 474 break; 475 } 476 case PRIMITIVE2D_ID_UNIFIEDTRANSPARENCEPRIMITIVE2D : 477 { 478 // Detect if a single PolyPolygonColorPrimitive2D is contained; in that case, 479 // use the faster OutputDevice::DrawTransparent method 480 const primitive2d::UnifiedTransparencePrimitive2D& rUniTransparenceCandidate = static_cast< const primitive2d::UnifiedTransparencePrimitive2D& >(rCandidate); 481 const primitive2d::Primitive2DSequence rContent = rUniTransparenceCandidate.getChildren(); 482 483 if(rContent.hasElements()) 484 { 485 if(0.0 == rUniTransparenceCandidate.getTransparence()) 486 { 487 // not transparent at all, use content 488 process(rUniTransparenceCandidate.getChildren()); 489 } 490 else if(rUniTransparenceCandidate.getTransparence() > 0.0 && rUniTransparenceCandidate.getTransparence() < 1.0) 491 { 492 bool bDrawTransparentUsed(false); 493 494 // since DEV300 m33 DrawTransparent is supported in VCL (for some targets 495 // natively), so i am now enabling this shortcut 496 static bool bAllowUsingDrawTransparent(true); 497 498 if(bAllowUsingDrawTransparent && 1 == rContent.getLength()) 499 { 500 const primitive2d::Primitive2DReference xReference(rContent[0]); 501 const primitive2d::BasePrimitive2D* pBasePrimitive = dynamic_cast< const primitive2d::BasePrimitive2D* >(xReference.get()); 502 503 if(pBasePrimitive) 504 { 505 switch(pBasePrimitive->getPrimitive2DID()) 506 { 507 case PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D: 508 { 509 // single transparent PolyPolygon identified, use directly 510 const primitive2d::PolyPolygonColorPrimitive2D* pPoPoColor = static_cast< const primitive2d::PolyPolygonColorPrimitive2D* >(pBasePrimitive); 511 OSL_ENSURE(pPoPoColor, "OOps, PrimitiveID and PrimitiveType do not match (!)"); 512 bDrawTransparentUsed = tryDrawPolyPolygonColorPrimitive2DDirect(*pPoPoColor, rUniTransparenceCandidate.getTransparence()); 513 break; 514 } 515 case PRIMITIVE2D_ID_POLYGONHAIRLINEPRIMITIVE2D: 516 { 517 // single transparent PolygonHairlinePrimitive2D identified, use directly 518 const primitive2d::PolygonHairlinePrimitive2D* pPoHair = static_cast< const primitive2d::PolygonHairlinePrimitive2D* >(pBasePrimitive); 519 OSL_ENSURE(pPoHair, "OOps, PrimitiveID and PrimitiveType do not match (!)"); 520 521 // do no tallow by default - problem is that self-overlapping parts of this geometry will 522 // not be in a all-same transparency but will already alpha-cover themselves with blending. 523 // This is not what the UnifiedTransparencePrimitive2D defines: It requires all it's 524 // content to be uniformely transparent. 525 // For hairline the effect is pretty minimal, but still not correct. 526 static bool bAllowed(false); 527 528 bDrawTransparentUsed = bAllowed && tryDrawPolygonHairlinePrimitive2DDirect(*pPoHair, rUniTransparenceCandidate.getTransparence()); 529 break; 530 } 531 case PRIMITIVE2D_ID_POLYGONSTROKEPRIMITIVE2D: 532 { 533 // single transparent PolygonStrokePrimitive2D identified, use directly 534 const primitive2d::PolygonStrokePrimitive2D* pPoStroke = static_cast< const primitive2d::PolygonStrokePrimitive2D* >(pBasePrimitive); 535 OSL_ENSURE(pPoStroke, "OOps, PrimitiveID and PrimitiveType do not match (!)"); 536 537 // do no tallow by default - problem is that self-overlapping parts of this geometry will 538 // not be in a all-same transparency but will already alpha-cover themselves with blending. 539 // This is not what the UnifiedTransparencePrimitive2D defines: It requires all it's 540 // content to be uniformely transparent. 541 // To check, acitvate and draw a wide transparent self-crossing line/curve 542 static bool bAllowed(false); 543 544 bDrawTransparentUsed = bAllowed && tryDrawPolygonStrokePrimitive2DDirect(*pPoStroke, rUniTransparenceCandidate.getTransparence()); 545 break; 546 } 547 } 548 } 549 } 550 551 if(!bDrawTransparentUsed) 552 { 553 // unified sub-transparence. Draw to VDev first. 554 RenderUnifiedTransparencePrimitive2D(rUniTransparenceCandidate); 555 } 556 } 557 } 558 559 break; 560 } 561 case PRIMITIVE2D_ID_TRANSPARENCEPRIMITIVE2D : 562 { 563 // sub-transparence group. Draw to VDev first. 564 RenderTransparencePrimitive2D(static_cast< const primitive2d::TransparencePrimitive2D& >(rCandidate)); 565 break; 566 } 567 case PRIMITIVE2D_ID_TRANSFORMPRIMITIVE2D : 568 { 569 // transform group. 570 RenderTransformPrimitive2D(static_cast< const primitive2d::TransformPrimitive2D& >(rCandidate)); 571 break; 572 } 573 case PRIMITIVE2D_ID_PAGEPREVIEWPRIMITIVE2D : 574 { 575 // new XDrawPage for ViewInformation2D 576 RenderPagePreviewPrimitive2D(static_cast< const primitive2d::PagePreviewPrimitive2D& >(rCandidate)); 577 break; 578 } 579 case PRIMITIVE2D_ID_MARKERARRAYPRIMITIVE2D : 580 { 581 // marker array 582 RenderMarkerArrayPrimitive2D(static_cast< const primitive2d::MarkerArrayPrimitive2D& >(rCandidate)); 583 break; 584 } 585 case PRIMITIVE2D_ID_POINTARRAYPRIMITIVE2D : 586 { 587 // point array 588 RenderPointArrayPrimitive2D(static_cast< const primitive2d::PointArrayPrimitive2D& >(rCandidate)); 589 break; 590 } 591 case PRIMITIVE2D_ID_CONTROLPRIMITIVE2D : 592 { 593 // control primitive 594 const primitive2d::ControlPrimitive2D& rControlPrimitive = static_cast< const primitive2d::ControlPrimitive2D& >(rCandidate); 595 const uno::Reference< awt::XControl >& rXControl(rControlPrimitive.getXControl()); 596 597 try 598 { 599 // remember old graphics and create new 600 uno::Reference< awt::XView > xControlView(rXControl, uno::UNO_QUERY_THROW); 601 const uno::Reference< awt::XGraphics > xOriginalGraphics(xControlView->getGraphics()); 602 const uno::Reference< awt::XGraphics > xNewGraphics(mpOutputDevice->CreateUnoGraphics()); 603 604 if(xNewGraphics.is()) 605 { 606 // link graphics and view 607 xControlView->setGraphics(xNewGraphics); 608 609 // get position 610 const basegfx::B2DHomMatrix aObjectToPixel(maCurrentTransformation * rControlPrimitive.getTransform()); 611 const basegfx::B2DPoint aTopLeftPixel(aObjectToPixel * basegfx::B2DPoint(0.0, 0.0)); 612 613 // find out if the control is already visualized as a VCL-ChildWindow. If yes, 614 // it does not need to be painted at all. 615 uno::Reference< awt::XWindow2 > xControlWindow(rXControl, uno::UNO_QUERY_THROW); 616 const bool bControlIsVisibleAsChildWindow(rXControl->getPeer().is() && xControlWindow->isVisible()); 617 618 if(!bControlIsVisibleAsChildWindow) 619 { 620 // draw it. Do not forget to use the evtl. offsetted origin of the target device, 621 // e.g. when used with mask/transparence buffer device 622 const Point aOrigin(mpOutputDevice->GetMapMode().GetOrigin()); 623 xControlView->draw( 624 aOrigin.X() + basegfx::fround(aTopLeftPixel.getX()), 625 aOrigin.Y() + basegfx::fround(aTopLeftPixel.getY())); 626 } 627 628 // restore original graphics 629 xControlView->setGraphics(xOriginalGraphics); 630 } 631 } 632 catch(const uno::Exception&) 633 { 634 // #i116763# removing since there is a good alternative when the xControlView 635 // is not found and it is allowed to happen 636 // DBG_UNHANDLED_EXCEPTION(); 637 638 // process recursively and use the decomposition as Bitmap 639 process(rCandidate.get2DDecomposition(getViewInformation2D())); 640 } 641 642 break; 643 } 644 case PRIMITIVE2D_ID_POLYGONSTROKEPRIMITIVE2D: 645 { 646 // try to use directly 647 const primitive2d::PolygonStrokePrimitive2D& rPolygonStrokePrimitive2D = static_cast< const primitive2d::PolygonStrokePrimitive2D& >(rCandidate); 648 649 if(tryDrawPolygonStrokePrimitive2DDirect(rPolygonStrokePrimitive2D, 0.0)) 650 { 651 break; 652 } 653 654 // the stroke primitive may be decomposed to filled polygons. To keep 655 // evtl. set DrawModes aka DRAWMODE_BLACKLINE, DRAWMODE_GRAYLINE, 656 // DRAWMODE_GHOSTEDLINE, DRAWMODE_WHITELINE or DRAWMODE_SETTINGSLINE 657 // working, these need to be copied to the corresponding fill modes 658 const sal_uInt32 nOriginalDrawMode(mpOutputDevice->GetDrawMode()); 659 adaptLineToFillDrawMode(); 660 661 // polygon stroke primitive 662 static bool bSuppressFatToHairlineCorrection(false); 663 664 if(bSuppressFatToHairlineCorrection) 665 { 666 // remember that we enter a PolygonStrokePrimitive2D decomposition, 667 // used for AA thick line drawing 668 mnPolygonStrokePrimitive2D++; 669 670 // with AA there is no need to handle thin lines special 671 process(rCandidate.get2DDecomposition(getViewInformation2D())); 672 673 // leave PolygonStrokePrimitive2D 674 mnPolygonStrokePrimitive2D--; 675 } 676 else 677 { 678 // Lines with 1 and 2 pixel width without AA need special treatment since their vsiualisation 679 // as filled polygons is geometrically corret but looks wrong since polygon filling avoids 680 // the right and bottom pixels. The used method evaluates that and takes the correct action, 681 // including calling recursively with decomposition if line is wide enough 682 RenderPolygonStrokePrimitive2D(rPolygonStrokePrimitive2D); 683 } 684 685 // restore DrawMode 686 mpOutputDevice->SetDrawMode(nOriginalDrawMode); 687 688 break; 689 } 690 case PRIMITIVE2D_ID_FILLHATCHPRIMITIVE2D : 691 { 692 static bool bForceIgnoreHatchSmoothing(false); 693 694 if(bForceIgnoreHatchSmoothing || getOptionsDrawinglayer().IsAntiAliasing()) 695 { 696 // if AA is used (or ignore smoothing is on), there is no need to smooth 697 // hatch painting, use decomposition 698 process(rCandidate.get2DDecomposition(getViewInformation2D())); 699 } 700 else 701 { 702 // without AA, use VCL to draw the hatch. It snaps hatch distances to the next pixel 703 // and forces hatch distance to be >= 3 pixels to make the hatch display look smoother. 704 // This is wrong in principle, but looks nicer. This could also be done here directly 705 // without VCL usage if needed 706 const primitive2d::FillHatchPrimitive2D& rFillHatchPrimitive = static_cast< const primitive2d::FillHatchPrimitive2D& >(rCandidate); 707 const attribute::FillHatchAttribute& rFillHatchAttributes = rFillHatchPrimitive.getFillHatch(); 708 709 // create hatch polygon in range size and discrete coordinates 710 basegfx::B2DRange aHatchRange(rFillHatchPrimitive.getOutputRange()); 711 aHatchRange.transform(maCurrentTransformation); 712 const basegfx::B2DPolygon aHatchPolygon(basegfx::tools::createPolygonFromRect(aHatchRange)); 713 714 if(rFillHatchAttributes.isFillBackground()) 715 { 716 // #i111846# background fill is active; draw fill polygon 717 const basegfx::BColor aPolygonColor(maBColorModifierStack.getModifiedColor(rFillHatchPrimitive.getBColor())); 718 719 mpOutputDevice->SetFillColor(Color(aPolygonColor)); 720 mpOutputDevice->SetLineColor(); 721 mpOutputDevice->DrawPolygon(aHatchPolygon); 722 } 723 724 // set hatch line color 725 const basegfx::BColor aHatchColor(maBColorModifierStack.getModifiedColor(rFillHatchPrimitive.getBColor())); 726 mpOutputDevice->SetFillColor(); 727 mpOutputDevice->SetLineColor(Color(aHatchColor)); 728 729 // get hatch style 730 HatchStyle eHatchStyle(HATCH_SINGLE); 731 732 switch(rFillHatchAttributes.getStyle()) 733 { 734 default : // HATCHSTYLE_SINGLE 735 { 736 break; 737 } 738 case attribute::HATCHSTYLE_DOUBLE : 739 { 740 eHatchStyle = HATCH_DOUBLE; 741 break; 742 } 743 case attribute::HATCHSTYLE_TRIPLE : 744 { 745 eHatchStyle = HATCH_TRIPLE; 746 break; 747 } 748 } 749 750 // create hatch 751 const basegfx::B2DVector aDiscreteDistance(maCurrentTransformation * basegfx::B2DVector(rFillHatchAttributes.getDistance(), 0.0)); 752 const sal_uInt32 nDistance(basegfx::fround(aDiscreteDistance.getLength())); 753 const sal_uInt16 nAngle10((sal_uInt16)basegfx::fround(rFillHatchAttributes.getAngle() / F_PI1800)); 754 ::Hatch aVCLHatch(eHatchStyle, Color(rFillHatchAttributes.getColor()), nDistance, nAngle10); 755 756 // draw hatch using VCL 757 mpOutputDevice->DrawHatch(PolyPolygon(Polygon(aHatchPolygon)), aVCLHatch); 758 } 759 break; 760 } 761 case PRIMITIVE2D_ID_BACKGROUNDCOLORPRIMITIVE2D : 762 { 763 // #i98404# Handle directly, especially when AA is active 764 const primitive2d::BackgroundColorPrimitive2D& rPrimitive = static_cast< const primitive2d::BackgroundColorPrimitive2D& >(rCandidate); 765 const sal_uInt16 nOriginalAA(mpOutputDevice->GetAntialiasing()); 766 767 // switch AA off in all cases 768 mpOutputDevice->SetAntialiasing(mpOutputDevice->GetAntialiasing() & ~ANTIALIASING_ENABLE_B2DDRAW); 769 770 // create color for fill 771 const basegfx::BColor aPolygonColor(maBColorModifierStack.getModifiedColor(rPrimitive.getBColor())); 772 mpOutputDevice->SetFillColor(Color(aPolygonColor)); 773 mpOutputDevice->SetLineColor(); 774 775 // create rectangle for fill 776 const basegfx::B2DRange& aViewport(getViewInformation2D().getDiscreteViewport()); 777 const Rectangle aRectangle( 778 (sal_Int32)floor(aViewport.getMinX()), (sal_Int32)floor(aViewport.getMinY()), 779 (sal_Int32)ceil(aViewport.getMaxX()), (sal_Int32)ceil(aViewport.getMaxY())); 780 mpOutputDevice->DrawRect(aRectangle); 781 782 // restore AA setting 783 mpOutputDevice->SetAntialiasing(nOriginalAA); 784 break; 785 } 786 case PRIMITIVE2D_ID_TEXTHIERARCHYEDITPRIMITIVE2D : 787 { 788 // #i97628# 789 // This primitive means that the content is derived from an active text edit, 790 // not from model data itself. Some renderers need to suppress this content, e.g. 791 // the pixel renderer used for displaying the edit view (like this one). It's 792 // not to be suppressed by the MetaFile renderers, so that the edited text is 793 // part of the MetaFile, e.g. needed for presentation previews. 794 // Action: Ignore here, do nothing. 795 break; 796 } 797 case PRIMITIVE2D_ID_INVERTPRIMITIVE2D : 798 { 799 // invert primitive (currently only used for HighContrast fallback for selection in SW and SC). 800 // Set OutDev to XOR and switch AA off (XOR does not work with AA) 801 mpOutputDevice->Push(); 802 mpOutputDevice->SetRasterOp( ROP_XOR ); 803 const sal_uInt16 nAntiAliasing(mpOutputDevice->GetAntialiasing()); 804 mpOutputDevice->SetAntialiasing(nAntiAliasing & ~ANTIALIASING_ENABLE_B2DDRAW); 805 806 // process content recursively 807 process(rCandidate.get2DDecomposition(getViewInformation2D())); 808 809 // restore OutDev 810 mpOutputDevice->Pop(); 811 mpOutputDevice->SetAntialiasing(nAntiAliasing); 812 break; 813 } 814 case PRIMITIVE2D_ID_EPSPRIMITIVE2D : 815 { 816 RenderEpsPrimitive2D(static_cast< const primitive2d::EpsPrimitive2D& >(rCandidate)); 817 break; 818 } 819 case PRIMITIVE2D_ID_SVGLINEARATOMPRIMITIVE2D: 820 { 821 RenderSvgLinearAtomPrimitive2D(static_cast< const primitive2d::SvgLinearAtomPrimitive2D& >(rCandidate)); 822 break; 823 } 824 case PRIMITIVE2D_ID_SVGRADIALATOMPRIMITIVE2D: 825 { 826 RenderSvgRadialAtomPrimitive2D(static_cast< const primitive2d::SvgRadialAtomPrimitive2D& >(rCandidate)); 827 break; 828 } 829 default : 830 { 831 // process recursively 832 process(rCandidate.get2DDecomposition(getViewInformation2D())); 833 break; 834 } 835 } 836 } 837 } // end of namespace processor2d 838 } // end of namespace drawinglayer 839 840 ////////////////////////////////////////////////////////////////////////////// 841 // eof 842