tdf#130857 qt weld: Support mail merge "Server Auth" dialog
[LibreOffice.git] / drawinglayer / source / primitive2d / graphicprimitivehelper2d.cxx
blob7ff6b1c32c710b3afee66f6384b85228077ff3fa
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/config.h>
22 #include <algorithm>
24 #include <drawinglayer/primitive2d/graphicprimitivehelper2d.hxx>
25 #include <drawinglayer/animation/animationtiming.hxx>
26 #include <drawinglayer/primitive2d/bitmapprimitive2d.hxx>
27 #include <drawinglayer/primitive2d/BitmapAlphaPrimitive2D.hxx>
28 #include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx>
29 #include <drawinglayer/primitive2d/animatedprimitive2d.hxx>
30 #include <drawinglayer/primitive2d/metafileprimitive2d.hxx>
31 #include <drawinglayer/primitive2d/transformprimitive2d.hxx>
32 #include <drawinglayer/primitive2d/maskprimitive2d.hxx>
33 #include <drawinglayer/primitive2d/modifiedcolorprimitive2d.hxx>
34 #include <drawinglayer/primitive2d/fillgraphicprimitive2d.hxx>
35 #include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
36 #include <drawinglayer/geometry/viewinformation2d.hxx>
37 #include <basegfx/polygon/b2dpolygon.hxx>
38 #include <basegfx/polygon/b2dpolygontools.hxx>
39 #include <basegfx/numeric/ftools.hxx>
41 // helper class for animated graphics
43 #include <utility>
44 #include <vcl/animate/Animation.hxx>
45 #include <vcl/graph.hxx>
46 #include <vcl/virdev.hxx>
47 #include <vcl/svapp.hxx>
48 #include <toolkit/helper/vclunohelper.hxx>
49 #include <vcl/skia/SkiaHelper.hxx>
51 namespace drawinglayer::primitive2d
53 namespace {
55 class AnimatedGraphicPrimitive2D : public AnimatedSwitchPrimitive2D
57 private:
58 /// the geometric definition
59 basegfx::B2DHomMatrix maTransform;
61 /** the Graphic with all its content possibilities, here only
62 animated is allowed and gets checked by isValidData().
63 an instance of Graphic is used here since it's ref-counted
64 and thus a safe copy for now
66 Graphic maGraphic;
68 /** defines parameters for tiling if this AnimatedGraphicPrimitive2D
69 is to be used for a FillGraphicPrimitive2D. In that case,
70 maFillGraphicAttribute.isDefault() will be false
72 drawinglayer::attribute::FillGraphicAttribute maFillGraphicAttribute;
74 /// local animation processing data, excerpt from maGraphic
75 ::Animation maAnimation;
77 /// the transparency in range [0.0 .. 1.0]
78 double mfTransparency;
80 /// the on-demand created VirtualDevices for frame creation
81 ScopedVclPtrInstance< VirtualDevice > maVirtualDevice;
82 ScopedVclPtrInstance< VirtualDevice > maVirtualDeviceMask;
84 // index of the next frame that would be regularly prepared
85 sal_uInt32 mnNextFrameToPrepare;
87 /// buffering of 1st frame (always active)
88 Primitive2DReference maBufferedFirstFrame;
90 /// buffering of all frames
91 std::vector<Primitive2DReference> maBufferedPrimitives;
92 bool mbBufferingAllowed;
94 /// set if the animation is huge so that just always the next frame
95 /// is used instead of using timing
96 bool mbHugeSize;
98 /// helper methods
99 bool isValidData() const
101 return (GraphicType::Bitmap == maGraphic.GetType()
102 && maGraphic.IsAnimated()
103 && maAnimation.Count()
104 && !basegfx::fTools::equal(getTransparency(), 1.0));
107 void ensureVirtualDeviceSizeAndState()
109 if (!isValidData())
110 return;
112 const Size aCurrent(maVirtualDevice->GetOutputSizePixel());
113 const Size aTarget(maAnimation.GetDisplaySizePixel());
115 if (aCurrent != aTarget)
117 maVirtualDevice->EnableMapMode(false);
118 maVirtualDeviceMask->EnableMapMode(false);
119 maVirtualDevice->SetOutputSizePixel(aTarget);
120 maVirtualDeviceMask->SetOutputSizePixel(aTarget);
122 // tdf#156630 make erase calls fill with transparency
123 maVirtualDevice->SetBackground(COL_BLACK);
124 maVirtualDeviceMask->SetBackground(COL_ALPHA_TRANSPARENT);
127 maVirtualDevice->Erase();
128 maVirtualDeviceMask->Erase();
129 const ::tools::Rectangle aRect(Point(0, 0), aTarget);
130 maVirtualDeviceMask->SetFillColor(COL_BLACK);
131 maVirtualDeviceMask->SetLineColor();
132 maVirtualDeviceMask->DrawRect(aRect);
135 sal_uInt32 generateStepTime(sal_uInt32 nIndex) const
137 const AnimationFrame& rAnimationFrame = maAnimation.Get(sal_uInt16(nIndex));
138 sal_uInt32 nWaitTime(rAnimationFrame.mnWait * 10);
140 // Take care of special value for MultiPage TIFFs. ATM these shall just
141 // show their first page. Later we will offer some switching when object
142 // is selected.
143 if (ANIMATION_TIMEOUT_ON_CLICK == rAnimationFrame.mnWait)
145 // ATM the huge value would block the timer, so
146 // use a long time to show first page (whole day)
147 nWaitTime = 100 * 60 * 60 * 24;
150 // Bad trap: There are animated gifs with no set WaitTime (!).
151 // In that case use a default value.
152 if (0 == nWaitTime)
154 nWaitTime = 100;
157 return nWaitTime;
160 void createAndSetAnimationTiming()
162 if (!isValidData())
163 return;
165 animation::AnimationEntryLoop aAnimationLoop(maAnimation.GetLoopCount() ? maAnimation.GetLoopCount() : 0xffff);
166 const sal_uInt32 nCount(maAnimation.Count());
168 for (sal_uInt32 a(0); a < nCount; a++)
170 const sal_uInt32 aStepTime(generateStepTime(a));
171 const animation::AnimationEntryFixed aTime(static_cast<double>(aStepTime), static_cast<double>(a) / static_cast<double>(nCount));
173 aAnimationLoop.append(aTime);
176 animation::AnimationEntryList aAnimationEntryList;
177 aAnimationEntryList.append(aAnimationLoop);
179 setAnimationEntry(aAnimationEntryList);
182 Primitive2DReference createFromBuffer() const
184 // create BitmapEx by extracting from VirtualDevices
185 const Bitmap aMainBitmap(maVirtualDevice->GetBitmap(Point(), maVirtualDevice->GetOutputSizePixel()));
186 bool useAlphaMask = false;
187 #if defined(MACOSX) || defined(IOS)
188 useAlphaMask = true;
189 #else
190 // GetBitmap()-> AlphaMask is optimized with SkiaSalBitmap::InterpretAs8Bit(), 1bpp mask is not.
191 if( SkiaHelper::isVCLSkiaEnabled())
192 useAlphaMask = true;
193 #endif
194 BitmapEx bitmap;
195 if( useAlphaMask )
197 const AlphaMask aMaskBitmap(maVirtualDeviceMask->GetBitmap(Point(), maVirtualDeviceMask->GetOutputSizePixel()));
198 bitmap = BitmapEx(aMainBitmap, aMaskBitmap);
200 else
202 Bitmap aMaskBitmap(maVirtualDeviceMask->GetBitmap(Point(), maVirtualDeviceMask->GetOutputSizePixel()));
203 // tdf#156630 invert the alpha mask
204 aMaskBitmap.Invert(); // convert from transparency to alpha
205 bitmap = BitmapEx(aMainBitmap, aMaskBitmap);
208 if (!maFillGraphicAttribute.isDefault())
210 // need to create FillGraphicPrimitive2D
211 const drawinglayer::attribute::FillGraphicAttribute aAttribute(
212 Graphic(bitmap),
213 maFillGraphicAttribute.getGraphicRange(),
214 maFillGraphicAttribute.getTiling(),
215 maFillGraphicAttribute.getOffsetX(),
216 maFillGraphicAttribute.getOffsetY());
218 return new FillGraphicPrimitive2D(
219 getTransform(),
220 aAttribute,
221 getTransparency());
224 // need to create BitmapAlphaPrimitive2D/BitmapPrimitive2D
225 if (basegfx::fTools::equal(getTransparency(), 0.0))
226 return new BitmapPrimitive2D(bitmap, getTransform());
228 return new BitmapAlphaPrimitive2D(bitmap, getTransform(), getTransparency());
231 void checkSafeToBuffer(sal_uInt32 nIndex)
233 if (mbBufferingAllowed)
235 // all frames buffered
236 if (!maBufferedPrimitives.empty() && nIndex < maBufferedPrimitives.size())
238 if (!maBufferedPrimitives[nIndex].is())
240 maBufferedPrimitives[nIndex] = createFromBuffer();
242 // check if buffering is complete
243 bool bBufferingComplete(true);
245 for (auto const & a: maBufferedPrimitives)
247 if (!a.is())
249 bBufferingComplete = false;
250 break;
254 if (bBufferingComplete)
256 maVirtualDevice.disposeAndClear();
257 maVirtualDeviceMask.disposeAndClear();
262 else
264 // always buffer first frame
265 if (0 == nIndex && !maBufferedFirstFrame.is())
267 maBufferedFirstFrame = createFromBuffer();
272 void createFrame(sal_uInt32 nTarget)
274 // mnNextFrameToPrepare is the target frame to create next (which implies that
275 // mnNextFrameToPrepare-1 *is* currently in the VirtualDevice when
276 // 0 != mnNextFrameToPrepare. nTarget is the target frame.
277 if (!isValidData())
278 return;
280 if (mnNextFrameToPrepare > nTarget)
282 // we are ahead request, reset mechanism to start at frame zero
283 ensureVirtualDeviceSizeAndState();
284 mnNextFrameToPrepare = 0;
287 while (mnNextFrameToPrepare <= nTarget)
289 // prepare step
290 const AnimationFrame& rAnimationFrame = maAnimation.Get(sal_uInt16(mnNextFrameToPrepare));
292 bool bSourceBlending = rAnimationFrame.meBlend == Blend::Source;
294 if (bSourceBlending)
296 tools::Rectangle aArea(rAnimationFrame.maPositionPixel, rAnimationFrame.maBitmapEx.GetSizePixel());
297 maVirtualDevice->Erase(aArea);
298 maVirtualDeviceMask->Erase(aArea);
301 switch (rAnimationFrame.meDisposal)
303 case Disposal::Not:
305 maVirtualDevice->DrawBitmapEx(rAnimationFrame.maPositionPixel, rAnimationFrame.maBitmapEx);
306 AlphaMask aAlphaMask = rAnimationFrame.maBitmapEx.GetAlphaMask();
308 if (aAlphaMask.IsEmpty())
310 const Point aEmpty;
311 const ::tools::Rectangle aRect(aEmpty, maVirtualDeviceMask->GetOutputSizePixel());
312 const Wallpaper aWallpaper(COL_BLACK);
313 maVirtualDeviceMask->DrawWallpaper(aRect, aWallpaper);
315 else
317 BitmapEx aExpandVisibilityMask(aAlphaMask.GetBitmap(), aAlphaMask);
318 maVirtualDeviceMask->DrawBitmapEx(rAnimationFrame.maPositionPixel, aExpandVisibilityMask);
321 break;
323 case Disposal::Back:
325 // #i70772# react on no mask, for primitives, too.
326 const AlphaMask & rMask(rAnimationFrame.maBitmapEx.GetAlphaMask());
328 maVirtualDeviceMask->Erase();
329 maVirtualDevice->DrawBitmapEx(rAnimationFrame.maPositionPixel, rAnimationFrame.maBitmapEx);
331 if (rMask.IsEmpty())
333 const ::tools::Rectangle aRect(rAnimationFrame.maPositionPixel, rAnimationFrame.maBitmapEx.GetSizePixel());
334 maVirtualDeviceMask->SetFillColor(COL_BLACK);
335 maVirtualDeviceMask->SetLineColor();
336 maVirtualDeviceMask->DrawRect(aRect);
338 else
340 BitmapEx aExpandVisibilityMask(rMask.GetBitmap(), rMask);
341 maVirtualDeviceMask->DrawBitmapEx(rAnimationFrame.maPositionPixel, aExpandVisibilityMask);
344 break;
346 case Disposal::Previous:
348 maVirtualDevice->DrawBitmapEx(rAnimationFrame.maPositionPixel, rAnimationFrame.maBitmapEx);
349 BitmapEx aExpandVisibilityMask(rAnimationFrame.maBitmapEx.GetAlphaMask().GetBitmap(), rAnimationFrame.maBitmapEx.GetAlphaMask());
350 maVirtualDeviceMask->DrawBitmapEx(rAnimationFrame.maPositionPixel, aExpandVisibilityMask);
351 break;
355 // to not waste created data, check adding to buffers
356 checkSafeToBuffer(mnNextFrameToPrepare);
358 mnNextFrameToPrepare++;
362 Primitive2DReference tryTogetFromBuffer(sal_uInt32 nIndex) const
364 if (mbBufferingAllowed)
366 // all frames buffered, check if available
367 if (!maBufferedPrimitives.empty() && nIndex < maBufferedPrimitives.size())
369 if (maBufferedPrimitives[nIndex].is())
371 return maBufferedPrimitives[nIndex];
375 else
377 // always buffer first frame, it's sometimes requested out-of-order
378 if (0 == nIndex && maBufferedFirstFrame.is())
380 return maBufferedFirstFrame;
384 return Primitive2DReference();
387 public:
388 /// constructor
389 AnimatedGraphicPrimitive2D(
390 const Graphic& rGraphic,
391 const drawinglayer::attribute::FillGraphicAttribute* pFillGraphicAttribute,
392 basegfx::B2DHomMatrix aTransform,
393 double fTransparency = 0.0);
394 virtual ~AnimatedGraphicPrimitive2D();
396 /// data read access
397 const basegfx::B2DHomMatrix& getTransform() const { return maTransform; }
398 double getTransparency() const { return mfTransparency; }
400 /// provide unique ID
401 virtual sal_uInt32 getPrimitive2DID() const override { return PRIMITIVE2D_ID_ANIMATEDGRAPHICPRIMITIVE2D; }
403 /// compare operator
404 virtual bool operator==(const BasePrimitive2D& rPrimitive) const override;
406 /// override to deliver the correct expected frame dependent of timing
407 virtual void get2DDecomposition(Primitive2DDecompositionVisitor& rVisitor, const geometry::ViewInformation2D& rViewInformation) const override;
409 /// get range
410 virtual basegfx::B2DRange getB2DRange(const geometry::ViewInformation2D& rViewInformation) const override;
415 AnimatedGraphicPrimitive2D::AnimatedGraphicPrimitive2D(
416 const Graphic& rGraphic,
417 const drawinglayer::attribute::FillGraphicAttribute* pFillGraphicAttribute,
418 basegfx::B2DHomMatrix aTransform,
419 double fTransparency)
420 : AnimatedSwitchPrimitive2D(
421 animation::AnimationEntryList(),
422 Primitive2DContainer(),
423 false),
424 maTransform(std::move(aTransform)),
425 maGraphic(rGraphic),
426 maFillGraphicAttribute(),
427 maAnimation(rGraphic.GetAnimation()),
428 mfTransparency(std::max(0.0, std::min(1.0, fTransparency))),
429 maVirtualDevice(*Application::GetDefaultDevice()),
430 maVirtualDeviceMask(*Application::GetDefaultDevice()),
431 mnNextFrameToPrepare(SAL_MAX_UINT32),
432 mbBufferingAllowed(false),
433 mbHugeSize(false)
435 // if FillGraphicAttribute copy it -> FillGraphicPrimitive2D is intended
436 if (nullptr != pFillGraphicAttribute)
437 maFillGraphicAttribute = *pFillGraphicAttribute;
439 // initialize AnimationTiming, needed to detect which frame is requested
440 // in get2DDecomposition
441 createAndSetAnimationTiming();
443 // check if we allow buffering
444 if (isValidData())
446 // allow buffering up to a size of:
447 // - 64 frames
448 // - sizes of 256x256 pixels
449 // This may be offered in option values if needed
450 static const sal_uInt64 nAllowedSize(64 * 256 * 256);
451 static const sal_uInt64 nHugeSize(10000000);
452 const Size aTarget(maAnimation.GetDisplaySizePixel());
453 const sal_uInt64 nUsedSize(static_cast<sal_uInt64>(maAnimation.Count()) * aTarget.Width() * aTarget.Height());
455 if (nUsedSize < nAllowedSize)
457 mbBufferingAllowed = true;
460 if (nUsedSize > nHugeSize)
462 mbHugeSize = true;
466 // prepare buffer space
467 if (mbBufferingAllowed && isValidData())
469 maBufferedPrimitives.resize(maAnimation.Count());
473 AnimatedGraphicPrimitive2D::~AnimatedGraphicPrimitive2D()
475 // Related: tdf#158807 mutex must be locked when disposing a VirtualDevice
476 // If the following .ppt document is opened in a debug build
477 // and the document is left open for a minute or two without
478 // changing any content, this destructor will be called on a
479 // non-main thread with the mutex unlocked:
480 // https://bugs.documentfoundation.org/attachment.cgi?id=46801
481 // This hits an assert in VirtualDevice::ReleaseGraphics() so
482 // explicitly lock the mutex and explicitly dispose and clear
483 // the VirtualDevice instances variables.
484 const SolarMutexGuard aSolarGuard;
486 maVirtualDevice.disposeAndClear();
487 maVirtualDeviceMask.disposeAndClear();
488 maAnimation.Clear();
489 maGraphic.Clear();
492 bool AnimatedGraphicPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
494 // do not use 'GroupPrimitive2D::operator==' here, that would compare
495 // the children. Also do not use 'BasePrimitive2D::operator==', that would
496 // check the ID-Type. Since we are a simple derivation without own ID,
497 // use the dynamic_cast RTTI directly
498 const AnimatedGraphicPrimitive2D* pCompare = dynamic_cast<const AnimatedGraphicPrimitive2D*>(&rPrimitive);
500 // use operator== of Graphic - if that is equal, the basic definition is equal
501 return (nullptr != pCompare
502 && getTransform() == pCompare->getTransform()
503 && maGraphic == pCompare->maGraphic);
506 void AnimatedGraphicPrimitive2D::get2DDecomposition(Primitive2DDecompositionVisitor& rVisitor, const geometry::ViewInformation2D& rViewInformation) const
508 if (!isValidData())
509 return;
511 Primitive2DReference aRetval;
512 const double fState(getAnimationEntry().getStateAtTime(rViewInformation.getViewTime()));
513 const sal_uInt32 nLen(maAnimation.Count());
514 sal_uInt32 nIndex(basegfx::fround(fState * static_cast<double>(nLen)));
516 // nIndex is the requested frame - it is in range [0..nLen[
517 // create frame representation in VirtualDevices
518 if (nIndex >= nLen)
520 nIndex = nLen - 1;
523 // check buffering shortcuts, may already be created
524 aRetval = tryTogetFromBuffer(nIndex);
526 if (aRetval.is())
528 rVisitor.visit(aRetval);
529 return;
532 // if huge size (and not the buffered 1st frame) simply
533 // create next frame
534 if (mbHugeSize && 0 != nIndex && mnNextFrameToPrepare <= nIndex)
536 nIndex = mnNextFrameToPrepare % nLen;
539 // frame not (yet) buffered or no buffering allowed, create it
540 const_cast<AnimatedGraphicPrimitive2D*>(this)->createFrame(nIndex);
542 // try to get from buffer again, may have been added from createFrame
543 aRetval = tryTogetFromBuffer(nIndex);
545 if (aRetval.is())
547 rVisitor.visit(aRetval);
548 return;
551 // did not work (not buffered and not 1st frame), create from buffer
552 aRetval = createFromBuffer();
554 rVisitor.visit(aRetval);
557 basegfx::B2DRange AnimatedGraphicPrimitive2D::getB2DRange(const geometry::ViewInformation2D& rViewInformation) const
559 // get object's range
560 basegfx::B2DRange aUnitRange(0.0, 0.0, 1.0, 1.0);
561 aUnitRange.transform(getTransform());
563 // intersect with visible part
564 aUnitRange.intersect(rViewInformation.getViewport());
566 return aUnitRange;
569 } // end of namespace
571 namespace drawinglayer::primitive2d
573 Primitive2DReference createFillGraphicPrimitive2D(
574 const basegfx::B2DHomMatrix& rTransform,
575 const drawinglayer::attribute::FillGraphicAttribute& rFillGraphicAttribute,
576 double fTransparency)
578 if (basegfx::fTools::equal(fTransparency, 1.0))
580 // completely transparent, done
581 return nullptr;
584 const Graphic& rGraphic(rFillGraphicAttribute.getGraphic());
585 const GraphicType aType(rGraphic.GetType());
587 if (GraphicType::Bitmap == aType && rGraphic.IsAnimated())
589 return new AnimatedGraphicPrimitive2D(
590 rGraphic,
591 &rFillGraphicAttribute,
592 rTransform,
593 fTransparency);
596 return new FillGraphicPrimitive2D(
597 rTransform,
598 rFillGraphicAttribute,
599 fTransparency);
602 void create2DDecompositionOfGraphic(
603 Primitive2DContainer& rContainer,
604 const Graphic& rGraphic,
605 const basegfx::B2DHomMatrix& rTransform,
606 double fTransparency)
608 if (basegfx::fTools::equal(fTransparency, 1.0))
610 // completely transparent, done
611 return;
614 switch(rGraphic.GetType())
616 case GraphicType::Bitmap :
618 if(rGraphic.IsAnimated())
620 // prepare specialized AnimatedGraphicPrimitive2D, now with
621 // support for alpha
622 rContainer.append(new AnimatedGraphicPrimitive2D(
623 rGraphic,
624 nullptr,
625 rTransform,
626 fTransparency));
628 else if(rGraphic.getVectorGraphicData())
630 // embedded Vector Graphic Data fill, create embed transform
631 const basegfx::B2DRange& rSvgRange(rGraphic.getVectorGraphicData()->getRange());
633 if(rSvgRange.getWidth() > 0.0 && rSvgRange.getHeight() > 0.0)
635 // translate back to origin, scale to unit coordinates
636 basegfx::B2DHomMatrix aEmbedVectorGraphic(
637 basegfx::utils::createTranslateB2DHomMatrix(
638 -rSvgRange.getMinX(),
639 -rSvgRange.getMinY()));
641 aEmbedVectorGraphic.scale(
642 1.0 / rSvgRange.getWidth(),
643 1.0 / rSvgRange.getHeight());
645 // apply created object transformation
646 aEmbedVectorGraphic = rTransform * aEmbedVectorGraphic;
648 // add Vector Graphic Data primitives embedded
649 rtl::Reference<BasePrimitive2D> aPrimitive(
650 new TransformPrimitive2D(
651 aEmbedVectorGraphic,
652 Primitive2DContainer(rGraphic.getVectorGraphicData()->getPrimitive2DSequence())));
654 // if needed embed to UnifiedTransparencePrimitive2D
655 if (!basegfx::fTools::equalZero(fTransparency, 0.0))
656 aPrimitive = new UnifiedTransparencePrimitive2D(
657 Primitive2DContainer { aPrimitive }, fTransparency);
659 rContainer.append(aPrimitive);
662 else
664 // dependent of transparency used create the needed bitmap primitive
665 if (basegfx::fTools::equalZero(fTransparency))
667 rContainer.append(
668 new BitmapPrimitive2D(
669 rGraphic.GetBitmapEx(),
670 rTransform));
672 else
674 rContainer.append(
675 new BitmapAlphaPrimitive2D(
676 rGraphic.GetBitmapEx(),
677 rTransform,
678 fTransparency));
682 break;
685 case GraphicType::GdiMetafile :
687 // create MetafilePrimitive2D
688 const GDIMetaFile& rMetafile = rGraphic.GetGDIMetaFile();
690 rtl::Reference<BasePrimitive2D> aPrimitive(
691 new MetafilePrimitive2D(
692 rTransform,
693 rMetafile));
695 // #i100357# find out if clipping is needed for this primitive. Unfortunately,
696 // there exist Metafiles who's content is bigger than the proposed PrefSize set
697 // at them. This is an error, but we need to work around this
698 const Size aMetaFilePrefSize(rMetafile.GetPrefSize());
699 const Size aMetaFileRealSize(
700 rMetafile.GetBoundRect(
701 *Application::GetDefaultDevice()).GetSize());
703 if(aMetaFileRealSize.getWidth() > aMetaFilePrefSize.getWidth()
704 || aMetaFileRealSize.getHeight() > aMetaFilePrefSize.getHeight())
706 // clipping needed. Embed to MaskPrimitive2D. Create children and mask polygon
707 basegfx::B2DPolygon aMaskPolygon(basegfx::utils::createUnitPolygon());
708 aMaskPolygon.transform(rTransform);
710 aPrimitive = new MaskPrimitive2D(
711 basegfx::B2DPolyPolygon(aMaskPolygon),
712 Primitive2DContainer { aPrimitive });
715 // if needed embed to UnifiedTransparencePrimitive2D
716 if (!basegfx::fTools::equalZero(fTransparency, 0.0))
717 aPrimitive = new UnifiedTransparencePrimitive2D(
718 Primitive2DContainer { aPrimitive }, fTransparency);
720 rContainer.append(aPrimitive);
721 break;
724 default:
726 // nothing to create
727 break;
732 Primitive2DContainer create2DColorModifierEmbeddingsAsNeeded(
733 Primitive2DContainer&& rChildren,
734 GraphicDrawMode aGraphicDrawMode,
735 double fLuminance,
736 double fContrast,
737 double fRed,
738 double fGreen,
739 double fBlue,
740 double fGamma,
741 bool bInvert)
743 Primitive2DContainer aRetval;
745 if(rChildren.empty())
747 // no child content, done
748 return aRetval;
751 // set child content as retval; that is what will be used as child content in all
752 // embeddings from here
753 aRetval = std::move(rChildren);
755 if(GraphicDrawMode::Watermark == aGraphicDrawMode)
757 // this is solved by applying fixed values additionally to luminance
758 // and contrast, do it here and reset DrawMode to GraphicDrawMode::Standard
759 // original in svtools uses:
760 // #define WATERMARK_LUM_OFFSET 50
761 // #define WATERMARK_CON_OFFSET -70
762 fLuminance = std::clamp(fLuminance + 0.5, -1.0, 1.0);
763 fContrast = std::clamp(fContrast - 0.7, -1.0, 1.0);
764 aGraphicDrawMode = GraphicDrawMode::Standard;
767 // DrawMode (GraphicDrawMode::Watermark already handled)
768 switch(aGraphicDrawMode)
770 case GraphicDrawMode::Greys:
772 // convert to grey
773 const Primitive2DReference aPrimitiveGrey(
774 new ModifiedColorPrimitive2D(
775 std::move(aRetval),
776 std::make_shared<basegfx::BColorModifier_gray>()));
778 aRetval = Primitive2DContainer { aPrimitiveGrey };
779 break;
781 case GraphicDrawMode::Mono:
783 // convert to mono (black/white with threshold 0.5)
784 const Primitive2DReference aPrimitiveBlackAndWhite(
785 new ModifiedColorPrimitive2D(
786 std::move(aRetval),
787 std::make_shared<basegfx::BColorModifier_black_and_white>(0.5)));
789 aRetval = Primitive2DContainer { aPrimitiveBlackAndWhite };
790 break;
792 default: // case GraphicDrawMode::Standard:
794 assert(
795 aGraphicDrawMode != GraphicDrawMode::Watermark
796 && "OOps, GraphicDrawMode::Watermark should already be handled (see above)");
797 // nothing to do
798 break;
802 // mnContPercent, mnLumPercent, mnRPercent, mnGPercent, mnBPercent
803 // handled in a single call
804 if(!basegfx::fTools::equalZero(fLuminance)
805 || !basegfx::fTools::equalZero(fContrast)
806 || !basegfx::fTools::equalZero(fRed)
807 || !basegfx::fTools::equalZero(fGreen)
808 || !basegfx::fTools::equalZero(fBlue))
810 const Primitive2DReference aPrimitiveRGBLuminannceContrast(
811 new ModifiedColorPrimitive2D(
812 std::move(aRetval),
813 std::make_shared<basegfx::BColorModifier_RGBLuminanceContrast>(
814 fRed,
815 fGreen,
816 fBlue,
817 fLuminance,
818 fContrast)));
820 aRetval = Primitive2DContainer { aPrimitiveRGBLuminannceContrast };
823 // gamma (boolean)
824 if(!basegfx::fTools::equal(fGamma, 1.0))
826 const Primitive2DReference aPrimitiveGamma(
827 new ModifiedColorPrimitive2D(
828 std::move(aRetval),
829 std::make_shared<basegfx::BColorModifier_gamma>(
830 fGamma)));
832 aRetval = Primitive2DContainer { aPrimitiveGamma };
835 // invert (boolean)
836 if(bInvert)
838 const Primitive2DReference aPrimitiveInvert(
839 new ModifiedColorPrimitive2D(
840 std::move(aRetval),
841 std::make_shared<basegfx::BColorModifier_invert>()));
843 aRetval = Primitive2DContainer { aPrimitiveInvert };
846 return aRetval;
849 } // end of namespace
851 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */