summaryrefslogtreecommitdiff
path: root/drawinglayer
diff options
context:
space:
mode:
authorMike Kaganski <mike.kaganski@collabora.com>2020-05-14 14:42:24 +0300
committerMike Kaganski <mike.kaganski@collabora.com>2020-05-29 10:30:40 +0200
commitbb591a57cf62714af291e1b0807e017c0763cd48 (patch)
treefa21386286c525d1ed6f618bffac086eb6c1dd39 /drawinglayer
parent2356a687e3abae2eecb9060d52bb4c4fadbaaae2 (diff)
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@collabora.com> (cherry picked from commit d4bfa55209eedcaae51c9ccba466f39620f82d49) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/95078
Diffstat (limited to 'drawinglayer')
-rw-r--r--drawinglayer/source/processor2d/vclhelperbufferdevice.cxx120
-rw-r--r--drawinglayer/source/processor2d/vclhelperbufferdevice.hxx4
2 files changed, 80 insertions, 44 deletions
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);