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/primitive2d/metafileprimitive2d.hxx> 28 #include <basegfx/tools/canvastools.hxx> 29 #include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx> 30 #include <basegfx/color/bcolor.hxx> 31 #include <drawinglayer/primitive2d/pointarrayprimitive2d.hxx> 32 #include <vcl/lineinfo.hxx> 33 #include <drawinglayer/attribute/lineattribute.hxx> 34 #include <drawinglayer/attribute/strokeattribute.hxx> 35 #include <drawinglayer/primitive2d/polygonprimitive2d.hxx> 36 #include <vcl/metaact.hxx> 37 #include <drawinglayer/primitive2d/transformprimitive2d.hxx> 38 #include <basegfx/matrix/b2dhommatrixtools.hxx> 39 #include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx> 40 #include <basegfx/polygon/b2dpolygontools.hxx> 41 #include <drawinglayer/primitive2d/discretebitmapprimitive2d.hxx> 42 #include <drawinglayer/primitive2d/bitmapprimitive2d.hxx> 43 #include <vcl/salbtype.hxx> 44 #include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx> 45 #include <drawinglayer/primitive2d/fillgradientprimitive2d.hxx> 46 #include <vcl/svapp.hxx> 47 #include <drawinglayer/primitive2d/transparenceprimitive2d.hxx> 48 #include <drawinglayer/primitive2d/fillhatchprimitive2d.hxx> 49 #include <drawinglayer/primitive2d/maskprimitive2d.hxx> 50 #include <basegfx/polygon/b2dpolygonclipper.hxx> 51 #include <drawinglayer/primitive2d/invertprimitive2d.hxx> 52 #include <drawinglayer/primitive2d/modifiedcolorprimitive2d.hxx> 53 #include <drawinglayer/primitive2d/fillbitmapprimitive2d.hxx> 54 #include <drawinglayer/primitive2d/wallpaperprimitive2d.hxx> 55 #include <drawinglayer/primitive2d/textprimitive2d.hxx> 56 #include <drawinglayer/primitive2d/textlayoutdevice.hxx> 57 #include <drawinglayer/primitive2d/textdecoratedprimitive2d.hxx> 58 #include <i18npool/mslangid.hxx> 59 #include <drawinglayer/primitive2d/textlineprimitive2d.hxx> 60 #include <drawinglayer/primitive2d/textstrikeoutprimitive2d.hxx> 61 #include <drawinglayer/primitive2d/epsprimitive2d.hxx> 62 #include <numeric> 63 64 ////////////////////////////////////////////////////////////////////////////// 65 66 using namespace com::sun::star; 67 68 ////////////////////////////////////////////////////////////////////////////// 69 70 namespace 71 { 72 /** helper class for graphic context 73 74 This class allows to hold a complete status of classic 75 VCL OutputDevice stati. This data is needed for correct 76 interpretation of the MetaFile action flow. 77 */ 78 class PropertyHolder 79 { 80 private: 81 /// current transformation (aka MapMode) 82 basegfx::B2DHomMatrix maTransformation; 83 MapUnit maMapUnit; 84 85 /// current colors 86 basegfx::BColor maLineColor; 87 basegfx::BColor maFillColor; 88 basegfx::BColor maTextColor; 89 basegfx::BColor maTextFillColor; 90 basegfx::BColor maTextLineColor; 91 basegfx::BColor maOverlineColor; 92 93 /// clipping 94 basegfx::B2DPolyPolygon maClipPolyPoygon; 95 96 /// font, etc. 97 Font maFont; 98 RasterOp maRasterOp; 99 sal_uInt32 mnLayoutMode; 100 LanguageType maLanguageType; 101 sal_uInt16 mnPushFlags; 102 103 /// bitfield 104 /// contains all active markers 105 bool mbLineColor : 1; 106 bool mbFillColor : 1; 107 bool mbTextColor : 1; 108 bool mbTextFillColor : 1; 109 bool mbTextLineColor : 1; 110 bool mbOverlineColor : 1; 111 bool mbClipPolyPolygonActive : 1; 112 113 public: 114 PropertyHolder() 115 : maTransformation(), 116 maMapUnit(MAP_100TH_MM), 117 maLineColor(), 118 maFillColor(), 119 maTextColor(COL_BLACK), 120 maTextFillColor(), 121 maTextLineColor(), 122 maOverlineColor(), 123 maClipPolyPoygon(), 124 maFont(), 125 maRasterOp(ROP_OVERPAINT), 126 mnLayoutMode(0), 127 maLanguageType(0), 128 mnPushFlags(0), 129 mbLineColor(false), 130 mbFillColor(false), 131 mbTextColor(true), 132 mbTextFillColor(false), 133 mbTextLineColor(false), 134 mbOverlineColor(false), 135 mbClipPolyPolygonActive(false) 136 { 137 } 138 139 ~PropertyHolder() 140 { 141 } 142 143 /// read/write accesses 144 const basegfx::B2DHomMatrix& getTransformation() const { return maTransformation; } 145 void setTransformation(const basegfx::B2DHomMatrix& rNew) { if(rNew != maTransformation) maTransformation = rNew; } 146 147 MapUnit getMapUnit() const { return maMapUnit; } 148 void setMapUnit(MapUnit eNew) { if(eNew != maMapUnit) maMapUnit = eNew; } 149 150 const basegfx::BColor& getLineColor() const { return maLineColor; } 151 void setLineColor(const basegfx::BColor& rNew) { if(rNew != maLineColor) maLineColor = rNew; } 152 bool getLineColorActive() const { return mbLineColor; } 153 void setLineColorActive(bool bNew) { if(bNew != mbLineColor) mbLineColor = bNew; } 154 155 const basegfx::BColor& getFillColor() const { return maFillColor; } 156 void setFillColor(const basegfx::BColor& rNew) { if(rNew != maFillColor) maFillColor = rNew; } 157 bool getFillColorActive() const { return mbFillColor; } 158 void setFillColorActive(bool bNew) { if(bNew != mbFillColor) mbFillColor = bNew; } 159 160 const basegfx::BColor& getTextColor() const { return maTextColor; } 161 void setTextColor(const basegfx::BColor& rNew) { if(rNew != maTextColor) maTextColor = rNew; } 162 bool getTextColorActive() const { return mbTextColor; } 163 void setTextColorActive(bool bNew) { if(bNew != mbTextColor) mbTextColor = bNew; } 164 165 const basegfx::BColor& getTextFillColor() const { return maTextFillColor; } 166 void setTextFillColor(const basegfx::BColor& rNew) { if(rNew != maTextFillColor) maTextFillColor = rNew; } 167 bool getTextFillColorActive() const { return mbTextFillColor; } 168 void setTextFillColorActive(bool bNew) { if(bNew != mbTextFillColor) mbTextFillColor = bNew; } 169 170 const basegfx::BColor& getTextLineColor() const { return maTextLineColor; } 171 void setTextLineColor(const basegfx::BColor& rNew) { if(rNew != maTextLineColor) maTextLineColor = rNew; } 172 bool getTextLineColorActive() const { return mbTextLineColor; } 173 void setTextLineColorActive(bool bNew) { if(bNew != mbTextLineColor) mbTextLineColor = bNew; } 174 175 const basegfx::BColor& getOverlineColor() const { return maOverlineColor; } 176 void setOverlineColor(const basegfx::BColor& rNew) { if(rNew != maOverlineColor) maOverlineColor = rNew; } 177 bool getOverlineColorActive() const { return mbOverlineColor; } 178 void setOverlineColorActive(bool bNew) { if(bNew != mbOverlineColor) mbOverlineColor = bNew; } 179 180 const basegfx::B2DPolyPolygon& getClipPolyPolygon() const { return maClipPolyPoygon; } 181 void setClipPolyPolygon(const basegfx::B2DPolyPolygon& rNew) { if(rNew != maClipPolyPoygon) maClipPolyPoygon = rNew; } 182 bool getClipPolyPolygonActive() const { return mbClipPolyPolygonActive; } 183 void setClipPolyPolygonActive(bool bNew) { if(bNew != mbClipPolyPolygonActive) mbClipPolyPolygonActive = bNew; } 184 185 const Font& getFont() const { return maFont; } 186 void setFont(const Font& rFont) { if(rFont != maFont) maFont = rFont; } 187 188 const RasterOp& getRasterOp() const { return maRasterOp; } 189 void setRasterOp(const RasterOp& rRasterOp) { if(rRasterOp != maRasterOp) maRasterOp = rRasterOp; } 190 bool isRasterOpInvert() const { return (ROP_XOR == maRasterOp || ROP_INVERT == maRasterOp); } 191 bool isRasterOpForceBlack() const { return ROP_0 == maRasterOp; } 192 bool isRasterOpActive() const { return isRasterOpInvert() || isRasterOpForceBlack(); } 193 194 sal_uInt32 getLayoutMode() const { return mnLayoutMode; } 195 void setLayoutMode(sal_uInt32 nNew) { if(nNew != mnLayoutMode) mnLayoutMode = nNew; } 196 197 LanguageType getLanguageType() const { return maLanguageType; } 198 void setLanguageType(LanguageType aNew) { if(aNew != maLanguageType) maLanguageType = aNew; } 199 200 sal_uInt16 getPushFlags() const { return mnPushFlags; } 201 void setPushFlags(sal_uInt16 nNew) { if(nNew != mnPushFlags) mnPushFlags = nNew; } 202 203 bool getLineOrFillActive() const { return (mbLineColor || mbFillColor); } 204 }; 205 } // end of anonymous namespace 206 207 ////////////////////////////////////////////////////////////////////////////// 208 209 namespace 210 { 211 /** stack for properites 212 213 This class builds a stack based on the PropertyHolder 214 class. It encapsulates the pointer/new/delete usage to 215 make it safe and implements the push/pop as needed by a 216 VCL Metafile interpreter. The critical part here are the 217 flag values VCL OutputDevice uses here; not all stuff is 218 pushed and thus needs to be copied at pop. 219 */ 220 class PropertyHolders 221 { 222 private: 223 std::vector< PropertyHolder* > maPropertyHolders; 224 225 public: 226 PropertyHolders() 227 { 228 maPropertyHolders.push_back(new PropertyHolder()); 229 } 230 231 sal_uInt32 size() 232 { 233 return maPropertyHolders.size(); 234 } 235 236 void PushDefault() 237 { 238 PropertyHolder* pNew = new PropertyHolder(); 239 maPropertyHolders.push_back(pNew); 240 } 241 242 void Push(sal_uInt16 nPushFlags) 243 { 244 if(nPushFlags) 245 { 246 OSL_ENSURE(maPropertyHolders.size(), "PropertyHolders: PUSH with no property holders (!)"); 247 if ( !maPropertyHolders.empty() ) 248 { 249 PropertyHolder* pNew = new PropertyHolder(*maPropertyHolders.back()); 250 pNew->setPushFlags(nPushFlags); 251 maPropertyHolders.push_back(pNew); 252 } 253 } 254 } 255 256 void Pop() 257 { 258 OSL_ENSURE(maPropertyHolders.size(), "PropertyHolders: POP with no property holders (!)"); 259 const sal_uInt32 nSize(maPropertyHolders.size()); 260 261 if(nSize) 262 { 263 const PropertyHolder* pTip = maPropertyHolders.back(); 264 const sal_uInt16 nPushFlags(pTip->getPushFlags()); 265 266 if(nPushFlags) 267 { 268 if(nSize > 1) 269 { 270 // copy back content for all non-set flags 271 PropertyHolder* pLast = maPropertyHolders[nSize - 2]; 272 273 if(PUSH_ALL != nPushFlags) 274 { 275 if(!(nPushFlags & PUSH_LINECOLOR )) 276 { 277 pLast->setLineColor(pTip->getLineColor()); 278 pLast->setLineColorActive(pTip->getLineColorActive()); 279 } 280 if(!(nPushFlags & PUSH_FILLCOLOR )) 281 { 282 pLast->setFillColor(pTip->getFillColor()); 283 pLast->setFillColorActive(pTip->getFillColorActive()); 284 } 285 if(!(nPushFlags & PUSH_FONT )) 286 { 287 pLast->setFont(pTip->getFont()); 288 } 289 if(!(nPushFlags & PUSH_TEXTCOLOR )) 290 { 291 pLast->setTextColor(pTip->getTextColor()); 292 pLast->setTextColorActive(pTip->getTextColorActive()); 293 } 294 if(!(nPushFlags & PUSH_MAPMODE )) 295 { 296 pLast->setTransformation(pTip->getTransformation()); 297 pLast->setMapUnit(pTip->getMapUnit()); 298 } 299 if(!(nPushFlags & PUSH_CLIPREGION )) 300 { 301 pLast->setClipPolyPolygon(pTip->getClipPolyPolygon()); 302 pLast->setClipPolyPolygonActive(pTip->getClipPolyPolygonActive()); 303 } 304 if(!(nPushFlags & PUSH_RASTEROP )) 305 { 306 pLast->setRasterOp(pTip->getRasterOp()); 307 } 308 if(!(nPushFlags & PUSH_TEXTFILLCOLOR )) 309 { 310 pLast->setTextFillColor(pTip->getTextFillColor()); 311 pLast->setTextFillColorActive(pTip->getTextFillColorActive()); 312 } 313 if(!(nPushFlags & PUSH_TEXTALIGN )) 314 { 315 if(pLast->getFont().GetAlign() != pTip->getFont().GetAlign()) 316 { 317 Font aFont(pLast->getFont()); 318 aFont.SetAlign(pTip->getFont().GetAlign()); 319 pLast->setFont(aFont); 320 } 321 } 322 if(!(nPushFlags & PUSH_REFPOINT )) 323 { 324 // not supported 325 } 326 if(!(nPushFlags & PUSH_TEXTLINECOLOR )) 327 { 328 pLast->setTextLineColor(pTip->getTextLineColor()); 329 pLast->setTextLineColorActive(pTip->getTextLineColorActive()); 330 } 331 if(!(nPushFlags & PUSH_TEXTLAYOUTMODE )) 332 { 333 pLast->setLayoutMode(pTip->getLayoutMode()); 334 } 335 if(!(nPushFlags & PUSH_TEXTLANGUAGE )) 336 { 337 pLast->setLanguageType(pTip->getLanguageType()); 338 } 339 if(!(nPushFlags & PUSH_OVERLINECOLOR )) 340 { 341 pLast->setOverlineColor(pTip->getOverlineColor()); 342 pLast->setOverlineColorActive(pTip->getOverlineColorActive()); 343 } 344 } 345 } 346 } 347 348 // execute the pop 349 delete maPropertyHolders.back(); 350 maPropertyHolders.pop_back(); 351 } 352 } 353 354 PropertyHolder& Current() 355 { 356 static PropertyHolder aDummy; 357 OSL_ENSURE(maPropertyHolders.size(), "PropertyHolders: CURRENT with no property holders (!)"); 358 return maPropertyHolders.empty() ? aDummy : *maPropertyHolders.back(); 359 } 360 361 ~PropertyHolders() 362 { 363 while(maPropertyHolders.size()) 364 { 365 delete maPropertyHolders.back(); 366 maPropertyHolders.pop_back(); 367 } 368 } 369 }; 370 } // end of anonymous namespace 371 372 ////////////////////////////////////////////////////////////////////////////// 373 374 namespace 375 { 376 /** helper to convert a Region to a B2DPolyPolygon 377 when it does not yet contain one. In the future 378 this may be expanded to merge the polygons created 379 from rectangles or use a special algo to directly turn 380 the spans of regions to a single, already merged 381 PolyPolygon. 382 */ 383 basegfx::B2DPolyPolygon getB2DPolyPolygonFromRegion(const Region& rRegion) 384 { 385 basegfx::B2DPolyPolygon aRetval; 386 387 if(!rRegion.IsEmpty()) 388 { 389 Region aRegion(rRegion); 390 aRetval = aRegion.GetB2DPolyPolygon(); 391 392 if(!aRetval.count()) 393 { 394 RegionHandle aRegionHandle(aRegion.BeginEnumRects()); 395 Rectangle aRegionRectangle; 396 397 while(aRegion.GetEnumRects(aRegionHandle, aRegionRectangle)) 398 { 399 if(!aRegionRectangle.IsEmpty()) 400 { 401 const basegfx::B2DRange aRegionRange( 402 aRegionRectangle.Left(), aRegionRectangle.Top(), 403 aRegionRectangle.Right(), aRegionRectangle.Bottom()); 404 aRetval.append(basegfx::tools::createPolygonFromRect(aRegionRange)); 405 } 406 } 407 408 aRegion.EndEnumRects(aRegionHandle); 409 } 410 } 411 412 return aRetval; 413 } 414 } // end of anonymous namespace 415 416 ////////////////////////////////////////////////////////////////////////////// 417 418 namespace 419 { 420 /** Helper class to buffer and hold a Primive target vector. It 421 encapsulates the new/delete functionality and aloows to work 422 on pointers of the implementation classes. All data will 423 be converted to uno sequences of uno references when accessing the 424 data. 425 */ 426 class TargetHolder 427 { 428 private: 429 std::vector< drawinglayer::primitive2d::BasePrimitive2D* > aTargets; 430 431 public: 432 TargetHolder() 433 : aTargets() 434 { 435 } 436 437 ~TargetHolder() 438 { 439 const sal_uInt32 nCount(aTargets.size()); 440 441 for(sal_uInt32 a(0); a < nCount; a++) 442 { 443 delete aTargets[a]; 444 } 445 } 446 447 sal_uInt32 size() 448 { 449 return aTargets.size(); 450 } 451 452 void append(drawinglayer::primitive2d::BasePrimitive2D* pCandidate) 453 { 454 if(pCandidate) 455 { 456 aTargets.push_back(pCandidate); 457 } 458 } 459 460 drawinglayer::primitive2d::Primitive2DSequence getPrimitive2DSequence(const PropertyHolder& rPropertyHolder) 461 { 462 const sal_uInt32 nCount(aTargets.size()); 463 drawinglayer::primitive2d::Primitive2DSequence xRetval(nCount); 464 465 for(sal_uInt32 a(0); a < nCount; a++) 466 { 467 xRetval[a] = aTargets[a]; 468 } 469 470 // All Targets were pointers, but do not need to be deleted since they 471 // were converted to UNO API references now, so they stay as long as 472 // referenced. Do NOT delete the C++ implementation classes here, but clear 473 // the buffer to not delete them in the destructor. 474 aTargets.clear(); 475 476 if(xRetval.hasElements() && rPropertyHolder.getClipPolyPolygonActive()) 477 { 478 const basegfx::B2DPolyPolygon& rClipPolyPolygon = rPropertyHolder.getClipPolyPolygon(); 479 480 if(rClipPolyPolygon.count()) 481 { 482 const drawinglayer::primitive2d::Primitive2DReference xMask( 483 new drawinglayer::primitive2d::MaskPrimitive2D( 484 rClipPolyPolygon, 485 xRetval)); 486 487 xRetval = drawinglayer::primitive2d::Primitive2DSequence(&xMask, 1); 488 } 489 } 490 491 return xRetval; 492 } 493 }; 494 } // end of anonymous namespace 495 496 ////////////////////////////////////////////////////////////////////////////// 497 498 namespace 499 { 500 /** Helper class which builds a stack on the TargetHolder class */ 501 class TargetHolders 502 { 503 private: 504 std::vector< TargetHolder* > maTargetHolders; 505 506 public: 507 TargetHolders() 508 { 509 maTargetHolders.push_back(new TargetHolder()); 510 } 511 512 sal_uInt32 size() 513 { 514 return maTargetHolders.size(); 515 } 516 517 void Push() 518 { 519 maTargetHolders.push_back(new TargetHolder()); 520 } 521 522 void Pop() 523 { 524 OSL_ENSURE(maTargetHolders.size(), "TargetHolders: POP with no property holders (!)"); 525 if(maTargetHolders.size()) 526 { 527 delete maTargetHolders.back(); 528 maTargetHolders.pop_back(); 529 } 530 } 531 532 TargetHolder& Current() 533 { 534 OSL_ENSURE(maTargetHolders.size(), "TargetHolders: CURRENT with no property holders (!)"); 535 return *maTargetHolders.back(); 536 } 537 538 ~TargetHolders() 539 { 540 while(maTargetHolders.size()) 541 { 542 delete maTargetHolders.back(); 543 maTargetHolders.pop_back(); 544 } 545 } 546 }; 547 } // end of anonymous namespace 548 549 ////////////////////////////////////////////////////////////////////////////// 550 551 namespace drawinglayer 552 { 553 namespace primitive2d 554 { 555 /** NonOverlappingFillGradientPrimitive2D class 556 557 This is a special version of the FillGradientPrimitive2D which decomposes 558 to a non-overlapping geometry version of the gradient. This needs to be 559 used to support the old XOR paint-'trick'. 560 561 It does not need an own identifier since a renderer who wants to interpret 562 it itself may do so. It just overloads the decomposition of the C++ 563 implementation class to do an alternative decomposition. 564 */ 565 class NonOverlappingFillGradientPrimitive2D : public FillGradientPrimitive2D 566 { 567 protected: 568 /// local decomposition. 569 virtual Primitive2DSequence create2DDecomposition( 570 const geometry::ViewInformation2D& rViewInformation) const; 571 572 public: 573 /// constructor 574 NonOverlappingFillGradientPrimitive2D( 575 const basegfx::B2DRange& rObjectRange, 576 const attribute::FillGradientAttribute& rFillGradient) 577 : FillGradientPrimitive2D(rObjectRange, rFillGradient) 578 { 579 } 580 }; 581 582 Primitive2DSequence NonOverlappingFillGradientPrimitive2D::create2DDecomposition( 583 const geometry::ViewInformation2D& /*rViewInformation*/) const 584 { 585 if(!getFillGradient().isDefault()) 586 { 587 return createFill(false); 588 } 589 else 590 { 591 return Primitive2DSequence(); 592 } 593 } 594 } // end of namespace primitive2d 595 } // end of namespace drawinglayer 596 597 ////////////////////////////////////////////////////////////////////////////// 598 599 namespace 600 { 601 /** helper to convert a MapMode to a transformation */ 602 basegfx::B2DHomMatrix getTransformFromMapMode(const MapMode& rMapMode) 603 { 604 basegfx::B2DHomMatrix aMapping; 605 const Fraction aNoScale(1, 1); 606 const Point& rOrigin(rMapMode.GetOrigin()); 607 608 if(0 != rOrigin.X() || 0 != rOrigin.Y()) 609 { 610 aMapping.translate(rOrigin.X(), rOrigin.Y()); 611 } 612 613 if(rMapMode.GetScaleX() != aNoScale || rMapMode.GetScaleY() != aNoScale) 614 { 615 aMapping.scale( 616 double(rMapMode.GetScaleX()), 617 double(rMapMode.GetScaleY())); 618 } 619 620 return aMapping; 621 } 622 623 /** helper to create a PointArrayPrimitive2D based on current context */ 624 void createPointArrayPrimitive( 625 const std::vector< basegfx::B2DPoint >& rPositions, 626 TargetHolder& rTarget, 627 PropertyHolder& rProperties, 628 basegfx::BColor aBColor) 629 { 630 if(rPositions.size()) 631 { 632 if(rProperties.getTransformation().isIdentity()) 633 { 634 rTarget.append( 635 new drawinglayer::primitive2d::PointArrayPrimitive2D( 636 rPositions, 637 aBColor)); 638 } 639 else 640 { 641 std::vector< basegfx::B2DPoint > aPositions(rPositions); 642 643 for(sal_uInt32 a(0); a < aPositions.size(); a++) 644 { 645 aPositions[a] = rProperties.getTransformation() * aPositions[a]; 646 } 647 648 rTarget.append( 649 new drawinglayer::primitive2d::PointArrayPrimitive2D( 650 aPositions, 651 aBColor)); 652 } 653 } 654 } 655 656 /** helper to create a PolygonHairlinePrimitive2D based on current context */ 657 void createHairlinePrimitive( 658 const basegfx::B2DPolygon& rLinePolygon, 659 TargetHolder& rTarget, 660 PropertyHolder& rProperties) 661 { 662 if(rLinePolygon.count()) 663 { 664 basegfx::B2DPolygon aLinePolygon(rLinePolygon); 665 aLinePolygon.transform(rProperties.getTransformation()); 666 rTarget.append( 667 new drawinglayer::primitive2d::PolygonHairlinePrimitive2D( 668 aLinePolygon, 669 rProperties.getLineColor())); 670 } 671 } 672 673 /** helper to create a PolyPolygonColorPrimitive2D based on current context */ 674 void createFillPrimitive( 675 const basegfx::B2DPolyPolygon& rFillPolyPolygon, 676 TargetHolder& rTarget, 677 PropertyHolder& rProperties) 678 { 679 if(rFillPolyPolygon.count()) 680 { 681 basegfx::B2DPolyPolygon aFillPolyPolygon(rFillPolyPolygon); 682 aFillPolyPolygon.transform(rProperties.getTransformation()); 683 rTarget.append( 684 new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D( 685 aFillPolyPolygon, 686 rProperties.getFillColor())); 687 } 688 } 689 690 /** helper to create a PolygonStrokePrimitive2D based on current context */ 691 void createLinePrimitive( 692 const basegfx::B2DPolygon& rLinePolygon, 693 const LineInfo& rLineInfo, 694 TargetHolder& rTarget, 695 PropertyHolder& rProperties) 696 { 697 if(rLinePolygon.count()) 698 { 699 const bool bDashDotUsed(LINE_DASH == rLineInfo.GetStyle()); 700 const bool bWidthUsed(rLineInfo.GetWidth() > 1); 701 702 if(bDashDotUsed || bWidthUsed) 703 { 704 basegfx::B2DPolygon aLinePolygon(rLinePolygon); 705 aLinePolygon.transform(rProperties.getTransformation()); 706 const drawinglayer::attribute::LineAttribute aLineAttribute( 707 rProperties.getLineColor(), 708 bWidthUsed ? rLineInfo.GetWidth() : 0.0, 709 rLineInfo.GetLineJoin()); 710 711 if(bDashDotUsed) 712 { 713 ::std::vector< double > fDotDashArray; 714 const double fDashLen(rLineInfo.GetDashLen()); 715 const double fDotLen(rLineInfo.GetDotLen()); 716 const double fDistance(rLineInfo.GetDistance()); 717 718 for(sal_uInt16 a(0); a < rLineInfo.GetDashCount(); a++) 719 { 720 fDotDashArray.push_back(fDashLen); 721 fDotDashArray.push_back(fDistance); 722 } 723 724 for(sal_uInt16 b(0); b < rLineInfo.GetDotCount(); b++) 725 { 726 fDotDashArray.push_back(fDotLen); 727 fDotDashArray.push_back(fDistance); 728 } 729 730 const double fAccumulated(::std::accumulate(fDotDashArray.begin(), fDotDashArray.end(), 0.0)); 731 const drawinglayer::attribute::StrokeAttribute aStrokeAttribute( 732 fDotDashArray, 733 fAccumulated); 734 735 rTarget.append( 736 new drawinglayer::primitive2d::PolygonStrokePrimitive2D( 737 aLinePolygon, 738 aLineAttribute, 739 aStrokeAttribute)); 740 } 741 else 742 { 743 rTarget.append( 744 new drawinglayer::primitive2d::PolygonStrokePrimitive2D( 745 aLinePolygon, 746 aLineAttribute)); 747 } 748 } 749 else 750 { 751 createHairlinePrimitive(rLinePolygon, rTarget, rProperties); 752 } 753 } 754 } 755 756 /** helper to create needed line and fill primitives based on current context */ 757 void createHairlineAndFillPrimitive( 758 const basegfx::B2DPolygon& rPolygon, 759 TargetHolder& rTarget, 760 PropertyHolder& rProperties) 761 { 762 if(rProperties.getFillColorActive()) 763 { 764 createFillPrimitive(basegfx::B2DPolyPolygon(rPolygon), rTarget, rProperties); 765 } 766 767 if(rProperties.getLineColorActive()) 768 { 769 createHairlinePrimitive(rPolygon, rTarget, rProperties); 770 } 771 } 772 773 /** helper to create needed line and fill primitives based on current context */ 774 void createHairlineAndFillPrimitive( 775 const basegfx::B2DPolyPolygon& rPolyPolygon, 776 TargetHolder& rTarget, 777 PropertyHolder& rProperties) 778 { 779 if(rProperties.getFillColorActive()) 780 { 781 createFillPrimitive(rPolyPolygon, rTarget, rProperties); 782 } 783 784 if(rProperties.getLineColorActive()) 785 { 786 for(sal_uInt32 a(0); a < rPolyPolygon.count(); a++) 787 { 788 createHairlinePrimitive(rPolyPolygon.getB2DPolygon(a), rTarget, rProperties); 789 } 790 } 791 } 792 793 /** helper to create DiscreteBitmapPrimitive2D based on current context. 794 The DiscreteBitmapPrimitive2D is especially created for this usage 795 since no other usage defines a bitmap visualisation based on top-left 796 position and size in pixels. At the end it will create a view-dependent 797 transformed embedding of a BitmapPrimitive2D. 798 */ 799 void createBitmapExPrimitive( 800 const BitmapEx& rBitmapEx, 801 const Point& rPoint, 802 TargetHolder& rTarget, 803 PropertyHolder& rProperties) 804 { 805 if(!rBitmapEx.IsEmpty()) 806 { 807 basegfx::B2DPoint aPoint(rPoint.X(), rPoint.Y()); 808 aPoint = rProperties.getTransformation() * aPoint; 809 810 rTarget.append( 811 new drawinglayer::primitive2d::DiscreteBitmapPrimitive2D( 812 rBitmapEx, 813 aPoint)); 814 } 815 } 816 817 /** helper to create BitmapPrimitive2D based on current context */ 818 void createBitmapExPrimitive( 819 const BitmapEx& rBitmapEx, 820 const Point& rPoint, 821 const Size& rSize, 822 TargetHolder& rTarget, 823 PropertyHolder& rProperties) 824 { 825 if(!rBitmapEx.IsEmpty()) 826 { 827 basegfx::B2DHomMatrix aObjectTransform; 828 829 aObjectTransform.set(0, 0, rSize.Width()); 830 aObjectTransform.set(1, 1, rSize.Height()); 831 aObjectTransform.set(0, 2, rPoint.X()); 832 aObjectTransform.set(1, 2, rPoint.Y()); 833 834 aObjectTransform = rProperties.getTransformation() * aObjectTransform; 835 836 rTarget.append( 837 new drawinglayer::primitive2d::BitmapPrimitive2D( 838 rBitmapEx, 839 aObjectTransform)); 840 } 841 } 842 843 /** helper to create a regular BotmapEx from a MaskAction (definitions 844 which use a bitmap without transparence but define one of the colors as 845 transparent) 846 */ 847 BitmapEx createMaskBmpEx(const Bitmap& rBitmap, const Color& rMaskColor) 848 { 849 const Color aWhite(COL_WHITE); 850 BitmapPalette aBiLevelPalette(2); 851 852 aBiLevelPalette[0] = aWhite; 853 aBiLevelPalette[1] = rMaskColor; 854 855 Bitmap aMask(rBitmap.CreateMask(aWhite)); 856 Bitmap aSolid(rBitmap.GetSizePixel(), 1, &aBiLevelPalette); 857 858 aSolid.Erase(rMaskColor); 859 860 return BitmapEx(aSolid, aMask); 861 } 862 863 /** helper to convert from a VCL Gradient definition to the corresponding 864 data for primitive representation 865 */ 866 drawinglayer::attribute::FillGradientAttribute createFillGradientAttribute(const Gradient& rGradient) 867 { 868 const Color aStartColor(rGradient.GetStartColor()); 869 const sal_uInt16 nStartIntens(rGradient.GetStartIntensity()); 870 basegfx::BColor aStart(aStartColor.getBColor()); 871 872 if(nStartIntens != 100) 873 { 874 const basegfx::BColor aBlack; 875 aStart = interpolate(aBlack, aStart, (double)nStartIntens * 0.01); 876 } 877 878 const Color aEndColor(rGradient.GetEndColor()); 879 const sal_uInt16 nEndIntens(rGradient.GetEndIntensity()); 880 basegfx::BColor aEnd(aEndColor.getBColor()); 881 882 if(nEndIntens != 100) 883 { 884 const basegfx::BColor aBlack; 885 aEnd = interpolate(aBlack, aEnd, (double)nEndIntens * 0.01); 886 } 887 888 drawinglayer::attribute::GradientStyle aGradientStyle(drawinglayer::attribute::GRADIENTSTYLE_RECT); 889 890 switch(rGradient.GetStyle()) 891 { 892 case GRADIENT_LINEAR : 893 { 894 aGradientStyle = drawinglayer::attribute::GRADIENTSTYLE_LINEAR; 895 break; 896 } 897 case GRADIENT_AXIAL : 898 { 899 aGradientStyle = drawinglayer::attribute::GRADIENTSTYLE_AXIAL; 900 break; 901 } 902 case GRADIENT_RADIAL : 903 { 904 aGradientStyle = drawinglayer::attribute::GRADIENTSTYLE_RADIAL; 905 break; 906 } 907 case GRADIENT_ELLIPTICAL : 908 { 909 aGradientStyle = drawinglayer::attribute::GRADIENTSTYLE_ELLIPTICAL; 910 break; 911 } 912 case GRADIENT_SQUARE : 913 { 914 aGradientStyle = drawinglayer::attribute::GRADIENTSTYLE_SQUARE; 915 break; 916 } 917 default : // GRADIENT_RECT 918 { 919 aGradientStyle = drawinglayer::attribute::GRADIENTSTYLE_RECT; 920 break; 921 } 922 } 923 924 return drawinglayer::attribute::FillGradientAttribute( 925 aGradientStyle, 926 (double)rGradient.GetBorder() * 0.01, 927 (double)rGradient.GetOfsX() * 0.01, 928 (double)rGradient.GetOfsY() * 0.01, 929 (double)rGradient.GetAngle() * F_PI1800, 930 aStart, 931 aEnd, 932 rGradient.GetSteps()); 933 } 934 935 /** helper to convert from a VCL Hatch definition to the corresponding 936 data for primitive representation 937 */ 938 drawinglayer::attribute::FillHatchAttribute createFillHatchAttribute(const Hatch& rHatch) 939 { 940 drawinglayer::attribute::HatchStyle aHatchStyle(drawinglayer::attribute::HATCHSTYLE_SINGLE); 941 942 switch(rHatch.GetStyle()) 943 { 944 default : // case HATCH_SINGLE : 945 { 946 aHatchStyle = drawinglayer::attribute::HATCHSTYLE_SINGLE; 947 break; 948 } 949 case HATCH_DOUBLE : 950 { 951 aHatchStyle = drawinglayer::attribute::HATCHSTYLE_DOUBLE; 952 break; 953 } 954 case HATCH_TRIPLE : 955 { 956 aHatchStyle = drawinglayer::attribute::HATCHSTYLE_TRIPLE; 957 break; 958 } 959 } 960 961 return drawinglayer::attribute::FillHatchAttribute( 962 aHatchStyle, 963 (double)rHatch.GetDistance(), 964 (double)rHatch.GetAngle() * F_PI1800, 965 rHatch.GetColor().getBColor(), 966 false); 967 } 968 969 /** helper to take needed action on ClipRegion change. This method needs to be called 970 on any Region change, e.g. at the obvious actions doing this, but also at pop-calls 971 whcih change the Region of the current context. It takes care of creating the 972 current embeddec context, set the new Region at the context and eventually prepare 973 a new target for embracing new geometry to the current region 974 */ 975 void HandleNewClipRegion( 976 const basegfx::B2DPolyPolygon& rClipPolyPolygon, 977 TargetHolders& rTargetHolders, 978 PropertyHolders& rPropertyHolders) 979 { 980 const bool bNewActive(rClipPolyPolygon.count()); 981 982 // #i108636# The handlig of new ClipPolyPolygons was not done as good as possible 983 // in the first version of this interpreter; e.g. when a ClipPolyPolygon was set 984 // initially and then using a lot of push/pop actions, the pop always leads 985 // to setting a 'new' ClipPolyPolygon which indeed is the return to the ClipPolyPolygon 986 // of the properties next on the stack. 987 // 988 // This ClipPolyPolygon is identical to the current one, so there is no need to 989 // create a MaskPrimitive2D containing the up-to-now created primitives, but 990 // this was done before. While this does not lead to wrong primitive 991 // representations of the metafile data, it creates unneccesarily expensive 992 // representations. Just detecting when no really 'new' ClipPolyPolygon gets set 993 // solves the problem. 994 995 if(!rPropertyHolders.Current().getClipPolyPolygonActive() && !bNewActive) 996 { 997 // no active ClipPolyPolygon exchanged by no new one, done 998 return; 999 } 1000 1001 if(rPropertyHolders.Current().getClipPolyPolygonActive() && bNewActive) 1002 { 1003 // active ClipPolyPolygon and new active ClipPolyPolygon 1004 if(rPropertyHolders.Current().getClipPolyPolygon() == rClipPolyPolygon) 1005 { 1006 // new is the same as old, done 1007 return; 1008 } 1009 } 1010 1011 // Here the old and the new are definitively different, maybe 1012 // old one and/or new one is not active. 1013 1014 // Handle deletion of old ClipPolyPolygon. The process evtl. created primitives which 1015 // belong to this active ClipPolyPolygon. These need to be embedded to a 1016 // MaskPrimitive2D accordingly. 1017 if(rPropertyHolders.Current().getClipPolyPolygonActive() && rTargetHolders.size() > 1) 1018 { 1019 drawinglayer::primitive2d::Primitive2DSequence aSubContent; 1020 1021 if(rPropertyHolders.Current().getClipPolyPolygon().count() 1022 && rTargetHolders.Current().size()) 1023 { 1024 aSubContent = rTargetHolders.Current().getPrimitive2DSequence( 1025 rPropertyHolders.Current()); 1026 } 1027 1028 rTargetHolders.Pop(); 1029 1030 if(aSubContent.hasElements()) 1031 { 1032 rTargetHolders.Current().append( 1033 new drawinglayer::primitive2d::GroupPrimitive2D( 1034 aSubContent)); 1035 } 1036 } 1037 1038 // apply new settings to current properties by setting 1039 // the new region now 1040 rPropertyHolders.Current().setClipPolyPolygonActive(bNewActive); 1041 1042 if(bNewActive) 1043 { 1044 rPropertyHolders.Current().setClipPolyPolygon(rClipPolyPolygon); 1045 1046 // prepare new content holder for new active region 1047 rTargetHolders.Push(); 1048 } 1049 } 1050 1051 /** helper to handle the change of RasterOp. It takes care of encapsulating all current 1052 geometry to the current RasterOp (if changed) and needs to be called on any RasterOp 1053 change. It will also start a new geometry target to embrace to the new RasterOp if 1054 a changuing RasterOp is used. Currently, ROP_XOR and ROP_INVERT are supported using 1055 InvertPrimitive2D, and ROP_0 by using a ModifiedColorPrimitive2D to force to black paint 1056 */ 1057 void HandleNewRasterOp( 1058 RasterOp aRasterOp, 1059 TargetHolders& rTargetHolders, 1060 PropertyHolders& rPropertyHolders) 1061 { 1062 // check if currently active 1063 if(rPropertyHolders.Current().isRasterOpActive() && rTargetHolders.size() > 1) 1064 { 1065 drawinglayer::primitive2d::Primitive2DSequence aSubContent; 1066 1067 if(rTargetHolders.Current().size()) 1068 { 1069 aSubContent = rTargetHolders.Current().getPrimitive2DSequence(rPropertyHolders.Current()); 1070 } 1071 1072 rTargetHolders.Pop(); 1073 1074 if(aSubContent.hasElements()) 1075 { 1076 if(rPropertyHolders.Current().isRasterOpForceBlack()) 1077 { 1078 // force content to black 1079 rTargetHolders.Current().append( 1080 new drawinglayer::primitive2d::ModifiedColorPrimitive2D( 1081 aSubContent, 1082 basegfx::BColorModifier(basegfx::BColor(0.0, 0.0, 0.0)))); 1083 } 1084 else // if(rPropertyHolders.Current().isRasterOpInvert()) 1085 { 1086 // invert content 1087 rTargetHolders.Current().append( 1088 new drawinglayer::primitive2d::InvertPrimitive2D( 1089 aSubContent)); 1090 } 1091 } 1092 } 1093 1094 // apply new settings 1095 rPropertyHolders.Current().setRasterOp(aRasterOp); 1096 1097 // check if now active 1098 if(rPropertyHolders.Current().isRasterOpActive()) 1099 { 1100 // prepare new content holder for new invert 1101 rTargetHolders.Push(); 1102 } 1103 } 1104 1105 /** helper to create needed data to emulate the VCL Wallpaper Metafile action. 1106 It is a quite mighty action. This helper is for simple color filled background. 1107 */ 1108 drawinglayer::primitive2d::BasePrimitive2D* CreateColorWallpaper( 1109 const basegfx::B2DRange& rRange, 1110 const basegfx::BColor& rColor, 1111 PropertyHolder& rPropertyHolder) 1112 { 1113 basegfx::B2DPolygon aOutline(basegfx::tools::createPolygonFromRect(rRange)); 1114 aOutline.transform(rPropertyHolder.getTransformation()); 1115 1116 return new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D( 1117 basegfx::B2DPolyPolygon(aOutline), 1118 rColor); 1119 } 1120 1121 /** helper to create needed data to emulate the VCL Wallpaper Metafile action. 1122 It is a quite mighty action. This helper is for gradient filled background. 1123 */ 1124 drawinglayer::primitive2d::BasePrimitive2D* CreateGradientWallpaper( 1125 const basegfx::B2DRange& rRange, 1126 const Gradient& rGradient, 1127 PropertyHolder& rPropertyHolder) 1128 { 1129 const drawinglayer::attribute::FillGradientAttribute aAttribute(createFillGradientAttribute(rGradient)); 1130 1131 if(aAttribute.getStartColor() == aAttribute.getEndColor()) 1132 { 1133 // not really a gradient. Create filled rectangle 1134 return CreateColorWallpaper(rRange, aAttribute.getStartColor(), rPropertyHolder); 1135 } 1136 else 1137 { 1138 // really a gradient 1139 drawinglayer::primitive2d::BasePrimitive2D* pRetval = 1140 new drawinglayer::primitive2d::FillGradientPrimitive2D( 1141 rRange, 1142 aAttribute); 1143 1144 if(!rPropertyHolder.getTransformation().isIdentity()) 1145 { 1146 const drawinglayer::primitive2d::Primitive2DReference xPrim(pRetval); 1147 const drawinglayer::primitive2d::Primitive2DSequence xSeq(&xPrim, 1); 1148 1149 pRetval = new drawinglayer::primitive2d::TransformPrimitive2D( 1150 rPropertyHolder.getTransformation(), 1151 xSeq); 1152 } 1153 1154 return pRetval; 1155 } 1156 } 1157 1158 /** helper to create needed data to emulate the VCL Wallpaper Metafile action. 1159 It is a quite mighty action. This helper decides if color and/or gradient 1160 background is needed for the wnated bitmap fill and then creates the needed 1161 WallpaperBitmapPrimitive2D. This primitive was created for this purpose and 1162 takes over all needed logic of orientations and tiling. 1163 */ 1164 void CreateAndAppendBitmapWallpaper( 1165 basegfx::B2DRange aWallpaperRange, 1166 const Wallpaper& rWallpaper, 1167 TargetHolder& rTarget, 1168 PropertyHolder& rProperty) 1169 { 1170 const BitmapEx aBitmapEx(rWallpaper.GetBitmap()); 1171 const WallpaperStyle eWallpaperStyle(rWallpaper.GetStyle()); 1172 1173 // if bitmap visualisation is transparent, maybe background 1174 // needs to be filled. Create background 1175 if(aBitmapEx.IsTransparent() 1176 || (WALLPAPER_TILE != eWallpaperStyle && WALLPAPER_SCALE != eWallpaperStyle)) 1177 { 1178 if(rWallpaper.IsGradient()) 1179 { 1180 rTarget.append( 1181 CreateGradientWallpaper( 1182 aWallpaperRange, 1183 rWallpaper.GetGradient(), 1184 rProperty)); 1185 } 1186 else if(!rWallpaper.GetColor().GetTransparency()) 1187 { 1188 rTarget.append( 1189 CreateColorWallpaper( 1190 aWallpaperRange, 1191 rWallpaper.GetColor().getBColor(), 1192 rProperty)); 1193 } 1194 } 1195 1196 // use wallpaper rect if set 1197 if(rWallpaper.IsRect() && !rWallpaper.GetRect().IsEmpty()) 1198 { 1199 aWallpaperRange = basegfx::B2DRange( 1200 rWallpaper.GetRect().Left(), rWallpaper.GetRect().Top(), 1201 rWallpaper.GetRect().Right(), rWallpaper.GetRect().Bottom()); 1202 } 1203 1204 drawinglayer::primitive2d::BasePrimitive2D* pBitmapWallpaperFill = 1205 new drawinglayer::primitive2d::WallpaperBitmapPrimitive2D( 1206 aWallpaperRange, 1207 aBitmapEx, 1208 eWallpaperStyle); 1209 1210 if(rProperty.getTransformation().isIdentity()) 1211 { 1212 // add directly 1213 rTarget.append(pBitmapWallpaperFill); 1214 } 1215 else 1216 { 1217 // when a transformation is set, embed to it 1218 const drawinglayer::primitive2d::Primitive2DReference xPrim(pBitmapWallpaperFill); 1219 1220 rTarget.append( 1221 new drawinglayer::primitive2d::TransformPrimitive2D( 1222 rProperty.getTransformation(), 1223 drawinglayer::primitive2d::Primitive2DSequence(&xPrim, 1))); 1224 } 1225 } 1226 1227 /** helper to decide UnderlineAbove for text primitives */ 1228 bool isUnderlineAbove(const Font& rFont) 1229 { 1230 if(!rFont.IsVertical()) 1231 { 1232 return false; 1233 } 1234 1235 if((LANGUAGE_JAPANESE == rFont.GetLanguage()) || (LANGUAGE_JAPANESE == rFont.GetCJKContextLanguage())) 1236 { 1237 // the underline is right for Japanese only 1238 return true; 1239 } 1240 1241 return false; 1242 } 1243 1244 void createFontAttributeTransformAndAlignment( 1245 drawinglayer::attribute::FontAttribute& rFontAttribute, 1246 basegfx::B2DHomMatrix& rTextTransform, 1247 basegfx::B2DVector& rAlignmentOffset, 1248 PropertyHolder& rProperty) 1249 { 1250 const Font& rFont = rProperty.getFont(); 1251 basegfx::B2DVector aFontScaling; 1252 1253 rFontAttribute = drawinglayer::attribute::FontAttribute( 1254 drawinglayer::primitive2d::getFontAttributeFromVclFont( 1255 aFontScaling, 1256 rFont, 1257 0 != (rProperty.getLayoutMode() & TEXT_LAYOUT_BIDI_RTL), 1258 0 != (rProperty.getLayoutMode() & TEXT_LAYOUT_BIDI_STRONG))); 1259 1260 // add FontScaling 1261 rTextTransform.scale(aFontScaling.getX(), aFontScaling.getY()); 1262 1263 // take text align into account 1264 if(ALIGN_BASELINE != rFont.GetAlign()) 1265 { 1266 drawinglayer::primitive2d::TextLayouterDevice aTextLayouterDevice; 1267 aTextLayouterDevice.setFont(rFont); 1268 1269 if(ALIGN_TOP == rFont.GetAlign()) 1270 { 1271 rAlignmentOffset.setY(aTextLayouterDevice.getFontAscent()); 1272 } 1273 else // ALIGN_BOTTOM 1274 { 1275 rAlignmentOffset.setY(-aTextLayouterDevice.getFontDescent()); 1276 } 1277 1278 rTextTransform.translate(rAlignmentOffset.getX(), rAlignmentOffset.getY()); 1279 } 1280 1281 // add FontRotation (if used) 1282 if(rFont.GetOrientation()) 1283 { 1284 rTextTransform.rotate(-rFont.GetOrientation() * F_PI1800); 1285 } 1286 } 1287 1288 /** helper which takes complete care for creating the needed text primitives. It 1289 takes care of decorated stuff and all the geometry adaptions needed 1290 */ 1291 void proccessMetaTextAction( 1292 const Point& rTextStartPosition, 1293 const XubString& rText, 1294 sal_uInt16 nTextStart, 1295 sal_uInt16 nTextLength, 1296 const ::std::vector< double >& rDXArray, 1297 TargetHolder& rTarget, 1298 PropertyHolder& rProperty) 1299 { 1300 drawinglayer::primitive2d::BasePrimitive2D* pResult = 0; 1301 const Font& rFont = rProperty.getFont(); 1302 basegfx::B2DVector aAlignmentOffset(0.0, 0.0); 1303 1304 if(nTextLength) 1305 { 1306 drawinglayer::attribute::FontAttribute aFontAttribute; 1307 basegfx::B2DHomMatrix aTextTransform; 1308 1309 // fill parameters derived from current font 1310 createFontAttributeTransformAndAlignment( 1311 aFontAttribute, 1312 aTextTransform, 1313 aAlignmentOffset, 1314 rProperty); 1315 1316 // add TextStartPosition 1317 aTextTransform.translate(rTextStartPosition.X(), rTextStartPosition.Y()); 1318 1319 // prepare FontColor and Locale 1320 const basegfx::BColor aFontColor(rProperty.getTextColor()); 1321 const com::sun::star::lang::Locale aLocale(MsLangId::convertLanguageToLocale(rProperty.getLanguageType())); 1322 const bool bWordLineMode(rFont.IsWordLineMode()); 1323 1324 const bool bDecoratedIsNeeded( 1325 UNDERLINE_NONE != rFont.GetOverline() 1326 || UNDERLINE_NONE != rFont.GetUnderline() 1327 || STRIKEOUT_NONE != rFont.GetStrikeout() 1328 || EMPHASISMARK_NONE != (rFont.GetEmphasisMark() & EMPHASISMARK_STYLE) 1329 || RELIEF_NONE != rFont.GetRelief() 1330 || rFont.IsShadow() 1331 || bWordLineMode); 1332 1333 if(bDecoratedIsNeeded) 1334 { 1335 // prepare overline, underline and srikeout data 1336 const drawinglayer::primitive2d::TextLine eFontOverline(drawinglayer::primitive2d::mapFontUnderlineToTextLine(rFont.GetOverline())); 1337 const drawinglayer::primitive2d::TextLine eFontUnderline(drawinglayer::primitive2d::mapFontUnderlineToTextLine(rFont.GetUnderline())); 1338 const drawinglayer::primitive2d::TextStrikeout eTextStrikeout(drawinglayer::primitive2d::mapFontStrikeoutToTextStrikeout(rFont.GetStrikeout())); 1339 1340 // check UndelineAbove 1341 const bool bUnderlineAbove(drawinglayer::primitive2d::TEXT_LINE_NONE != eFontUnderline && isUnderlineAbove(rFont)); 1342 1343 // prepare emphasis mark data 1344 drawinglayer::primitive2d::TextEmphasisMark eTextEmphasisMark(drawinglayer::primitive2d::TEXT_EMPHASISMARK_NONE); 1345 1346 switch(rFont.GetEmphasisMark() & EMPHASISMARK_STYLE) 1347 { 1348 case EMPHASISMARK_DOT : eTextEmphasisMark = drawinglayer::primitive2d::TEXT_EMPHASISMARK_DOT; break; 1349 case EMPHASISMARK_CIRCLE : eTextEmphasisMark = drawinglayer::primitive2d::TEXT_EMPHASISMARK_CIRCLE; break; 1350 case EMPHASISMARK_DISC : eTextEmphasisMark = drawinglayer::primitive2d::TEXT_EMPHASISMARK_DISC; break; 1351 case EMPHASISMARK_ACCENT : eTextEmphasisMark = drawinglayer::primitive2d::TEXT_EMPHASISMARK_ACCENT; break; 1352 } 1353 1354 const bool bEmphasisMarkAbove(rFont.GetEmphasisMark() & EMPHASISMARK_POS_ABOVE); 1355 const bool bEmphasisMarkBelow(rFont.GetEmphasisMark() & EMPHASISMARK_POS_BELOW); 1356 1357 // prepare font relief data 1358 drawinglayer::primitive2d::TextRelief eTextRelief(drawinglayer::primitive2d::TEXT_RELIEF_NONE); 1359 1360 switch(rFont.GetRelief()) 1361 { 1362 case RELIEF_EMBOSSED : eTextRelief = drawinglayer::primitive2d::TEXT_RELIEF_EMBOSSED; break; 1363 case RELIEF_ENGRAVED : eTextRelief = drawinglayer::primitive2d::TEXT_RELIEF_ENGRAVED; break; 1364 default : break; // RELIEF_NONE, FontRelief_FORCE_EQUAL_SIZE 1365 } 1366 1367 // prepare shadow/outline data 1368 const bool bShadow(rFont.IsShadow()); 1369 1370 // TextDecoratedPortionPrimitive2D is needed, create one 1371 pResult = new drawinglayer::primitive2d::TextDecoratedPortionPrimitive2D( 1372 1373 // attributes for TextSimplePortionPrimitive2D 1374 aTextTransform, 1375 rText, 1376 nTextStart, 1377 nTextLength, 1378 rDXArray, 1379 aFontAttribute, 1380 aLocale, 1381 aFontColor, 1382 1383 // attributes for TextDecoratedPortionPrimitive2D 1384 rProperty.getOverlineColorActive() ? rProperty.getOverlineColor() : aFontColor, 1385 rProperty.getTextLineColorActive() ? rProperty.getTextLineColor() : aFontColor, 1386 eFontOverline, 1387 eFontUnderline, 1388 bUnderlineAbove, 1389 eTextStrikeout, 1390 bWordLineMode, 1391 eTextEmphasisMark, 1392 bEmphasisMarkAbove, 1393 bEmphasisMarkBelow, 1394 eTextRelief, 1395 bShadow); 1396 } 1397 else 1398 { 1399 // TextSimplePortionPrimitive2D is enough 1400 pResult = new drawinglayer::primitive2d::TextSimplePortionPrimitive2D( 1401 aTextTransform, 1402 rText, 1403 nTextStart, 1404 nTextLength, 1405 rDXArray, 1406 aFontAttribute, 1407 aLocale, 1408 aFontColor); 1409 } 1410 } 1411 1412 if(pResult && rProperty.getTextFillColorActive()) 1413 { 1414 // text background is requested, add and encapsulate both to new primitive 1415 drawinglayer::primitive2d::TextLayouterDevice aTextLayouterDevice; 1416 aTextLayouterDevice.setFont(rFont); 1417 1418 // get text width 1419 double fTextWidth(0.0); 1420 1421 if(rDXArray.empty()) 1422 { 1423 fTextWidth = aTextLayouterDevice.getTextWidth(rText, nTextStart, nTextLength); 1424 } 1425 else 1426 { 1427 fTextWidth = rDXArray.back(); 1428 } 1429 1430 if(basegfx::fTools::more(fTextWidth, 0.0)) 1431 { 1432 // build text range 1433 const basegfx::B2DRange aTextRange( 1434 0.0, -aTextLayouterDevice.getFontAscent(), 1435 fTextWidth, aTextLayouterDevice.getFontDescent()); 1436 1437 // create Transform 1438 basegfx::B2DHomMatrix aTextTransform; 1439 1440 aTextTransform.translate(aAlignmentOffset.getX(), aAlignmentOffset.getY()); 1441 1442 if(rFont.GetOrientation()) 1443 { 1444 aTextTransform.rotate(-rFont.GetOrientation() * F_PI1800); 1445 } 1446 1447 aTextTransform.translate(rTextStartPosition.X(), rTextStartPosition.Y()); 1448 1449 // prepare Primitive2DSequence, put text in foreground 1450 drawinglayer::primitive2d::Primitive2DSequence aSequence(2); 1451 aSequence[1] = drawinglayer::primitive2d::Primitive2DReference(pResult); 1452 1453 // prepare filled polygon 1454 basegfx::B2DPolygon aOutline(basegfx::tools::createPolygonFromRect(aTextRange)); 1455 aOutline.transform(aTextTransform); 1456 1457 aSequence[0] = drawinglayer::primitive2d::Primitive2DReference( 1458 new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D( 1459 basegfx::B2DPolyPolygon(aOutline), 1460 rProperty.getTextFillColor())); 1461 1462 // set as group at pResult 1463 pResult = new drawinglayer::primitive2d::GroupPrimitive2D(aSequence); 1464 } 1465 } 1466 1467 if(pResult) 1468 { 1469 // add created text primitive to target 1470 if(rProperty.getTransformation().isIdentity()) 1471 { 1472 rTarget.append(pResult); 1473 } 1474 else 1475 { 1476 // when a transformation is set, embed to it 1477 const drawinglayer::primitive2d::Primitive2DReference aReference(pResult); 1478 1479 rTarget.append( 1480 new drawinglayer::primitive2d::TransformPrimitive2D( 1481 rProperty.getTransformation(), 1482 drawinglayer::primitive2d::Primitive2DSequence(&aReference, 1))); 1483 } 1484 } 1485 } 1486 1487 /** helper which takes complete care for creating the needed textLine primitives */ 1488 void proccessMetaTextLineAction( 1489 const MetaTextLineAction& rAction, 1490 TargetHolder& rTarget, 1491 PropertyHolder& rProperty) 1492 { 1493 const double fLineWidth(fabs((double)rAction.GetWidth())); 1494 1495 if(fLineWidth > 0.0) 1496 { 1497 const drawinglayer::primitive2d::TextLine aOverlineMode(drawinglayer::primitive2d::mapFontUnderlineToTextLine(rAction.GetOverline())); 1498 const drawinglayer::primitive2d::TextLine aUnderlineMode(drawinglayer::primitive2d::mapFontUnderlineToTextLine(rAction.GetUnderline())); 1499 const drawinglayer::primitive2d::TextStrikeout aTextStrikeout(drawinglayer::primitive2d::mapFontStrikeoutToTextStrikeout(rAction.GetStrikeout())); 1500 1501 const bool bOverlineUsed(drawinglayer::primitive2d::TEXT_LINE_NONE != aOverlineMode); 1502 const bool bUnderlineUsed(drawinglayer::primitive2d::TEXT_LINE_NONE != aUnderlineMode); 1503 const bool bStrikeoutUsed(drawinglayer::primitive2d::TEXT_STRIKEOUT_NONE != aTextStrikeout); 1504 1505 if(bUnderlineUsed || bStrikeoutUsed || bOverlineUsed) 1506 { 1507 std::vector< drawinglayer::primitive2d::BasePrimitive2D* > aTargetVector; 1508 basegfx::B2DVector aAlignmentOffset(0.0, 0.0); 1509 drawinglayer::attribute::FontAttribute aFontAttribute; 1510 basegfx::B2DHomMatrix aTextTransform; 1511 1512 // fill parameters derived from current font 1513 createFontAttributeTransformAndAlignment( 1514 aFontAttribute, 1515 aTextTransform, 1516 aAlignmentOffset, 1517 rProperty); 1518 1519 // add TextStartPosition 1520 aTextTransform.translate(rAction.GetStartPoint().X(), rAction.GetStartPoint().Y()); 1521 1522 // prepare TextLayouter (used in most cases) 1523 drawinglayer::primitive2d::TextLayouterDevice aTextLayouter; 1524 aTextLayouter.setFont(rProperty.getFont()); 1525 1526 if(bOverlineUsed) 1527 { 1528 // create primitive geometry for overline 1529 aTargetVector.push_back( 1530 new drawinglayer::primitive2d::TextLinePrimitive2D( 1531 aTextTransform, 1532 fLineWidth, 1533 aTextLayouter.getOverlineOffset(), 1534 aTextLayouter.getOverlineHeight(), 1535 aOverlineMode, 1536 rProperty.getOverlineColor())); 1537 } 1538 1539 if(bUnderlineUsed) 1540 { 1541 // create primitive geometry for underline 1542 aTargetVector.push_back( 1543 new drawinglayer::primitive2d::TextLinePrimitive2D( 1544 aTextTransform, 1545 fLineWidth, 1546 aTextLayouter.getUnderlineOffset(), 1547 aTextLayouter.getUnderlineHeight(), 1548 aUnderlineMode, 1549 rProperty.getTextLineColor())); 1550 } 1551 1552 if(bStrikeoutUsed) 1553 { 1554 // create primitive geometry for strikeout 1555 if(drawinglayer::primitive2d::TEXT_STRIKEOUT_SLASH == aTextStrikeout 1556 || drawinglayer::primitive2d::TEXT_STRIKEOUT_X == aTextStrikeout) 1557 { 1558 // strikeout with character 1559 const sal_Unicode aStrikeoutChar( 1560 drawinglayer::primitive2d::TEXT_STRIKEOUT_SLASH == aTextStrikeout ? '/' : 'X'); 1561 const com::sun::star::lang::Locale aLocale(MsLangId::convertLanguageToLocale( 1562 rProperty.getLanguageType())); 1563 1564 aTargetVector.push_back( 1565 new drawinglayer::primitive2d::TextCharacterStrikeoutPrimitive2D( 1566 aTextTransform, 1567 fLineWidth, 1568 rProperty.getTextColor(), 1569 aStrikeoutChar, 1570 aFontAttribute, 1571 aLocale)); 1572 } 1573 else 1574 { 1575 // strikeout with geometry 1576 aTargetVector.push_back( 1577 new drawinglayer::primitive2d::TextGeometryStrikeoutPrimitive2D( 1578 aTextTransform, 1579 fLineWidth, 1580 rProperty.getTextColor(), 1581 aTextLayouter.getUnderlineHeight(), 1582 aTextLayouter.getStrikeoutOffset(), 1583 aTextStrikeout)); 1584 } 1585 } 1586 1587 if(aTargetVector.size()) 1588 { 1589 // add created text primitive to target 1590 if(rProperty.getTransformation().isIdentity()) 1591 { 1592 for(sal_uInt32 a(0); a < aTargetVector.size(); a++) 1593 { 1594 rTarget.append(aTargetVector[a]); 1595 } 1596 } 1597 else 1598 { 1599 // when a transformation is set, embed to it 1600 drawinglayer::primitive2d::Primitive2DSequence xTargets(aTargetVector.size()); 1601 1602 for(sal_uInt32 a(0); a < aTargetVector.size(); a++) 1603 { 1604 xTargets[a] = drawinglayer::primitive2d::Primitive2DReference(aTargetVector[a]); 1605 } 1606 1607 rTarget.append( 1608 new drawinglayer::primitive2d::TransformPrimitive2D( 1609 rProperty.getTransformation(), 1610 xTargets)); 1611 } 1612 } 1613 } 1614 } 1615 1616 } 1617 1618 /** This is the main interpreter method. It is designed to handle the given Metafile 1619 completely inside the given context and target. It may use and modify the context and 1620 target. This design allows to call itself recursively wich adapted contexts and 1621 targets as e.g. needed for the META_FLOATTRANSPARENT_ACTION where the content is expressed 1622 as a metafile as sub-content. 1623 1624 This interpreter is as free of VCL functionality as possible. It uses VCL data classes 1625 (else reading the data would not be possible), but e.g. does NOT use a local OutputDevice 1626 as most other MetaFile interpreters/exporters do to hold and work with the current context. 1627 This is necessary to be able to get away from the strong internal VCL-binding. 1628 1629 It tries to combine e.g. pixel and/or point actions and to stitch together single line primitives 1630 where possible (which is not trivial with the possible line geometry definitions). 1631 1632 It tries to handle clipping no longer as Regions and spans of Rectangles, but as PolyPolygon 1633 ClipRegions with (where possible) high precision by using the best possible data quality 1634 from the Region. The Region is unavoidable as data container, but nowadays allows the transport 1635 of Polygon-based clip regions. Where this is not used, a Polygon is constructed from the 1636 Region ranges. All primitive clipping uses the MaskPrimitive2D with Polygon-based clipping. 1637 1638 I have marked the single MetaActions with: 1639 1640 SIMPLE, DONE: 1641 Simple, e.g nothing to do or value setting in the context 1642 1643 CHECKED, WORKS WELL: 1644 Thoroughly tested with extra written test code which created a replacement 1645 Metafile just to test this action in various combinations 1646 1647 NEEDS IMPLEMENTATION: 1648 Not implemented and asserted, but also no usage found, neither in own Metafile 1649 creations, nor in EMF/WMF imports (checked with a whole bunch of critical EMF/WMF 1650 bugdocs) 1651 1652 For more commens, see the single action implementations. 1653 */ 1654 void interpretMetafile( 1655 const GDIMetaFile& rMetaFile, 1656 TargetHolders& rTargetHolders, 1657 PropertyHolders& rPropertyHolders, 1658 const drawinglayer::geometry::ViewInformation2D& rViewInformation) 1659 { 1660 const sal_uInt32 nCount(rMetaFile.GetActionCount()); 1661 1662 for(sal_uInt32 nAction(0); nAction < nCount; nAction++) 1663 { 1664 MetaAction* pAction = rMetaFile.GetAction(nAction); 1665 1666 switch(pAction->GetType()) 1667 { 1668 case META_NULL_ACTION : 1669 { 1670 /** SIMPLE, DONE */ 1671 break; 1672 } 1673 case META_PIXEL_ACTION : 1674 { 1675 /** CHECKED, WORKS WELL */ 1676 std::vector< basegfx::B2DPoint > aPositions; 1677 Color aLastColor(COL_BLACK); 1678 1679 while(META_PIXEL_ACTION == pAction->GetType() && nAction < nCount) 1680 { 1681 const MetaPixelAction* pA = (const MetaPixelAction*)pAction; 1682 1683 if(pA->GetColor() != aLastColor) 1684 { 1685 if(aPositions.size()) 1686 { 1687 createPointArrayPrimitive(aPositions, rTargetHolders.Current(), rPropertyHolders.Current(), aLastColor.getBColor()); 1688 aPositions.clear(); 1689 } 1690 1691 aLastColor = pA->GetColor(); 1692 } 1693 1694 const Point& rPoint = pA->GetPoint(); 1695 aPositions.push_back(basegfx::B2DPoint(rPoint.X(), rPoint.Y())); 1696 nAction++; if(nAction < nCount) pAction = rMetaFile.GetAction(nAction); 1697 } 1698 1699 nAction--; 1700 1701 if(aPositions.size()) 1702 { 1703 createPointArrayPrimitive(aPositions, rTargetHolders.Current(), rPropertyHolders.Current(), aLastColor.getBColor()); 1704 } 1705 1706 break; 1707 } 1708 case META_POINT_ACTION : 1709 { 1710 /** CHECKED, WORKS WELL */ 1711 if(rPropertyHolders.Current().getLineColorActive()) 1712 { 1713 std::vector< basegfx::B2DPoint > aPositions; 1714 1715 while(META_POINT_ACTION == pAction->GetType() && nAction < nCount) 1716 { 1717 const MetaPointAction* pA = (const MetaPointAction*)pAction; 1718 const Point& rPoint = pA->GetPoint(); 1719 aPositions.push_back(basegfx::B2DPoint(rPoint.X(), rPoint.Y())); 1720 nAction++; if(nAction < nCount) pAction = rMetaFile.GetAction(nAction); 1721 } 1722 1723 nAction--; 1724 1725 if(aPositions.size()) 1726 { 1727 createPointArrayPrimitive(aPositions, rTargetHolders.Current(), rPropertyHolders.Current(), rPropertyHolders.Current().getLineColor()); 1728 } 1729 } 1730 1731 break; 1732 } 1733 case META_LINE_ACTION : 1734 { 1735 /** CHECKED, WORKS WELL */ 1736 if(rPropertyHolders.Current().getLineColorActive()) 1737 { 1738 basegfx::B2DPolygon aLinePolygon; 1739 LineInfo aLineInfo; 1740 1741 while(META_LINE_ACTION == pAction->GetType() && nAction < nCount) 1742 { 1743 const MetaLineAction* pA = (const MetaLineAction*)pAction; 1744 const Point& rStartPoint = pA->GetStartPoint(); 1745 const Point& rEndPoint = pA->GetEndPoint(); 1746 const basegfx::B2DPoint aStart(rStartPoint.X(), rStartPoint.Y()); 1747 const basegfx::B2DPoint aEnd(rEndPoint.X(), rEndPoint.Y()); 1748 1749 if(aLinePolygon.count()) 1750 { 1751 if(pA->GetLineInfo() == aLineInfo 1752 && aStart == aLinePolygon.getB2DPoint(aLinePolygon.count() - 1)) 1753 { 1754 aLinePolygon.append(aEnd); 1755 } 1756 else 1757 { 1758 aLineInfo.SetLineJoin(basegfx::B2DLINEJOIN_NONE); // It were lines; force to NONE 1759 createLinePrimitive(aLinePolygon, aLineInfo, rTargetHolders.Current(), rPropertyHolders.Current()); 1760 aLinePolygon.clear(); 1761 aLineInfo = pA->GetLineInfo(); 1762 aLinePolygon.append(aStart); 1763 aLinePolygon.append(aEnd); 1764 } 1765 } 1766 else 1767 { 1768 aLineInfo = pA->GetLineInfo(); 1769 aLinePolygon.append(aStart); 1770 aLinePolygon.append(aEnd); 1771 } 1772 1773 nAction++; if(nAction < nCount) pAction = rMetaFile.GetAction(nAction); 1774 } 1775 1776 nAction--; 1777 1778 if(aLinePolygon.count()) 1779 { 1780 aLineInfo.SetLineJoin(basegfx::B2DLINEJOIN_NONE); // It were lines; force to NONE 1781 createLinePrimitive(aLinePolygon, aLineInfo, rTargetHolders.Current(), rPropertyHolders.Current()); 1782 } 1783 } 1784 1785 break; 1786 } 1787 case META_RECT_ACTION : 1788 { 1789 /** CHECKED, WORKS WELL */ 1790 if(rPropertyHolders.Current().getLineOrFillActive()) 1791 { 1792 const MetaRectAction* pA = (const MetaRectAction*)pAction; 1793 const Rectangle& rRectangle = pA->GetRect(); 1794 1795 if(!rRectangle.IsEmpty()) 1796 { 1797 const basegfx::B2DRange aRange(rRectangle.Left(), rRectangle.Top(), rRectangle.Right(), rRectangle.Bottom()); 1798 1799 if(!aRange.isEmpty()) 1800 { 1801 const basegfx::B2DPolygon aOutline(basegfx::tools::createPolygonFromRect(aRange)); 1802 createHairlineAndFillPrimitive(aOutline, rTargetHolders.Current(), rPropertyHolders.Current()); 1803 } 1804 } 1805 } 1806 1807 break; 1808 } 1809 case META_ROUNDRECT_ACTION : 1810 { 1811 /** CHECKED, WORKS WELL */ 1812 /** The original OutputDevice::DrawRect paints nothing when nHor or nVer is zero; but just 1813 because the tools::Polygon operator creating the rounding does produce nonsense. I assume 1814 this an error and create an unrounded rectangle in that case (implicit in 1815 createPolygonFromRect) 1816 */ 1817 if(rPropertyHolders.Current().getLineOrFillActive()) 1818 { 1819 const MetaRoundRectAction* pA = (const MetaRoundRectAction*)pAction; 1820 const Rectangle& rRectangle = pA->GetRect(); 1821 1822 if(!rRectangle.IsEmpty()) 1823 { 1824 const basegfx::B2DRange aRange(rRectangle.Left(), rRectangle.Top(), rRectangle.Right(), rRectangle.Bottom()); 1825 1826 if(!aRange.isEmpty()) 1827 { 1828 const sal_uInt32 nHor(pA->GetHorzRound()); 1829 const sal_uInt32 nVer(pA->GetVertRound()); 1830 basegfx::B2DPolygon aOutline; 1831 1832 if(nHor || nVer) 1833 { 1834 double fRadiusX((nHor * 2.0) / (aRange.getWidth() > 0.0 ? aRange.getWidth() : 1.0)); 1835 double fRadiusY((nVer * 2.0) / (aRange.getHeight() > 0.0 ? aRange.getHeight() : 1.0)); 1836 fRadiusX = std::max(0.0, std::min(1.0, fRadiusX)); 1837 fRadiusY = std::max(0.0, std::min(1.0, fRadiusY)); 1838 1839 aOutline = basegfx::tools::createPolygonFromRect(aRange, fRadiusX, fRadiusY); 1840 } 1841 else 1842 { 1843 aOutline = basegfx::tools::createPolygonFromRect(aRange); 1844 } 1845 1846 createHairlineAndFillPrimitive(aOutline, rTargetHolders.Current(), rPropertyHolders.Current()); 1847 } 1848 } 1849 } 1850 1851 break; 1852 } 1853 case META_ELLIPSE_ACTION : 1854 { 1855 /** CHECKED, WORKS WELL */ 1856 if(rPropertyHolders.Current().getLineOrFillActive()) 1857 { 1858 const MetaEllipseAction* pA = (const MetaEllipseAction*)pAction; 1859 const Rectangle& rRectangle = pA->GetRect(); 1860 1861 if(!rRectangle.IsEmpty()) 1862 { 1863 const basegfx::B2DRange aRange(rRectangle.Left(), rRectangle.Top(), rRectangle.Right(), rRectangle.Bottom()); 1864 1865 if(!aRange.isEmpty()) 1866 { 1867 const basegfx::B2DPolygon aOutline(basegfx::tools::createPolygonFromEllipse( 1868 aRange.getCenter(), aRange.getWidth() * 0.5, aRange.getHeight() * 0.5)); 1869 1870 createHairlineAndFillPrimitive(aOutline, rTargetHolders.Current(), rPropertyHolders.Current()); 1871 } 1872 } 1873 } 1874 1875 break; 1876 } 1877 case META_ARC_ACTION : 1878 { 1879 /** CHECKED, WORKS WELL */ 1880 if(rPropertyHolders.Current().getLineColorActive()) 1881 { 1882 const MetaArcAction* pA = (const MetaArcAction*)pAction; 1883 const Polygon aToolsPoly(pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint(), POLY_ARC); 1884 const basegfx::B2DPolygon aOutline(aToolsPoly.getB2DPolygon()); 1885 1886 createHairlinePrimitive(aOutline, rTargetHolders.Current(), rPropertyHolders.Current()); 1887 } 1888 1889 break; 1890 } 1891 case META_PIE_ACTION : 1892 { 1893 /** CHECKED, WORKS WELL */ 1894 if(rPropertyHolders.Current().getLineOrFillActive()) 1895 { 1896 const MetaPieAction* pA = (const MetaPieAction*)pAction; 1897 const Polygon aToolsPoly(pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint(), POLY_PIE); 1898 const basegfx::B2DPolygon aOutline(aToolsPoly.getB2DPolygon()); 1899 1900 createHairlineAndFillPrimitive(aOutline, rTargetHolders.Current(), rPropertyHolders.Current()); 1901 } 1902 1903 break; 1904 } 1905 case META_CHORD_ACTION : 1906 { 1907 /** CHECKED, WORKS WELL */ 1908 if(rPropertyHolders.Current().getLineOrFillActive()) 1909 { 1910 const MetaChordAction* pA = (const MetaChordAction*)pAction; 1911 const Polygon aToolsPoly(pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint(), POLY_CHORD); 1912 const basegfx::B2DPolygon aOutline(aToolsPoly.getB2DPolygon()); 1913 1914 createHairlineAndFillPrimitive(aOutline, rTargetHolders.Current(), rPropertyHolders.Current()); 1915 } 1916 1917 break; 1918 } 1919 case META_POLYLINE_ACTION : 1920 { 1921 /** CHECKED, WORKS WELL */ 1922 if(rPropertyHolders.Current().getLineColorActive()) 1923 { 1924 const MetaPolyLineAction* pA = (const MetaPolyLineAction*)pAction; 1925 createLinePrimitive(pA->GetPolygon().getB2DPolygon(), pA->GetLineInfo(), rTargetHolders.Current(), rPropertyHolders.Current()); 1926 } 1927 1928 break; 1929 } 1930 case META_POLYGON_ACTION : 1931 { 1932 /** CHECKED, WORKS WELL */ 1933 if(rPropertyHolders.Current().getLineOrFillActive()) 1934 { 1935 const MetaPolygonAction* pA = (const MetaPolygonAction*)pAction; 1936 basegfx::B2DPolygon aOutline(pA->GetPolygon().getB2DPolygon()); 1937 1938 // the metafile play interprets the polygons from MetaPolygonAction 1939 // always as closed and always paints an edge from last to first point, 1940 // so force to closed here to emulate that 1941 if(aOutline.count() > 1 && !aOutline.isClosed()) 1942 { 1943 aOutline.setClosed(true); 1944 } 1945 1946 createHairlineAndFillPrimitive(aOutline, rTargetHolders.Current(), rPropertyHolders.Current()); 1947 } 1948 1949 break; 1950 } 1951 case META_POLYPOLYGON_ACTION : 1952 { 1953 /** CHECKED, WORKS WELL */ 1954 if(rPropertyHolders.Current().getLineOrFillActive()) 1955 { 1956 const MetaPolyPolygonAction* pA = (const MetaPolyPolygonAction*)pAction; 1957 basegfx::B2DPolyPolygon aPolyPolygonOutline(pA->GetPolyPolygon().getB2DPolyPolygon()); 1958 1959 // the metafile play interprets the single polygons from MetaPolyPolygonAction 1960 // always as closed and always paints an edge from last to first point, 1961 // so force to closed here to emulate that 1962 for(sal_uInt32 b(0); b < aPolyPolygonOutline.count(); b++) 1963 { 1964 basegfx::B2DPolygon aPolygonOutline(aPolyPolygonOutline.getB2DPolygon(b)); 1965 1966 if(aPolygonOutline.count() > 1 && !aPolygonOutline.isClosed()) 1967 { 1968 aPolygonOutline.setClosed(true); 1969 aPolyPolygonOutline.setB2DPolygon(b, aPolygonOutline); 1970 } 1971 } 1972 1973 createHairlineAndFillPrimitive(aPolyPolygonOutline, rTargetHolders.Current(), rPropertyHolders.Current()); 1974 } 1975 1976 break; 1977 } 1978 case META_TEXT_ACTION : 1979 { 1980 /** CHECKED, WORKS WELL */ 1981 const MetaTextAction* pA = (const MetaTextAction*)pAction; 1982 sal_uInt32 nTextLength(pA->GetLen()); 1983 const sal_uInt32 nTextIndex(pA->GetIndex()); 1984 const sal_uInt32 nStringLength(pA->GetText().Len()); 1985 1986 if(nTextLength + nTextIndex > nStringLength) 1987 { 1988 nTextLength = nStringLength - nTextIndex; 1989 } 1990 1991 if(nTextLength && rPropertyHolders.Current().getTextColorActive()) 1992 { 1993 const std::vector< double > aDXArray; 1994 proccessMetaTextAction( 1995 pA->GetPoint(), 1996 pA->GetText(), 1997 nTextIndex, 1998 nTextLength, 1999 aDXArray, 2000 rTargetHolders.Current(), 2001 rPropertyHolders.Current()); 2002 } 2003 2004 break; 2005 } 2006 case META_TEXTARRAY_ACTION : 2007 { 2008 /** CHECKED, WORKS WELL */ 2009 const MetaTextArrayAction* pA = (const MetaTextArrayAction*)pAction; 2010 sal_uInt32 nTextLength(pA->GetLen()); 2011 const sal_uInt32 nTextIndex(pA->GetIndex()); 2012 const sal_uInt32 nStringLength(pA->GetText().Len()); 2013 2014 if(nTextLength + nTextIndex > nStringLength) 2015 { 2016 nTextLength = nTextIndex > nStringLength ? 0 : nStringLength - nTextIndex; 2017 } 2018 2019 if(nTextLength && rPropertyHolders.Current().getTextColorActive()) 2020 { 2021 // preapare DXArray (if used) 2022 std::vector< double > aDXArray; 2023 sal_Int32* pDXArray = pA->GetDXArray(); 2024 2025 if(pDXArray) 2026 { 2027 aDXArray.reserve(nTextLength); 2028 2029 for(sal_uInt32 a(0); a < nTextLength; a++) 2030 { 2031 aDXArray.push_back((double)(*(pDXArray + a))); 2032 } 2033 } 2034 2035 proccessMetaTextAction( 2036 pA->GetPoint(), 2037 pA->GetText(), 2038 nTextIndex, 2039 nTextLength, 2040 aDXArray, 2041 rTargetHolders.Current(), 2042 rPropertyHolders.Current()); 2043 } 2044 2045 break; 2046 } 2047 case META_STRETCHTEXT_ACTION : 2048 { 2049 // #i108440# StarMath uses MetaStretchTextAction, thus support is needed. 2050 // It looks as if it pretty never really uses a width different from 2051 // the default text-layout width, but it's not possible to be sure. 2052 // Implemented getting the DXArray and checking for scale at all. If 2053 // scale is more than 3.5% different, scale the DXArray before usage. 2054 // New status: 2055 2056 /** CHECKED, WORKS WELL */ 2057 const MetaStretchTextAction* pA = (const MetaStretchTextAction*)pAction; 2058 sal_uInt32 nTextLength(pA->GetLen()); 2059 const sal_uInt32 nTextIndex(pA->GetIndex()); 2060 const sal_uInt32 nStringLength(pA->GetText().Len()); 2061 2062 if(nTextLength + nTextIndex > nStringLength) 2063 { 2064 nTextLength = nStringLength - nTextIndex; 2065 } 2066 2067 if(nTextLength && rPropertyHolders.Current().getTextColorActive()) 2068 { 2069 drawinglayer::primitive2d::TextLayouterDevice aTextLayouterDevice; 2070 aTextLayouterDevice.setFont(rPropertyHolders.Current().getFont()); 2071 2072 ::std::vector< double > aTextArray( 2073 aTextLayouterDevice.getTextArray( 2074 pA->GetText(), 2075 nTextIndex, 2076 nTextLength)); 2077 2078 if(!aTextArray.empty()) 2079 { 2080 const double fTextLength(aTextArray.back()); 2081 2082 if(0.0 != fTextLength && pA->GetWidth()) 2083 { 2084 const double fRelative(pA->GetWidth() / fTextLength); 2085 2086 if(fabs(fRelative - 1.0) >= 0.035) 2087 { 2088 // when derivation is more than 3,5% from default text size, 2089 // scale the DXArray 2090 for(sal_uInt32 a(0); a < aTextArray.size(); a++) 2091 { 2092 aTextArray[a] *= fRelative; 2093 } 2094 } 2095 } 2096 } 2097 2098 proccessMetaTextAction( 2099 pA->GetPoint(), 2100 pA->GetText(), 2101 nTextIndex, 2102 nTextLength, 2103 aTextArray, 2104 rTargetHolders.Current(), 2105 rPropertyHolders.Current()); 2106 } 2107 2108 break; 2109 } 2110 case META_TEXTRECT_ACTION : 2111 { 2112 /** CHECKED, WORKS WELL */ 2113 // OSL_ENSURE(false, "META_TEXTRECT_ACTION requested (!)"); 2114 const MetaTextRectAction* pA = (const MetaTextRectAction*)pAction; 2115 const Rectangle& rRectangle = pA->GetRect(); 2116 const sal_uInt32 nStringLength(pA->GetText().Len()); 2117 2118 if(!rRectangle.IsEmpty() && 0 != nStringLength) 2119 { 2120 // The problem with this action is that it describes unlayouted text 2121 // and the layout capabilities are in EditEngine/Outliner in SVX. The 2122 // same problem is true for VCL which internally has implementations 2123 // to layout text in this case. There exists even a call 2124 // OutputDevice::AddTextRectActions(...) to create the needed actions 2125 // as 'sub-content' of a Metafile. Unfortunately i do not have an 2126 // OutputDevice here since this interpreter tries to work without 2127 // VCL AFAP. 2128 // Since AddTextRectActions is the only way as long as we do not have 2129 // a simple text layouter available, i will try to add it to the 2130 // TextLayouterDevice isloation. 2131 drawinglayer::primitive2d::TextLayouterDevice aTextLayouterDevice; 2132 aTextLayouterDevice.setFont(rPropertyHolders.Current().getFont()); 2133 GDIMetaFile aGDIMetaFile; 2134 2135 aTextLayouterDevice.addTextRectActions( 2136 rRectangle, pA->GetText(), pA->GetStyle(), aGDIMetaFile); 2137 2138 if(aGDIMetaFile.GetActionCount()) 2139 { 2140 // cerate sub-content 2141 drawinglayer::primitive2d::Primitive2DSequence xSubContent; 2142 { 2143 rTargetHolders.Push(); 2144 // #i# for sub-Mteafile contents, do start with new, default render state 2145 rPropertyHolders.PushDefault(); 2146 interpretMetafile(aGDIMetaFile, rTargetHolders, rPropertyHolders, rViewInformation); 2147 xSubContent = rTargetHolders.Current().getPrimitive2DSequence(rPropertyHolders.Current()); 2148 rPropertyHolders.Pop(); 2149 rTargetHolders.Pop(); 2150 } 2151 2152 if(xSubContent.hasElements()) 2153 { 2154 // add with transformation 2155 rTargetHolders.Current().append( 2156 new drawinglayer::primitive2d::TransformPrimitive2D( 2157 rPropertyHolders.Current().getTransformation(), 2158 xSubContent)); 2159 } 2160 } 2161 } 2162 2163 break; 2164 } 2165 case META_BMP_ACTION : 2166 { 2167 /** CHECKED, WORKS WELL */ 2168 const MetaBmpAction* pA = (const MetaBmpAction*)pAction; 2169 const BitmapEx aBitmapEx(pA->GetBitmap()); 2170 2171 createBitmapExPrimitive(aBitmapEx, pA->GetPoint(), rTargetHolders.Current(), rPropertyHolders.Current()); 2172 2173 break; 2174 } 2175 case META_BMPSCALE_ACTION : 2176 { 2177 /** CHECKED, WORKS WELL */ 2178 const MetaBmpScaleAction* pA = (const MetaBmpScaleAction*)pAction; 2179 const Bitmap aBitmapEx(pA->GetBitmap()); 2180 2181 createBitmapExPrimitive(aBitmapEx, pA->GetPoint(), pA->GetSize(), rTargetHolders.Current(), rPropertyHolders.Current()); 2182 2183 break; 2184 } 2185 case META_BMPSCALEPART_ACTION : 2186 { 2187 /** CHECKED, WORKS WELL */ 2188 const MetaBmpScalePartAction* pA = (const MetaBmpScalePartAction*)pAction; 2189 const Bitmap& rBitmap = pA->GetBitmap(); 2190 2191 if(!rBitmap.IsEmpty()) 2192 { 2193 Bitmap aCroppedBitmap(rBitmap); 2194 const Rectangle aCropRectangle(pA->GetSrcPoint(), pA->GetSrcSize()); 2195 2196 if(!aCropRectangle.IsEmpty()) 2197 { 2198 aCroppedBitmap.Crop(aCropRectangle); 2199 } 2200 2201 const BitmapEx aCroppedBitmapEx(aCroppedBitmap); 2202 createBitmapExPrimitive(aCroppedBitmapEx, pA->GetDestPoint(), pA->GetDestSize(), rTargetHolders.Current(), rPropertyHolders.Current()); 2203 } 2204 2205 break; 2206 } 2207 case META_BMPEX_ACTION : 2208 { 2209 /** CHECKED, WORKS WELL: Simply same as META_BMP_ACTION */ 2210 const MetaBmpExAction* pA = (const MetaBmpExAction*)pAction; 2211 const BitmapEx& rBitmapEx = pA->GetBitmapEx(); 2212 2213 createBitmapExPrimitive(rBitmapEx, pA->GetPoint(), rTargetHolders.Current(), rPropertyHolders.Current()); 2214 2215 break; 2216 } 2217 case META_BMPEXSCALE_ACTION : 2218 { 2219 /** CHECKED, WORKS WELL: Simply same as META_BMPSCALE_ACTION */ 2220 const MetaBmpExScaleAction* pA = (const MetaBmpExScaleAction*)pAction; 2221 const BitmapEx& rBitmapEx = pA->GetBitmapEx(); 2222 2223 createBitmapExPrimitive(rBitmapEx, pA->GetPoint(), pA->GetSize(), rTargetHolders.Current(), rPropertyHolders.Current()); 2224 2225 break; 2226 } 2227 case META_BMPEXSCALEPART_ACTION : 2228 { 2229 /** CHECKED, WORKS WELL: Simply same as META_BMPSCALEPART_ACTION */ 2230 const MetaBmpExScalePartAction* pA = (const MetaBmpExScalePartAction*)pAction; 2231 const BitmapEx& rBitmapEx = pA->GetBitmapEx(); 2232 2233 if(!rBitmapEx.IsEmpty()) 2234 { 2235 BitmapEx aCroppedBitmapEx(rBitmapEx); 2236 const Rectangle aCropRectangle(pA->GetSrcPoint(), pA->GetSrcSize()); 2237 2238 if(!aCropRectangle.IsEmpty()) 2239 { 2240 aCroppedBitmapEx.Crop(aCropRectangle); 2241 } 2242 2243 createBitmapExPrimitive(aCroppedBitmapEx, pA->GetDestPoint(), pA->GetDestSize(), rTargetHolders.Current(), rPropertyHolders.Current()); 2244 } 2245 2246 break; 2247 } 2248 case META_MASK_ACTION : 2249 { 2250 /** CHECKED, WORKS WELL: Simply same as META_BMP_ACTION */ 2251 const MetaMaskAction* pA = (const MetaMaskAction*)pAction; 2252 const BitmapEx aBitmapEx(createMaskBmpEx(pA->GetBitmap(), pA->GetColor())); 2253 2254 createBitmapExPrimitive(aBitmapEx, pA->GetPoint(), rTargetHolders.Current(), rPropertyHolders.Current()); 2255 2256 break; 2257 } 2258 case META_MASKSCALE_ACTION : 2259 { 2260 /** CHECKED, WORKS WELL: Simply same as META_BMPSCALE_ACTION */ 2261 const MetaMaskScaleAction* pA = (const MetaMaskScaleAction*)pAction; 2262 const BitmapEx aBitmapEx(createMaskBmpEx(pA->GetBitmap(), pA->GetColor())); 2263 2264 createBitmapExPrimitive(aBitmapEx, pA->GetPoint(), pA->GetSize(), rTargetHolders.Current(), rPropertyHolders.Current()); 2265 2266 break; 2267 } 2268 case META_MASKSCALEPART_ACTION : 2269 { 2270 /** CHECKED, WORKS WELL: Simply same as META_BMPSCALEPART_ACTION */ 2271 const MetaMaskScalePartAction* pA = (const MetaMaskScalePartAction*)pAction; 2272 const Bitmap& rBitmap = pA->GetBitmap(); 2273 2274 if(!rBitmap.IsEmpty()) 2275 { 2276 Bitmap aCroppedBitmap(rBitmap); 2277 const Rectangle aCropRectangle(pA->GetSrcPoint(), pA->GetSrcSize()); 2278 2279 if(!aCropRectangle.IsEmpty()) 2280 { 2281 aCroppedBitmap.Crop(aCropRectangle); 2282 } 2283 2284 const BitmapEx aCroppedBitmapEx(createMaskBmpEx(aCroppedBitmap, pA->GetColor())); 2285 createBitmapExPrimitive(aCroppedBitmapEx, pA->GetDestPoint(), pA->GetDestSize(), rTargetHolders.Current(), rPropertyHolders.Current()); 2286 } 2287 2288 break; 2289 } 2290 case META_GRADIENT_ACTION : 2291 { 2292 /** CHECKED, WORKS WELL */ 2293 const MetaGradientAction* pA = (const MetaGradientAction*)pAction; 2294 const Rectangle& rRectangle = pA->GetRect(); 2295 2296 if(!rRectangle.IsEmpty()) 2297 { 2298 basegfx::B2DRange aRange(rRectangle.Left(), rRectangle.Top(), rRectangle.Right(), rRectangle.Bottom()); 2299 2300 if(!aRange.isEmpty()) 2301 { 2302 const Gradient& rGradient = pA->GetGradient(); 2303 const drawinglayer::attribute::FillGradientAttribute aAttribute(createFillGradientAttribute(rGradient)); 2304 basegfx::B2DPolyPolygon aOutline(basegfx::tools::createPolygonFromRect(aRange)); 2305 2306 if(aAttribute.getStartColor() == aAttribute.getEndColor()) 2307 { 2308 // not really a gradient. Create filled rectangle 2309 createFillPrimitive( 2310 aOutline, 2311 rTargetHolders.Current(), 2312 rPropertyHolders.Current()); 2313 } 2314 else 2315 { 2316 // really a gradient 2317 aRange.transform(rPropertyHolders.Current().getTransformation()); 2318 drawinglayer::primitive2d::Primitive2DSequence xGradient(1); 2319 2320 if(rPropertyHolders.Current().isRasterOpInvert()) 2321 { 2322 // use a special version of FillGradientPrimitive2D which creates 2323 // non-overlapping geometry on decomposition to makethe old XOR 2324 // paint 'trick' work. 2325 xGradient[0] = drawinglayer::primitive2d::Primitive2DReference( 2326 new drawinglayer::primitive2d::NonOverlappingFillGradientPrimitive2D( 2327 aRange, 2328 aAttribute)); 2329 } 2330 else 2331 { 2332 xGradient[0] = drawinglayer::primitive2d::Primitive2DReference( 2333 new drawinglayer::primitive2d::FillGradientPrimitive2D( 2334 aRange, 2335 aAttribute)); 2336 } 2337 2338 // #i112300# clip against polygon representing the rectangle from 2339 // the action. This is implicitely done using a temp Clipping in VCL 2340 // when a MetaGradientAction is executed 2341 aOutline.transform(rPropertyHolders.Current().getTransformation()); 2342 rTargetHolders.Current().append( 2343 new drawinglayer::primitive2d::MaskPrimitive2D( 2344 aOutline, 2345 xGradient)); 2346 } 2347 } 2348 } 2349 2350 break; 2351 } 2352 case META_HATCH_ACTION : 2353 { 2354 /** CHECKED, WORKS WELL */ 2355 const MetaHatchAction* pA = (const MetaHatchAction*)pAction; 2356 basegfx::B2DPolyPolygon aOutline(pA->GetPolyPolygon().getB2DPolyPolygon()); 2357 2358 if(aOutline.count()) 2359 { 2360 const Hatch& rHatch = pA->GetHatch(); 2361 const drawinglayer::attribute::FillHatchAttribute aAttribute(createFillHatchAttribute(rHatch)); 2362 2363 aOutline.transform(rPropertyHolders.Current().getTransformation()); 2364 2365 const basegfx::B2DRange aObjectRange(aOutline.getB2DRange()); 2366 const drawinglayer::primitive2d::Primitive2DReference aFillHatch( 2367 new drawinglayer::primitive2d::FillHatchPrimitive2D( 2368 aObjectRange, 2369 basegfx::BColor(), 2370 aAttribute)); 2371 2372 rTargetHolders.Current().append( 2373 new drawinglayer::primitive2d::MaskPrimitive2D( 2374 aOutline, 2375 drawinglayer::primitive2d::Primitive2DSequence(&aFillHatch, 1))); 2376 } 2377 2378 break; 2379 } 2380 case META_WALLPAPER_ACTION : 2381 { 2382 /** CHECKED, WORKS WELL */ 2383 const MetaWallpaperAction* pA = (const MetaWallpaperAction*)pAction; 2384 Rectangle aWallpaperRectangle(pA->GetRect()); 2385 2386 if(!aWallpaperRectangle.IsEmpty()) 2387 { 2388 const Wallpaper& rWallpaper = pA->GetWallpaper(); 2389 const WallpaperStyle eWallpaperStyle(rWallpaper.GetStyle()); 2390 basegfx::B2DRange aWallpaperRange( 2391 aWallpaperRectangle.Left(), aWallpaperRectangle.Top(), 2392 aWallpaperRectangle.Right(), aWallpaperRectangle.Bottom()); 2393 2394 if(WALLPAPER_NULL != eWallpaperStyle) 2395 { 2396 if(rWallpaper.IsBitmap()) 2397 { 2398 // create bitmap background. Caution: This 2399 // also will create gradient/color background(s) 2400 // when the bitmap is transparent or not tiled 2401 CreateAndAppendBitmapWallpaper( 2402 aWallpaperRange, 2403 rWallpaper, 2404 rTargetHolders.Current(), 2405 rPropertyHolders.Current()); 2406 } 2407 else if(rWallpaper.IsGradient()) 2408 { 2409 // create gradient background 2410 rTargetHolders.Current().append( 2411 CreateGradientWallpaper( 2412 aWallpaperRange, 2413 rWallpaper.GetGradient(), 2414 rPropertyHolders.Current())); 2415 } 2416 else if(!rWallpaper.GetColor().GetTransparency()) 2417 { 2418 // create color background 2419 rTargetHolders.Current().append( 2420 CreateColorWallpaper( 2421 aWallpaperRange, 2422 rWallpaper.GetColor().getBColor(), 2423 rPropertyHolders.Current())); 2424 } 2425 } 2426 } 2427 2428 break; 2429 } 2430 case META_CLIPREGION_ACTION : 2431 { 2432 /** CHECKED, WORKS WELL */ 2433 const MetaClipRegionAction* pA = (const MetaClipRegionAction*)pAction; 2434 2435 if(pA->IsClipping()) 2436 { 2437 // new clipping. Get PolyPolygon and transform with current transformation 2438 basegfx::B2DPolyPolygon aNewClipPolyPolygon(getB2DPolyPolygonFromRegion(pA->GetRegion())); 2439 2440 aNewClipPolyPolygon.transform(rPropertyHolders.Current().getTransformation()); 2441 HandleNewClipRegion(aNewClipPolyPolygon, rTargetHolders, rPropertyHolders); 2442 } 2443 else 2444 { 2445 // end clipping 2446 const basegfx::B2DPolyPolygon aEmptyPolyPolygon; 2447 2448 HandleNewClipRegion(aEmptyPolyPolygon, rTargetHolders, rPropertyHolders); 2449 } 2450 2451 break; 2452 } 2453 case META_ISECTRECTCLIPREGION_ACTION : 2454 { 2455 /** CHECKED, WORKS WELL */ 2456 const MetaISectRectClipRegionAction* pA = (const MetaISectRectClipRegionAction*)pAction; 2457 const Rectangle& rRectangle = pA->GetRect(); 2458 2459 if(rRectangle.IsEmpty()) 2460 { 2461 // intersect with empty rectangle will always give empty 2462 // ClipPolyPolygon; start new clipping with empty PolyPolygon 2463 const basegfx::B2DPolyPolygon aEmptyPolyPolygon; 2464 2465 HandleNewClipRegion(aEmptyPolyPolygon, rTargetHolders, rPropertyHolders); 2466 } 2467 else 2468 { 2469 // create transformed ClipRange 2470 basegfx::B2DRange aClipRange( 2471 rRectangle.Left(), rRectangle.Top(), 2472 rRectangle.Right(), rRectangle.Bottom()); 2473 2474 aClipRange.transform(rPropertyHolders.Current().getTransformation()); 2475 2476 if(rPropertyHolders.Current().getClipPolyPolygonActive()) 2477 { 2478 if(0 == rPropertyHolders.Current().getClipPolyPolygon().count()) 2479 { 2480 // nothing to do, empty active clipPolyPolygon will stay 2481 // empty when intersecting 2482 } 2483 else 2484 { 2485 // AND existing region and new ClipRange 2486 const basegfx::B2DPolyPolygon aOriginalPolyPolygon( 2487 rPropertyHolders.Current().getClipPolyPolygon()); 2488 basegfx::B2DPolyPolygon aClippedPolyPolygon; 2489 2490 if(aOriginalPolyPolygon.count()) 2491 { 2492 aClippedPolyPolygon = basegfx::tools::clipPolyPolygonOnRange( 2493 aOriginalPolyPolygon, 2494 aClipRange, 2495 true, 2496 false); 2497 } 2498 2499 if(aClippedPolyPolygon != aOriginalPolyPolygon) 2500 { 2501 // start new clipping with intersected region 2502 HandleNewClipRegion( 2503 aClippedPolyPolygon, 2504 rTargetHolders, 2505 rPropertyHolders); 2506 } 2507 } 2508 } 2509 else 2510 { 2511 // start new clipping with ClipRange 2512 const basegfx::B2DPolyPolygon aNewClipPolyPolygon( 2513 basegfx::tools::createPolygonFromRect(aClipRange)); 2514 2515 HandleNewClipRegion(aNewClipPolyPolygon, rTargetHolders, rPropertyHolders); 2516 } 2517 } 2518 2519 break; 2520 } 2521 case META_ISECTREGIONCLIPREGION_ACTION : 2522 { 2523 /** CHECKED, WORKS WELL */ 2524 const MetaISectRegionClipRegionAction* pA = (const MetaISectRegionClipRegionAction*)pAction; 2525 const Region& rNewRegion = pA->GetRegion(); 2526 2527 if(rNewRegion.IsEmpty()) 2528 { 2529 // intersect with empty region will always give empty 2530 // region; start new clipping with empty PolyPolygon 2531 const basegfx::B2DPolyPolygon aEmptyPolyPolygon; 2532 2533 HandleNewClipRegion(aEmptyPolyPolygon, rTargetHolders, rPropertyHolders); 2534 } 2535 else 2536 { 2537 // get new ClipPolyPolygon, transform it with current transformation 2538 basegfx::B2DPolyPolygon aNewClipPolyPolygon(getB2DPolyPolygonFromRegion(rNewRegion)); 2539 aNewClipPolyPolygon.transform(rPropertyHolders.Current().getTransformation()); 2540 2541 if(rPropertyHolders.Current().getClipPolyPolygonActive()) 2542 { 2543 if(0 == rPropertyHolders.Current().getClipPolyPolygon().count()) 2544 { 2545 // nothing to do, empty active clipPolyPolygon will stay empty 2546 // when intersecting with any region 2547 } 2548 else 2549 { 2550 // AND existing and new region 2551 const basegfx::B2DPolyPolygon aOriginalPolyPolygon( 2552 rPropertyHolders.Current().getClipPolyPolygon()); 2553 basegfx::B2DPolyPolygon aClippedPolyPolygon; 2554 2555 if(aOriginalPolyPolygon.count()) 2556 { 2557 aClippedPolyPolygon = basegfx::tools::clipPolyPolygonOnPolyPolygon( 2558 aOriginalPolyPolygon, aNewClipPolyPolygon, true, false); 2559 } 2560 2561 if(aClippedPolyPolygon != aOriginalPolyPolygon) 2562 { 2563 // start new clipping with intersected ClipPolyPolygon 2564 HandleNewClipRegion(aClippedPolyPolygon, rTargetHolders, rPropertyHolders); 2565 } 2566 } 2567 } 2568 else 2569 { 2570 // start new clipping with new ClipPolyPolygon 2571 HandleNewClipRegion(aNewClipPolyPolygon, rTargetHolders, rPropertyHolders); 2572 } 2573 } 2574 2575 break; 2576 } 2577 case META_MOVECLIPREGION_ACTION : 2578 { 2579 /** CHECKED, WORKS WELL */ 2580 const MetaMoveClipRegionAction* pA = (const MetaMoveClipRegionAction*)pAction; 2581 2582 if(rPropertyHolders.Current().getClipPolyPolygonActive()) 2583 { 2584 if(0 == rPropertyHolders.Current().getClipPolyPolygon().count()) 2585 { 2586 // nothing to do 2587 } 2588 else 2589 { 2590 const sal_Int32 nHor(pA->GetHorzMove()); 2591 const sal_Int32 nVer(pA->GetVertMove()); 2592 2593 if(0 != nHor || 0 != nVer) 2594 { 2595 // prepare translation, add current transformation 2596 basegfx::B2DVector aVector(pA->GetHorzMove(), pA->GetVertMove()); 2597 aVector *= rPropertyHolders.Current().getTransformation(); 2598 basegfx::B2DHomMatrix aTransform( 2599 basegfx::tools::createTranslateB2DHomMatrix(aVector)); 2600 2601 // transform existing region 2602 basegfx::B2DPolyPolygon aClipPolyPolygon( 2603 rPropertyHolders.Current().getClipPolyPolygon()); 2604 2605 aClipPolyPolygon.transform(aTransform); 2606 HandleNewClipRegion(aClipPolyPolygon, rTargetHolders, rPropertyHolders); 2607 } 2608 } 2609 } 2610 2611 break; 2612 } 2613 case META_LINECOLOR_ACTION : 2614 { 2615 /** CHECKED, WORKS WELL */ 2616 const MetaLineColorAction* pA = (const MetaLineColorAction*)pAction; 2617 const bool bActive(pA->IsSetting()); 2618 2619 rPropertyHolders.Current().setLineColorActive(bActive); 2620 if(bActive) 2621 rPropertyHolders.Current().setLineColor(pA->GetColor().getBColor()); 2622 2623 break; 2624 } 2625 case META_FILLCOLOR_ACTION : 2626 { 2627 /** CHECKED, WORKS WELL */ 2628 const MetaFillColorAction* pA = (const MetaFillColorAction*)pAction; 2629 const bool bActive(pA->IsSetting()); 2630 2631 rPropertyHolders.Current().setFillColorActive(bActive); 2632 if(bActive) 2633 rPropertyHolders.Current().setFillColor(pA->GetColor().getBColor()); 2634 2635 break; 2636 } 2637 case META_TEXTCOLOR_ACTION : 2638 { 2639 /** SIMPLE, DONE */ 2640 const MetaTextColorAction* pA = (const MetaTextColorAction*)pAction; 2641 const bool bActivate(COL_TRANSPARENT != pA->GetColor().GetColor()); 2642 2643 rPropertyHolders.Current().setTextColorActive(bActivate); 2644 rPropertyHolders.Current().setTextColor(pA->GetColor().getBColor()); 2645 2646 break; 2647 } 2648 case META_TEXTFILLCOLOR_ACTION : 2649 { 2650 /** SIMPLE, DONE */ 2651 const MetaTextFillColorAction* pA = (const MetaTextFillColorAction*)pAction; 2652 const bool bWithColorArgument(pA->IsSetting()); 2653 2654 if(bWithColorArgument) 2655 { 2656 // emulate OutputDevice::SetTextFillColor(...) WITH argument 2657 const Color& rFontFillColor = pA->GetColor(); 2658 rPropertyHolders.Current().setTextFillColor(rFontFillColor.getBColor()); 2659 rPropertyHolders.Current().setTextFillColorActive(COL_TRANSPARENT != rFontFillColor.GetColor()); 2660 } 2661 else 2662 { 2663 // emulate SetFillColor() <- NO argument (!) 2664 rPropertyHolders.Current().setTextFillColorActive(false); 2665 } 2666 2667 break; 2668 } 2669 case META_TEXTALIGN_ACTION : 2670 { 2671 /** SIMPLE, DONE */ 2672 const MetaTextAlignAction* pA = (const MetaTextAlignAction*)pAction; 2673 const TextAlign aNewTextAlign = pA->GetTextAlign(); 2674 2675 // TextAlign is applied to the current font (as in 2676 // OutputDevice::SetTextAlign which would be used when 2677 // playing the Metafile) 2678 if(rPropertyHolders.Current().getFont().GetAlign() != aNewTextAlign) 2679 { 2680 Font aNewFont(rPropertyHolders.Current().getFont()); 2681 aNewFont.SetAlign(aNewTextAlign); 2682 rPropertyHolders.Current().setFont(aNewFont); 2683 } 2684 2685 break; 2686 } 2687 case META_MAPMODE_ACTION : 2688 { 2689 /** CHECKED, WORKS WELL */ 2690 // the most necessary MapMode to be interpreted is MAP_RELATIVE, 2691 // but also the others may occur. Even not yet supported ones 2692 // may need to be added here later 2693 const MetaMapModeAction* pA = (const MetaMapModeAction*)pAction; 2694 const MapMode& rMapMode = pA->GetMapMode(); 2695 basegfx::B2DHomMatrix aMapping; 2696 2697 if(MAP_RELATIVE == rMapMode.GetMapUnit()) 2698 { 2699 aMapping = getTransformFromMapMode(rMapMode); 2700 } 2701 else 2702 { 2703 switch(rMapMode.GetMapUnit()) 2704 { 2705 case MAP_100TH_MM : 2706 { 2707 if(MAP_TWIP == rPropertyHolders.Current().getMapUnit()) 2708 { 2709 // MAP_TWIP -> MAP_100TH_MM 2710 const double fTwipTo100thMm(127.0 / 72.0); 2711 aMapping.scale(fTwipTo100thMm, fTwipTo100thMm); 2712 } 2713 break; 2714 } 2715 case MAP_TWIP : 2716 { 2717 if(MAP_100TH_MM == rPropertyHolders.Current().getMapUnit()) 2718 { 2719 // MAP_100TH_MM -> MAP_TWIP 2720 const double f100thMmToTwip(72.0 / 127.0); 2721 aMapping.scale(f100thMmToTwip, f100thMmToTwip); 2722 } 2723 break; 2724 } 2725 default : 2726 { 2727 OSL_ENSURE(false, "interpretMetafile: META_MAPMODE_ACTION with unsupported MapUnit (!)"); 2728 break; 2729 } 2730 } 2731 2732 aMapping = getTransformFromMapMode(rMapMode) * aMapping; 2733 rPropertyHolders.Current().setMapUnit(rMapMode.GetMapUnit()); 2734 } 2735 2736 if(!aMapping.isIdentity()) 2737 { 2738 aMapping = aMapping * rPropertyHolders.Current().getTransformation(); 2739 rPropertyHolders.Current().setTransformation(aMapping); 2740 } 2741 2742 break; 2743 } 2744 case META_FONT_ACTION : 2745 { 2746 /** SIMPLE, DONE */ 2747 const MetaFontAction* pA = (const MetaFontAction*)pAction; 2748 rPropertyHolders.Current().setFont(pA->GetFont()); 2749 Size aFontSize(pA->GetFont().GetSize()); 2750 2751 if(0 == aFontSize.Height()) 2752 { 2753 // this should not happen but i got Metafiles where this was the 2754 // case. A height needs to be guessed (similar to OutputDevice::ImplNewFont()) 2755 Font aCorrectedFont(pA->GetFont()); 2756 2757 // guess 16 pixel (as in VCL) 2758 aFontSize = Size(0, 16); 2759 2760 // convert to target MapUnit if not pixels 2761 aFontSize = Application::GetDefaultDevice()->LogicToLogic( 2762 aFontSize, MAP_PIXEL, rPropertyHolders.Current().getMapUnit()); 2763 2764 aCorrectedFont.SetSize(aFontSize); 2765 rPropertyHolders.Current().setFont(aCorrectedFont); 2766 } 2767 2768 // older Metafiles have no META_TEXTCOLOR_ACTION which defines 2769 // the FontColor now, so use the Font's color when not transparent 2770 const Color& rFontColor = pA->GetFont().GetColor(); 2771 const bool bActivate(COL_TRANSPARENT != rFontColor.GetColor()); 2772 2773 if(bActivate) 2774 { 2775 rPropertyHolders.Current().setTextColor(rFontColor.getBColor()); 2776 } 2777 2778 // caution: do NOT decativate here on transparet, see 2779 // OutputDevice::SetFont(..) for more info 2780 // rPropertyHolders.Current().setTextColorActive(bActivate); 2781 2782 // for fill color emulate a MetaTextFillColorAction with !transparent as bool, 2783 // see OutputDevice::SetFont(..) the if(mpMetaFile) case 2784 if(bActivate) 2785 { 2786 const Color& rFontFillColor = pA->GetFont().GetFillColor(); 2787 rPropertyHolders.Current().setTextFillColor(rFontFillColor.getBColor()); 2788 rPropertyHolders.Current().setTextFillColorActive(COL_TRANSPARENT != rFontFillColor.GetColor()); 2789 } 2790 else 2791 { 2792 rPropertyHolders.Current().setTextFillColorActive(false); 2793 } 2794 2795 break; 2796 } 2797 case META_PUSH_ACTION : 2798 { 2799 /** CHECKED, WORKS WELL */ 2800 const MetaPushAction* pA = (const MetaPushAction*)pAction; 2801 rPropertyHolders.Push(pA->GetFlags()); 2802 2803 break; 2804 } 2805 case META_POP_ACTION : 2806 { 2807 /** CHECKED, WORKS WELL */ 2808 const bool bRegionMayChange(rPropertyHolders.Current().getPushFlags() & PUSH_CLIPREGION); 2809 const bool bRasterOpMayChange(rPropertyHolders.Current().getPushFlags() & PUSH_RASTEROP); 2810 2811 if(bRegionMayChange && rPropertyHolders.Current().getClipPolyPolygonActive()) 2812 { 2813 // end evtl. clipping 2814 const basegfx::B2DPolyPolygon aEmptyPolyPolygon; 2815 2816 HandleNewClipRegion(aEmptyPolyPolygon, rTargetHolders, rPropertyHolders); 2817 } 2818 2819 if(bRasterOpMayChange && rPropertyHolders.Current().isRasterOpActive()) 2820 { 2821 // end evtl. RasterOp 2822 HandleNewRasterOp(ROP_OVERPAINT, rTargetHolders, rPropertyHolders); 2823 } 2824 2825 rPropertyHolders.Pop(); 2826 2827 if(bRasterOpMayChange && rPropertyHolders.Current().isRasterOpActive()) 2828 { 2829 // start evtl. RasterOp 2830 HandleNewRasterOp(rPropertyHolders.Current().getRasterOp(), rTargetHolders, rPropertyHolders); 2831 } 2832 2833 if(bRegionMayChange && rPropertyHolders.Current().getClipPolyPolygonActive()) 2834 { 2835 // start evtl. clipping 2836 HandleNewClipRegion( 2837 rPropertyHolders.Current().getClipPolyPolygon(), rTargetHolders, rPropertyHolders); 2838 } 2839 2840 break; 2841 } 2842 case META_RASTEROP_ACTION : 2843 { 2844 /** CHECKED, WORKS WELL */ 2845 const MetaRasterOpAction* pA = (const MetaRasterOpAction*)pAction; 2846 const RasterOp aRasterOp = pA->GetRasterOp(); 2847 2848 HandleNewRasterOp(aRasterOp, rTargetHolders, rPropertyHolders); 2849 2850 break; 2851 } 2852 case META_TRANSPARENT_ACTION : 2853 { 2854 /** CHECKED, WORKS WELL */ 2855 const MetaTransparentAction* pA = (const MetaTransparentAction*)pAction; 2856 const basegfx::B2DPolyPolygon aOutline(pA->GetPolyPolygon().getB2DPolyPolygon()); 2857 2858 if(aOutline.count()) 2859 { 2860 const sal_uInt16 nTransparence(pA->GetTransparence()); 2861 2862 if(0 == nTransparence) 2863 { 2864 // not transparent 2865 createHairlineAndFillPrimitive(aOutline, rTargetHolders.Current(), rPropertyHolders.Current()); 2866 } 2867 else if(nTransparence >= 100) 2868 { 2869 // fully or more than transparent 2870 } 2871 else 2872 { 2873 // transparent. Create new target 2874 rTargetHolders.Push(); 2875 2876 // create primitives there and get them 2877 createHairlineAndFillPrimitive(aOutline, rTargetHolders.Current(), rPropertyHolders.Current()); 2878 const drawinglayer::primitive2d::Primitive2DSequence aSubContent( 2879 rTargetHolders.Current().getPrimitive2DSequence(rPropertyHolders.Current())); 2880 2881 // back to old target 2882 rTargetHolders.Pop(); 2883 2884 if(aSubContent.hasElements()) 2885 { 2886 rTargetHolders.Current().append( 2887 new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D( 2888 aSubContent, 2889 nTransparence * 0.01)); 2890 } 2891 } 2892 } 2893 2894 break; 2895 } 2896 case META_EPS_ACTION : 2897 { 2898 /** CHECKED, WORKS WELL */ 2899 // To support this action, i have added a EpsPrimitive2D which will 2900 // by default decompose to the Metafile replacement data. To support 2901 // this EPS on screen, the renderer visualizing this has to support 2902 // that primitive and visualize the Eps file (e.g. printing) 2903 const MetaEPSAction* pA = (const MetaEPSAction*)pAction; 2904 const Rectangle aRectangle(pA->GetPoint(), pA->GetSize()); 2905 2906 if(!aRectangle.IsEmpty()) 2907 { 2908 // create object transform 2909 basegfx::B2DHomMatrix aObjectTransform; 2910 2911 aObjectTransform.set(0, 0, aRectangle.GetWidth()); 2912 aObjectTransform.set(1, 1, aRectangle.GetHeight()); 2913 aObjectTransform.set(0, 2, aRectangle.Left()); 2914 aObjectTransform.set(1, 2, aRectangle.Top()); 2915 2916 // add current transformation 2917 aObjectTransform = rPropertyHolders.Current().getTransformation() * aObjectTransform; 2918 2919 // embed using EpsPrimitive 2920 rTargetHolders.Current().append( 2921 new drawinglayer::primitive2d::EpsPrimitive2D( 2922 aObjectTransform, 2923 pA->GetLink(), 2924 pA->GetSubstitute())); 2925 } 2926 2927 break; 2928 } 2929 case META_REFPOINT_ACTION : 2930 { 2931 /** SIMPLE, DONE */ 2932 // only used for hatch and line pattern offsets, pretty much no longer 2933 // supported today 2934 // const MetaRefPointAction* pA = (const MetaRefPointAction*)pAction; 2935 break; 2936 } 2937 case META_TEXTLINECOLOR_ACTION : 2938 { 2939 /** SIMPLE, DONE */ 2940 const MetaTextLineColorAction* pA = (const MetaTextLineColorAction*)pAction; 2941 const bool bActive(pA->IsSetting()); 2942 2943 rPropertyHolders.Current().setTextLineColorActive(bActive); 2944 if(bActive) 2945 rPropertyHolders.Current().setTextLineColor(pA->GetColor().getBColor()); 2946 2947 break; 2948 } 2949 case META_TEXTLINE_ACTION : 2950 { 2951 /** CHECKED, WORKS WELL */ 2952 // actually creates overline, underline and strikeouts, so 2953 // these should be isolated from TextDecoratedPortionPrimitive2D 2954 // to own primitives. Done, available now. 2955 // 2956 // This Metaaction seems not to be used (was not used in any 2957 // checked files). It's used in combination with the current 2958 // Font. 2959 const MetaTextLineAction* pA = (const MetaTextLineAction*)pAction; 2960 2961 proccessMetaTextLineAction( 2962 *pA, 2963 rTargetHolders.Current(), 2964 rPropertyHolders.Current()); 2965 2966 break; 2967 } 2968 case META_FLOATTRANSPARENT_ACTION : 2969 { 2970 /** CHECKED, WORKS WELL */ 2971 const MetaFloatTransparentAction* pA = (const MetaFloatTransparentAction*)pAction; 2972 const Rectangle aTargetRectangle(pA->GetPoint(), pA->GetSize()); 2973 2974 if(!aTargetRectangle.IsEmpty()) 2975 { 2976 const GDIMetaFile& rContent = pA->GetGDIMetaFile(); 2977 2978 if(rContent.GetActionCount()) 2979 { 2980 // create the sub-content with no embedding specific to the 2981 // sub-metafile, this seems not to be used. 2982 drawinglayer::primitive2d::Primitive2DSequence xSubContent; 2983 { 2984 rTargetHolders.Push(); 2985 // #i# for sub-Mteafile contents, do start with new, default render state 2986 rPropertyHolders.PushDefault(); 2987 interpretMetafile(rContent, rTargetHolders, rPropertyHolders, rViewInformation); 2988 xSubContent = rTargetHolders.Current().getPrimitive2DSequence(rPropertyHolders.Current()); 2989 rPropertyHolders.Pop(); 2990 rTargetHolders.Pop(); 2991 } 2992 2993 if(xSubContent.hasElements()) 2994 { 2995 // check if gradient is a real gradient 2996 const Gradient& rGradient = pA->GetGradient(); 2997 const drawinglayer::attribute::FillGradientAttribute aAttribute(createFillGradientAttribute(rGradient)); 2998 2999 if(aAttribute.getStartColor() == aAttribute.getEndColor()) 3000 { 3001 // not really a gradient; create UnifiedTransparencePrimitive2D 3002 rTargetHolders.Current().append( 3003 new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D( 3004 xSubContent, 3005 aAttribute.getStartColor().luminance())); 3006 } 3007 else 3008 { 3009 // really a gradient. Create gradient sub-content (with correct scaling) 3010 basegfx::B2DRange aRange( 3011 aTargetRectangle.Left(), aTargetRectangle.Top(), 3012 aTargetRectangle.Right(), aTargetRectangle.Bottom()); 3013 aRange.transform(rPropertyHolders.Current().getTransformation()); 3014 3015 // prepare gradient for transparent content 3016 const drawinglayer::primitive2d::Primitive2DReference xTransparence( 3017 new drawinglayer::primitive2d::FillGradientPrimitive2D( 3018 aRange, 3019 aAttribute)); 3020 3021 // create transparence primitive 3022 rTargetHolders.Current().append( 3023 new drawinglayer::primitive2d::TransparencePrimitive2D( 3024 xSubContent, 3025 drawinglayer::primitive2d::Primitive2DSequence(&xTransparence, 1))); 3026 } 3027 } 3028 } 3029 } 3030 3031 break; 3032 } 3033 case META_GRADIENTEX_ACTION : 3034 { 3035 /** SIMPLE, DONE */ 3036 // This is only a data holder which is interpreted inside comment actions, 3037 // see META_COMMENT_ACTION for more info 3038 // const MetaGradientExAction* pA = (const MetaGradientExAction*)pAction; 3039 break; 3040 } 3041 case META_LAYOUTMODE_ACTION : 3042 { 3043 /** SIMPLE, DONE */ 3044 const MetaLayoutModeAction* pA = (const MetaLayoutModeAction*)pAction; 3045 rPropertyHolders.Current().setLayoutMode(pA->GetLayoutMode()); 3046 break; 3047 } 3048 case META_TEXTLANGUAGE_ACTION : 3049 { 3050 /** SIMPLE, DONE */ 3051 const MetaTextLanguageAction* pA = (const MetaTextLanguageAction*)pAction; 3052 rPropertyHolders.Current().setLanguageType(pA->GetTextLanguage()); 3053 break; 3054 } 3055 case META_OVERLINECOLOR_ACTION : 3056 { 3057 /** SIMPLE, DONE */ 3058 const MetaOverlineColorAction* pA = (const MetaOverlineColorAction*)pAction; 3059 const bool bActive(pA->IsSetting()); 3060 3061 rPropertyHolders.Current().setOverlineColorActive(bActive); 3062 if(bActive) 3063 rPropertyHolders.Current().setOverlineColor(pA->GetColor().getBColor()); 3064 3065 break; 3066 } 3067 case META_COMMENT_ACTION : 3068 { 3069 /** CHECKED, WORKS WELL */ 3070 // I already implemented 3071 // XPATHFILL_SEQ_BEGIN, XPATHFILL_SEQ_END 3072 // XPATHSTROKE_SEQ_BEGIN, XPATHSTROKE_SEQ_END, 3073 // but opted to remove these again; it works well without them 3074 // and makes the code less dependent from those Metafile Add-Ons 3075 const MetaCommentAction* pA = (const MetaCommentAction*)pAction; 3076 3077 if(COMPARE_EQUAL == pA->GetComment().CompareIgnoreCaseToAscii("XGRAD_SEQ_BEGIN")) 3078 { 3079 // XGRAD_SEQ_BEGIN, XGRAD_SEQ_END should be supported since the 3080 // pure recorded paint of the gradients uses the XOR paint functionality 3081 // ('trick'). This is (and will be) broblematic with AntAliasing, so it's 3082 // better to use this info 3083 const MetaGradientExAction* pMetaGradientExAction = 0; 3084 bool bDone(false); 3085 sal_uInt32 b(nAction + 1); 3086 3087 for(; !bDone && b < nCount; b++) 3088 { 3089 pAction = rMetaFile.GetAction(b); 3090 3091 if(META_GRADIENTEX_ACTION == pAction->GetType()) 3092 { 3093 pMetaGradientExAction = (const MetaGradientExAction*)pAction; 3094 } 3095 else if(META_COMMENT_ACTION == pAction->GetType()) 3096 { 3097 if(COMPARE_EQUAL == ((const MetaCommentAction*)pAction)->GetComment().CompareIgnoreCaseToAscii("XGRAD_SEQ_END")) 3098 { 3099 bDone = true; 3100 } 3101 } 3102 } 3103 3104 if(bDone && pMetaGradientExAction) 3105 { 3106 // consume actions and skip forward 3107 nAction = b - 1; 3108 3109 // get geometry data 3110 basegfx::B2DPolyPolygon aPolyPolygon(pMetaGradientExAction->GetPolyPolygon().getB2DPolyPolygon()); 3111 3112 if(aPolyPolygon.count()) 3113 { 3114 // transform geometry 3115 aPolyPolygon.transform(rPropertyHolders.Current().getTransformation()); 3116 3117 // get and check if gradient is a real gradient 3118 const Gradient& rGradient = pMetaGradientExAction->GetGradient(); 3119 const drawinglayer::attribute::FillGradientAttribute aAttribute(createFillGradientAttribute(rGradient)); 3120 3121 if(aAttribute.getStartColor() == aAttribute.getEndColor()) 3122 { 3123 // not really a gradient 3124 rTargetHolders.Current().append( 3125 new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D( 3126 aPolyPolygon, 3127 aAttribute.getStartColor())); 3128 } 3129 else 3130 { 3131 // really a gradient 3132 rTargetHolders.Current().append( 3133 new drawinglayer::primitive2d::PolyPolygonGradientPrimitive2D( 3134 aPolyPolygon, 3135 aAttribute)); 3136 } 3137 } 3138 } 3139 } 3140 3141 break; 3142 } 3143 default: 3144 { 3145 OSL_ENSURE(false, "Unknown MetaFile Action (!)"); 3146 break; 3147 } 3148 } 3149 } 3150 } 3151 } // end of anonymous namespace 3152 3153 ////////////////////////////////////////////////////////////////////////////// 3154 3155 namespace drawinglayer 3156 { 3157 namespace primitive2d 3158 { 3159 Primitive2DSequence MetafilePrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& rViewInformation) const 3160 { 3161 // prepare target and porperties; each will have one default entry 3162 TargetHolders aTargetHolders; 3163 PropertyHolders aPropertyHolders; 3164 3165 // set target MapUnit at Properties 3166 aPropertyHolders.Current().setMapUnit(getMetaFile().GetPrefMapMode().GetMapUnit()); 3167 3168 // interpret the Metafile 3169 interpretMetafile(getMetaFile(), aTargetHolders, aPropertyHolders, rViewInformation); 3170 3171 // get the content. There should be ony one target, as in the start condition, 3172 // but iterating will be the right thing to do when some push/pop is not closed 3173 Primitive2DSequence xRetval; 3174 3175 while(aTargetHolders.size() > 1) 3176 { 3177 appendPrimitive2DSequenceToPrimitive2DSequence(xRetval, 3178 aTargetHolders.Current().getPrimitive2DSequence(aPropertyHolders.Current())); 3179 aTargetHolders.Pop(); 3180 } 3181 3182 appendPrimitive2DSequenceToPrimitive2DSequence(xRetval, 3183 aTargetHolders.Current().getPrimitive2DSequence(aPropertyHolders.Current())); 3184 3185 if(xRetval.hasElements()) 3186 { 3187 // get target size 3188 const Rectangle aMtfTarget(getMetaFile().GetPrefMapMode().GetOrigin(), getMetaFile().GetPrefSize()); 3189 3190 // create transformation 3191 basegfx::B2DHomMatrix aAdaptedTransform; 3192 3193 aAdaptedTransform.translate(-aMtfTarget.Left(), -aMtfTarget.Top()); 3194 aAdaptedTransform.scale( 3195 aMtfTarget.getWidth() ? 1.0 / aMtfTarget.getWidth() : 1.0, 3196 aMtfTarget.getHeight() ? 1.0 / aMtfTarget.getHeight() : 1.0); 3197 aAdaptedTransform = getTransform() * aAdaptedTransform; 3198 3199 // embed to target transformation 3200 const Primitive2DReference aEmbeddedTransform( 3201 new TransformPrimitive2D( 3202 aAdaptedTransform, 3203 xRetval)); 3204 3205 xRetval = Primitive2DSequence(&aEmbeddedTransform, 1); 3206 } 3207 3208 return xRetval; 3209 } 3210 3211 MetafilePrimitive2D::MetafilePrimitive2D( 3212 const basegfx::B2DHomMatrix& rMetaFileTransform, 3213 const GDIMetaFile& rMetaFile) 3214 : BufferedDecompositionPrimitive2D(), 3215 maMetaFileTransform(rMetaFileTransform), 3216 maMetaFile(rMetaFile) 3217 { 3218 } 3219 3220 bool MetafilePrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const 3221 { 3222 if(BufferedDecompositionPrimitive2D::operator==(rPrimitive)) 3223 { 3224 const MetafilePrimitive2D& rCompare = (MetafilePrimitive2D&)rPrimitive; 3225 3226 return (getTransform() == rCompare.getTransform() 3227 && getMetaFile() == rCompare.getMetaFile()); 3228 } 3229 3230 return false; 3231 } 3232 3233 basegfx::B2DRange MetafilePrimitive2D::getB2DRange(const geometry::ViewInformation2D& /*rViewInformation*/) const 3234 { 3235 // use own implementation to quickly answer the getB2DRange question. The 3236 // MetafilePrimitive2D assumes that all geometry is inside of the shape. If 3237 // this is not the case (i have already seen some wrong Metafiles) it should 3238 // be embedded to a MaskPrimitive2D 3239 basegfx::B2DRange aRetval(0.0, 0.0, 1.0, 1.0); 3240 aRetval.transform(getTransform()); 3241 3242 return aRetval; 3243 } 3244 3245 // provide unique ID 3246 ImplPrimitrive2DIDBlock(MetafilePrimitive2D, PRIMITIVE2D_ID_METAFILEPRIMITIVE2D) 3247 3248 } // end of namespace primitive2d 3249 } // end of namespace drawinglayer 3250 3251 ////////////////////////////////////////////////////////////////////////////// 3252 // eof 3253