[Libreoffice-commits] core.git: drawinglayer/source

Mike Kaganski (via logerrit) logerrit at kemper.freedesktop.org
Fri May 29 04:24:29 UTC 2020


 drawinglayer/source/processor2d/vclhelperbufferdevice.cxx |  120 ++++++++------
 drawinglayer/source/processor2d/vclhelperbufferdevice.hxx |    4 
 2 files changed, 80 insertions(+), 44 deletions(-)

New commits:
commit d4bfa55209eedcaae51c9ccba466f39620f82d49
Author:     Mike Kaganski <mike.kaganski at collabora.com>
AuthorDate: Thu May 14 14:42:24 2020 +0300
Commit:     Mike Kaganski <mike.kaganski at collabora.com>
CommitDate: Fri May 29 06:23:57 2020 +0200

    Allow creation of virtual device with alpha as content of impBufferDevice
    
    impBufferDevice now can create its mpContent with alpha; that is used
    when painting, blending mpContent's alpha with mpMask/mpAlpha/fTrans.
    
    That allows to paint to the buffer device and get actual transparency
    of the painted objects in one pass, to process further (e.g., modify
    transparency separately, or use it to get mask).
    
    Required for subsequent soft edge effect improvement
    
    Change-Id: If19c160581ce9a515d86222dd2fab06f746df2da
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/95030
    Tested-by: Jenkins
    Reviewed-by: Mike Kaganski <mike.kaganski at collabora.com>

diff --git a/drawinglayer/source/processor2d/vclhelperbufferdevice.cxx b/drawinglayer/source/processor2d/vclhelperbufferdevice.cxx
index 534c512daa42..647825959108 100644
--- a/drawinglayer/source/processor2d/vclhelperbufferdevice.cxx
+++ b/drawinglayer/source/processor2d/vclhelperbufferdevice.cxx
@@ -42,11 +42,22 @@ namespace
 class VDevBuffer : public Timer, protected cppu::BaseMutex
 {
 private:
+    struct Entry
+    {
+        VclPtr<VirtualDevice> buf;
+        bool isTransparent = false;
+        Entry(const VclPtr<VirtualDevice>& vdev, bool bTransparent)
+            : buf(vdev)
+            , isTransparent(bTransparent)
+        {
+        }
+    };
+
     // available buffers
-    std::vector<VclPtr<VirtualDevice>> maFreeBuffers;
+    std::vector<Entry> maFreeBuffers;
 
     // allocated/used buffers (remembered to allow deleting them in destructor)
-    std::vector<VclPtr<VirtualDevice>> maUsedBuffers;
+    std::vector<Entry> maUsedBuffers;
 
     // remember what outputdevice was the template passed to VirtualDevice::Create
     // so we can test if that OutputDevice was disposed before reusing a
@@ -58,7 +69,7 @@ public:
     virtual ~VDevBuffer() override;
 
     VclPtr<VirtualDevice> alloc(OutputDevice& rOutDev, const Size& rSizePixel, bool bClear,
-                                bool bMonoChrome);
+                                bool bMonoChrome, bool bTransparent);
     void free(VirtualDevice& rDevice);
 
     // Timer virtuals
