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