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