drawinglayer/source/primitive2d/graphicprimitivehelper2d.cxx |   14 ++++++++---
 include/vcl/animate/AnimationFrame.hxx                       |   14 +++++++++--
 vcl/source/animate/AnimationFrame.cxx                        |    3 ++
 vcl/source/filter/png/PngImageReader.cxx                     |    6 +++-
 4 files changed, 30 insertions(+), 7 deletions(-)

New commits:
commit 8dfde7d69a8bbdc8ce88aefded231b94e30271d6
Author:     Paris Oplopoios <paris.oplopo...@collabora.com>
AuthorDate: Sat Jun 24 17:36:09 2023 +0300
Commit:     Tomaž Vajngerl <qui...@gmail.com>
CommitDate: Thu Jun 29 15:19:54 2023 +0200

    tdf#104877 Implement APNG blending modes
    
    Change-Id: Ib7ce4d113ccaa4843b8332087ebe52ac3828180e
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/153556
    Tested-by: Jenkins
    Reviewed-by: Tomaž Vajngerl <qui...@gmail.com>

diff --git a/drawinglayer/source/primitive2d/graphicprimitivehelper2d.cxx 
b/drawinglayer/source/primitive2d/graphicprimitivehelper2d.cxx
index a95df2474744..f3c4cf69911c 100644
--- a/drawinglayer/source/primitive2d/graphicprimitivehelper2d.cxx
+++ b/drawinglayer/source/primitive2d/graphicprimitivehelper2d.cxx
@@ -252,6 +252,15 @@ namespace drawinglayer::primitive2d
                     // prepare step
                     const AnimationFrame& rAnimationFrame = 
maAnimation.Get(sal_uInt16(mnNextFrameToPrepare));
 
