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