@@ -81,19 +92,19 @@ VDevBuffer::~VDevBuffer()
 
     while (!maFreeBuffers.empty())
     {
-        maFreeBuffers.back().disposeAndClear();
+        maFreeBuffers.back().buf.disposeAndClear();
         maFreeBuffers.pop_back();
     }
 
     while (!maUsedBuffers.empty())
     {
-        maUsedBuffers.back().disposeAndClear();
+        maUsedBuffers.back().buf.disposeAndClear();
         maUsedBuffers.pop_back();
     }
 }
 
 VclPtr<VirtualDevice> VDevBuffer::alloc(OutputDevice& rOutDev, const Size& rSizePixel, bool bClear,
-                                        bool bMonoChrome)
+                                        bool bMonoChrome, bool bTransparent)
 {
     ::osl::MutexGuard aGuard(m_aMutex);
     VclPtr<VirtualDevice> pRetval;
@@ -107,9 +118,9 @@ VclPtr<VirtualDevice> VDevBuffer::alloc(OutputDevice& rOutDev, const Size& rSize
 
         for (auto a = maFreeBuffers.begin(); a != maFreeBuffers.end(); ++a)
         {
-            assert(*a && "Empty pointer in VDevBuffer (!)");
+            assert(a->buf && "Empty pointer in VDevBuffer (!)");
 
-            if (nBits == (*a)->GetBitCount())
+            if (nBits == a->buf->GetBitCount() && bTransparent == a->isTransparent)
             {
                 // candidate is valid due to bit depth
                 if (aFound != maFreeBuffers.end())
@@ -119,16 +130,16 @@ VclPtr<VirtualDevice> VDevBuffer::alloc(OutputDevice& rOutDev, const Size& rSize
                     {
                         // found is valid
                         const bool bCandidateOkay(
-                            (*a)->GetOutputWidthPixel() >= rSizePixel.getWidth()
-                            && (*a)->GetOutputHeightPixel() >= rSizePixel.getHeight());
+                            a->buf->GetOutputWidthPixel() >= rSizePixel.getWidth()
+                            && a->buf->GetOutputHeightPixel() >= rSizePixel.getHeight());
 
                         if (bCandidateOkay)
                         {
                             // found and candidate are valid
-                            const sal_uLong aSquare((*aFound)->GetOutputWidthPixel()
-                                                    * (*aFound)->GetOutputHeightPixel());
-                            const sal_uLong aCandidateSquare((*a)->GetOutputWidthPixel()
-                                                             * (*a)->GetOutputHeightPixel());
+                            const sal_uLong aSquare(aFound->buf->GetOutputWidthPixel()
+                                                    * aFound->buf->GetOutputHeightPixel());
+                            const sal_uLong aCandidateSquare(a->buf->GetOutputWidthPixel()
+                                                             * a->buf->GetOutputHeightPixel());
 
                             if (aCandidateSquare < aSquare)
                             {
@@ -145,23 +156,23 @@ VclPtr<VirtualDevice> VDevBuffer::alloc(OutputDevice& rOutDev, const Size& rSize
                     {
                         // found is invalid, use candidate
                         aFound = a;
-                        bOkay = (*aFound)->GetOutputWidthPixel() >= rSizePixel.getWidth()
-                                && (*aFound)->GetOutputHeightPixel() >= rSizePixel.getHeight();
+                        bOkay = aFound->buf->GetOutputWidthPixel() >= rSizePixel.getWidth()
+                                && aFound->buf->GetOutputHeightPixel() >= rSizePixel.getHeight();
                     }
                 }
                 else
                 {
                     // none yet, use candidate
                     aFound = a;
-                    bOkay = (*aFound)->GetOutputWidthPixel() >= rSizePixel.getWidth()
-                            && (*aFound)->GetOutputHeightPixel() >= rSizePixel.getHeight();
+                    bOkay = aFound->buf->GetOutputWidthPixel() >= rSizePixel.getWidth()
+                            && aFound->buf->GetOutputHeightPixel() >= rSizePixel.getHeight();
                 }
             }
         }
 
         if (aFound != maFreeBuffers.end())
         {
-            pRetval = *aFound;
+            pRetval = aFound->buf;
             maFreeBuffers.erase(aFound);
         }
     }
@@ -197,8 +208,9 @@ VclPtr<VirtualDevice> VDevBuffer::alloc(OutputDevice& rOutDev, const Size& rSize
     // no success yet, create new buffer
     if (!pRetval)
     {
-        pRetval = VclPtr<VirtualDevice>::Create(rOutDev, bMonoChrome ? DeviceFormat::BITMASK
-                                                                     : DeviceFormat::DEFAULT);
+        pRetval = VclPtr<VirtualDevice>::Create(
+            rOutDev, bMonoChrome ? DeviceFormat::BITMASK : DeviceFormat::DEFAULT,
+            bTransparent ? DeviceFormat::DEFAULT : DeviceFormat::NONE);
         maDeviceTemplates[pRetval] = &rOutDev;
         pRetval->SetOutputSizePixel(rSizePixel, bClear);
     }
@@ -210,7 +222,7 @@ VclPtr<VirtualDevice> VDevBuffer::alloc(OutputDevice& rOutDev, const Size& rSize
     }
 
     // remember allocated buffer
-    maUsedBuffers.push_back(pRetval);
+    maUsedBuffers.emplace_back(pRetval, bTransparent);
 
     return pRetval;
 }
@@ -218,14 +230,18 @@ VclPtr<VirtualDevice> VDevBuffer::alloc(OutputDevice& rOutDev, const Size& rSize
 void VDevBuffer::free(VirtualDevice& rDevice)
 {
     ::osl::MutexGuard aGuard(m_aMutex);
-    const auto aUsedFound = std::find(maUsedBuffers.begin(), maUsedBuffers.end(), &rDevice);
+    const auto aUsedFound
+        = std::find_if(maUsedBuffers.begin(), maUsedBuffers.end(),
+                       [&rDevice](const Entry& el) { return el.buf == &rDevice; });
     SAL_WARN_IF(aUsedFound == maUsedBuffers.end(), "drawinglayer",
                 "OOps, non-registered buffer freed (!)");
-
-    maUsedBuffers.erase(aUsedFound);
-    maFreeBuffers.emplace_back(&rDevice);
-    SAL_WARN_IF(maFreeBuffers.size() > 1000, "drawinglayer",
-                "excessive cached buffers, " << maFreeBuffers.size() << " entries!");
+    if (aUsedFound != maUsedBuffers.end())
+    {
+        maFreeBuffers.emplace_back(*aUsedFound);
+        maUsedBuffers.erase(aUsedFound);
+        SAL_WARN_IF(maFreeBuffers.size() > 1000, "drawinglayer",
+                    "excessive cached buffers, " << maFreeBuffers.size() << " entries!");
+    }
     Start();
 }
 
@@ -236,8 +252,8 @@ void VDevBuffer::Invoke()
     while (!maFreeBuffers.empty())
     {
         auto aLastOne = maFreeBuffers.back();
-        maDeviceTemplates.erase(aLastOne);
-        aLastOne.disposeAndClear();
+        maDeviceTemplates.erase(aLastOne.buf);
+        aLastOne.buf.disposeAndClear();
         maFreeBuffers.pop_back();
     }
 }
@@ -257,11 +273,13 @@ VDevBuffer& getVDevBuffer()
     return *aVDevBuffer.get();
 }
 
-impBufferDevice::impBufferDevice(OutputDevice& rOutDev, const basegfx::B2DRange& rRange)
+impBufferDevice::impBufferDevice(OutputDevice& rOutDev, const basegfx::B2DRange& rRange,
+                                 bool bContentTransparent)
     : mrOutDev(rOutDev)
     , mpContent(nullptr)
     , mpMask(nullptr)
     , mpAlpha(nullptr)
+    , mbContentTransparent(bContentTransparent)
 {
     basegfx::B2DRange aRangePixel(rRange);
     aRangePixel.transform(mrOutDev.GetViewTransformation());
@@ -281,9 +299,11 @@ impBufferDevice::impBufferDevice(OutputDevice& rOutDev, const basegfx::B2DRange&
     // rendering, especially shadows, is broken on iOS unless
     // we pass 'true' here. Are virtual devices always de
     // facto cleared when created on other platforms?
-    mpContent = getVDevBuffer().alloc(mrOutDev, maDestPixel.GetSize(), true, false);
+    mpContent
+        = getVDevBuffer().alloc(mrOutDev, maDestPixel.GetSize(), true, false, bContentTransparent);
 #else
-    mpContent = getVDevBuffer().alloc(mrOutDev, maDestPixel.GetSize(), false, false);
+    mpContent
+        = getVDevBuffer().alloc(mrOutDev, maDestPixel.GetSize(), false, false, bContentTransparent);
 #endif
 
     // #i93485# assert when copying from window to VDev is used
@@ -366,7 +386,7 @@ void impBufferDevice::paint(double fTrans)
     if (mpAlpha)
     {
         mpAlpha->EnableMapMode(false);
-        const AlphaMask aAlphaMask(mpAlpha->GetBitmap(aEmptyPoint, aSizePixel));
+        AlphaMask aAlphaMask(mpAlpha->GetBitmap(aEmptyPoint, aSizePixel));
 
 #ifdef DBG_UTIL
         if (bDoSaveForVisualControl)
@@ -382,8 +402,10 @@ void impBufferDevice::paint(double fTrans)
         }
 #endif
 
-        Bitmap aContent(mpContent->GetBitmap(aEmptyPoint, aSizePixel));
-        mrOutDev.DrawBitmapEx(maDestPixel.TopLeft(), BitmapEx(aContent, aAlphaMask));
+        BitmapEx aContent(mpContent->GetBitmapEx(aEmptyPoint, aSizePixel));
+        if (mbContentTransparent)
+            aAlphaMask.BlendWith(aContent.GetAlpha());
+        mrOutDev.DrawBitmapEx(maDestPixel.TopLeft(), BitmapEx(aContent.GetBitmap(), aAlphaMask));
     }
     else if (mpMask)
     {
@@ -404,15 +426,27 @@ void impBufferDevice::paint(double fTrans)
         }
 #endif
 
-        Bitmap aContent(mpContent->GetBitmap(aEmptyPoint, aSizePixel));
-        mrOutDev.DrawBitmapEx(maDestPixel.TopLeft(), BitmapEx(aContent, aMask));
+        if (mbContentTransparent)
+        {
+            BitmapEx aContent(mpContent->GetBitmapEx(aEmptyPoint, aSizePixel));
+            AlphaMask aAlpha(aContent.GetAlpha());
+            aAlpha.BlendWith(aMask);
+            mrOutDev.DrawBitmapEx(maDestPixel.TopLeft(), BitmapEx(aContent.GetBitmap(), aAlpha));
+        }
+        else
+        {
+            Bitmap aContent(mpContent->GetBitmap(aEmptyPoint, aSizePixel));
+            mrOutDev.DrawBitmapEx(maDestPixel.TopLeft(), BitmapEx(aContent, aMask));
+        }
     }
     else if (0.0 != fTrans)
     {
         sal_uInt8 nMaskValue(static_cast<sal_uInt8>(basegfx::fround(fTrans * 255.0)));
-        const AlphaMask aAlphaMask(aSizePixel, &nMaskValue);
-        Bitmap aContent(mpContent->GetBitmap(aEmptyPoint, aSizePixel));
-        mrOutDev.DrawBitmapEx(maDestPixel.TopLeft(), BitmapEx(aContent, aAlphaMask));
+        AlphaMask aAlphaMask(aSizePixel, &nMaskValue);
+        BitmapEx aContent(mpContent->GetBitmapEx(aEmptyPoint, aSizePixel));
+        if (mbContentTransparent)
+            aAlphaMask.BlendWith(aContent.GetAlpha());
+        mrOutDev.DrawBitmapEx(maDestPixel.TopLeft(), BitmapEx(aContent.GetBitmap(), aAlphaMask));
     }
     else
     {
@@ -436,7 +470,7 @@ VirtualDevice& impBufferDevice::getMask()
                 "impBufferDevice: No content, check isVisible() before accessing (!)");
     if (!mpMask)
     {
-        mpMask = getVDevBuffer().alloc(mrOutDev, maDestPixel.GetSize(), true, true);
+        mpMask = getVDevBuffer().alloc(mrOutDev, maDestPixel.GetSize(), true, true, false);
         mpMask->SetMapMode(mpContent->GetMapMode());
 
         // do NOT copy AA flag for mask!
@@ -451,7 +485,7 @@ VirtualDevice& impBufferDevice::getTransparence()
                 "impBufferDevice: No content, check isVisible() before accessing (!)");
     if (!mpAlpha)
     {
-        mpAlpha = getVDevBuffer().alloc(mrOutDev, maDestPixel.GetSize(), true, false);
+        mpAlpha = getVDevBuffer().alloc(mrOutDev, maDestPixel.GetSize(), true, false, false);
         mpAlpha->SetMapMode(mpContent->GetMapMode());
 
         // copy AA flag for new target; masking needs to be smooth
diff --git a/drawinglayer/source/processor2d/vclhelperbufferdevice.hxx b/drawinglayer/source/processor2d/vclhelperbufferdevice.hxx
index 90d351eac50f..c85e3c4a6048 100644
--- a/drawinglayer/source/processor2d/vclhelperbufferdevice.hxx
+++ b/drawinglayer/source/processor2d/vclhelperbufferdevice.hxx
@@ -37,9 +37,11 @@ class impBufferDevice
     VclPtr<VirtualDevice> mpMask;
     VclPtr<VirtualDevice> mpAlpha;
     tools::Rectangle maDestPixel;
+    bool mbContentTransparent;
 
 public:
-    impBufferDevice(OutputDevice& rOutDev, const basegfx::B2DRange& rRange);
+    impBufferDevice(OutputDevice& rOutDev, const basegfx::B2DRange& rRange,
+                    bool bContentTransparent = false);
     ~impBufferDevice();
 
     void paint(double fTrans = 0.0);


More information about the Libreoffice-commits mailing list