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