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