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