1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
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
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
55 class AnimatedGraphicPrimitive2D
: public AnimatedSwitchPrimitive2D
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
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
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()
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
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.
160 void createAndSetAnimationTiming()
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)
190 // GetBitmap()-> AlphaMask is optimized with SkiaSalBitmap::InterpretAs8Bit(), 1bpp mask is not.
191 if( SkiaHelper::isVCLSkiaEnabled())
197 const AlphaMask
aMaskBitmap(maVirtualDeviceMask
->GetBitmap(Point(), maVirtualDeviceMask
->GetOutputSizePixel()));
198 bitmap
= BitmapEx(aMainBitmap
, aMaskBitmap
);
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(
213 maFillGraphicAttribute
.getGraphicRange(),
214 maFillGraphicAttribute
.getTiling(),
215 maFillGraphicAttribute
.getOffsetX(),
216 maFillGraphicAttribute
.getOffsetY());
218 return new FillGraphicPrimitive2D(
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
)
249 bBufferingComplete
= false;
254 if (bBufferingComplete
)
256 maVirtualDevice
.disposeAndClear();
257 maVirtualDeviceMask
.disposeAndClear();
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.
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
)
290 const AnimationFrame
& rAnimationFrame
= maAnimation
.Get(sal_uInt16(mnNextFrameToPrepare
));
292 bool bSourceBlending
= rAnimationFrame
.meBlend
== Blend::Source
;
296 tools::Rectangle
aArea(rAnimationFrame
.maPositionPixel
, rAnimationFrame
.maBitmapEx
.GetSizePixel());
297 maVirtualDevice
->Erase(aArea
);
298 maVirtualDeviceMask
->Erase(aArea
);
301 switch (rAnimationFrame
.meDisposal
)
305 maVirtualDevice
->DrawBitmapEx(rAnimationFrame
.maPositionPixel
, rAnimationFrame
.maBitmapEx
);
306 AlphaMask aAlphaMask
= rAnimationFrame
.maBitmapEx
.GetAlphaMask();
308 if (aAlphaMask
.IsEmpty())
311 const ::tools::Rectangle
aRect(aEmpty
, maVirtualDeviceMask
->GetOutputSizePixel());
312 const Wallpaper
aWallpaper(COL_BLACK
);
313 maVirtualDeviceMask
->DrawWallpaper(aRect
, aWallpaper
);
317 BitmapEx
aExpandVisibilityMask(aAlphaMask
.GetBitmap(), aAlphaMask
);
318 maVirtualDeviceMask
->DrawBitmapEx(rAnimationFrame
.maPositionPixel
, aExpandVisibilityMask
);
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
);
333 const ::tools::Rectangle
aRect(rAnimationFrame
.maPositionPixel
, rAnimationFrame
.maBitmapEx
.GetSizePixel());
334 maVirtualDeviceMask
->SetFillColor(COL_BLACK
);
335 maVirtualDeviceMask
->SetLineColor();
336 maVirtualDeviceMask
->DrawRect(aRect
);
340 BitmapEx
aExpandVisibilityMask(rMask
.GetBitmap(), rMask
);
341 maVirtualDeviceMask
->DrawBitmapEx(rAnimationFrame
.maPositionPixel
, aExpandVisibilityMask
);
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
);
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
];
377 // always buffer first frame, it's sometimes requested out-of-order
378 if (0 == nIndex
&& maBufferedFirstFrame
.is())
380 return maBufferedFirstFrame
;
384 return Primitive2DReference();
389 AnimatedGraphicPrimitive2D(
390 const Graphic
& rGraphic
,
391 const drawinglayer::attribute::FillGraphicAttribute
* pFillGraphicAttribute
,
392 basegfx::B2DHomMatrix aTransform
,
393 double fTransparency
= 0.0);
394 virtual ~AnimatedGraphicPrimitive2D();
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
; }
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
;
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(),
424 maTransform(std::move(aTransform
)),
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),
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
446 // allow buffering up to a size of:
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
)
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();
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
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
523 // check buffering shortcuts, may already be created
524 aRetval
= tryTogetFromBuffer(nIndex
);
528 rVisitor
.visit(aRetval
);
532 // if huge size (and not the buffered 1st frame) simply
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
);
547 rVisitor
.visit(aRetval
);
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());
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
584 const Graphic
& rGraphic(rFillGraphicAttribute
.getGraphic());
585 const GraphicType
aType(rGraphic
.GetType());
587 if (GraphicType::Bitmap
== aType
&& rGraphic
.IsAnimated())
589 return new AnimatedGraphicPrimitive2D(
591 &rFillGraphicAttribute
,
596 return new FillGraphicPrimitive2D(
598 rFillGraphicAttribute
,
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
614 switch(rGraphic
.GetType())
616 case GraphicType::Bitmap
:
618 if(rGraphic
.IsAnimated())
620 // prepare specialized AnimatedGraphicPrimitive2D, now with
622 rContainer
.append(new AnimatedGraphicPrimitive2D(
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(
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
);
664 // dependent of transparency used create the needed bitmap primitive
665 if (basegfx::fTools::equalZero(fTransparency
))
668 new BitmapPrimitive2D(
669 rGraphic
.GetBitmapEx(),
675 new BitmapAlphaPrimitive2D(
676 rGraphic
.GetBitmapEx(),
685 case GraphicType::GdiMetafile
:
687 // create MetafilePrimitive2D
688 const GDIMetaFile
& rMetafile
= rGraphic
.GetGDIMetaFile();
690 rtl::Reference
<BasePrimitive2D
> aPrimitive(
691 new MetafilePrimitive2D(
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
);
732 Primitive2DContainer
create2DColorModifierEmbeddingsAsNeeded(
733 Primitive2DContainer
&& rChildren
,
734 GraphicDrawMode aGraphicDrawMode
,
743 Primitive2DContainer aRetval
;
745 if(rChildren
.empty())
747 // no child content, done
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
:
773 const Primitive2DReference
aPrimitiveGrey(
774 new ModifiedColorPrimitive2D(
776 std::make_shared
<basegfx::BColorModifier_gray
>()));
778 aRetval
= Primitive2DContainer
{ aPrimitiveGrey
};
781 case GraphicDrawMode::Mono
:
783 // convert to mono (black/white with threshold 0.5)
784 const Primitive2DReference
aPrimitiveBlackAndWhite(
785 new ModifiedColorPrimitive2D(
787 std::make_shared
<basegfx::BColorModifier_black_and_white
>(0.5)));
789 aRetval
= Primitive2DContainer
{ aPrimitiveBlackAndWhite
};
792 default: // case GraphicDrawMode::Standard:
795 aGraphicDrawMode
!= GraphicDrawMode::Watermark
796 && "OOps, GraphicDrawMode::Watermark should already be handled (see above)");
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(
813 std::make_shared
<basegfx::BColorModifier_RGBLuminanceContrast
>(
820 aRetval
= Primitive2DContainer
{ aPrimitiveRGBLuminannceContrast
};
824 if(!basegfx::fTools::equal(fGamma
, 1.0))
826 const Primitive2DReference
aPrimitiveGamma(
827 new ModifiedColorPrimitive2D(
829 std::make_shared
<basegfx::BColorModifier_gamma
>(
832 aRetval
= Primitive2DContainer
{ aPrimitiveGamma
};
838 const Primitive2DReference
aPrimitiveInvert(
839 new ModifiedColorPrimitive2D(
841 std::make_shared
<basegfx::BColorModifier_invert
>()));
843 aRetval
= Primitive2DContainer
{ aPrimitiveInvert
};
849 } // end of namespace
851 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */