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