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