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/graphicprimitive2d.hxx> 28 #include <drawinglayer/animation/animationtiming.hxx> 29 #include <drawinglayer/primitive2d/bitmapprimitive2d.hxx> 30 #include <drawinglayer/primitive2d/animatedprimitive2d.hxx> 31 #include <drawinglayer/primitive2d/metafileprimitive2d.hxx> 32 #include <drawinglayer/primitive2d/transformprimitive2d.hxx> 33 #include <basegfx/polygon/b2dpolygon.hxx> 34 #include <basegfx/polygon/b2dpolygontools.hxx> 35 #include <drawinglayer/primitive2d/cropprimitive2d.hxx> 36 #include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx> 37 #include <drawinglayer/primitive2d/maskprimitive2d.hxx> 38 39 ////////////////////////////////////////////////////////////////////////////// 40 // helper class for animated graphics 41 42 #include <vcl/animate.hxx> 43 #include <vcl/graph.hxx> 44 #include <vcl/virdev.hxx> 45 #include <vcl/svapp.hxx> 46 #include <vcl/metaact.hxx> 47 48 ////////////////////////////////////////////////////////////////////////////// 49 // includes for testing MetafilePrimitive2D::create2DDecomposition 50 51 // this switch defines if the test code is included or not 52 #undef USE_DEBUG_CODE_TO_TEST_METAFILE_DECOMPOSE 53 54 #ifdef USE_DEBUG_CODE_TO_TEST_METAFILE_DECOMPOSE 55 #include <vcl/gradient.hxx> 56 #include <vcl/pngread.hxx> 57 #include <vcl/lineinfo.hxx> 58 #endif // USE_DEBUG_CODE_TO_TEST_METAFILE_DECOMPOSE 59 60 ////////////////////////////////////////////////////////////////////////////// 61 62 namespace 63 { 64 struct animationStep 65 { 66 BitmapEx maBitmapEx; 67 sal_uInt32 mnTime; 68 }; 69 70 class animatedBitmapExPreparator 71 { 72 ::Animation maAnimation; 73 ::std::vector< animationStep > maSteps; 74 75 sal_uInt32 generateStepTime(sal_uInt32 nIndex) const; 76 77 public: 78 animatedBitmapExPreparator(const Graphic& rGraphic); 79 80 sal_uInt32 count() const { return maSteps.size(); } 81 sal_uInt32 loopCount() const { return (sal_uInt32)maAnimation.GetLoopCount(); } 82 sal_uInt32 stepTime(sal_uInt32 a) const { return maSteps[a].mnTime; } 83 const BitmapEx& stepBitmapEx(sal_uInt32 a) const { return maSteps[a].maBitmapEx; } 84 }; 85 86 sal_uInt32 animatedBitmapExPreparator::generateStepTime(sal_uInt32 nIndex) const 87 { 88 const AnimationBitmap& rAnimBitmap = maAnimation.Get(sal_uInt16(nIndex)); 89 sal_uInt32 nWaitTime(rAnimBitmap.nWait * 10); 90 91 // #115934# 92 // Take care of special value for MultiPage TIFFs. ATM these shall just 93 // show their first page. Later we will offer some switching when object 94 // is selected. 95 if(ANIMATION_TIMEOUT_ON_CLICK == rAnimBitmap.nWait) 96 { 97 // ATM the huge value would block the timer, so 98 // use a long time to show first page (whole day) 99 nWaitTime = 100 * 60 * 60 * 24; 100 } 101 102 // Bad trap: There are animated gifs with no set WaitTime (!). 103 // In that case use a default value. 104 if(0L == nWaitTime) 105 { 106 nWaitTime = 100L; 107 } 108 109 return nWaitTime; 110 } 111 112 animatedBitmapExPreparator::animatedBitmapExPreparator(const Graphic& rGraphic) 113 : maAnimation(rGraphic.GetAnimation()) 114 { 115 OSL_ENSURE(GRAPHIC_BITMAP == rGraphic.GetType() && rGraphic.IsAnimated(), "animatedBitmapExPreparator: graphic is not animated (!)"); 116 117 // #128539# secure access to Animation, looks like there exist animated GIFs out there 118 // with a step count of zero 119 if(maAnimation.Count()) 120 { 121 VirtualDevice aVirtualDevice(*Application::GetDefaultDevice()); 122 VirtualDevice aVirtualDeviceMask(*Application::GetDefaultDevice(), 1L); 123 124 // Prepare VirtualDevices and their states 125 aVirtualDevice.EnableMapMode(sal_False); 126 aVirtualDeviceMask.EnableMapMode(sal_False); 127 aVirtualDevice.SetOutputSizePixel(maAnimation.GetDisplaySizePixel()); 128 aVirtualDeviceMask.SetOutputSizePixel(maAnimation.GetDisplaySizePixel()); 129 aVirtualDevice.Erase(); 130 aVirtualDeviceMask.Erase(); 131 132 for(sal_uInt16 a(0L); a < maAnimation.Count(); a++) 133 { 134 animationStep aNextStep; 135 aNextStep.mnTime = generateStepTime(a); 136 137 // prepare step 138 const AnimationBitmap& rAnimBitmap = maAnimation.Get(sal_uInt16(a)); 139 140 switch(rAnimBitmap.eDisposal) 141 { 142 case DISPOSE_NOT: 143 { 144 aVirtualDevice.DrawBitmapEx(rAnimBitmap.aPosPix, rAnimBitmap.aBmpEx); 145 Bitmap aMask = rAnimBitmap.aBmpEx.GetMask(); 146 147 if(aMask.IsEmpty()) 148 { 149 const Point aEmpty; 150 const Rectangle aRect(aEmpty, aVirtualDeviceMask.GetOutputSizePixel()); 151 const Wallpaper aWallpaper(COL_BLACK); 152 aVirtualDeviceMask.DrawWallpaper(aRect, aWallpaper); 153 } 154 else 155 { 156 BitmapEx aExpandVisibilityMask = BitmapEx(aMask, aMask); 157 aVirtualDeviceMask.DrawBitmapEx(rAnimBitmap.aPosPix, aExpandVisibilityMask); 158 } 159 160 break; 161 } 162 case DISPOSE_BACK: 163 { 164 // #i70772# react on no mask, for primitives, too. 165 const Bitmap aMask(rAnimBitmap.aBmpEx.GetMask()); 166 const Bitmap aContent(rAnimBitmap.aBmpEx.GetBitmap()); 167 168 aVirtualDeviceMask.Erase(); 169 aVirtualDevice.DrawBitmap(rAnimBitmap.aPosPix, aContent); 170 171 if(aMask.IsEmpty()) 172 { 173 const Rectangle aRect(rAnimBitmap.aPosPix, aContent.GetSizePixel()); 174 aVirtualDeviceMask.SetFillColor(COL_BLACK); 175 aVirtualDeviceMask.SetLineColor(); 176 aVirtualDeviceMask.DrawRect(aRect); 177 } 178 else 179 { 180 aVirtualDeviceMask.DrawBitmap(rAnimBitmap.aPosPix, aMask); 181 } 182 183 break; 184 } 185 case DISPOSE_FULL: 186 { 187 aVirtualDevice.DrawBitmapEx(rAnimBitmap.aPosPix, rAnimBitmap.aBmpEx); 188 break; 189 } 190 case DISPOSE_PREVIOUS : 191 { 192 aVirtualDevice.DrawBitmapEx(rAnimBitmap.aPosPix, rAnimBitmap.aBmpEx); 193 aVirtualDeviceMask.DrawBitmap(rAnimBitmap.aPosPix, rAnimBitmap.aBmpEx.GetMask()); 194 break; 195 } 196 } 197 198 // create BitmapEx 199 Bitmap aMainBitmap = aVirtualDevice.GetBitmap(Point(), aVirtualDevice.GetOutputSizePixel()); 200 Bitmap aMaskBitmap = aVirtualDeviceMask.GetBitmap(Point(), aVirtualDeviceMask.GetOutputSizePixel()); 201 aNextStep.maBitmapEx = BitmapEx(aMainBitmap, aMaskBitmap); 202 203 // add to vector 204 maSteps.push_back(aNextStep); 205 } 206 } 207 } 208 } // end of anonymous namespace 209 210 ////////////////////////////////////////////////////////////////////////////// 211 212 namespace drawinglayer 213 { 214 namespace primitive2d 215 { 216 Primitive2DSequence GraphicPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& 217 #ifdef USE_DEBUG_CODE_TO_TEST_METAFILE_DECOMPOSE 218 rViewInformation 219 #else 220 /*rViewInformation*/ 221 #endif // USE_DEBUG_CODE_TO_TEST_METAFILE_DECOMPOSE 222 ) const 223 { 224 Primitive2DSequence aRetval; 225 226 if(255L != getGraphicAttr().GetTransparency()) 227 { 228 Primitive2DReference xPrimitive; 229 230 // do not apply mirroring from GraphicAttr to the Metafile by calling 231 // GetTransformedGraphic, this will try to mirror the Metafile using Scale() 232 // at the Metafile. This again calls Scale at the single MetaFile actions, 233 // but this implementation never worked. I reworked that implementations, 234 // but for security reasons i will try not to use it. 235 basegfx::B2DHomMatrix aTransform(getTransform()); 236 237 if(getGraphicAttr().IsMirrored()) 238 { 239 // content needs mirroring 240 const bool bHMirr(getGraphicAttr().GetMirrorFlags() & BMP_MIRROR_HORZ); 241 const bool bVMirr(getGraphicAttr().GetMirrorFlags() & BMP_MIRROR_VERT); 242 243 // mirror by applying negative scale to the unit primitive and 244 // applying the object transformation on it. 245 aTransform = basegfx::tools::createScaleB2DHomMatrix( 246 bHMirr ? -1.0 : 1.0, 247 bVMirr ? -1.0 : 1.0); 248 aTransform.translate( 249 bHMirr ? 1.0 : 0.0, 250 bVMirr ? 1.0 : 0.0); 251 aTransform = getTransform() * aTransform; 252 } 253 254 // Get transformed graphic. Suppress rotation and cropping, only filtering is needed 255 // here (and may be replaced later on). Cropping is handled below as mask primitive (if set). 256 // Also need to suppress mirroring, it is part of the transformation now (see above). 257 GraphicAttr aSuppressGraphicAttr(getGraphicAttr()); 258 aSuppressGraphicAttr.SetCrop(0, 0, 0, 0); 259 aSuppressGraphicAttr.SetRotation(0); 260 aSuppressGraphicAttr.SetMirrorFlags(0); 261 262 const GraphicObject& rGraphicObject = getGraphicObject(); 263 const Graphic aTransformedGraphic(rGraphicObject.GetTransformedGraphic(&aSuppressGraphicAttr)); 264 265 switch(aTransformedGraphic.GetType()) 266 { 267 case GRAPHIC_BITMAP : 268 { 269 if(aTransformedGraphic.IsAnimated()) 270 { 271 // prepare animation data 272 animatedBitmapExPreparator aData(aTransformedGraphic); 273 274 if(aData.count()) 275 { 276 // create sub-primitives for animated bitmap and the needed animation loop 277 animation::AnimationEntryLoop aAnimationLoop(aData.loopCount() ? aData.loopCount() : 0xffff); 278 Primitive2DSequence aBitmapPrimitives(aData.count()); 279 280 for(sal_uInt32 a(0L); a < aData.count(); a++) 281 { 282 animation::AnimationEntryFixed aTime((double)aData.stepTime(a), (double)a / (double)aData.count()); 283 aAnimationLoop.append(aTime); 284 const Primitive2DReference xRef(new BitmapPrimitive2D(aData.stepBitmapEx(a), aTransform)); 285 aBitmapPrimitives[a] = xRef; 286 } 287 288 // prepare animation list 289 animation::AnimationEntryList aAnimationList; 290 aAnimationList.append(aAnimationLoop); 291 292 // create and add animated switch primitive 293 xPrimitive = Primitive2DReference(new AnimatedSwitchPrimitive2D(aAnimationList, aBitmapPrimitives, false)); 294 } 295 } 296 else if(aTransformedGraphic.getSvgData().get()) 297 { 298 // embedded Svg fill, create embed transform 299 const basegfx::B2DRange& rSvgRange(aTransformedGraphic.getSvgData()->getRange()); 300 301 if(basegfx::fTools::more(rSvgRange.getWidth(), 0.0) && basegfx::fTools::more(rSvgRange.getHeight(), 0.0)) 302 { 303 // translate back to origin, scale to unit coordinates 304 basegfx::B2DHomMatrix aEmbedSvg( 305 basegfx::tools::createTranslateB2DHomMatrix( 306 -rSvgRange.getMinX(), 307 -rSvgRange.getMinY())); 308 309 aEmbedSvg.scale( 310 1.0 / rSvgRange.getWidth(), 311 1.0 / rSvgRange.getHeight()); 312 313 // apply created object transformation 314 aEmbedSvg = aTransform * aEmbedSvg; 315 316 // add Svg primitives embedded 317 xPrimitive = new TransformPrimitive2D( 318 aEmbedSvg, 319 aTransformedGraphic.getSvgData()->getPrimitive2DSequence()); 320 } 321 } 322 else 323 { 324 xPrimitive = Primitive2DReference(new BitmapPrimitive2D(aTransformedGraphic.GetBitmapEx(), aTransform)); 325 } 326 327 break; 328 } 329 330 case GRAPHIC_GDIMETAFILE : 331 { 332 #ifdef USE_DEBUG_CODE_TO_TEST_METAFILE_DECOMPOSE 333 static bool bDoTest(false); 334 335 if(bDoTest) 336 { 337 // All this is/was test code for testing MetafilePrimitive2D::create2DDecomposition 338 // extensively. It may be needed again when diverse actions need debugging, so i leave 339 // it in here, but take it out using USE_DEBUG_CODE_TO_TEST_METAFILE_DECOMPOSE. 340 // Use it by compiling with the code, insert any DrawObject, convert to Metafile. The 341 // debugger will then stop here (when breakpoint set, of course). You may enter single 342 // parts of actions and/or change to true what You want to check. 343 GDIMetaFile aMtf; 344 VirtualDevice aOut; 345 const basegfx::B2DRange aRange(getB2DRange(rViewInformation)); 346 const Rectangle aRectangle( 347 basegfx::fround(aRange.getMinX()), basegfx::fround(aRange.getMinY()), 348 basegfx::fround(aRange.getMaxX()), basegfx::fround(aRange.getMaxY())); 349 const Point aOrigin(aRectangle.TopLeft()); 350 const Fraction aScaleX(aRectangle.getWidth()); 351 const Fraction aScaleY(aRectangle.getHeight()); 352 MapMode aMapMode(MAP_100TH_MM, aOrigin, aScaleX, aScaleY); 353 354 Size aDummySize(2, 2); 355 aOut.SetOutputSizePixel(aDummySize); 356 aOut.EnableOutput(FALSE); 357 aOut.SetMapMode(aMapMode); 358 359 aMtf.Clear(); 360 aMtf.Record(&aOut); 361 362 const Fraction aNeutralFraction(1, 1); 363 const MapMode aRelativeMapMode( 364 MAP_RELATIVE, 365 Point(-aRectangle.Left(), -aRectangle.Top()), 366 aNeutralFraction, aNeutralFraction); 367 aOut.SetMapMode(aRelativeMapMode); 368 369 if(false) 370 { 371 const sal_Int32 nHor(aRectangle.getWidth() / 4); 372 const sal_Int32 nVer(aRectangle.getHeight() / 4); 373 const Rectangle aCenteredRectangle( 374 aRectangle.Left() + nHor, aRectangle.Top() + nVer, 375 aRectangle.Right() - nHor, aRectangle.Bottom() - nVer); 376 aOut.SetClipRegion(aCenteredRectangle); 377 } 378 379 if(false) 380 { 381 const Rectangle aRightRectangle(aRectangle.TopCenter(), aRectangle.BottomRight()); 382 aOut.IntersectClipRegion(aRightRectangle); 383 } 384 385 if(false) 386 { 387 const Rectangle aRightRectangle(aRectangle.TopCenter(), aRectangle.BottomRight()); 388 const Rectangle aBottomRectangle(aRectangle.LeftCenter(), aRectangle.BottomRight()); 389 Region aRegion(aRightRectangle); 390 aRegion.Intersect(aBottomRectangle); 391 aOut.IntersectClipRegion(aRegion); 392 } 393 394 if(false) 395 { 396 const sal_Int32 nHor(aRectangle.getWidth() / 10); 397 const sal_Int32 nVer(aRectangle.getHeight() / 10); 398 aOut.MoveClipRegion(nHor, nVer); 399 } 400 401 if(false) 402 { 403 Wallpaper aWallpaper(Color(COL_BLACK)); 404 aOut.DrawWallpaper(aRectangle, aWallpaper); 405 } 406 407 if(false) 408 { 409 Wallpaper aWallpaper(Gradient(GRADIENT_LINEAR, Color(COL_RED), Color(COL_GREEN))); 410 aOut.DrawWallpaper(aRectangle, aWallpaper); 411 } 412 413 if(false) 414 { 415 SvFileStream aRead((const String&)String(ByteString( "c:\\test.png" ), RTL_TEXTENCODING_UTF8), STREAM_READ); 416 vcl::PNGReader aPNGReader(aRead); 417 BitmapEx aBitmapEx(aPNGReader.Read()); 418 Wallpaper aWallpaper(aBitmapEx); 419 aOut.DrawWallpaper(aRectangle, aWallpaper); 420 } 421 422 if(false) 423 { 424 const double fHor(aRectangle.getWidth()); 425 const double fVer(aRectangle.getHeight()); 426 Color aColor(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0)); 427 428 for(sal_uInt32 a(0); a < 5000; a++) 429 { 430 const Point aPoint( 431 aRectangle.Left() + basegfx::fround(rand() * (fHor / 32767.0)), 432 aRectangle.Top() + basegfx::fround(rand() * (fVer / 32767.0))); 433 434 if(!(a % 3)) 435 { 436 aColor = Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0)); 437 } 438 439 aOut.DrawPixel(aPoint, aColor); 440 } 441 } 442 443 if(false) 444 { 445 const double fHor(aRectangle.getWidth()); 446 const double fVer(aRectangle.getHeight()); 447 448 aOut.SetLineColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0))); 449 aOut.SetFillColor(); 450 451 for(sal_uInt32 a(0); a < 5000; a++) 452 { 453 const Point aPoint( 454 aRectangle.Left() + basegfx::fround(rand() * (fHor / 32767.0)), 455 aRectangle.Top() + basegfx::fround(rand() * (fVer / 32767.0))); 456 aOut.DrawPixel(aPoint); 457 } 458 } 459 460 if(false) 461 { 462 const double fHor(aRectangle.getWidth()); 463 const double fVer(aRectangle.getHeight()); 464 465 aOut.SetLineColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0))); 466 aOut.SetFillColor(); 467 468 Point aStart( 469 aRectangle.Left() + basegfx::fround(rand() * (fHor / 32767.0)), 470 aRectangle.Top() + basegfx::fround(rand() * (fVer / 32767.0))); 471 Point aStop( 472 aRectangle.Left() + basegfx::fround(rand() * (fHor / 32767.0)), 473 aRectangle.Top() + basegfx::fround(rand() * (fVer / 32767.0))); 474 475 LineInfo aLineInfo(LINE_SOLID, basegfx::fround(fHor / 50.0)); 476 bool bUseLineInfo(false); 477 478 for(sal_uInt32 a(0); a < 20; a++) 479 { 480 if(!(a%6)) 481 { 482 bUseLineInfo = !bUseLineInfo; 483 } 484 485 if(!(a%4)) 486 { 487 aOut.SetLineColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0))); 488 } 489 490 if(a%3) 491 { 492 aStart = aStop; 493 aStop = Point( 494 aRectangle.Left() + basegfx::fround(rand() * (fHor / 32767.0)), 495 aRectangle.Top() + basegfx::fround(rand() * (fVer / 32767.0))); 496 } 497 else 498 { 499 aStart = Point( 500 aRectangle.Left() + basegfx::fround(rand() * (fHor / 32767.0)), 501 aRectangle.Top() + basegfx::fround(rand() * (fVer / 32767.0))); 502 aStop = Point( 503 aRectangle.Left() + basegfx::fround(rand() * (fHor / 32767.0)), 504 aRectangle.Top() + basegfx::fround(rand() * (fVer / 32767.0))); 505 } 506 507 if(bUseLineInfo) 508 { 509 aOut.DrawLine(aStart, aStop, aLineInfo); 510 } 511 else 512 { 513 aOut.DrawLine(aStart, aStop); 514 } 515 } 516 } 517 518 if(false) 519 { 520 aOut.SetLineColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0))); 521 aOut.SetFillColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0))); 522 aOut.DrawRect(aRectangle); 523 } 524 525 if(false) 526 { 527 aOut.SetLineColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0))); 528 aOut.SetFillColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0))); 529 const sal_uInt32 nHor(aRectangle.getWidth() / 10); 530 const sal_uInt32 nVer(aRectangle.getHeight() / 10); 531 aOut.DrawRect(aRectangle, nHor, nVer); 532 } 533 534 if(false) 535 { 536 aOut.SetLineColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0))); 537 aOut.SetFillColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0))); 538 aOut.DrawEllipse(aRectangle); 539 } 540 541 if(false) 542 { 543 aOut.SetLineColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0))); 544 aOut.SetFillColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0))); 545 aOut.DrawArc(aRectangle, aRectangle.TopLeft(), aRectangle.BottomCenter()); 546 } 547 548 if(false) 549 { 550 aOut.SetLineColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0))); 551 aOut.SetFillColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0))); 552 aOut.DrawPie(aRectangle, aRectangle.TopLeft(), aRectangle.BottomCenter()); 553 } 554 555 if(false) 556 { 557 aOut.SetLineColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0))); 558 aOut.SetFillColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0))); 559 aOut.DrawChord(aRectangle, aRectangle.TopLeft(), aRectangle.BottomCenter()); 560 } 561 562 if(false) 563 { 564 const double fHor(aRectangle.getWidth()); 565 const double fVer(aRectangle.getHeight()); 566 567 for(sal_uInt32 b(0); b < 5; b++) 568 { 569 const sal_uInt32 nCount(basegfx::fround(rand() * (20 / 32767.0))); 570 const bool bClose(basegfx::fround(rand() / 32767.0)); 571 Polygon aPolygon(nCount + (bClose ? 1 : 0)); 572 573 for(sal_uInt32 a(0); a < nCount; a++) 574 { 575 const Point aPoint( 576 aRectangle.Left() + basegfx::fround(rand() * (fHor / 32767.0)), 577 aRectangle.Top() + basegfx::fround(rand() * (fVer / 32767.0))); 578 aPolygon[a] = aPoint; 579 } 580 581 if(bClose) 582 { 583 aPolygon[aPolygon.GetSize() - 1] = aPolygon[0]; 584 } 585 586 aOut.SetLineColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0))); 587 aOut.SetFillColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0))); 588 589 if(!(b%2)) 590 { 591 const LineInfo aLineInfo(LINE_SOLID, basegfx::fround(fHor / 50.0)); 592 aOut.DrawPolyLine(aPolygon, aLineInfo); 593 } 594 else 595 { 596 aOut.DrawPolyLine(aPolygon); 597 } 598 } 599 } 600 601 if(false) 602 { 603 const double fHor(aRectangle.getWidth()); 604 const double fVer(aRectangle.getHeight()); 605 606 for(sal_uInt32 b(0); b < 5; b++) 607 { 608 const sal_uInt32 nCount(basegfx::fround(rand() * (20 / 32767.0))); 609 const bool bClose(basegfx::fround(rand() / 32767.0)); 610 Polygon aPolygon(nCount + (bClose ? 1 : 0)); 611 612 for(sal_uInt32 a(0); a < nCount; a++) 613 { 614 const Point aPoint( 615 aRectangle.Left() + basegfx::fround(rand() * (fHor / 32767.0)), 616 aRectangle.Top() + basegfx::fround(rand() * (fVer / 32767.0))); 617 aPolygon[a] = aPoint; 618 } 619 620 if(bClose) 621 { 622 aPolygon[aPolygon.GetSize() - 1] = aPolygon[0]; 623 } 624 625 aOut.SetLineColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0))); 626 aOut.SetFillColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0))); 627 aOut.DrawPolygon(aPolygon); 628 } 629 } 630 631 if(false) 632 { 633 const double fHor(aRectangle.getWidth()); 634 const double fVer(aRectangle.getHeight()); 635 PolyPolygon aPolyPolygon; 636 637 for(sal_uInt32 b(0); b < 3; b++) 638 { 639 const sal_uInt32 nCount(basegfx::fround(rand() * (6 / 32767.0))); 640 const bool bClose(basegfx::fround(rand() / 32767.0)); 641 Polygon aPolygon(nCount + (bClose ? 1 : 0)); 642 643 for(sal_uInt32 a(0); a < nCount; a++) 644 { 645 const Point aPoint( 646 aRectangle.Left() + basegfx::fround(rand() * (fHor / 32767.0)), 647 aRectangle.Top() + basegfx::fround(rand() * (fVer / 32767.0))); 648 aPolygon[a] = aPoint; 649 } 650 651 if(bClose) 652 { 653 aPolygon[aPolygon.GetSize() - 1] = aPolygon[0]; 654 } 655 656 aPolyPolygon.Insert(aPolygon); 657 } 658 659 aOut.SetLineColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0))); 660 aOut.SetFillColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0))); 661 aOut.DrawPolyPolygon(aPolyPolygon); 662 } 663 664 if(false) 665 { 666 SvFileStream aRead((const String&)String(ByteString( "c:\\test.png" ), RTL_TEXTENCODING_UTF8), STREAM_READ); 667 vcl::PNGReader aPNGReader(aRead); 668 BitmapEx aBitmapEx(aPNGReader.Read()); 669 aOut.DrawBitmapEx(aRectangle.TopLeft(), aBitmapEx); 670 } 671 672 if(false) 673 { 674 SvFileStream aRead((const String&)String(ByteString( "c:\\test.png" ), RTL_TEXTENCODING_UTF8), STREAM_READ); 675 vcl::PNGReader aPNGReader(aRead); 676 BitmapEx aBitmapEx(aPNGReader.Read()); 677 aOut.DrawBitmapEx(aRectangle.TopLeft(), aRectangle.GetSize(), aBitmapEx); 678 } 679 680 if(false) 681 { 682 SvFileStream aRead((const String&)String(ByteString( "c:\\test.png" ), RTL_TEXTENCODING_UTF8), STREAM_READ); 683 vcl::PNGReader aPNGReader(aRead); 684 BitmapEx aBitmapEx(aPNGReader.Read()); 685 const Size aSizePixel(aBitmapEx.GetSizePixel()); 686 aOut.DrawBitmapEx( 687 aRectangle.TopLeft(), 688 aRectangle.GetSize(), 689 Point(0, 0), 690 Size(aSizePixel.Width() /2, aSizePixel.Height() / 2), 691 aBitmapEx); 692 } 693 694 if(false) 695 { 696 const double fHor(aRectangle.getWidth()); 697 const double fVer(aRectangle.getHeight()); 698 const Point aPointA( 699 aRectangle.Left() + basegfx::fround(fHor * 0.2), 700 aRectangle.Top() + basegfx::fround(fVer * 0.3)); 701 const Point aPointB( 702 aRectangle.Left() + basegfx::fround(fHor * 0.2), 703 aRectangle.Top() + basegfx::fround(fVer * 0.5)); 704 const Point aPointC( 705 aRectangle.Left() + basegfx::fround(fHor * 0.2), 706 aRectangle.Top() + basegfx::fround(fVer * 0.7)); 707 const String aText(ByteString("Hello, World!"), RTL_TEXTENCODING_UTF8); 708 709 const String aFontName(ByteString("Comic Sans MS"), RTL_TEXTENCODING_UTF8); 710 Font aFont(aFontName, Size(0, 1000)); 711 aFont.SetAlign(ALIGN_BASELINE); 712 aFont.SetColor(COL_RED); 713 //sal_Int32* pDXArray = new sal_Int32[aText.Len()]; 714 715 aFont.SetOutline(true); 716 aOut.SetFont(aFont); 717 aOut.DrawText(aPointA, aText, 0, aText.Len()); 718 719 aFont.SetShadow(true); 720 aOut.SetFont(aFont); 721 aOut.DrawText(aPointB, aText, 0, aText.Len()); 722 723 aFont.SetRelief(RELIEF_EMBOSSED); 724 aOut.SetFont(aFont); 725 aOut.DrawText(aPointC, aText, 0, aText.Len()); 726 727 //delete pDXArray; 728 } 729 730 if(false) 731 { 732 const double fHor(aRectangle.getWidth()); 733 const double fVer(aRectangle.getHeight()); 734 const Point aPointA( 735 aRectangle.Left() + basegfx::fround(fHor * 0.2), 736 aRectangle.Top() + basegfx::fround(fVer * 0.3)); 737 const Point aPointB( 738 aRectangle.Left() + basegfx::fround(fHor * 0.2), 739 aRectangle.Top() + basegfx::fround(fVer * 0.5)); 740 const Point aPointC( 741 aRectangle.Left() + basegfx::fround(fHor * 0.2), 742 aRectangle.Top() + basegfx::fround(fVer * 0.7)); 743 const String aText(ByteString("Hello, World!"), RTL_TEXTENCODING_UTF8); 744 745 const String aFontName(ByteString("Comic Sans MS"), RTL_TEXTENCODING_UTF8); 746 Font aFont(aFontName, Size(0, 1000)); 747 aFont.SetAlign(ALIGN_BASELINE); 748 aFont.SetColor(COL_RED); 749 750 aOut.SetFont(aFont); 751 const sal_Int32 nWidth(aOut.GetTextWidth(aText, 0, aText.Len())); 752 aOut.DrawText(aPointA, aText, 0, aText.Len()); 753 aOut.DrawTextLine(aPointA, nWidth, STRIKEOUT_SINGLE, UNDERLINE_SINGLE, UNDERLINE_SMALLWAVE); 754 aOut.DrawTextLine(aPointB, nWidth, STRIKEOUT_SINGLE, UNDERLINE_SINGLE, UNDERLINE_SMALLWAVE); 755 aOut.DrawTextLine(aPointC, nWidth, STRIKEOUT_SINGLE, UNDERLINE_SINGLE, UNDERLINE_SMALLWAVE); 756 } 757 758 aMtf.Stop(); 759 aMtf.WindStart(); 760 aMtf.SetPrefMapMode(MapMode(MAP_100TH_MM)); 761 aMtf.SetPrefSize(Size(aRectangle.getWidth(), aRectangle.getHeight())); 762 763 xPrimitive = Primitive2DReference( 764 new MetafilePrimitive2D( 765 aTransform, 766 aMtf)); 767 } 768 else 769 { 770 #endif // USE_DEBUG_CODE_TO_TEST_METAFILE_DECOMPOSE 771 // create MetafilePrimitive2D 772 const GDIMetaFile& rMetafile = aTransformedGraphic.GetGDIMetaFile(); 773 774 xPrimitive = Primitive2DReference( 775 new MetafilePrimitive2D( 776 aTransform, 777 rMetafile)); 778 779 // #i100357# find out if clipping is needed for this primitive. Unfortunately, 780 // there exist Metafiles who's content is bigger than the proposed PrefSize set 781 // at them. This is an error, but we need to work around this 782 const Size aMetaFilePrefSize(rMetafile.GetPrefSize()); 783 const Size aMetaFileRealSize( 784 const_cast< GDIMetaFile& >(rMetafile).GetBoundRect( 785 *Application::GetDefaultDevice()).GetSize()); 786 787 if(aMetaFileRealSize.getWidth() > aMetaFilePrefSize.getWidth() 788 || aMetaFileRealSize.getHeight() > aMetaFilePrefSize.getHeight()) 789 { 790 // clipping needed. Embed to MaskPrimitive2D. Create childs and mask polygon 791 const primitive2d::Primitive2DSequence aChildContent(&xPrimitive, 1); 792 basegfx::B2DPolygon aMaskPolygon(basegfx::tools::createUnitPolygon()); 793 aMaskPolygon.transform(aTransform); 794 795 xPrimitive = Primitive2DReference( 796 new MaskPrimitive2D( 797 basegfx::B2DPolyPolygon(aMaskPolygon), 798 aChildContent)); 799 } 800 #ifdef USE_DEBUG_CODE_TO_TEST_METAFILE_DECOMPOSE 801 } 802 #endif // USE_DEBUG_CODE_TO_TEST_METAFILE_DECOMPOSE 803 804 break; 805 } 806 807 default: 808 { 809 // nothing to create 810 break; 811 } 812 } 813 814 if(xPrimitive.is()) 815 { 816 // check for cropping 817 if(getGraphicAttr().IsCropped()) 818 { 819 // calculate scalings between real image size and logic object size. This 820 // is necessary since the crop values are relative to original bitmap size 821 double fFactorX(1.0); 822 double fFactorY(1.0); 823 824 { 825 const MapMode aMapMode100thmm(MAP_100TH_MM); 826 Size aBitmapSize(rGraphicObject.GetPrefSize()); 827 828 // #i95968# better support PrefMapMode; special for MAP_PIXEL was missing 829 if(MAP_PIXEL == rGraphicObject.GetPrefMapMode().GetMapUnit()) 830 { 831 aBitmapSize = Application::GetDefaultDevice()->PixelToLogic(aBitmapSize, aMapMode100thmm); 832 } 833 else 834 { 835 aBitmapSize = Application::GetDefaultDevice()->LogicToLogic(aBitmapSize, rGraphicObject.GetPrefMapMode(), aMapMode100thmm); 836 } 837 838 const double fDivX(aBitmapSize.Width() - getGraphicAttr().GetLeftCrop() - getGraphicAttr().GetRightCrop()); 839 const double fDivY(aBitmapSize.Height() - getGraphicAttr().GetTopCrop() - getGraphicAttr().GetBottomCrop()); 840 const basegfx::B2DVector aScale(aTransform * basegfx::B2DVector(1.0, 1.0)); 841 842 if(!basegfx::fTools::equalZero(fDivX)) 843 { 844 fFactorX = fabs(aScale.getX()) / fDivX; 845 } 846 847 if(!basegfx::fTools::equalZero(fDivY)) 848 { 849 fFactorY = fabs(aScale.getY()) / fDivY; 850 } 851 } 852 853 // embed content in cropPrimitive 854 xPrimitive = new CropPrimitive2D( 855 Primitive2DSequence(&xPrimitive, 1), 856 aTransform, 857 getGraphicAttr().GetLeftCrop() * fFactorX, 858 getGraphicAttr().GetTopCrop() * fFactorY, 859 getGraphicAttr().GetRightCrop() * fFactorX, 860 getGraphicAttr().GetBottomCrop() * fFactorY); 861 } 862 863 // add to decomposition 864 appendPrimitive2DReferenceToPrimitive2DSequence(aRetval, xPrimitive); 865 } 866 } 867 868 return aRetval; 869 } 870 871 GraphicPrimitive2D::GraphicPrimitive2D( 872 const basegfx::B2DHomMatrix& rTransform, 873 const GraphicObject& rGraphicObject, 874 const GraphicAttr& rGraphicAttr) 875 : BufferedDecompositionPrimitive2D(), 876 maTransform(rTransform), 877 maGraphicObject(rGraphicObject), 878 maGraphicAttr(rGraphicAttr) 879 { 880 } 881 882 GraphicPrimitive2D::GraphicPrimitive2D( 883 const basegfx::B2DHomMatrix& rTransform, 884 const GraphicObject& rGraphicObject) 885 : BufferedDecompositionPrimitive2D(), 886 maTransform(rTransform), 887 maGraphicObject(rGraphicObject), 888 maGraphicAttr() 889 { 890 } 891 892 bool GraphicPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const 893 { 894 if(BufferedDecompositionPrimitive2D::operator==(rPrimitive)) 895 { 896 const GraphicPrimitive2D& rCompare = (GraphicPrimitive2D&)rPrimitive; 897 898 return (getTransform() == rCompare.getTransform() 899 && getGraphicObject() == rCompare.getGraphicObject() 900 && getGraphicAttr() == rCompare.getGraphicAttr()); 901 } 902 903 return false; 904 } 905 906 basegfx::B2DRange GraphicPrimitive2D::getB2DRange(const geometry::ViewInformation2D& /*rViewInformation*/) const 907 { 908 basegfx::B2DRange aRetval(0.0, 0.0, 1.0, 1.0); 909 aRetval.transform(getTransform()); 910 return aRetval; 911 } 912 913 // provide unique ID 914 ImplPrimitrive2DIDBlock(GraphicPrimitive2D, PRIMITIVE2D_ID_GRAPHICPRIMITIVE2D) 915 916 } // end of namespace primitive2d 917 } // end of namespace drawinglayer 918 919 ////////////////////////////////////////////////////////////////////////////// 920 // eof 921