+                    bool bSourceBlending = rAnimationFrame.meBlend == 
Blend::Source;
+
+                    if (bSourceBlending)
+                    {
+                        tools::Rectangle 
aArea(rAnimationFrame.maPositionPixel, 
rAnimationFrame.maBitmapEx.GetSizePixel());
+                        maVirtualDevice->Erase(aArea);
+                        maVirtualDeviceMask->Erase(aArea);
+                    }
+
                     switch (rAnimationFrame.meDisposal)
                     {
                         case Disposal::Not:
@@ -278,14 +287,13 @@ namespace drawinglayer::primitive2d
                         {
                             // #i70772# react on no mask, for primitives, too.
                             const AlphaMask & 
rMask(rAnimationFrame.maBitmapEx.GetAlphaMask());
-                            const Bitmap & 
rContent(rAnimationFrame.maBitmapEx.GetBitmap());
 
                             maVirtualDeviceMask->Erase();
-                            
maVirtualDevice->DrawBitmap(rAnimationFrame.maPositionPixel, rContent);
+                            
maVirtualDevice->DrawBitmapEx(rAnimationFrame.maPositionPixel, 
rAnimationFrame.maBitmapEx);
 
                             if (rMask.IsEmpty())
                             {
-                                const ::tools::Rectangle 
aRect(rAnimationFrame.maPositionPixel, rContent.GetSizePixel());
+                                const ::tools::Rectangle 
aRect(rAnimationFrame.maPositionPixel, 
rAnimationFrame.maBitmapEx.GetSizePixel());
                                 maVirtualDeviceMask->SetFillColor(COL_BLACK);
                                 maVirtualDeviceMask->SetLineColor();
                                 maVirtualDeviceMask->DrawRect(aRect);
diff --git a/include/vcl/animate/AnimationFrame.hxx 
b/include/vcl/animate/AnimationFrame.hxx
index 7aa6f0d54a2b..3e9a4b21d168 100644
--- a/include/vcl/animate/AnimationFrame.hxx
+++ b/include/vcl/animate/AnimationFrame.hxx
@@ -28,6 +28,12 @@ enum class Disposal
     Previous
 };
 
+enum class Blend
+{
+    Source,
+    Over
+};
+
 struct AnimationFrame
 {
     BitmapEx maBitmapEx;
@@ -35,22 +41,26 @@ struct AnimationFrame
     Size maSizePixel;
     tools::Long mnWait;
     Disposal meDisposal;
+    Blend meBlend;
     bool mbUserInput;
 
     AnimationFrame()
         : mnWait(0)
         , meDisposal(Disposal::Not)
+        , meBlend(Blend::Over)
         , mbUserInput(false)
     {
     }
 
     AnimationFrame(const BitmapEx& rBitmapEx, const Point& rPositionPixel, 
const Size& rSizePixel,
-                   tools::Long nWait = 0, Disposal eDisposal = Disposal::Not)
+                   tools::Long nWait = 0, Disposal eDisposal = Disposal::Not,
+                   Blend eBlend = Blend::Over)
         : maBitmapEx(rBitmapEx)
         , maPositionPixel(rPositionPixel)
         , maSizePixel(rSizePixel)
         , mnWait(nWait)
         , meDisposal(eDisposal)
+        , meBlend(eBlend)
         , mbUserInput(false)
     {
     }
@@ -60,7 +70,7 @@ struct AnimationFrame
         return (rAnimationFrame.maBitmapEx == maBitmapEx
                 && rAnimationFrame.maPositionPixel == maPositionPixel
                 && rAnimationFrame.maSizePixel == maSizePixel && 
rAnimationFrame.mnWait == mnWait
-                && rAnimationFrame.meDisposal == meDisposal
+                && rAnimationFrame.meDisposal == meDisposal && 
rAnimationFrame.meBlend == meBlend
                 && rAnimationFrame.mbUserInput == mbUserInput);
     }
 
diff --git a/vcl/source/animate/AnimationFrame.cxx 
b/vcl/source/animate/AnimationFrame.cxx
index e2f9bae931fb..3593a0ab17e1 100644
--- a/vcl/source/animate/AnimationFrame.cxx
+++ b/vcl/source/animate/AnimationFrame.cxx
@@ -45,6 +45,9 @@ BitmapChecksum AnimationFrame::GetChecksum() const
     UInt32ToSVBT32(o3tl::to_underlying(meDisposal), aBT32);
     nCrc = vcl_get_checksum(nCrc, aBT32, 4);
 
+    UInt32ToSVBT32(o3tl::to_underlying(meBlend), aBT32);
+    nCrc = vcl_get_checksum(nCrc, aBT32, 4);
+
     UInt32ToSVBT32(sal_uInt32(mbUserInput), aBT32);
     nCrc = vcl_get_checksum(nCrc, aBT32, 4);
 
diff --git a/vcl/source/filter/png/PngImageReader.cxx 
b/vcl/source/filter/png/PngImageReader.cxx
index a04344b4afe6..e7b5c414762b 100644
--- a/vcl/source/filter/png/PngImageReader.cxx
+++ b/vcl/source/filter/png/PngImageReader.cxx
@@ -685,11 +685,12 @@ bool reader(SvStream& rStream, Graphic& rGraphic,
             {
                 Point aFirstPoint(0, 0);
                 auto aDisposal = static_cast<Disposal>(aFctlChunk->dispose_op);
+                auto aBlend = static_cast<Blend>(aFctlChunk->blend_op);
                 if (aDisposal == Disposal::Previous)
                     aDisposal = Disposal::Back;
                 AnimationFrame aAnimationFrame(
                     aBitmapEx, aFirstPoint, aCanvasSize,
-                    NumDenToTime(aFctlChunk->delay_num, 
aFctlChunk->delay_den), aDisposal);
+                    NumDenToTime(aFctlChunk->delay_num, 
aFctlChunk->delay_den), aDisposal, aBlend);
                 aAnimation.Insert(aAnimationFrame);
             }
         }
@@ -699,6 +700,7 @@ bool reader(SvStream& rStream, Graphic& rGraphic,
             fcTLChunk* aFctlChunk
                 = 
static_cast<fcTLChunk*>(aAPNGInfo.maFrameData[nSequenceIndex++].get());
             Disposal aDisposal = static_cast<Disposal>(aFctlChunk->dispose_op);
+            Blend aBlend = static_cast<Blend>(aFctlChunk->blend_op);
             if (i == 0 && aDisposal == Disposal::Back)
                 aDisposal = Disposal::Previous;
             SvMemoryStream aFrameStream;
@@ -730,7 +732,7 @@ bool reader(SvStream& rStream, Graphic& rGraphic,
             Size aSize(aFctlChunk->width, aFctlChunk->height);
             AnimationFrame aAnimationFrame(
                 aFrameBitmapEx, aStartPoint, aSize,
-                NumDenToTime(aFctlChunk->delay_num, aFctlChunk->delay_den), 
aDisposal);
+                NumDenToTime(aFctlChunk->delay_num, aFctlChunk->delay_den), 
aDisposal, aBlend);
             aAnimation.Insert(aAnimationFrame);
         }
         rGraphic = aAnimation;

Reply via email to