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