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