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/vclmetafileprocessor2d.hxx> 28 #include <tools/gen.hxx> 29 #include <vcl/virdev.hxx> 30 #include <vcl/gdimtf.hxx> 31 #include <vcl/gradient.hxx> 32 #include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx> 33 #include <drawinglayer/primitive2d/textprimitive2d.hxx> 34 #include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx> 35 #include <drawinglayer/primitive2d/polygonprimitive2d.hxx> 36 #include <drawinglayer/primitive2d/bitmapprimitive2d.hxx> 37 #include <drawinglayer/primitive2d/metafileprimitive2d.hxx> 38 #include <drawinglayer/primitive2d/maskprimitive2d.hxx> 39 #include <basegfx/polygon/b2dpolygonclipper.hxx> 40 #include <basegfx/polygon/b2dpolypolygontools.hxx> 41 #include <drawinglayer/primitive2d/modifiedcolorprimitive2d.hxx> 42 #include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx> 43 #include <drawinglayer/primitive2d/transparenceprimitive2d.hxx> 44 #include <drawinglayer/primitive2d/fillgradientprimitive2d.hxx> 45 #include <drawinglayer/processor2d/vclpixelprocessor2d.hxx> 46 #include <tools/stream.hxx> 47 #include <drawinglayer/primitive2d/transformprimitive2d.hxx> 48 #include <drawinglayer/primitive2d/markerarrayprimitive2d.hxx> 49 #include <drawinglayer/primitive2d/pointarrayprimitive2d.hxx> 50 #include <vcl/graphictools.hxx> 51 #include <vcl/metaact.hxx> 52 #include <drawinglayer/primitive2d/texthierarchyprimitive2d.hxx> 53 #include <drawinglayer/primitive2d/textdecoratedprimitive2d.hxx> 54 #include <comphelper/processfactory.hxx> 55 #include <rtl/ustring.hxx> 56 #include <com/sun/star/i18n/CharacterIteratorMode.hdl> 57 #include <com/sun/star/i18n/WordType.hpp> 58 #include <drawinglayer/primitive2d/controlprimitive2d.hxx> 59 #include <drawinglayer/primitive2d/graphicprimitive2d.hxx> 60 #include <basegfx/polygon/b2dpolygontools.hxx> 61 #include <drawinglayer/primitive2d/pagepreviewprimitive2d.hxx> 62 #include <drawinglayer/primitive2d/epsprimitive2d.hxx> 63 #include <basegfx/polygon/b2dlinegeometry.hxx> 64 65 ////////////////////////////////////////////////////////////////////////////// 66 // for PDFExtOutDevData Graphic support 67 68 #include <vcl/graph.hxx> 69 #include <vcl/svapp.hxx> 70 #include <toolkit/helper/formpdfexport.hxx> 71 72 ////////////////////////////////////////////////////////////////////////////// 73 // for Control printing 74 75 #include <com/sun/star/beans/XPropertySet.hpp> 76 77 ////////////////////////////////////////////////////////////////////////////// 78 // for StructureTagPrimitive support in sd's unomodel.cxx 79 80 #include <drawinglayer/primitive2d/structuretagprimitive2d.hxx> 81 82 ////////////////////////////////////////////////////////////////////////////// 83 84 using namespace com::sun::star; 85 86 ////////////////////////////////////////////////////////////////////////////// 87 // #112245# definition for maximum allowed point count due to Metafile target. 88 // To be on the safe side with the old tools polygon, use slightly less then 89 // the theoretical maximum (bad experiences with tools polygon) 90 91 #define MAX_POLYGON_POINT_COUNT_METAFILE (0x0000fff0) 92 93 ////////////////////////////////////////////////////////////////////////////// 94 95 namespace 96 { 97 // #112245# helper to split line polygon in half 98 void splitLinePolygon( 99 const basegfx::B2DPolygon& rBasePolygon, 100 basegfx::B2DPolygon& o_aLeft, 101 basegfx::B2DPolygon& o_aRight) 102 { 103 const sal_uInt32 nCount(rBasePolygon.count()); 104 105 if(nCount) 106 { 107 const sal_uInt32 nHalfCount((nCount - 1) >> 1); 108 109 o_aLeft = basegfx::B2DPolygon(rBasePolygon, 0, nHalfCount + 1); 110 o_aLeft.setClosed(false); 111 112 o_aRight = basegfx::B2DPolygon(rBasePolygon, nHalfCount, nCount - nHalfCount); 113 o_aRight.setClosed(false); 114 115 if(rBasePolygon.isClosed()) 116 { 117 o_aRight.append(rBasePolygon.getB2DPoint(0)); 118 119 if(rBasePolygon.areControlPointsUsed()) 120 { 121 o_aRight.setControlPoints( 122 o_aRight.count() - 1, 123 rBasePolygon.getPrevControlPoint(0), 124 rBasePolygon.getNextControlPoint(0)); 125 } 126 } 127 } 128 else 129 { 130 o_aLeft.clear(); 131 o_aRight.clear(); 132 } 133 } 134 135 // #112245# helper to evtl. split filled polygons to maximum metafile point count 136 bool fillPolyPolygonNeededToBeSplit(basegfx::B2DPolyPolygon& rPolyPolygon) 137 { 138 bool bRetval(false); 139 const sal_uInt32 nPolyCount(rPolyPolygon.count()); 140 141 if(nPolyCount) 142 { 143 basegfx::B2DPolyPolygon aSplitted; 144 145 for(sal_uInt32 a(0); a < nPolyCount; a++) 146 { 147 const basegfx::B2DPolygon aCandidate(rPolyPolygon.getB2DPolygon(a)); 148 const sal_uInt32 nPointCount(aCandidate.count()); 149 bool bNeedToSplit(false); 150 151 if(aCandidate.areControlPointsUsed()) 152 { 153 // compare with the maximum for bezier curved polygons 154 bNeedToSplit = nPointCount > ((MAX_POLYGON_POINT_COUNT_METAFILE / 3L) - 1L); 155 } 156 else 157 { 158 // compare with the maximum for simple point polygons 159 bNeedToSplit = nPointCount > (MAX_POLYGON_POINT_COUNT_METAFILE - 1); 160 } 161 162 if(bNeedToSplit) 163 { 164 // need to split the partial polygon 165 const basegfx::B2DRange aRange(aCandidate.getB2DRange()); 166 const basegfx::B2DPoint aCenter(aRange.getCenter()); 167 168 if(aRange.getWidth() > aRange.getHeight()) 169 { 170 // clip in left and right 171 const basegfx::B2DPolyPolygon aLeft( 172 basegfx::tools::clipPolygonOnParallelAxis( 173 aCandidate, 174 false, 175 true, 176 aCenter.getX(), 177 false)); 178 const basegfx::B2DPolyPolygon aRight( 179 basegfx::tools::clipPolygonOnParallelAxis( 180 aCandidate, 181 false, 182 false, 183 aCenter.getX(), 184 false)); 185 186 aSplitted.append(aLeft); 187 aSplitted.append(aRight); 188 } 189 else 190 { 191 // clip in top and bottom 192 const basegfx::B2DPolyPolygon aTop( 193 basegfx::tools::clipPolygonOnParallelAxis( 194 aCandidate, 195 true, 196 true, 197 aCenter.getY(), 198 false)); 199 const basegfx::B2DPolyPolygon aBottom( 200 basegfx::tools::clipPolygonOnParallelAxis( 201 aCandidate, 202 true, 203 false, 204 aCenter.getY(), 205 false)); 206 207 aSplitted.append(aTop); 208 aSplitted.append(aBottom); 209 } 210 } 211 else 212 { 213 aSplitted.append(aCandidate); 214 } 215 } 216 217 if(aSplitted.count() != nPolyCount) 218 { 219 rPolyPolygon = aSplitted; 220 } 221 } 222 223 return bRetval; 224 } 225 } // end of anonymous namespace 226 227 ////////////////////////////////////////////////////////////////////////////// 228 229 namespace drawinglayer 230 { 231 namespace processor2d 232 { 233 Rectangle VclMetafileProcessor2D::impDumpToMetaFile( 234 const primitive2d::Primitive2DSequence& rContent, 235 GDIMetaFile& o_rContentMetafile) 236 { 237 // Prepare VDev, MetaFile and connections 238 OutputDevice* pLastOutputDevice = mpOutputDevice; 239 GDIMetaFile* pLastMetafile = mpMetaFile; 240 basegfx::B2DRange aPrimitiveRange(primitive2d::getB2DRangeFromPrimitive2DSequence(rContent, getViewInformation2D())); 241 242 // transform primitive range with current transformation (e.g shadow offset) 243 aPrimitiveRange.transform(maCurrentTransformation); 244 245 const Rectangle aPrimitiveRectangle( 246 basegfx::fround(aPrimitiveRange.getMinX()), basegfx::fround(aPrimitiveRange.getMinY()), 247 basegfx::fround(aPrimitiveRange.getMaxX()), basegfx::fround(aPrimitiveRange.getMaxY())); 248 VirtualDevice aContentVDev; 249 MapMode aNewMapMode(pLastOutputDevice->GetMapMode()); 250 251 mpOutputDevice = &aContentVDev; 252 mpMetaFile = &o_rContentMetafile; 253 aContentVDev.EnableOutput(false); 254 aContentVDev.SetMapMode(pLastOutputDevice->GetMapMode()); 255 o_rContentMetafile.Record(&aContentVDev); 256 aContentVDev.SetLineColor(pLastOutputDevice->GetLineColor()); 257 aContentVDev.SetFillColor(pLastOutputDevice->GetFillColor()); 258 aContentVDev.SetFont(pLastOutputDevice->GetFont()); 259 aContentVDev.SetDrawMode(pLastOutputDevice->GetDrawMode()); 260 aContentVDev.SetSettings(pLastOutputDevice->GetSettings()); 261 aContentVDev.SetRefPoint(pLastOutputDevice->GetRefPoint()); 262 263 // dump to MetaFile 264 process(rContent); 265 266 // cleanups 267 o_rContentMetafile.Stop(); 268 o_rContentMetafile.WindStart(); 269 aNewMapMode.SetOrigin(aPrimitiveRectangle.TopLeft()); 270 o_rContentMetafile.SetPrefMapMode(aNewMapMode); 271 o_rContentMetafile.SetPrefSize(aPrimitiveRectangle.GetSize()); 272 mpOutputDevice = pLastOutputDevice; 273 mpMetaFile = pLastMetafile; 274 275 return aPrimitiveRectangle; 276 } 277 278 void VclMetafileProcessor2D::impConvertFillGradientAttributeToVCLGradient( 279 Gradient& o_rVCLGradient, 280 const attribute::FillGradientAttribute& rFiGrAtt, 281 bool bIsTransparenceGradient) 282 { 283 if(bIsTransparenceGradient) 284 { 285 // it's about transparence channel intensities (black/white), do not use color modifier 286 o_rVCLGradient.SetStartColor(Color(rFiGrAtt.getStartColor())); 287 o_rVCLGradient.SetEndColor(Color(rFiGrAtt.getEndColor())); 288 } 289 else 290 { 291 // use color modifier to influence start/end color of gradient 292 o_rVCLGradient.SetStartColor(Color(maBColorModifierStack.getModifiedColor(rFiGrAtt.getStartColor()))); 293 o_rVCLGradient.SetEndColor(Color(maBColorModifierStack.getModifiedColor(rFiGrAtt.getEndColor()))); 294 } 295 296 o_rVCLGradient.SetAngle(static_cast< sal_uInt16 >(rFiGrAtt.getAngle() * (1.0 / F_PI1800))); 297 o_rVCLGradient.SetBorder(static_cast< sal_uInt16 >(rFiGrAtt.getBorder() * 100.0)); 298 o_rVCLGradient.SetOfsX(static_cast< sal_uInt16 >(rFiGrAtt.getOffsetX() * 100.0)); 299 o_rVCLGradient.SetOfsY(static_cast< sal_uInt16 >(rFiGrAtt.getOffsetY() * 100.0)); 300 o_rVCLGradient.SetSteps(rFiGrAtt.getSteps()); 301 302 // defaults for intensity; those were computed into the start/end colors already 303 o_rVCLGradient.SetStartIntensity(100); 304 o_rVCLGradient.SetEndIntensity(100); 305 306 switch(rFiGrAtt.getStyle()) 307 { 308 default : // attribute::GRADIENTSTYLE_LINEAR : 309 { 310 o_rVCLGradient.SetStyle(GRADIENT_LINEAR); 311 break; 312 } 313 case attribute::GRADIENTSTYLE_AXIAL : 314 { 315 o_rVCLGradient.SetStyle(GRADIENT_AXIAL); 316 break; 317 } 318 case attribute::GRADIENTSTYLE_RADIAL : 319 { 320 o_rVCLGradient.SetStyle(GRADIENT_RADIAL); 321 break; 322 } 323 case attribute::GRADIENTSTYLE_ELLIPTICAL : 324 { 325 o_rVCLGradient.SetStyle(GRADIENT_ELLIPTICAL); 326 break; 327 } 328 case attribute::GRADIENTSTYLE_SQUARE : 329 { 330 o_rVCLGradient.SetStyle(GRADIENT_SQUARE); 331 break; 332 } 333 case attribute::GRADIENTSTYLE_RECT : 334 { 335 o_rVCLGradient.SetStyle(GRADIENT_RECT); 336 break; 337 } 338 } 339 } 340 341 void VclMetafileProcessor2D::impStartSvtGraphicFill(SvtGraphicFill* pSvtGraphicFill) 342 { 343 if(pSvtGraphicFill && !mnSvtGraphicFillCount) 344 { 345 SvMemoryStream aMemStm; 346 347 aMemStm << *pSvtGraphicFill; 348 mpMetaFile->AddAction(new MetaCommentAction("XPATHFILL_SEQ_BEGIN", 0, static_cast< const sal_uInt8* >(aMemStm.GetData()), aMemStm.Seek(STREAM_SEEK_TO_END))); 349 mnSvtGraphicFillCount++; 350 } 351 } 352 353 void VclMetafileProcessor2D::impEndSvtGraphicFill(SvtGraphicFill* pSvtGraphicFill) 354 { 355 if(pSvtGraphicFill && mnSvtGraphicFillCount) 356 { 357 mnSvtGraphicFillCount--; 358 mpMetaFile->AddAction(new MetaCommentAction("XPATHFILL_SEQ_END")); 359 delete pSvtGraphicFill; 360 } 361 } 362 363 SvtGraphicStroke* VclMetafileProcessor2D::impTryToCreateSvtGraphicStroke( 364 const basegfx::B2DPolygon& rB2DPolygon, 365 const basegfx::BColor* pColor, 366 const attribute::LineAttribute* pLineAttribute, 367 const attribute::StrokeAttribute* pStrokeAttribute, 368 const attribute::LineStartEndAttribute* pStart, 369 const attribute::LineStartEndAttribute* pEnd) 370 { 371 SvtGraphicStroke* pRetval = 0; 372 373 if(rB2DPolygon.count() && !mnSvtGraphicStrokeCount) 374 { 375 basegfx::BColor aStrokeColor; 376 basegfx::B2DPolyPolygon aStartArrow; 377 basegfx::B2DPolyPolygon aEndArrow; 378 379 if(pColor) 380 { 381 aStrokeColor = *pColor; 382 } 383 else if(pLineAttribute) 384 { 385 aStrokeColor = maBColorModifierStack.getModifiedColor(pLineAttribute->getColor()); 386 } 387 388 // It IS needed to record the stroke color at all in the metafile, 389 // SvtGraphicStroke has NO entry for stroke color(!) 390 mpOutputDevice->SetLineColor(Color(aStrokeColor)); 391 392 if(!rB2DPolygon.isClosed()) 393 { 394 double fPolyLength(0.0); 395 396 if(pStart && pStart->isActive()) 397 { 398 fPolyLength = basegfx::tools::getLength(rB2DPolygon); 399 400 aStartArrow = basegfx::tools::createAreaGeometryForLineStartEnd( 401 rB2DPolygon, pStart->getB2DPolyPolygon(), true, pStart->getWidth(), 402 fPolyLength, pStart->isCentered() ? 0.5 : 0.0, 0); 403 } 404 405 if(pEnd && pEnd->isActive()) 406 { 407 if(basegfx::fTools::equalZero(fPolyLength)) 408 { 409 fPolyLength = basegfx::tools::getLength(rB2DPolygon); 410 } 411 412 aEndArrow = basegfx::tools::createAreaGeometryForLineStartEnd( 413 rB2DPolygon, pEnd->getB2DPolyPolygon(), false, pEnd->getWidth(), 414 fPolyLength, pEnd->isCentered() ? 0.5 : 0.0, 0); 415 } 416 } 417 418 SvtGraphicStroke::JoinType eJoin(SvtGraphicStroke::joinNone); 419 SvtGraphicStroke::CapType eCap(SvtGraphicStroke::capButt); 420 double fLineWidth(0.0); 421 double fMiterLength(0.0); 422 SvtGraphicStroke::DashArray aDashArray; 423 424 if(pLineAttribute) 425 { 426 // pre-fill fLineWidth #119198# Need to apply maCurrentTransformation, too (!) 427 const basegfx::B2DVector aDiscreteUnit(maCurrentTransformation * basegfx::B2DVector(pLineAttribute->getWidth(), 0.0)); 428 fLineWidth = aDiscreteUnit.getLength(); 429 430 // pre-fill fMiterLength 431 fMiterLength = fLineWidth; 432 433 // get Join 434 switch(pLineAttribute->getLineJoin()) 435 { 436 default : // basegfx::B2DLINEJOIN_NONE : 437 { 438 eJoin = SvtGraphicStroke::joinNone; 439 break; 440 } 441 case basegfx::B2DLINEJOIN_BEVEL : 442 { 443 eJoin = SvtGraphicStroke::joinBevel; 444 break; 445 } 446 case basegfx::B2DLINEJOIN_MIDDLE : 447 case basegfx::B2DLINEJOIN_MITER : 448 { 449 eJoin = SvtGraphicStroke::joinMiter; 450 // ATM 15 degrees is assumed 451 fMiterLength /= rtl::math::sin(M_PI * (15.0 / 360.0)); 452 break; 453 } 454 case basegfx::B2DLINEJOIN_ROUND : 455 { 456 eJoin = SvtGraphicStroke::joinRound; 457 break; 458 } 459 } 460 461 // get stroke 462 switch(pLineAttribute->getLineCap()) 463 { 464 default: /* com::sun::star::drawing::LineCap_BUTT */ 465 { 466 eCap = SvtGraphicStroke::capButt; 467 break; 468 } 469 case com::sun::star::drawing::LineCap_ROUND: 470 { 471 eCap = SvtGraphicStroke::capRound; 472 break; 473 } 474 case com::sun::star::drawing::LineCap_SQUARE: 475 { 476 eCap = SvtGraphicStroke::capSquare; 477 break; 478 } 479 } 480 } 481 482 if(pStrokeAttribute) 483 { 484 // copy dash array 485 aDashArray = pStrokeAttribute->getDotDashArray(); 486 } 487 488 // #i101734# apply current object transformation to created geometry. 489 // This is a partial fix. When a object transformation is used which 490 // e.g. contains a scaleX != scaleY, an unproportional scaling would 491 // have to be applied to the evtl. existing fat line. The current 492 // concept of PDF export and SvtGraphicStroke usage does simply not 493 // allow handling such definitions. The only clean way would be to 494 // add the transformation to SvtGraphicStroke and to handle it there 495 basegfx::B2DPolygon aB2DPolygon(rB2DPolygon); 496 497 aB2DPolygon.transform(maCurrentTransformation); 498 aStartArrow.transform(maCurrentTransformation); 499 aEndArrow.transform(maCurrentTransformation); 500 501 pRetval = new SvtGraphicStroke( 502 Polygon(aB2DPolygon), 503 PolyPolygon(aStartArrow), 504 PolyPolygon(aEndArrow), 505 mfCurrentUnifiedTransparence, 506 fLineWidth, 507 eCap, 508 eJoin, 509 fMiterLength, 510 aDashArray); 511 } 512 513 return pRetval; 514 } 515 516 void VclMetafileProcessor2D::impStartSvtGraphicStroke(SvtGraphicStroke* pSvtGraphicStroke) 517 { 518 if(pSvtGraphicStroke && !mnSvtGraphicStrokeCount) 519 { 520 SvMemoryStream aMemStm; 521 522 aMemStm << *pSvtGraphicStroke; 523 mpMetaFile->AddAction(new MetaCommentAction("XPATHSTROKE_SEQ_BEGIN", 0, static_cast< const sal_uInt8* >(aMemStm.GetData()), aMemStm.Seek(STREAM_SEEK_TO_END))); 524 mnSvtGraphicStrokeCount++; 525 } 526 } 527 528 void VclMetafileProcessor2D::impEndSvtGraphicStroke(SvtGraphicStroke* pSvtGraphicStroke) 529 { 530 if(pSvtGraphicStroke && mnSvtGraphicStrokeCount) 531 { 532 mnSvtGraphicStrokeCount--; 533 mpMetaFile->AddAction(new MetaCommentAction("XPATHSTROKE_SEQ_END")); 534 delete pSvtGraphicStroke; 535 } 536 } 537 538 // init static break iterator 539 uno::Reference< ::com::sun::star::i18n::XBreakIterator > VclMetafileProcessor2D::mxBreakIterator; 540 541 VclMetafileProcessor2D::VclMetafileProcessor2D(const geometry::ViewInformation2D& rViewInformation, OutputDevice& rOutDev) 542 : VclProcessor2D(rViewInformation, rOutDev), 543 mpMetaFile(rOutDev.GetConnectMetaFile()), 544 mnSvtGraphicFillCount(0), 545 mnSvtGraphicStrokeCount(0), 546 mfCurrentUnifiedTransparence(0.0), 547 mpPDFExtOutDevData(dynamic_cast< vcl::PDFExtOutDevData* >(rOutDev.GetExtOutDevData())) 548 { 549 OSL_ENSURE(rOutDev.GetConnectMetaFile(), "VclMetafileProcessor2D: Used on OutDev which has no MetaFile Target (!)"); 550 // draw to logic coordinates, do not initialize maCurrentTransformation to viewTransformation 551 // but only to ObjectTransformation. Do not change MapMode of destination. 552 maCurrentTransformation = rViewInformation.getObjectTransformation(); 553 } 554 555 VclMetafileProcessor2D::~VclMetafileProcessor2D() 556 { 557 // MapMode was not changed, no restore necessary 558 } 559 560 /*********************************************************************************************** 561 562 Support of MetaCommentActions in the VclMetafileProcessor2D 563 Found MetaCommentActions and how they are supported: 564 565 XGRAD_SEQ_BEGIN, XGRAD_SEQ_END: 566 567 Used inside OutputDevice::DrawGradient to mark the start and end of a MetaGradientEx action. 568 It is used in various exporters/importers to have direct access to the gradient before it 569 is rendered by VCL (and thus fragmented to polygon color actions and others). On that base, e.g. 570 the Metafile to SdrObject import creates it's gradient objects. 571 Best (and safest) way to support it here is to use PRIMITIVE2D_ID_POLYPOLYGONGRADIENTPRIMITIVE2D, 572 map it back to the corresponding tools PolyPolygon and the Gradient and just call 573 OutputDevice::DrawGradient which creates the necessary compatible actions. 574 575 XPATHFILL_SEQ_BEGIN, XPATHFILL_SEQ_END: 576 577 Two producers, one is vcl/source/gdi/gdimtf.cxx, line 1273. There, it is transformed 578 inside GDIMetaFile::Rotate, nothing to take care of here. 579 The second producer is in graphics/svx/source/svdraw/impgrfll.cxx, line 374. This is used 580 with each incarnation of Imp_GraphicFill when a metafile is recorded, fillstyle is not 581 XFILL_NONE and not completely transparent. It creates a SvtGraphicFill and streams it 582 to the comment action. A closing end token is created in the destructor. 583 Usages of Imp_GraphicFill are in Do_Paint_Object-methods of SdrCircObj, SdrPathObj and 584 SdrRectObj. 585 The token users pick various actions from SvtGraphicFill, so it may need to be added for all kind 586 of filled objects, even simple colored polygons. It is added as extra information; the 587 Metafile actions between the two tokens are interpreted as output generated from those 588 fills. Thus, users have the choice to use the SvtGraphicFill info or the created output 589 actions. 590 Even for XFillTransparenceItem it is used, thus it may need to be supported in 591 UnifiedTransparencePrimitive2D, too, when interpreted as normally filled PolyPolygon. 592 Implemented for: 593 PRIMITIVE2D_ID_POLYPOLYGONGRAPHICPRIMITIVE2D, 594 PRIMITIVE2D_ID_POLYPOLYGONHATCHPRIMITIVE2D, 595 PRIMITIVE2D_ID_POLYPOLYGONGRADIENTPRIMITIVE2D, 596 PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D, 597 and for PRIMITIVE2D_ID_UNIFIEDTRANSPARENCEPRIMITIVE2D when detected unified transparence 598 599 XPATHSTROKE_SEQ_BEGIN, XPATHSTROKE_SEQ_END: 600 601 Similar to pathfill, but using SvtGraphicStroke instead. It also has two producers where one 602 is also the GDIMetaFile::Rotate. Another user is MetaCommentAction::Move which modifies the 603 contained path accordingly. 604 The other one is SdrObject::Imp_DrawLineGeometry. It's done when MetaFile is set at OutDev and 605 only when geometry is a single polygon (!). I see no reason for that; in the PS exporter this 606 would hinder to make use of PolyPolygon strokes. I will need to add support at: 607 PRIMITIVE2D_ID_POLYGONHAIRLINEPRIMITIVE2D 608 PRIMITIVE2D_ID_POLYGONSTROKEPRIMITIVE2D 609 PRIMITIVE2D_ID_POLYGONSTROKEARROWPRIMITIVE2D 610 This can be done hierarchical, too. 611 Okay, base implementation done based on those three primitives. 612 613 FIELD_SEQ_BEGIN, FIELD_SEQ_END 614 615 Used from slideshow for URLs, created from diverse SvxField implementations inside 616 createBeginComment()/createEndComment(). createBeginComment() is used from editeng\impedit3.cxx 617 inside ImpEditEngine::Paint. 618 Created TextHierarchyFieldPrimitive2D and added needed infos there; it is an group primitive and wraps 619 text primitives (but is not limited to that). It contains the field type if special actions for the 620 support of FIELD_SEQ_BEGIN/END are needed; this is the case for Page and URL fields. If more is 621 needed, it may be supported there. 622 FIELD_SEQ_BEGIN;PageField 623 FIELD_SEQ_END 624 Okay, these are now completely supported by TextHierarchyFieldPrimitive2D. URL works, too. 625 626 XTEXT 627 628 XTEXT_EOC(i) end of character 629 XTEXT_EOW(i) end of word 630 XTEXT_EOS(i) end of sentence 631 632 this three are with index and are created with the help of a i18n::XBreakIterator in 633 ImplDrawWithComments. Simplifying, moving out text painting, reworking to create some 634 data structure for holding those TEXT infos. 635 Supported directly by TextSimplePortionPrimitive2D with adding a Locale to the basic text 636 primitive. In the MetaFileRenderer, the creation is now done (see below). This has the advantage 637 that this creations do not need to be done for all paints all the time. This would be 638 expensive since the BreakIterator and it's usage is expensive and for each paint also the 639 whole character stops would need to be created. 640 Created only for TextDecoratedPortionPrimitive2D due to XTEXT_EOL and XTEXT_EOP (see below) 641 642 XTEXT_EOL() end of line 643 XTEXT_EOP() end of paragraph 644 645 First try with boolean marks at TextDecoratedPortionPrimitive2D did not work too well, 646 i decided to solve it with structure. I added the TextHierarchyPrimitives for this, 647 namely: 648 - TextHierarchyLinePrimitive2D: Encapsulates single line 649 - TextHierarchyParagraphPrimitive2D: Encapsulates single paragraph 650 - TextHierarchyBlockPrimitive2D: encapsulates object texts (only one ATM) 651 Those are now supported in hierarchy. This means the MetaFile renderer will support them 652 by using them, reculrively using their content and adding MetaFile comments as needed. 653 This also means that when another text layouter will be used it will be necessary to 654 create/support the same HierarchyPrimitives to support users. 655 To transport the information using this hierarchy is best suited to all future needs; 656 the slideshow will be able to profit from it directly when using primitives; all other 657 renderers not interested in the text structure will just ignore the encapsulations. 658 659 XTEXT_PAINTSHAPE_BEGIN, XTEXT_PAINTSHAPE_END 660 Supported now by the TextHierarchyBlockPrimitive2D. 661 662 EPSReplacementGraphic: 663 Only used in goodies\source\filter.vcl\ieps\ieps.cxx and svx\source\xml\xmlgrhlp.cxx to 664 hold the original EPS which was imported in the same MetaFile as first 2 entries. Only 665 used to export the original again (if exists). 666 Not necessary to support with MetaFuleRenderer. 667 668 XTEXT_SCROLLRECT, XTEXT_PAINTRECT 669 Currently used to get extra MetaFile infos using GraphicExporter which again uses 670 SdrTextObj::GetTextScrollMetaFileAndRectangle(). ATM works with primitives since 671 the rectangle data is added directly by the GraphicsExporter as comment. Does not need 672 to be adapted at once. 673 When adapting later, the only user - the diashow - should directly use the provided 674 Anination infos in the appropriate primitives (e.g. AnimatedSwitchPrimitive2D) 675 676 PRNSPOOL_TRANSPARENTBITMAP_BEGIN, PRNSPOOL_TRANSPARENTBITMAP_END 677 VCL usage when printing PL -> THB. Okay, THB confirms that it is only used as 678 a fix (hack) while VCL printing. It is needed to not downscale a bitmap which 679 was explicitely created for the printer already again to some default maximum 680 bitmap sizes. 681 Nothing to do here for the primitive renderer. 682 683 Support for vcl::PDFExtOutDevData: 684 PL knows that SJ did that stuff, it's used to hold a pointer to PDFExtOutDevData at 685 the OutDev. When set, some extra data is written there. Trying simple PDF export and 686 watching if i get those infos. 687 Well, a PDF export does not use e.g. ImpEditEngine::Paint since the PdfFilter uses 688 the SdXImpressDocument::render and thus uses the VclMetafileProcessor2D. I will check 689 if i get a PDFExtOutDevData at the target output device. 690 Indeed, i get one. Checking what all may be done when that extra-device-info is there. 691 692 All in all i have to talk to SJ. I will need to emulate some of those actions, but 693 i need to discuss which ones. 694 In the future, all those infos would be taken from the primitive sequence anyways, 695 thus these extensions would potentially be temporary, too. 696 Discussed with SJ, added the necessary support and tested it. Details follow. 697 698 - In ImpEditEngine::Paint, paragraph infos and URL stuff is added. 699 Added in primitive MetaFile renderer. 700 Checking URL: Indeed, current version exports it, but it is missing in primitive 701 CWS version. Adding support. 702 Okay, URLs work. Checked, Done. 703 704 - UnoControlPDFExportContact is only created when PDFExtOutDevData is used at the 705 target and uno control data is created in UnoControlPDFExportContact::do_PaintObject. 706 This may be added in primitive MetaFile renderer. 707 Adding support... 708 OOps, the necessary helper stuff is in svx/source/form/formpdxexport.cxx in namespace 709 svxform. Have to talk to FS if this has to be like that. Especially since 710 ::vcl::PDFWriter::AnyWidget is filled out, which is already part of vcl. 711 Wrote an eMail to FS, he is on vacation currently. I see no reason why not to move 712 that stuff to somewhere else, maybe tools or svtools ?!? We will see... 713 Moved to toolkit, so i have to link against it. I tried VCL first, but it did 714 not work since VCLUnoHelper::CreateFont is unresolved in VCL (!). Other then the name 715 may imply, it is defined in toolkit (!). Since toolkit is linked against VCL itself, 716 the lowest move,ment plave is toolkit. 717 Checked form control export, it works well. Done. 718 719 - In goodies, in GraphicObject::Draw, when the used Graphic is linked, infos are 720 generated. I will need to check what happens here with primitives. 721 To support, use of GraphicPrimitive2D (PRIMITIVE2D_ID_GRAPHICPRIMITIVE2D) may be needed. 722 Added support, but feature is broken in main version, so i cannot test at all. 723 Writing a bug to CL (or SJ) and seeing what happens (#i80380#). 724 SJ took a look and we got it working. Tested VCL MetaFile Renderer based export, 725 as intended, the original file is exported. Works, Done. 726 727 728 729 730 To be done: 731 732 - Maybe there are more places to take care of for vcl::PDFExtOutDevData! 733 734 735 736 ****************************************************************************************************/ 737 738 void VclMetafileProcessor2D::processBasePrimitive2D(const primitive2d::BasePrimitive2D& rCandidate) 739 { 740 switch(rCandidate.getPrimitive2DID()) 741 { 742 case PRIMITIVE2D_ID_WRONGSPELLPRIMITIVE2D : 743 { 744 // directdraw of wrong spell primitive 745 // Ignore for VclMetafileProcessor2D, this is for printing and MetaFile recording only 746 break; 747 } 748 case PRIMITIVE2D_ID_GRAPHICPRIMITIVE2D : 749 { 750 const primitive2d::GraphicPrimitive2D& rGraphicPrimitive = static_cast< const primitive2d::GraphicPrimitive2D& >(rCandidate); 751 bool bUsingPDFExtOutDevData(false); 752 basegfx::B2DVector aTranslate, aScale; 753 static bool bSuppressPDFExtOutDevDataSupport(false); 754 755 if(mpPDFExtOutDevData && !bSuppressPDFExtOutDevDataSupport) 756 { 757 // emulate data handling from UnoControlPDFExportContact, original see 758 // svtools/source/graphic/grfmgr.cxx 759 const Graphic& rGraphic = rGraphicPrimitive.getGraphicObject().GetGraphic(); 760 761 if(rGraphic.IsLink()) 762 { 763 const GraphicAttr& rAttr = rGraphicPrimitive.getGraphicAttr(); 764 765 if(!rAttr.IsSpecialDrawMode() && !rAttr.IsAdjusted()) 766 { 767 const basegfx::B2DHomMatrix& rTransform = rGraphicPrimitive.getTransform(); 768 double fRotate, fShearX; 769 rTransform.decompose(aScale, aTranslate, fRotate, fShearX); 770 771 if( basegfx::fTools::equalZero( fRotate ) && ( aScale.getX() > 0.0 ) && ( aScale.getY() > 0.0 ) ) 772 { 773 bUsingPDFExtOutDevData = true; 774 mpPDFExtOutDevData->BeginGroup(); 775 } 776 } 777 } 778 } 779 780 // process recursively and add MetaFile comment 781 process(rGraphicPrimitive.get2DDecomposition(getViewInformation2D())); 782 783 if(bUsingPDFExtOutDevData) 784 { 785 // emulate data handling from UnoControlPDFExportContact, original see 786 // svtools/source/graphic/grfmgr.cxx 787 const basegfx::B2DRange aCurrentRange( 788 aTranslate.getX(), aTranslate.getY(), 789 aTranslate.getX() + aScale.getX(), aTranslate.getY() + aScale.getY()); 790 const Rectangle aCurrentRect( 791 sal_Int32(floor(aCurrentRange.getMinX())), sal_Int32(floor(aCurrentRange.getMinY())), 792 sal_Int32(ceil(aCurrentRange.getMaxX())), sal_Int32(ceil(aCurrentRange.getMaxY()))); 793 const GraphicAttr& rAttr = rGraphicPrimitive.getGraphicAttr(); 794 Rectangle aCropRect; 795 796 if(rAttr.IsCropped()) 797 { 798 // calculate scalings between real image size and logic object size. This 799 // is necessary since the crop values are relative to original bitmap size 800 double fFactorX(1.0); 801 double fFactorY(1.0); 802 803 { 804 const MapMode aMapMode100thmm(MAP_100TH_MM); 805 const Size aBitmapSize(Application::GetDefaultDevice()->LogicToLogic( 806 rGraphicPrimitive.getGraphicObject().GetPrefSize(), 807 rGraphicPrimitive.getGraphicObject().GetPrefMapMode(), aMapMode100thmm)); 808 const double fDivX(aBitmapSize.Width() - rAttr.GetLeftCrop() - rAttr.GetRightCrop()); 809 const double fDivY(aBitmapSize.Height() - rAttr.GetTopCrop() - rAttr.GetBottomCrop()); 810 811 if(!basegfx::fTools::equalZero(fDivX)) 812 { 813 fFactorX = aScale.getX() / fDivX; 814 } 815 816 if(!basegfx::fTools::equalZero(fDivY)) 817 { 818 fFactorY = aScale.getY() / fDivY; 819 } 820 } 821 822 // calculate crop range and rect 823 basegfx::B2DRange aCropRange; 824 aCropRange.expand(aCurrentRange.getMinimum() - basegfx::B2DPoint(rAttr.GetLeftCrop() * fFactorX, rAttr.GetTopCrop() * fFactorY)); 825 aCropRange.expand(aCurrentRange.getMaximum() + basegfx::B2DPoint(rAttr.GetRightCrop() * fFactorX, rAttr.GetBottomCrop() * fFactorY)); 826 827 aCropRect = Rectangle( 828 sal_Int32(floor(aCropRange.getMinX())), sal_Int32(floor(aCropRange.getMinY())), 829 sal_Int32(ceil(aCropRange.getMaxX())), sal_Int32(ceil(aCropRange.getMaxY()))); 830 } 831 832 mpPDFExtOutDevData->EndGroup(rGraphicPrimitive.getGraphicObject().GetGraphic(), 833 rAttr.GetTransparency(), 834 aCurrentRect, 835 aCropRect); 836 } 837 838 break; 839 } 840 case PRIMITIVE2D_ID_CONTROLPRIMITIVE2D : 841 { 842 const primitive2d::ControlPrimitive2D& rControlPrimitive = static_cast< const primitive2d::ControlPrimitive2D& >(rCandidate); 843 const uno::Reference< awt::XControl >& rXControl(rControlPrimitive.getXControl()); 844 bool bIsPrintableControl(false); 845 846 // find out if control is printable 847 if(rXControl.is()) 848 { 849 try 850 { 851 uno::Reference< beans::XPropertySet > xModelProperties(rXControl->getModel(), uno::UNO_QUERY); 852 uno::Reference< beans::XPropertySetInfo > xPropertyInfo(xModelProperties.is() 853 ? xModelProperties->getPropertySetInfo() 854 : uno::Reference< beans::XPropertySetInfo >()); 855 const ::rtl::OUString sPrintablePropertyName(RTL_CONSTASCII_USTRINGPARAM("Printable")); 856 857 if(xPropertyInfo.is() && xPropertyInfo->hasPropertyByName(sPrintablePropertyName)) 858 { 859 OSL_VERIFY(xModelProperties->getPropertyValue(sPrintablePropertyName) >>= bIsPrintableControl); 860 } 861 } 862 catch(const uno::Exception&) 863 { 864 OSL_ENSURE(false, "VclMetafileProcessor2D: No access to printable flag of Control, caught an exception!"); 865 } 866 } 867 868 // PDF export and printing only for printable controls 869 if(bIsPrintableControl) 870 { 871 const bool bPDFExport(mpPDFExtOutDevData && mpPDFExtOutDevData->GetIsExportFormFields()); 872 bool bDoProcessRecursively(true); 873 874 if(bPDFExport) 875 { 876 // PDF export. Emulate data handling from UnoControlPDFExportContact 877 // I have now moved describePDFControl to toolkit, thus i can implement the PDF 878 // form control support now as follows 879 ::std::auto_ptr< ::vcl::PDFWriter::AnyWidget > pPDFControl; 880 ::toolkitform::describePDFControl( rXControl, pPDFControl, *mpPDFExtOutDevData ); 881 882 if(pPDFControl.get()) 883 { 884 // still need to fill in the location (is a class Rectangle) 885 const basegfx::B2DRange aRangeLogic(rControlPrimitive.getB2DRange(getViewInformation2D())); 886 const Rectangle aRectLogic( 887 (sal_Int32)floor(aRangeLogic.getMinX()), (sal_Int32)floor(aRangeLogic.getMinY()), 888 (sal_Int32)ceil(aRangeLogic.getMaxX()), (sal_Int32)ceil(aRangeLogic.getMaxY())); 889 pPDFControl->Location = aRectLogic; 890 891 Size aFontSize(pPDFControl->TextFont.GetSize()); 892 aFontSize = mpOutputDevice->LogicToLogic(aFontSize, MapMode(MAP_POINT), mpOutputDevice->GetMapMode()); 893 pPDFControl->TextFont.SetSize(aFontSize); 894 895 mpPDFExtOutDevData->BeginStructureElement(vcl::PDFWriter::Form); 896 mpPDFExtOutDevData->CreateControl(*pPDFControl.get()); 897 mpPDFExtOutDevData->EndStructureElement(); 898 899 // no normal paint needed (see original UnoControlPDFExportContact::do_PaintObject); 900 // do not process recursively 901 bDoProcessRecursively = false; 902 } 903 else 904 { 905 // PDF export did not work, try simple output. 906 // Fallback to printer output by not setting bDoProcessRecursively 907 // to false. 908 } 909 } 910 911 // #i93169# used flag the wrong way; true means that nothing was done yet 912 if(bDoProcessRecursively) 913 { 914 // printer output 915 try 916 { 917 // remember old graphics and create new 918 uno::Reference< awt::XView > xControlView(rXControl, uno::UNO_QUERY_THROW); 919 const uno::Reference< awt::XGraphics > xOriginalGraphics(xControlView->getGraphics()); 920 const uno::Reference< awt::XGraphics > xNewGraphics(mpOutputDevice->CreateUnoGraphics()); 921 922 if(xNewGraphics.is()) 923 { 924 // link graphics and view 925 xControlView->setGraphics(xNewGraphics); 926 927 // get position 928 const basegfx::B2DHomMatrix aObjectToDiscrete(getViewInformation2D().getObjectToViewTransformation() * rControlPrimitive.getTransform()); 929 const basegfx::B2DPoint aTopLeftDiscrete(aObjectToDiscrete * basegfx::B2DPoint(0.0, 0.0)); 930 931 // draw it 932 xControlView->draw(basegfx::fround(aTopLeftDiscrete.getX()), basegfx::fround(aTopLeftDiscrete.getY())); 933 bDoProcessRecursively = false; 934 935 // restore original graphics 936 xControlView->setGraphics(xOriginalGraphics); 937 } 938 } 939 catch( const uno::Exception& ) 940 { 941 OSL_ENSURE(false, "VclMetafileProcessor2D: Printing of Control failed, caught an exception!"); 942 } 943 } 944 945 // process recursively if not done yet to export as decomposition (bitmap) 946 if(bDoProcessRecursively) 947 { 948 process(rControlPrimitive.get2DDecomposition(getViewInformation2D())); 949 } 950 } 951 952 break; 953 } 954 case PRIMITIVE2D_ID_TEXTHIERARCHYFIELDPRIMITIVE2D : 955 { 956 // support for FIELD_SEQ_BEGIN, FIELD_SEQ_END and URL. It wraps text primitives (but is not limited to) 957 // thus do the MetafileAction embedding stuff but just handle recursively. 958 const primitive2d::TextHierarchyFieldPrimitive2D& rFieldPrimitive = static_cast< const primitive2d::TextHierarchyFieldPrimitive2D& >(rCandidate); 959 static const ByteString aCommentStringCommon("FIELD_SEQ_BEGIN"); 960 static const ByteString aCommentStringPage("FIELD_SEQ_BEGIN;PageField"); 961 static const ByteString aCommentStringEnd("FIELD_SEQ_END"); 962 963 switch(rFieldPrimitive.getType()) 964 { 965 default : // case drawinglayer::primitive2d::FIELD_TYPE_COMMON : 966 { 967 mpMetaFile->AddAction(new MetaCommentAction(aCommentStringCommon)); 968 break; 969 } 970 case drawinglayer::primitive2d::FIELD_TYPE_PAGE : 971 { 972 mpMetaFile->AddAction(new MetaCommentAction(aCommentStringPage)); 973 break; 974 } 975 case drawinglayer::primitive2d::FIELD_TYPE_URL : 976 { 977 const rtl::OUString& rURL = rFieldPrimitive.getString(); 978 const String aOldString(rURL); 979 mpMetaFile->AddAction(new MetaCommentAction(aCommentStringCommon, 0, reinterpret_cast< const sal_uInt8* >(aOldString.GetBuffer()), 2 * aOldString.Len())); 980 break; 981 } 982 } 983 984 // process recursively 985 const primitive2d::Primitive2DSequence rContent = rFieldPrimitive.get2DDecomposition(getViewInformation2D()); 986 process(rContent); 987 988 // for the end comment the type is not relevant yet, they are all the same. Just add. 989 mpMetaFile->AddAction(new MetaCommentAction(aCommentStringEnd)); 990 991 if(mpPDFExtOutDevData && drawinglayer::primitive2d::FIELD_TYPE_URL == rFieldPrimitive.getType()) 992 { 993 // emulate data handling from ImpEditEngine::Paint 994 const basegfx::B2DRange aViewRange(primitive2d::getB2DRangeFromPrimitive2DSequence(rContent, getViewInformation2D())); 995 const Rectangle aRectLogic( 996 (sal_Int32)floor(aViewRange.getMinX()), (sal_Int32)floor(aViewRange.getMinY()), 997 (sal_Int32)ceil(aViewRange.getMaxX()), (sal_Int32)ceil(aViewRange.getMaxY())); 998 vcl::PDFExtOutDevBookmarkEntry aBookmark; 999 aBookmark.nLinkId = mpPDFExtOutDevData->CreateLink(aRectLogic); 1000 aBookmark.aBookmark = rFieldPrimitive.getString(); 1001 std::vector< vcl::PDFExtOutDevBookmarkEntry >& rBookmarks = mpPDFExtOutDevData->GetBookmarks(); 1002 rBookmarks.push_back( aBookmark ); 1003 } 1004 1005 break; 1006 } 1007 case PRIMITIVE2D_ID_TEXTHIERARCHYLINEPRIMITIVE2D : 1008 { 1009 const primitive2d::TextHierarchyLinePrimitive2D& rLinePrimitive = static_cast< const primitive2d::TextHierarchyLinePrimitive2D& >(rCandidate); 1010 static const ByteString aCommentString("XTEXT_EOL"); 1011 1012 // process recursively and add MetaFile comment 1013 process(rLinePrimitive.get2DDecomposition(getViewInformation2D())); 1014 mpMetaFile->AddAction(new MetaCommentAction(aCommentString)); 1015 1016 break; 1017 } 1018 case PRIMITIVE2D_ID_TEXTHIERARCHYBULLETPRIMITIVE2D : 1019 { 1020 // in Outliner::PaintBullet(), a MetafileComment for bullets is added, too. The 1021 // "XTEXT_EOC" is used, use here, too. 1022 const primitive2d::TextHierarchyBulletPrimitive2D& rBulletPrimitive = static_cast< const primitive2d::TextHierarchyBulletPrimitive2D& >(rCandidate); 1023 static const ByteString aCommentString("XTEXT_EOC"); 1024 1025 // process recursively and add MetaFile comment 1026 process(rBulletPrimitive.get2DDecomposition(getViewInformation2D())); 1027 mpMetaFile->AddAction(new MetaCommentAction(aCommentString)); 1028 1029 break; 1030 } 1031 case PRIMITIVE2D_ID_TEXTHIERARCHYPARAGRAPHPRIMITIVE2D : 1032 { 1033 const primitive2d::TextHierarchyParagraphPrimitive2D& rParagraphPrimitive = static_cast< const primitive2d::TextHierarchyParagraphPrimitive2D& >(rCandidate); 1034 static const ByteString aCommentString("XTEXT_EOP"); 1035 1036 if(mpPDFExtOutDevData) 1037 { 1038 // emulate data handling from ImpEditEngine::Paint 1039 mpPDFExtOutDevData->BeginStructureElement( vcl::PDFWriter::Paragraph ); 1040 } 1041 1042 // process recursively and add MetaFile comment 1043 process(rParagraphPrimitive.get2DDecomposition(getViewInformation2D())); 1044 mpMetaFile->AddAction(new MetaCommentAction(aCommentString)); 1045 1046 if(mpPDFExtOutDevData) 1047 { 1048 // emulate data handling from ImpEditEngine::Paint 1049 mpPDFExtOutDevData->EndStructureElement(); 1050 } 1051 1052 break; 1053 } 1054 case PRIMITIVE2D_ID_TEXTHIERARCHYBLOCKPRIMITIVE2D : 1055 { 1056 const primitive2d::TextHierarchyBlockPrimitive2D& rBlockPrimitive = static_cast< const primitive2d::TextHierarchyBlockPrimitive2D& >(rCandidate); 1057 static const ByteString aCommentStringA("XTEXT_PAINTSHAPE_BEGIN"); 1058 static const ByteString aCommentStringB("XTEXT_PAINTSHAPE_END"); 1059 1060 // add MetaFile comment, process recursively and add MetaFile comment 1061 mpMetaFile->AddAction(new MetaCommentAction(aCommentStringA)); 1062 process(rBlockPrimitive.get2DDecomposition(getViewInformation2D())); 1063 mpMetaFile->AddAction(new MetaCommentAction(aCommentStringB)); 1064 1065 break; 1066 } 1067 case PRIMITIVE2D_ID_TEXTSIMPLEPORTIONPRIMITIVE2D : 1068 case PRIMITIVE2D_ID_TEXTDECORATEDPORTIONPRIMITIVE2D : 1069 { 1070 // for supporting TEXT_ MetaFile actions there is more to do here; get the candidate 1071 const primitive2d::TextSimplePortionPrimitive2D& rTextCandidate = static_cast< const primitive2d::TextSimplePortionPrimitive2D& >(rCandidate); 1072 // const primitive2d::TextDecoratedPortionPrimitive2D* pTextDecoratedCandidate = dynamic_cast< const primitive2d::TextDecoratedPortionPrimitive2D* >(&rCandidate); 1073 1074 // Adapt evtl. used special DrawMode 1075 const sal_uInt32 nOriginalDrawMode(mpOutputDevice->GetDrawMode()); 1076 adaptTextToFillDrawMode(); 1077 1078 // directdraw of text simple portion; use default processing 1079 RenderTextSimpleOrDecoratedPortionPrimitive2D(rTextCandidate); 1080 1081 // restore DrawMode 1082 mpOutputDevice->SetDrawMode(nOriginalDrawMode); 1083 1084 // #i101169# if(pTextDecoratedCandidate) 1085 { 1086 // support for TEXT_ MetaFile actions only for decorated texts 1087 if(!mxBreakIterator.is()) 1088 { 1089 uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > xMSF(::comphelper::getProcessServiceFactory()); 1090 mxBreakIterator.set(xMSF->createInstance(rtl::OUString::createFromAscii("com.sun.star.i18n.BreakIterator")), uno::UNO_QUERY); 1091 } 1092 1093 if(mxBreakIterator.is()) 1094 { 1095 const rtl::OUString& rTxt = rTextCandidate.getText(); 1096 const sal_Int32 nTextLength(rTextCandidate.getTextLength()); // rTxt.getLength()); 1097 1098 if(nTextLength) 1099 { 1100 const ::com::sun::star::lang::Locale& rLocale = rTextCandidate.getLocale(); 1101 const sal_Int32 nTextPosition(rTextCandidate.getTextPosition()); 1102 1103 sal_Int32 nDone; 1104 sal_Int32 nNextCellBreak(mxBreakIterator->nextCharacters(rTxt, nTextPosition, rLocale, ::com::sun::star::i18n::CharacterIteratorMode::SKIPCELL, 0, nDone)); 1105 ::com::sun::star::i18n::Boundary nNextWordBoundary(mxBreakIterator->getWordBoundary(rTxt, nTextPosition, rLocale, ::com::sun::star::i18n::WordType::ANY_WORD, sal_True)); 1106 sal_Int32 nNextSentenceBreak(mxBreakIterator->endOfSentence(rTxt, nTextPosition, rLocale)); 1107 static const ByteString aCommentStringA("XTEXT_EOC"); 1108 static const ByteString aCommentStringB("XTEXT_EOW"); 1109 static const ByteString aCommentStringC("XTEXT_EOS"); 1110 1111 for(sal_Int32 i(nTextPosition); i < nTextPosition + nTextLength; i++) 1112 { 1113 // create the entries for the respective break positions 1114 if(i == nNextCellBreak) 1115 { 1116 mpMetaFile->AddAction(new MetaCommentAction(aCommentStringA, i - nTextPosition)); 1117 nNextCellBreak = mxBreakIterator->nextCharacters(rTxt, i, rLocale, ::com::sun::star::i18n::CharacterIteratorMode::SKIPCELL, 1, nDone); 1118 } 1119 if(i == nNextWordBoundary.endPos) 1120 { 1121 mpMetaFile->AddAction(new MetaCommentAction(aCommentStringB, i - nTextPosition)); 1122 nNextWordBoundary = mxBreakIterator->getWordBoundary(rTxt, i + 1, rLocale, ::com::sun::star::i18n::WordType::ANY_WORD, sal_True); 1123 } 1124 if(i == nNextSentenceBreak) 1125 { 1126 mpMetaFile->AddAction(new MetaCommentAction(aCommentStringC, i - nTextPosition)); 1127 nNextSentenceBreak = mxBreakIterator->endOfSentence(rTxt, i + 1, rLocale); 1128 } 1129 } 1130 } 1131 } 1132 } 1133 1134 break; 1135 } 1136 case PRIMITIVE2D_ID_POLYGONHAIRLINEPRIMITIVE2D : 1137 { 1138 const primitive2d::PolygonHairlinePrimitive2D& rHairlinePrimitive = static_cast< const primitive2d::PolygonHairlinePrimitive2D& >(rCandidate); 1139 const basegfx::B2DPolygon& rBasePolygon = rHairlinePrimitive.getB2DPolygon(); 1140 1141 if(rBasePolygon.count() > (MAX_POLYGON_POINT_COUNT_METAFILE - 1)) 1142 { 1143 // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points 1144 // per polygon. If there are more, split the polygon in half and call recursively 1145 basegfx::B2DPolygon aLeft, aRight; 1146 splitLinePolygon(rBasePolygon, aLeft, aRight); 1147 const primitive2d::PolygonHairlinePrimitive2D aPLeft(aLeft, rHairlinePrimitive.getBColor()); 1148 const primitive2d::PolygonHairlinePrimitive2D aPRight(aRight, rHairlinePrimitive.getBColor()); 1149 1150 processBasePrimitive2D(aPLeft); 1151 processBasePrimitive2D(aPRight); 1152 } 1153 else 1154 { 1155 // direct draw of hairline; use default processing 1156 // support SvtGraphicStroke MetaCommentAction 1157 const basegfx::BColor aLineColor(maBColorModifierStack.getModifiedColor(rHairlinePrimitive.getBColor())); 1158 SvtGraphicStroke* pSvtGraphicStroke = 0; 1159 1160 // #121267# Not needed, does not give better quality compared with 1161 // the META_POLYPOLYGON_ACTION written by RenderPolygonHairlinePrimitive2D 1162 // below 1163 bool bSupportSvtGraphicStroke(false); 1164 1165 if(bSupportSvtGraphicStroke) 1166 { 1167 pSvtGraphicStroke = impTryToCreateSvtGraphicStroke( 1168 rHairlinePrimitive.getB2DPolygon(), 1169 &aLineColor, 1170 0, 0, 0, 0); 1171 1172 impStartSvtGraphicStroke(pSvtGraphicStroke); 1173 } 1174 1175 RenderPolygonHairlinePrimitive2D(static_cast< const primitive2d::PolygonHairlinePrimitive2D& >(rCandidate), false); 1176 1177 if(bSupportSvtGraphicStroke) 1178 { 1179 impEndSvtGraphicStroke(pSvtGraphicStroke); 1180 } 1181 } 1182 break; 1183 } 1184 case PRIMITIVE2D_ID_POLYGONSTROKEPRIMITIVE2D : 1185 { 1186 const primitive2d::PolygonStrokePrimitive2D& rStrokePrimitive = static_cast< const primitive2d::PolygonStrokePrimitive2D& >(rCandidate); 1187 const basegfx::B2DPolygon& rBasePolygon = rStrokePrimitive.getB2DPolygon(); 1188 1189 if(rBasePolygon.count() > (MAX_POLYGON_POINT_COUNT_METAFILE - 1)) 1190 { 1191 // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points 1192 // per polygon. If there are more, split the polygon in half and call recursively 1193 basegfx::B2DPolygon aLeft, aRight; 1194 splitLinePolygon(rBasePolygon, aLeft, aRight); 1195 const primitive2d::PolygonStrokePrimitive2D aPLeft( 1196 aLeft, rStrokePrimitive.getLineAttribute(), rStrokePrimitive.getStrokeAttribute()); 1197 const primitive2d::PolygonStrokePrimitive2D aPRight( 1198 aRight, rStrokePrimitive.getLineAttribute(), rStrokePrimitive.getStrokeAttribute()); 1199 1200 processBasePrimitive2D(aPLeft); 1201 processBasePrimitive2D(aPRight); 1202 } 1203 else 1204 { 1205 // support SvtGraphicStroke MetaCommentAction 1206 SvtGraphicStroke* pSvtGraphicStroke = impTryToCreateSvtGraphicStroke( 1207 rBasePolygon, 0, 1208 &rStrokePrimitive.getLineAttribute(), 1209 &rStrokePrimitive.getStrokeAttribute(), 1210 0, 0); 1211 1212 impStartSvtGraphicStroke(pSvtGraphicStroke); 1213 const attribute::LineAttribute& rLine = rStrokePrimitive.getLineAttribute(); 1214 1215 // create MetaPolyLineActions, but without LINE_DASH 1216 if(basegfx::fTools::more(rLine.getWidth(), 0.0)) 1217 { 1218 const attribute::StrokeAttribute& rStroke = rStrokePrimitive.getStrokeAttribute(); 1219 basegfx::B2DPolyPolygon aHairLinePolyPolygon; 1220 1221 if(0.0 == rStroke.getFullDotDashLen()) 1222 { 1223 aHairLinePolyPolygon.append(rBasePolygon); 1224 } 1225 else 1226 { 1227 basegfx::tools::applyLineDashing( 1228 rBasePolygon, rStroke.getDotDashArray(), 1229 &aHairLinePolyPolygon, 0, rStroke.getFullDotDashLen()); 1230 } 1231 1232 const basegfx::BColor aHairlineColor(maBColorModifierStack.getModifiedColor(rLine.getColor())); 1233 mpOutputDevice->SetLineColor(Color(aHairlineColor)); 1234 mpOutputDevice->SetFillColor(); 1235 aHairLinePolyPolygon.transform(maCurrentTransformation); 1236 1237 // #i113922# LineWidth needs to be transformed, too 1238 const basegfx::B2DVector aDiscreteUnit(maCurrentTransformation * basegfx::B2DVector(rLine.getWidth(), 0.0)); 1239 const double fDiscreteLineWidth(aDiscreteUnit.getLength()); 1240 1241 LineInfo aLineInfo(LINE_SOLID, basegfx::fround(fDiscreteLineWidth)); 1242 aLineInfo.SetLineJoin(rLine.getLineJoin()); 1243 aLineInfo.SetLineCap(rLine.getLineCap()); 1244 1245 for(sal_uInt32 a(0); a < aHairLinePolyPolygon.count(); a++) 1246 { 1247 const basegfx::B2DPolygon aCandidate(aHairLinePolyPolygon.getB2DPolygon(a)); 1248 1249 if(aCandidate.count() > 1) 1250 { 1251 const Polygon aToolsPolygon(aCandidate); 1252 1253 mpMetaFile->AddAction(new MetaPolyLineAction(aToolsPolygon, aLineInfo)); 1254 } 1255 } 1256 } 1257 else 1258 { 1259 process(rCandidate.get2DDecomposition(getViewInformation2D())); 1260 } 1261 1262 impEndSvtGraphicStroke(pSvtGraphicStroke); 1263 } 1264 1265 break; 1266 } 1267 case PRIMITIVE2D_ID_POLYGONSTROKEARROWPRIMITIVE2D : 1268 { 1269 const primitive2d::PolygonStrokeArrowPrimitive2D& rStrokeArrowPrimitive = static_cast< const primitive2d::PolygonStrokeArrowPrimitive2D& >(rCandidate); 1270 const basegfx::B2DPolygon& rBasePolygon = rStrokeArrowPrimitive.getB2DPolygon(); 1271 1272 if(rBasePolygon.count() > (MAX_POLYGON_POINT_COUNT_METAFILE - 1)) 1273 { 1274 // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points 1275 // per polygon. If there are more, split the polygon in half and call recursively 1276 basegfx::B2DPolygon aLeft, aRight; 1277 splitLinePolygon(rBasePolygon, aLeft, aRight); 1278 const attribute::LineStartEndAttribute aEmpty; 1279 const primitive2d::PolygonStrokeArrowPrimitive2D aPLeft( 1280 aLeft, 1281 rStrokeArrowPrimitive.getLineAttribute(), 1282 rStrokeArrowPrimitive.getStrokeAttribute(), 1283 rStrokeArrowPrimitive.getStart(), 1284 aEmpty); 1285 const primitive2d::PolygonStrokeArrowPrimitive2D aPRight( 1286 aRight, 1287 rStrokeArrowPrimitive.getLineAttribute(), 1288 rStrokeArrowPrimitive.getStrokeAttribute(), 1289 aEmpty, 1290 rStrokeArrowPrimitive.getEnd()); 1291 1292 processBasePrimitive2D(aPLeft); 1293 processBasePrimitive2D(aPRight); 1294 } 1295 else 1296 { 1297 // support SvtGraphicStroke MetaCommentAction 1298 SvtGraphicStroke* pSvtGraphicStroke = impTryToCreateSvtGraphicStroke( 1299 rBasePolygon, 0, 1300 &rStrokeArrowPrimitive.getLineAttribute(), 1301 &rStrokeArrowPrimitive.getStrokeAttribute(), 1302 &rStrokeArrowPrimitive.getStart(), 1303 &rStrokeArrowPrimitive.getEnd()); 1304 1305 // write LineGeometry start marker 1306 impStartSvtGraphicStroke(pSvtGraphicStroke); 1307 1308 // #116162# When B&W is set as DrawMode, DRAWMODE_WHITEFILL is used 1309 // to let all fills be just white; for lines DRAWMODE_BLACKLINE is used 1310 // so all line geometry is supposed to get black. Since in the in-between 1311 // stages of line geometry drawing filled polygons are used (e.g. line 1312 // start/ends) it is necessary to change these drawmodes to preserve 1313 // that lines shall be black; thus change DRAWMODE_WHITEFILL to 1314 // DRAWMODE_BLACKFILL during line geometry processing to have line geometry 1315 // parts filled black. 1316 const sal_uLong nOldDrawMode(mpOutputDevice->GetDrawMode()); 1317 const bool bDrawmodeChange(nOldDrawMode & DRAWMODE_WHITEFILL && mnSvtGraphicStrokeCount); 1318 1319 if(bDrawmodeChange) 1320 { 1321 mpOutputDevice->SetDrawMode((nOldDrawMode & ~DRAWMODE_WHITEFILL) | DRAWMODE_BLACKFILL); 1322 } 1323 1324 // process sub-line geometry (evtl. filled PolyPolygons) 1325 process(rCandidate.get2DDecomposition(getViewInformation2D())); 1326 1327 if(bDrawmodeChange) 1328 { 1329 mpOutputDevice->SetDrawMode(nOldDrawMode); 1330 } 1331 1332 // write LineGeometry end marker 1333 impEndSvtGraphicStroke(pSvtGraphicStroke); 1334 } 1335 1336 break; 1337 } 1338 case PRIMITIVE2D_ID_BITMAPPRIMITIVE2D : 1339 { 1340 // direct draw of transformed BitmapEx primitive; use default processing 1341 RenderBitmapPrimitive2D(static_cast< const primitive2d::BitmapPrimitive2D& >(rCandidate)); 1342 break; 1343 } 1344 case PRIMITIVE2D_ID_POLYPOLYGONGRAPHICPRIMITIVE2D : 1345 { 1346 // need to handle PolyPolygonGraphicPrimitive2D here to support XPATHFILL_SEQ_BEGIN/XPATHFILL_SEQ_END 1347 const primitive2d::PolyPolygonGraphicPrimitive2D& rBitmapCandidate = static_cast< const primitive2d::PolyPolygonGraphicPrimitive2D& >(rCandidate); 1348 basegfx::B2DPolyPolygon aLocalPolyPolygon(rBitmapCandidate.getB2DPolyPolygon()); 1349 1350 if(fillPolyPolygonNeededToBeSplit(aLocalPolyPolygon)) 1351 { 1352 // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points 1353 // per polygon. If there are more use the splitted polygon and call recursively 1354 const primitive2d::PolyPolygonGraphicPrimitive2D aSplitted( 1355 aLocalPolyPolygon, 1356 rBitmapCandidate.getFillGraphic()); 1357 1358 processBasePrimitive2D(aSplitted); 1359 } 1360 else 1361 { 1362 SvtGraphicFill* pSvtGraphicFill = 0; 1363 1364 if(!mnSvtGraphicFillCount && aLocalPolyPolygon.count()) 1365 { 1366 // #121194# Changed implementation and checked usages fo convert to metafile, 1367 // presentation start (uses SvtGraphicFill) and printing. 1368 1369 // calculate transformation. Get real object size, all values in FillGraphicAttribute 1370 // are relative to the unified object 1371 aLocalPolyPolygon.transform(maCurrentTransformation); 1372 const basegfx::B2DVector aOutlineSize(aLocalPolyPolygon.getB2DRange().getRange()); 1373 1374 // the scaling needs scale from pixel to logic coordinate system 1375 const attribute::FillGraphicAttribute& rFillGraphicAttribute = rBitmapCandidate.getFillGraphic(); 1376 const Size aBmpSizePixel(rFillGraphicAttribute.getGraphic().GetSizePixel()); 1377 1378 // setup transformation like in impgrfll. Multiply with aOutlineSize 1379 // to get from unit coordinates in rFillGraphicAttribute.getGraphicRange() 1380 // to object coordinates with object's top left being at (0,0). Divide 1381 // by pixel size so that scale from pixel to logic will work in SvtGraphicFill. 1382 const basegfx::B2DVector aTransformScale( 1383 rFillGraphicAttribute.getGraphicRange().getRange() / 1384 basegfx::B2DVector( 1385 std::max(1.0, double(aBmpSizePixel.Width())), 1386 std::max(1.0, double(aBmpSizePixel.Height()))) * 1387 aOutlineSize); 1388 const basegfx::B2DPoint aTransformPosition( 1389 rFillGraphicAttribute.getGraphicRange().getMinimum() * aOutlineSize); 1390 1391 // setup transformation like in impgrfll 1392 SvtGraphicFill::Transform aTransform; 1393 1394 // scale values are divided by bitmap pixel sizes 1395 aTransform.matrix[0] = aTransformScale.getX(); 1396 aTransform.matrix[4] = aTransformScale.getY(); 1397 1398 // translates are absolute 1399 aTransform.matrix[2] = aTransformPosition.getX(); 1400 aTransform.matrix[5] = aTransformPosition.getY(); 1401 1402 pSvtGraphicFill = new SvtGraphicFill( 1403 PolyPolygon(aLocalPolyPolygon), 1404 Color(), 1405 0.0, 1406 SvtGraphicFill::fillEvenOdd, 1407 SvtGraphicFill::fillTexture, 1408 aTransform, 1409 rFillGraphicAttribute.getTiling(), 1410 SvtGraphicFill::hatchSingle, 1411 Color(), 1412 SvtGraphicFill::gradientLinear, 1413 Color(), 1414 Color(), 1415 0, 1416 rFillGraphicAttribute.getGraphic()); 1417 } 1418 1419 // Do use decomposition; encapsulate with SvtGraphicFill 1420 impStartSvtGraphicFill(pSvtGraphicFill); 1421 process(rCandidate.get2DDecomposition(getViewInformation2D())); 1422 impEndSvtGraphicFill(pSvtGraphicFill); 1423 } 1424 1425 break; 1426 } 1427 case PRIMITIVE2D_ID_POLYPOLYGONHATCHPRIMITIVE2D : 1428 { 1429 // need to handle PolyPolygonHatchPrimitive2D here to support XPATHFILL_SEQ_BEGIN/XPATHFILL_SEQ_END 1430 const primitive2d::PolyPolygonHatchPrimitive2D& rHatchCandidate = static_cast< const primitive2d::PolyPolygonHatchPrimitive2D& >(rCandidate); 1431 const attribute::FillHatchAttribute& rFillHatchAttribute = rHatchCandidate.getFillHatch(); 1432 basegfx::B2DPolyPolygon aLocalPolyPolygon(rHatchCandidate.getB2DPolyPolygon()); 1433 1434 // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points 1435 // per polygon. Split polygon until there are less than that 1436 while(fillPolyPolygonNeededToBeSplit(aLocalPolyPolygon)) 1437 ; 1438 1439 if(rFillHatchAttribute.isFillBackground()) 1440 { 1441 // with fixing #i111954# (see below) the possible background 1442 // fill of a hatched object was lost.Generate a background fill 1443 // primitive and render it 1444 const primitive2d::Primitive2DReference xBackground( 1445 new primitive2d::PolyPolygonColorPrimitive2D( 1446 aLocalPolyPolygon, 1447 rHatchCandidate.getBackgroundColor())); 1448 1449 process(primitive2d::Primitive2DSequence(&xBackground, 1)); 1450 } 1451 1452 SvtGraphicFill* pSvtGraphicFill = 0; 1453 aLocalPolyPolygon.transform(maCurrentTransformation); 1454 1455 if(!mnSvtGraphicFillCount && aLocalPolyPolygon.count()) 1456 { 1457 // re-create a VCL hatch as base data 1458 SvtGraphicFill::HatchType eHatch(SvtGraphicFill::hatchSingle); 1459 1460 switch(rFillHatchAttribute.getStyle()) 1461 { 1462 default: // attribute::HATCHSTYLE_SINGLE : 1463 { 1464 eHatch = SvtGraphicFill::hatchSingle; 1465 break; 1466 } 1467 case attribute::HATCHSTYLE_DOUBLE : 1468 { 1469 eHatch = SvtGraphicFill::hatchDouble; 1470 break; 1471 } 1472 case attribute::HATCHSTYLE_TRIPLE : 1473 { 1474 eHatch = SvtGraphicFill::hatchTriple; 1475 break; 1476 } 1477 } 1478 1479 SvtGraphicFill::Transform aTransform; 1480 1481 // scale 1482 aTransform.matrix[0] *= rFillHatchAttribute.getDistance(); 1483 aTransform.matrix[4] *= rFillHatchAttribute.getDistance(); 1484 1485 // rotate (was never correct in impgrfll anyways, use correct angle now) 1486 aTransform.matrix[0] *= cos(rFillHatchAttribute.getAngle()); 1487 aTransform.matrix[1] *= -sin(rFillHatchAttribute.getAngle()); 1488 aTransform.matrix[3] *= sin(rFillHatchAttribute.getAngle()); 1489 aTransform.matrix[4] *= cos(rFillHatchAttribute.getAngle()); 1490 1491 pSvtGraphicFill = new SvtGraphicFill( 1492 PolyPolygon(aLocalPolyPolygon), 1493 Color(), 1494 0.0, 1495 SvtGraphicFill::fillEvenOdd, 1496 SvtGraphicFill::fillHatch, 1497 aTransform, 1498 false, 1499 eHatch, 1500 Color(rFillHatchAttribute.getColor()), 1501 SvtGraphicFill::gradientLinear, 1502 Color(), 1503 Color(), 1504 0, 1505 Graphic()); 1506 } 1507 1508 // Do use decomposition; encapsulate with SvtGraphicFill 1509 impStartSvtGraphicFill(pSvtGraphicFill); 1510 1511 // #i111954# do NOT use decomposition, but use direct VCL-command 1512 // process(rCandidate.get2DDecomposition(getViewInformation2D())); 1513 const PolyPolygon aToolsPolyPolygon(aLocalPolyPolygon); 1514 const HatchStyle aHatchStyle( 1515 attribute::HATCHSTYLE_SINGLE == rFillHatchAttribute.getStyle() ? HATCH_SINGLE : 1516 attribute::HATCHSTYLE_DOUBLE == rFillHatchAttribute.getStyle() ? HATCH_DOUBLE : 1517 HATCH_TRIPLE); 1518 1519 mpOutputDevice->DrawHatch(aToolsPolyPolygon, 1520 Hatch(aHatchStyle, 1521 Color(rFillHatchAttribute.getColor()), 1522 basegfx::fround(rFillHatchAttribute.getDistance()), 1523 basegfx::fround(rFillHatchAttribute.getAngle() / F_PI1800))); 1524 1525 impEndSvtGraphicFill(pSvtGraphicFill); 1526 1527 break; 1528 } 1529 case PRIMITIVE2D_ID_POLYPOLYGONGRADIENTPRIMITIVE2D : 1530 { 1531 basegfx::B2DVector aScale, aTranslate; 1532 double fRotate, fShearX; 1533 1534 maCurrentTransformation.decompose(aScale, aTranslate, fRotate, fShearX); 1535 1536 if(!basegfx::fTools::equalZero(fRotate) || !basegfx::fTools::equalZero(fShearX)) 1537 { 1538 // #121185# When rotation or shear is used, a VCL Gradient cannot be used directly. 1539 // This is because VCL Gradient mechanism does *not* support to rotate the gradient 1540 // with objects and this case is not expressable in a Metafile (and cannot be added 1541 // since the FileFormats used, e.g. *.wmf, do not support it either). 1542 // Such cases happen when a graphic object uses a Metafile as graphic information or 1543 // a fill style definition uses a Metafile. In this cases the graphic content is 1544 // rotated with the graphic or filled object; this is not supported by the target 1545 // format of this conversion renderer - Metafiles. 1546 // To solve this, not a Gradient is written, but the decomposition of this object 1547 // is written to the Metafile. This is the PolyPolygons building the gradient fill. 1548 // These will need more space and time, but the result will be as if the Gradient 1549 // was rotated with the object. 1550 // This mechanism is used by all exporters still not using Primtives (e.g. Print, 1551 // Slideshow, Export rto PDF, export to Picture, ...) but relying on Metafile 1552 // transfers. One more reason to *change* these to primitives. 1553 // BTW: One more example how useful the principles of primitives are; the decomposition 1554 // is by definition a simpler, maybe more expensive representation of the same content. 1555 process(rCandidate.get2DDecomposition(getViewInformation2D())); 1556 } 1557 else 1558 { 1559 const primitive2d::PolyPolygonGradientPrimitive2D& rGradientCandidate = static_cast< const primitive2d::PolyPolygonGradientPrimitive2D& >(rCandidate); 1560 basegfx::B2DPolyPolygon aLocalPolyPolygon(rGradientCandidate.getB2DPolyPolygon()); 1561 1562 // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points 1563 // per polygon. Split polygon until there are less than that 1564 while(fillPolyPolygonNeededToBeSplit(aLocalPolyPolygon)) 1565 ; 1566 1567 // for support of MetaCommentActions of the form XGRAD_SEQ_BEGIN, XGRAD_SEQ_END 1568 // it is safest to use the VCL OutputDevice::DrawGradient method which creates those. 1569 // re-create a VCL-gradient from FillGradientPrimitive2D and the needed tools PolyPolygon 1570 Gradient aVCLGradient; 1571 impConvertFillGradientAttributeToVCLGradient(aVCLGradient, rGradientCandidate.getFillGradient(), false); 1572 aLocalPolyPolygon.transform(maCurrentTransformation); 1573 1574 // #i82145# ATM VCL printing of gradients using curved shapes does not work, 1575 // i submitted the bug with the given ID to THB. When that task is fixed it is 1576 // necessary to again remove this subdivision since it decreases possible 1577 // printing quality (not even resolution-dependent for now). THB will tell 1578 // me when that task is fixed in the master 1579 const PolyPolygon aToolsPolyPolygon(basegfx::tools::adaptiveSubdivideByAngle(aLocalPolyPolygon)); 1580 1581 // XPATHFILL_SEQ_BEGIN/XPATHFILL_SEQ_END support 1582 SvtGraphicFill* pSvtGraphicFill = 0; 1583 1584 if(!mnSvtGraphicFillCount && aLocalPolyPolygon.count()) 1585 { 1586 // setup gradient stuff like in like in impgrfll 1587 SvtGraphicFill::GradientType eGrad(SvtGraphicFill::gradientLinear); 1588 1589 switch(aVCLGradient.GetStyle()) 1590 { 1591 default : // GRADIENT_LINEAR: 1592 case GRADIENT_AXIAL: 1593 eGrad = SvtGraphicFill::gradientLinear; 1594 break; 1595 case GRADIENT_RADIAL: 1596 case GRADIENT_ELLIPTICAL: 1597 eGrad = SvtGraphicFill::gradientRadial; 1598 break; 1599 case GRADIENT_SQUARE: 1600 case GRADIENT_RECT: 1601 eGrad = SvtGraphicFill::gradientRectangular; 1602 break; 1603 } 1604 1605 pSvtGraphicFill = new SvtGraphicFill( 1606 aToolsPolyPolygon, 1607 Color(), 1608 0.0, 1609 SvtGraphicFill::fillEvenOdd, 1610 SvtGraphicFill::fillGradient, 1611 SvtGraphicFill::Transform(), 1612 false, 1613 SvtGraphicFill::hatchSingle, 1614 Color(), 1615 eGrad, 1616 aVCLGradient.GetStartColor(), 1617 aVCLGradient.GetEndColor(), 1618 aVCLGradient.GetSteps(), 1619 Graphic()); 1620 } 1621 1622 // call VCL directly; encapsulate with SvtGraphicFill 1623 impStartSvtGraphicFill(pSvtGraphicFill); 1624 mpOutputDevice->DrawGradient(aToolsPolyPolygon, aVCLGradient); 1625 impEndSvtGraphicFill(pSvtGraphicFill); 1626 1627 // NO usage of common own gradient randerer, not used ATM for VCL MetaFile, see text above 1628 // RenderPolyPolygonGradientPrimitive2D(static_cast< const primitive2d::PolyPolygonGradientPrimitive2D& >(rCandidate)); 1629 } 1630 1631 break; 1632 } 1633 case PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D : 1634 { 1635 const primitive2d::PolyPolygonColorPrimitive2D& rPolygonCandidate(static_cast< const primitive2d::PolyPolygonColorPrimitive2D& >(rCandidate)); 1636 basegfx::B2DPolyPolygon aLocalPolyPolygon(rPolygonCandidate.getB2DPolyPolygon()); 1637 1638 // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points 1639 // per polygon. Split polygon until there are less than that 1640 while(fillPolyPolygonNeededToBeSplit(aLocalPolyPolygon)) 1641 ; 1642 1643 const basegfx::BColor aPolygonColor(maBColorModifierStack.getModifiedColor(rPolygonCandidate.getBColor())); 1644 aLocalPolyPolygon.transform(maCurrentTransformation); 1645 1646 // XPATHFILL_SEQ_BEGIN/XPATHFILL_SEQ_END support 1647 SvtGraphicFill* pSvtGraphicFill = 0; 1648 1649 // #121267# Not needed, does not give better quality compared with 1650 // the META_POLYPOLYGON_ACTION written by the DrawPolyPolygon command 1651 // below 1652 bool bSupportSvtGraphicFill(false); 1653 1654 if(bSupportSvtGraphicFill && !mnSvtGraphicFillCount && aLocalPolyPolygon.count()) 1655 { 1656 // setup simple color fill stuff like in impgrfll 1657 pSvtGraphicFill = new SvtGraphicFill( 1658 PolyPolygon(aLocalPolyPolygon), 1659 Color(aPolygonColor), 1660 0.0, 1661 SvtGraphicFill::fillEvenOdd, 1662 SvtGraphicFill::fillSolid, 1663 SvtGraphicFill::Transform(), 1664 false, 1665 SvtGraphicFill::hatchSingle, 1666 Color(), 1667 SvtGraphicFill::gradientLinear, 1668 Color(), 1669 Color(), 1670 0, 1671 Graphic()); 1672 } 1673 1674 // set line and fill color 1675 mpOutputDevice->SetFillColor(Color(aPolygonColor)); 1676 mpOutputDevice->SetLineColor(); 1677 1678 // call VCL directly; encapsulate with SvtGraphicFill 1679 if(bSupportSvtGraphicFill) 1680 { 1681 impStartSvtGraphicFill(pSvtGraphicFill); 1682 } 1683 1684 mpOutputDevice->DrawPolyPolygon(aLocalPolyPolygon); 1685 1686 if(bSupportSvtGraphicFill) 1687 { 1688 impEndSvtGraphicFill(pSvtGraphicFill); 1689 } 1690 1691 break; 1692 } 1693 case PRIMITIVE2D_ID_METAFILEPRIMITIVE2D : 1694 { 1695 static bool bUseMetaFilePrimitiveDecomposition(true); 1696 1697 if(bUseMetaFilePrimitiveDecomposition) 1698 { 1699 // use new Metafile decomposition 1700 process(rCandidate.get2DDecomposition(getViewInformation2D())); 1701 } 1702 else 1703 { 1704 // direct draw of MetaFile, use default pocessing 1705 RenderMetafilePrimitive2D(static_cast< const primitive2d::MetafilePrimitive2D& >(rCandidate)); 1706 } 1707 1708 break; 1709 } 1710 case PRIMITIVE2D_ID_MASKPRIMITIVE2D : 1711 { 1712 // mask group. Special handling for MetaFiles. 1713 const primitive2d::MaskPrimitive2D& rMaskCandidate = static_cast< const primitive2d::MaskPrimitive2D& >(rCandidate); 1714 1715 if(rMaskCandidate.getChildren().hasElements()) 1716 { 1717 basegfx::B2DPolyPolygon aMask(rMaskCandidate.getMask()); 1718 1719 if(aMask.count()) 1720 { 1721 // prepare new mask polygon and rescue current one 1722 aMask.transform(maCurrentTransformation); 1723 const basegfx::B2DPolyPolygon aLastClipPolyPolygon(maClipPolyPolygon); 1724 1725 if(maClipPolyPolygon.count()) 1726 { 1727 // there is already a clip polygon set; build clipped union of 1728 // current mask polygon and new one 1729 maClipPolyPolygon = basegfx::tools::clipPolyPolygonOnPolyPolygon( 1730 aMask, 1731 maClipPolyPolygon, 1732 true, // #i106516# we want the inside of aMask, not the outside 1733 false); 1734 } 1735 else 1736 { 1737 // use mask directly 1738 maClipPolyPolygon = aMask; 1739 } 1740 1741 if(maClipPolyPolygon.count()) 1742 { 1743 // set VCL clip region; subdivide before conversion to tools polygon. Subdivision necessary (!) 1744 // Removed subdivision and fixed in Region::ImplPolyPolyRegionToBandRegionFunc() in VCL where 1745 // the ClipRegion is built from the Polygon. A AdaptiveSubdivide on the source polygon was missing there 1746 mpOutputDevice->Push(PUSH_CLIPREGION); 1747 mpOutputDevice->SetClipRegion(Region(maClipPolyPolygon)); 1748 1749 // recursively paint content 1750 // #121267# Only need to process sub-content when clip polygon is *not* empty. 1751 // If it is empty, the clip is empty and there can be nothing inside. 1752 process(rMaskCandidate.getChildren()); 1753 1754 // restore VCL clip region 1755 mpOutputDevice->Pop(); 1756 } 1757 1758 // restore to rescued clip polygon 1759 maClipPolyPolygon = aLastClipPolyPolygon; 1760 } 1761 else 1762 { 1763 // no mask, no clipping. recursively paint content 1764 process(rMaskCandidate.getChildren()); 1765 } 1766 } 1767 1768 break; 1769 } 1770 case PRIMITIVE2D_ID_MODIFIEDCOLORPRIMITIVE2D : 1771 { 1772 // modified color group. Force output to unified color. Use default pocessing. 1773 RenderModifiedColorPrimitive2D(static_cast< const primitive2d::ModifiedColorPrimitive2D& >(rCandidate)); 1774 break; 1775 } 1776 case PRIMITIVE2D_ID_HIDDENGEOMETRYPRIMITIVE2D : 1777 { 1778 // HiddenGeometryPrimitive2D; to rebuilt the old MetaFile creation, it is necessary to 1779 // not ignore them (as it was thought), but to add a MetaFile entry for them. 1780 basegfx::B2DRange aInvisibleRange(rCandidate.getB2DRange(getViewInformation2D())); 1781 1782 if(!aInvisibleRange.isEmpty()) 1783 { 1784 aInvisibleRange.transform(maCurrentTransformation); 1785 const Rectangle aRectLogic( 1786 (sal_Int32)floor(aInvisibleRange.getMinX()), (sal_Int32)floor(aInvisibleRange.getMinY()), 1787 (sal_Int32)ceil(aInvisibleRange.getMaxX()), (sal_Int32)ceil(aInvisibleRange.getMaxY())); 1788 1789 mpOutputDevice->SetFillColor(); 1790 mpOutputDevice->SetLineColor(); 1791 mpOutputDevice->DrawRect(aRectLogic); 1792 } 1793 1794 break; 1795 } 1796 case PRIMITIVE2D_ID_UNIFIEDTRANSPARENCEPRIMITIVE2D : 1797 { 1798 // for metafile: Need to examine what the pure vcl version is doing here actually 1799 // - uses DrawTransparent with metafile for content and a gradient 1800 // - uses DrawTransparent for single PolyPoylgons directly. Can be detected by 1801 // checking the content for single PolyPolygonColorPrimitive2D 1802 const primitive2d::UnifiedTransparencePrimitive2D& rUniTransparenceCandidate = static_cast< const primitive2d::UnifiedTransparencePrimitive2D& >(rCandidate); 1803 const primitive2d::Primitive2DSequence rContent = rUniTransparenceCandidate.getChildren(); 1804 1805 if(rContent.hasElements()) 1806 { 1807 if(0.0 == rUniTransparenceCandidate.getTransparence()) 1808 { 1809 // not transparent at all, use content 1810 process(rUniTransparenceCandidate.getChildren()); 1811 } 1812 else if(rUniTransparenceCandidate.getTransparence() > 0.0 && rUniTransparenceCandidate.getTransparence() < 1.0) 1813 { 1814 // try to identify a single PolyPolygonColorPrimitive2D in the 1815 // content part of the transparence primitive 1816 const primitive2d::PolyPolygonColorPrimitive2D* pPoPoColor = 0; 1817 static bool bForceToMetafile(false); 1818 1819 if(!bForceToMetafile && 1 == rContent.getLength()) 1820 { 1821 const primitive2d::Primitive2DReference xReference(rContent[0]); 1822 pPoPoColor = dynamic_cast< const primitive2d::PolyPolygonColorPrimitive2D* >(xReference.get()); 1823 } 1824 1825 // PolyPolygonGradientPrimitive2D, PolyPolygonHatchPrimitive2D and 1826 // PolyPolygonGraphicPrimitive2D are derived from PolyPolygonColorPrimitive2D. 1827 // Check also for correct ID to exclude derived implementations 1828 if(pPoPoColor && PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D == pPoPoColor->getPrimitive2DID()) 1829 { 1830 // single transparent PolyPolygon identified, use directly 1831 const basegfx::BColor aPolygonColor(maBColorModifierStack.getModifiedColor(pPoPoColor->getBColor())); 1832 basegfx::B2DPolyPolygon aLocalPolyPolygon(pPoPoColor->getB2DPolyPolygon()); 1833 1834 // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points 1835 // per polygon. Split polygon until there are less than that 1836 while(fillPolyPolygonNeededToBeSplit(aLocalPolyPolygon)) 1837 ; 1838 1839 // now transform 1840 aLocalPolyPolygon.transform(maCurrentTransformation); 1841 1842 // XPATHFILL_SEQ_BEGIN/XPATHFILL_SEQ_END support 1843 SvtGraphicFill* pSvtGraphicFill = 0; 1844 1845 // #121267# Not needed, does not give better quality compared with 1846 // the META_POLYPOLYGON_ACTION written by the DrawPolyPolygon command 1847 // below 1848 bool bSupportSvtGraphicFill(false); 1849 1850 if(bSupportSvtGraphicFill && !mnSvtGraphicFillCount && aLocalPolyPolygon.count()) 1851 { 1852 // setup simple color with transparence fill stuff like in impgrfll 1853 pSvtGraphicFill = new SvtGraphicFill( 1854 PolyPolygon(aLocalPolyPolygon), 1855 Color(aPolygonColor), 1856 rUniTransparenceCandidate.getTransparence(), 1857 SvtGraphicFill::fillEvenOdd, 1858 SvtGraphicFill::fillSolid, 1859 SvtGraphicFill::Transform(), 1860 false, 1861 SvtGraphicFill::hatchSingle, 1862 Color(), 1863 SvtGraphicFill::gradientLinear, 1864 Color(), 1865 Color(), 1866 0, 1867 Graphic()); 1868 } 1869 1870 // set line and fill color 1871 const sal_uInt16 nTransPercentVcl((sal_uInt16)basegfx::fround(rUniTransparenceCandidate.getTransparence() * 100.0)); 1872 mpOutputDevice->SetFillColor(Color(aPolygonColor)); 1873 mpOutputDevice->SetLineColor(); 1874 1875 // call VCL directly; encapsulate with SvtGraphicFill 1876 if(bSupportSvtGraphicFill) 1877 { 1878 impStartSvtGraphicFill(pSvtGraphicFill); 1879 } 1880 1881 mpOutputDevice->DrawTransparent( 1882 PolyPolygon(aLocalPolyPolygon), 1883 nTransPercentVcl); 1884 1885 if(bSupportSvtGraphicFill) 1886 { 1887 impEndSvtGraphicFill(pSvtGraphicFill); 1888 } 1889 } 1890 else 1891 { 1892 // svae old mfCurrentUnifiedTransparence and set new one 1893 // so that contained SvtGraphicStroke may use the current one 1894 const double fLastCurrentUnifiedTransparence(mfCurrentUnifiedTransparence); 1895 // #i105377# paint the content metafile opaque as the transparency gets 1896 // split of into the gradient below 1897 // mfCurrentUnifiedTransparence = rUniTransparenceCandidate.getTransparence(); 1898 mfCurrentUnifiedTransparence = 0; 1899 1900 // various content, create content-metafile 1901 GDIMetaFile aContentMetafile; 1902 const Rectangle aPrimitiveRectangle(impDumpToMetaFile(rContent, aContentMetafile)); 1903 1904 // restore mfCurrentUnifiedTransparence; it may have been used 1905 // while processing the sub-content in impDumpToMetaFile 1906 mfCurrentUnifiedTransparence = fLastCurrentUnifiedTransparence; 1907 1908 // create uniform VCL gradient for uniform transparency 1909 Gradient aVCLGradient; 1910 const sal_uInt8 nTransPercentVcl((sal_uInt8)basegfx::fround(rUniTransparenceCandidate.getTransparence() * 255.0)); 1911 const Color aTransColor(nTransPercentVcl, nTransPercentVcl, nTransPercentVcl); 1912 1913 aVCLGradient.SetStyle(GRADIENT_LINEAR); 1914 aVCLGradient.SetStartColor(aTransColor); 1915 aVCLGradient.SetEndColor(aTransColor); 1916 aVCLGradient.SetAngle(0); 1917 aVCLGradient.SetBorder(0); 1918 aVCLGradient.SetOfsX(0); 1919 aVCLGradient.SetOfsY(0); 1920 aVCLGradient.SetStartIntensity(100); 1921 aVCLGradient.SetEndIntensity(100); 1922 aVCLGradient.SetSteps(2); 1923 1924 // render it to VCL 1925 mpOutputDevice->DrawTransparent( 1926 aContentMetafile, aPrimitiveRectangle.TopLeft(), 1927 aPrimitiveRectangle.GetSize(), aVCLGradient); 1928 } 1929 } 1930 } 1931 1932 break; 1933 } 1934 case PRIMITIVE2D_ID_TRANSPARENCEPRIMITIVE2D : 1935 { 1936 // for metafile: Need to examine what the pure vcl version is doing here actually 1937 // - uses DrawTransparent with metafile for content and a gradient 1938 // i can detect this here with checking the gradient part for a single 1939 // FillGradientPrimitive2D and reconstruct the gradient. 1940 // If that detection goes wrong, i have to create an transparence-blended bitmap. Eventually 1941 // do that in stripes, else RenderTransparencePrimitive2D may just be used 1942 const primitive2d::TransparencePrimitive2D& rTransparenceCandidate = static_cast< const primitive2d::TransparencePrimitive2D& >(rCandidate); 1943 const primitive2d::Primitive2DSequence rContent = rTransparenceCandidate.getChildren(); 1944 const primitive2d::Primitive2DSequence rTransparence = rTransparenceCandidate.getTransparence(); 1945 1946 if(rContent.hasElements() && rTransparence.hasElements()) 1947 { 1948 // try to identify a single FillGradientPrimitive2D in the 1949 // transparence part of the primitive 1950 const primitive2d::FillGradientPrimitive2D* pFiGradient = 0; 1951 static bool bForceToBigTransparentVDev(false); 1952 1953 if(!bForceToBigTransparentVDev && 1 == rTransparence.getLength()) 1954 { 1955 const primitive2d::Primitive2DReference xReference(rTransparence[0]); 1956 pFiGradient = dynamic_cast< const primitive2d::FillGradientPrimitive2D* >(xReference.get()); 1957 } 1958 1959 // Check also for correct ID to exclude derived implementations 1960 if(pFiGradient && PRIMITIVE2D_ID_FILLGRADIENTPRIMITIVE2D == pFiGradient->getPrimitive2DID()) 1961 { 1962 // various content, create content-metafile 1963 GDIMetaFile aContentMetafile; 1964 const Rectangle aPrimitiveRectangle(impDumpToMetaFile(rContent, aContentMetafile)); 1965 1966 // re-create a VCL-gradient from FillGradientPrimitive2D 1967 Gradient aVCLGradient; 1968 impConvertFillGradientAttributeToVCLGradient(aVCLGradient, pFiGradient->getFillGradient(), true); 1969 1970 // render it to VCL 1971 mpOutputDevice->DrawTransparent( 1972 aContentMetafile, aPrimitiveRectangle.TopLeft(), 1973 aPrimitiveRectangle.GetSize(), aVCLGradient); 1974 } 1975 else 1976 { 1977 // sub-transparence group. Draw to VDev first. 1978 // this may get refined to tiling when resolution is too big here 1979 1980 // need to avoid switching off MapMode stuff here; maybe need another 1981 // tooling class, cannot just do the same as with the pixel renderer. 1982 // Need to experiment... 1983 1984 // Okay, basic implementation finished and tested. The DPI stuff was hard 1985 // and not easy to find out that it's needed. 1986 // Since this will not yet happen normally (as long as noone constructs 1987 // transparence primitives with non-trivial transparence content) i will for now not 1988 // refine to tiling here. 1989 1990 basegfx::B2DRange aViewRange(primitive2d::getB2DRangeFromPrimitive2DSequence(rContent, getViewInformation2D())); 1991 aViewRange.transform(maCurrentTransformation); 1992 const Rectangle aRectLogic( 1993 (sal_Int32)floor(aViewRange.getMinX()), (sal_Int32)floor(aViewRange.getMinY()), 1994 (sal_Int32)ceil(aViewRange.getMaxX()), (sal_Int32)ceil(aViewRange.getMaxY())); 1995 const Rectangle aRectPixel(mpOutputDevice->LogicToPixel(aRectLogic)); 1996 Size aSizePixel(aRectPixel.GetSize()); 1997 const Point aEmptyPoint; 1998 VirtualDevice aBufferDevice; 1999 const sal_uInt32 nMaxQuadratPixels(500000); 2000 const sal_uInt32 nViewVisibleArea(aSizePixel.getWidth() * aSizePixel.getHeight()); 2001 double fReduceFactor(1.0); 2002 2003 if(nViewVisibleArea > nMaxQuadratPixels) 2004 { 2005 // reduce render size 2006 fReduceFactor = sqrt((double)nMaxQuadratPixels / (double)nViewVisibleArea); 2007 aSizePixel = Size(basegfx::fround((double)aSizePixel.getWidth() * fReduceFactor), 2008 basegfx::fround((double)aSizePixel.getHeight() * fReduceFactor)); 2009 } 2010 2011 if(aBufferDevice.SetOutputSizePixel(aSizePixel)) 2012 { 2013 // create and set MapModes for target devices 2014 MapMode aNewMapMode(mpOutputDevice->GetMapMode()); 2015 aNewMapMode.SetOrigin(Point(-aRectLogic.Left(), -aRectLogic.Top())); 2016 aBufferDevice.SetMapMode(aNewMapMode); 2017 2018 // prepare view transformation for target renderers 2019 // ATTENTION! Need to apply another scaling because of the potential DPI differences 2020 // between Printer and VDev (mpOutputDevice and aBufferDevice here). 2021 // To get the DPI, LogicToPixel from (1,1) from MAP_INCH needs to be used. 2022 basegfx::B2DHomMatrix aViewTransform(aBufferDevice.GetViewTransformation()); 2023 const Size aDPIOld(mpOutputDevice->LogicToPixel(Size(1, 1), MAP_INCH)); 2024 const Size aDPINew(aBufferDevice.LogicToPixel(Size(1, 1), MAP_INCH)); 2025 const double fDPIXChange((double)aDPIOld.getWidth() / (double)aDPINew.getWidth()); 2026 const double fDPIYChange((double)aDPIOld.getHeight() / (double)aDPINew.getHeight()); 2027 2028 if(!basegfx::fTools::equal(fDPIXChange, 1.0) || !basegfx::fTools::equal(fDPIYChange, 1.0)) 2029 { 2030 aViewTransform.scale(fDPIXChange, fDPIYChange); 2031 } 2032 2033 // also take scaling from Size reduction into acount 2034 if(!basegfx::fTools::equal(fReduceFactor, 1.0)) 2035 { 2036 aViewTransform.scale(fReduceFactor, fReduceFactor); 2037 } 2038 2039 // create view information and pixel renderer. Reuse known ViewInformation 2040 // except new transformation and range 2041 const geometry::ViewInformation2D aViewInfo( 2042 getViewInformation2D().getObjectTransformation(), 2043 aViewTransform, 2044 aViewRange, 2045 getViewInformation2D().getVisualizedPage(), 2046 getViewInformation2D().getViewTime(), 2047 getViewInformation2D().getExtendedInformationSequence()); 2048 2049 VclPixelProcessor2D aBufferProcessor(aViewInfo, aBufferDevice); 2050 2051 // draw content using pixel renderer 2052 aBufferProcessor.process(rContent); 2053 const Bitmap aBmContent(aBufferDevice.GetBitmap(aEmptyPoint, aSizePixel)); 2054 2055 // draw transparence using pixel renderer 2056 aBufferDevice.Erase(); 2057 aBufferProcessor.process(rTransparence); 2058 const AlphaMask aBmAlpha(aBufferDevice.GetBitmap(aEmptyPoint, aSizePixel)); 2059 2060 #ifdef DBG_UTIL 2061 static bool bDoSaveForVisualControl(false); 2062 if(bDoSaveForVisualControl) 2063 { 2064 SvFileStream aNew(String(ByteString( "c:\\test.bmp" ), RTL_TEXTENCODING_UTF8), STREAM_WRITE|STREAM_TRUNC); 2065 aNew << aBmContent; 2066 } 2067 #endif 2068 2069 // paint 2070 mpOutputDevice->DrawBitmapEx( 2071 aRectLogic.TopLeft(), 2072 aRectLogic.GetSize(), 2073 BitmapEx(aBmContent, aBmAlpha)); 2074 } 2075 } 2076 } 2077 2078 break; 2079 } 2080 case PRIMITIVE2D_ID_TRANSFORMPRIMITIVE2D : 2081 { 2082 // use default transform group pocessing 2083 RenderTransformPrimitive2D(static_cast< const primitive2d::TransformPrimitive2D& >(rCandidate)); 2084 break; 2085 } 2086 case PRIMITIVE2D_ID_PAGEPREVIEWPRIMITIVE2D : 2087 { 2088 // new XDrawPage for ViewInformation2D 2089 RenderPagePreviewPrimitive2D(static_cast< const primitive2d::PagePreviewPrimitive2D& >(rCandidate)); 2090 break; 2091 } 2092 case PRIMITIVE2D_ID_MARKERARRAYPRIMITIVE2D : 2093 { 2094 // use default marker array pocessing 2095 RenderMarkerArrayPrimitive2D(static_cast< const primitive2d::MarkerArrayPrimitive2D& >(rCandidate)); 2096 break; 2097 } 2098 case PRIMITIVE2D_ID_POINTARRAYPRIMITIVE2D : 2099 { 2100 // use default point array pocessing 2101 RenderPointArrayPrimitive2D(static_cast< const primitive2d::PointArrayPrimitive2D& >(rCandidate)); 2102 break; 2103 } 2104 case PRIMITIVE2D_ID_STRUCTURETAGPRIMITIVE2D : 2105 { 2106 // structured tag primitive 2107 const primitive2d::StructureTagPrimitive2D& rStructureTagCandidate = static_cast< const primitive2d::StructureTagPrimitive2D& >(rCandidate); 2108 const vcl::PDFWriter::StructElement& rTagElement(rStructureTagCandidate.getStructureElement()); 2109 const bool bTagUsed(vcl::PDFWriter::NonStructElement != rTagElement); 2110 2111 if(mpPDFExtOutDevData && bTagUsed) 2112 { 2113 // write start tag 2114 mpPDFExtOutDevData->BeginStructureElement(rTagElement); 2115 } 2116 2117 // proccess childs normally 2118 process(rStructureTagCandidate.getChildren()); 2119 2120 if(mpPDFExtOutDevData && bTagUsed) 2121 { 2122 // write end tag 2123 mpPDFExtOutDevData->EndStructureElement(); 2124 } 2125 2126 break; 2127 } 2128 case PRIMITIVE2D_ID_EPSPRIMITIVE2D : 2129 { 2130 RenderEpsPrimitive2D(static_cast< const primitive2d::EpsPrimitive2D& >(rCandidate)); 2131 break; 2132 } 2133 default : 2134 { 2135 // process recursively 2136 process(rCandidate.get2DDecomposition(getViewInformation2D())); 2137 break; 2138 } 2139 } 2140 } 2141 } // end of namespace processor2d 2142 } // end of namespace drawinglayer 2143 2144 ////////////////////////////////////////////////////////////////////////////// 2145 // eof 2146