summaryrefslogtreecommitdiff
path: root/vcl
diff options
context:
space:
mode:
authorLuboš Luňák <l.lunak@collabora.com>2021-11-16 13:34:37 +0100
committerLuboš Luňák <l.lunak@collabora.com>2021-11-16 18:37:21 +0100
commita0a4709eb4226ae15931999fc17afe5b5b9f8081 (patch)
tree3fcbd0cd908ff498ff68c918a880c271e48dcb58 /vcl
parentf33b76b4e675818deae244427cef84c576a1a1f8 (diff)
try to avoid scaling bitmaps twice in Skia when drawing
The scenario is that something scales a bitmap and then asks for it to be drawn (possibly drawn scaled again). One example is OutputDevice::DrawBitmap() subsampling the bitmap that according to c0ce7ca4884f7f6d1 is supposed to improve quality with headless(?) backend, but with Skia it's pointless and it breaks things like caching during repeated drawing, because then GetSkImage() will need to generate a new SkImage each time. Since Skia backend uses delayed scaling, these cases can be sorted out by checking the stored SkImage and using it if suitable, as the original image is as good as the rescaled one, but often it's better - it may be cached, sometimes the scaling operations cancel each other out (often the case in HiDPI mode). Change-Id: I0af32f7abdf057a3bdda75247d2dc374eaf1bc4b Reviewed-on: https://gerrit.libreoffice.org/c/core/+/125311 Tested-by: Jenkins Reviewed-by: Luboš Luňák <l.lunak@collabora.com>
Diffstat (limited to 'vcl')
-rw-r--r--vcl/inc/skia/gdiimpl.hxx4
-rw-r--r--vcl/inc/skia/salbmp.hxx21
-rw-r--r--vcl/inc/skia/utils.hxx8
-rw-r--r--vcl/qa/cppunit/skia/skia.cxx37
-rw-r--r--vcl/skia/gdiimpl.cxx141
-rw-r--r--vcl/skia/salbmp.cxx49
6 files changed, 212 insertions, 48 deletions
diff --git a/vcl/inc/skia/gdiimpl.hxx b/vcl/inc/skia/gdiimpl.hxx
index abfa89ca8bfa..9cf14f176185 100644
--- a/vcl/inc/skia/gdiimpl.hxx
+++ b/vcl/inc/skia/gdiimpl.hxx
@@ -284,6 +284,10 @@ protected:
static void setCanvasClipRegion(SkCanvas* canvas, const vcl::Region& region);
sk_sp<SkImage> mergeCacheBitmaps(const SkiaSalBitmap& bitmap, const SkiaSalBitmap* alphaBitmap,
const Size& targetSize);
+ using DirectImage = SkiaHelper::DirectImage;
+ static OString makeCachedImageKey(const SkiaSalBitmap& bitmap, const SkiaSalBitmap* alphaBitmap,
+ const Size& targetSize, DirectImage bitmapType,
+ DirectImage alphaBitmapType);
// Skia uses floating point coordinates, so when we use integer coordinates, sometimes
// rounding results in off-by-one errors (down), especially when drawing using GPU,
diff --git a/vcl/inc/skia/salbmp.hxx b/vcl/inc/skia/salbmp.hxx
index aa8d245ce741..2959952a3442 100644
--- a/vcl/inc/skia/salbmp.hxx
+++ b/vcl/inc/skia/salbmp.hxx
@@ -70,17 +70,21 @@ public:
// True if GetSkShader() should be preferred to GetSkImage() (or the Alpha variants).
bool PreferSkShader() const;
+ // Direct image means direct access to the stored SkImage, without checking
+ // if its size is up to date. This should be used only in special cases with care.
+ using DirectImage = SkiaHelper::DirectImage;
// Returns the contents as SkImage (possibly GPU-backed).
- const sk_sp<SkImage>& GetSkImage() const;
- sk_sp<SkShader> GetSkShader(const SkSamplingOptions& samplingOptions) const;
-
+ const sk_sp<SkImage>& GetSkImage(DirectImage direct = DirectImage::No) const;
+ sk_sp<SkShader> GetSkShader(const SkSamplingOptions& samplingOptions,
+ DirectImage direct = DirectImage::No) const;
// Returns the contents as alpha SkImage (possibly GPU-backed)
- const sk_sp<SkImage>& GetAlphaSkImage() const;
- sk_sp<SkShader> GetAlphaSkShader(const SkSamplingOptions& samplingOptions) const;
+ const sk_sp<SkImage>& GetAlphaSkImage(DirectImage direct = DirectImage::No) const;
+ sk_sp<SkShader> GetAlphaSkShader(const SkSamplingOptions& samplingOptions,
+ DirectImage direct = DirectImage::No) const;
// Key for caching/hashing.
- OString GetImageKey() const;
- OString GetAlphaImageKey() const;
+ OString GetImageKey(DirectImage direct = DirectImage::No) const;
+ OString GetAlphaImageKey(DirectImage direct = DirectImage::No) const;
// Returns true if it is known that this bitmap can be ignored if it's to be used
// as an alpha bitmap. An optimization, not guaranteed to return true for all such cases.
@@ -88,6 +92,9 @@ public:
// Alpha type best suitable for the content.
SkAlphaType alphaType() const;
+ // Tries to create direct GetAlphaSkImage() from direct GetSkImage().
+ void TryDirectConvertToAlphaNoScaling();
+
// Dump contents to a file for debugging.
void dump(const char* file) const;
diff --git a/vcl/inc/skia/utils.hxx b/vcl/inc/skia/utils.hxx
index 0a17ee81bc4d..92df0325c870 100644
--- a/vcl/inc/skia/utils.hxx
+++ b/vcl/inc/skia/utils.hxx
@@ -73,6 +73,14 @@ VCL_DLLPUBLIC sk_sp<SkImage> makeCheckedImageSnapshot(sk_sp<SkSurface> surface,
inline Size imageSize(const sk_sp<SkImage>& image) { return Size(image->width(), image->height()); }
+// Whether to use GetSkImage() that checks for delayed scaling or whether to access
+// the stored image directly without checks.
+enum DirectImage
+{
+ Yes,
+ No
+};
+
// Do 'paint->setBlendMode(SkBlendMode::kDifference)' (workaround for buggy drivers).
void setBlendModeDifference(SkPaint* paint);
diff --git a/vcl/qa/cppunit/skia/skia.cxx b/vcl/qa/cppunit/skia/skia.cxx
index 128829aecc18..f6920ccf1d8a 100644
--- a/vcl/qa/cppunit/skia/skia.cxx
+++ b/vcl/qa/cppunit/skia/skia.cxx
@@ -43,6 +43,7 @@ public:
void testMatrixQuality();
void testDelayedScale();
void testDelayedScaleAlphaImage();
+ void testDrawDelayedScaleImage();
void testTdf137329();
void testTdf140848();
void testTdf132367();
@@ -56,6 +57,7 @@ public:
CPPUNIT_TEST(testMatrixQuality);
CPPUNIT_TEST(testDelayedScale);
CPPUNIT_TEST(testDelayedScaleAlphaImage);
+ CPPUNIT_TEST(testDrawDelayedScaleImage);
CPPUNIT_TEST(testTdf137329);
CPPUNIT_TEST(testTdf140848);
CPPUNIT_TEST(testTdf132367);
@@ -429,6 +431,41 @@ void SkiaTest::testDelayedScaleAlphaImage()
CPPUNIT_ASSERT_EQUAL(Size(240, 240), bitmapCopy.GetSize());
}
+void SkiaTest::testDrawDelayedScaleImage()
+{
+ if (!SkiaHelper::isVCLSkiaEnabled())
+ return;
+ ScopedVclPtr<VirtualDevice> device = VclPtr<VirtualDevice>::Create(DeviceFormat::DEFAULT);
+ device->SetOutputSizePixel(Size(10, 10));
+ device->SetBackground(Wallpaper(COL_WHITE));
+ device->Erase();
+ Bitmap bitmap(Size(10, 10), vcl::PixelFormat::N24_BPP);
+ bitmap.Erase(COL_RED);
+ // Set a pixel to create pixel data.
+ BitmapWriteAccess(bitmap).SetPixel(0, 0, COL_BLUE);
+ SkiaSalBitmap* skiaBitmap1 = dynamic_cast<SkiaSalBitmap*>(bitmap.ImplGetSalBitmap().get());
+ // Force creating of image.
+ sk_sp<SkImage> image1 = skiaBitmap1->GetSkImage();
+ CPPUNIT_ASSERT(skiaBitmap1->unittestHasImage());
+ CPPUNIT_ASSERT(bitmap.Scale(Size(5, 5)));
+ // Make sure delayed scaling has not changed the image.
+ SkiaSalBitmap* skiaBitmap2 = dynamic_cast<SkiaSalBitmap*>(bitmap.ImplGetSalBitmap().get());
+ CPPUNIT_ASSERT(skiaBitmap2->unittestHasImage());
+ sk_sp<SkImage> image2 = skiaBitmap2->GetSkImage(SkiaHelper::DirectImage::Yes);
+ CPPUNIT_ASSERT_EQUAL(image1, image2);
+ CPPUNIT_ASSERT_EQUAL(Size(5, 5), bitmap.GetSizePixel());
+ CPPUNIT_ASSERT_EQUAL(Size(10, 10), SkiaHelper::imageSize(image2));
+ // Draw the bitmap scaled to size 10x10 and check that the 10x10 image was used (and kept),
+ // even though technically the bitmap is 5x5.
+ device->DrawBitmap(Point(0, 0), Size(10, 10), bitmap);
+ SkiaSalBitmap* skiaBitmap3 = dynamic_cast<SkiaSalBitmap*>(bitmap.ImplGetSalBitmap().get());
+ CPPUNIT_ASSERT(skiaBitmap3->unittestHasImage());
+ sk_sp<SkImage> image3 = skiaBitmap3->GetSkImage(SkiaHelper::DirectImage::Yes);
+ CPPUNIT_ASSERT_EQUAL(image1, image3);
+ CPPUNIT_ASSERT_EQUAL(Size(5, 5), bitmap.GetSizePixel());
+ CPPUNIT_ASSERT_EQUAL(Size(10, 10), SkiaHelper::imageSize(image3));
+}
+
void SkiaTest::testTdf137329()
{
if (!SkiaHelper::isVCLSkiaEnabled())
diff --git a/vcl/skia/gdiimpl.cxx b/vcl/skia/gdiimpl.cxx
index f532e48528a9..13925700f31d 100644
--- a/vcl/skia/gdiimpl.cxx
+++ b/vcl/skia/gdiimpl.cxx
@@ -1489,11 +1489,10 @@ std::shared_ptr<SalBitmap> SkiaSalGraphicsImpl::getBitmap(tools::Long nX, tools:
sk_sp<SkImage> image = makeCheckedImageSnapshot(
mSurface, scaleRect(SkIRect::MakeXYWH(nX, nY, nWidth, nHeight), mScaling));
std::shared_ptr<SkiaSalBitmap> bitmap = std::make_shared<SkiaSalBitmap>(image);
- // TODO: If the surface is scaled for HiDPI, the bitmap needs to be scaled down, otherwise
- // it would have incorrect size from the API point of view. This could lead to loss of quality
- // if the bitmap is drawn to another scaled surface. Since the bitmap scaling is done only
- // on-demand, this state should be detected when drawing the bitmap and the scaling
- // should be ignored.
+ // If the surface is scaled for HiDPI, the bitmap needs to be scaled down, otherwise
+ // it would have incorrect size from the API point of view. The DirectImage::Yes handling
+ // in mergeCacheBitmaps() should access the original unscaled bitmap data to avoid
+ // pointless scaling back and forth.
if (mScaling != 1)
{
if (!isUnitTestRunning())
@@ -1621,20 +1620,68 @@ sk_sp<SkImage> SkiaSalGraphicsImpl::mergeCacheBitmaps(const SkiaSalBitmap& bitma
const SkiaSalBitmap* alphaBitmap,
const Size& targetSize)
{
- sk_sp<SkImage> image;
+ if (alphaBitmap)
+ assert(bitmap.GetSize() == alphaBitmap->GetSize());
+
if (targetSize.IsEmpty())
- return image;
+ return {};
if (alphaBitmap && alphaBitmap->IsFullyOpaqueAsAlpha())
alphaBitmap = nullptr; // the alpha can be ignored
if (bitmap.PreferSkShader() && (!alphaBitmap || alphaBitmap->PreferSkShader()))
- return image;
+ return {};
+
+ // If the bitmap has SkImage that matches the required size, try to use it, even
+ // if it doesn't match bitmap.GetSize(). This can happen with delayed scaling.
+ // This will catch cases such as some code pre-scaling the bitmap, which would make GetSkImage()
+ // scale, changing GetImageKey() in the process so we'd have to re-cache, and then we'd need
+ // to scale again in this function.
+ bool bitmapReady = false;
+ bool alphaBitmapReady = false;
+ if (const sk_sp<SkImage>& image = bitmap.GetSkImage(DirectImage::Yes))
+ {
+ assert(!bitmap.PreferSkShader());
+ if (imageSize(image) == targetSize)
+ bitmapReady = true;
+ }
+ // If the image usable and there's no alpha, then it matches exactly what's wanted.
+ if (bitmapReady && !alphaBitmap)
+ return bitmap.GetSkImage(DirectImage::Yes);
+ if (alphaBitmap)
+ {
+ if (!alphaBitmap->GetAlphaSkImage(DirectImage::Yes)
+ && alphaBitmap->GetSkImage(DirectImage::Yes)
+ && imageSize(alphaBitmap->GetSkImage(DirectImage::Yes)) == targetSize)
+ {
+ // There's a usable non-alpha image, try to convert it to alpha.
+ assert(!alphaBitmap->PreferSkShader());
+ const_cast<SkiaSalBitmap*>(alphaBitmap)->TryDirectConvertToAlphaNoScaling();
+ }
+ if (const sk_sp<SkImage>& image = alphaBitmap->GetAlphaSkImage(DirectImage::Yes))
+ {
+ assert(!alphaBitmap->PreferSkShader());
+ if (imageSize(image) == targetSize)
+ alphaBitmapReady = true;
+ }
+ }
+
+ if (bitmapReady && (!alphaBitmap || alphaBitmapReady))
+ {
+ // Try to find a cached image based on the already existing images.
+ OString key = makeCachedImageKey(bitmap, alphaBitmap, targetSize, DirectImage::Yes,
+ DirectImage::Yes);
+ if (sk_sp<SkImage> image = findCachedImage(key))
+ {
+ assert(imageSize(image) == targetSize);
+ return image;
+ }
+ }
// Probably not much point in caching of just doing a copy.
if (alphaBitmap == nullptr && targetSize == bitmap.GetSize())
- return image;
+ return {};
// Image too small to be worth caching if not scaling.
if (targetSize == bitmap.GetSize() && targetSize.Width() < 100 && targetSize.Height() < 100)
- return image;
+ return {};
// GPU-accelerated drawing with SkShader should be fast enough to not need caching.
if (isGPU())
{
@@ -1643,7 +1690,7 @@ sk_sp<SkImage> SkiaSalGraphicsImpl::mergeCacheBitmaps(const SkiaSalBitmap& bitma
int reduceRatio = bitmap.GetSize().Width() * bitmap.GetSize().Height() / targetSize.Width()
/ targetSize.Height();
if (reduceRatio < 10)
- return image;
+ return {};
}
// In some cases (tdf#134237) the target size may be very large. In that case it's
// better to rely on Skia to clip and draw only the necessary, rather than prepare
@@ -1669,22 +1716,45 @@ sk_sp<SkImage> SkiaSalGraphicsImpl::mergeCacheBitmaps(const SkiaSalBitmap& bitma
<< this << "): not caching, ratio:" << ratio << ", "
<< bitmap.GetSize() << "->" << targetSize << " in "
<< drawAreaSize);
- return image;
+ return {};
}
}
// Do not cache the result if it would take most of the cache and thus get evicted soon.
if (targetSize.Width() * targetSize.Height() * 4 > maxImageCacheSize() * 0.7)
- return image;
- OString key = OString::number(targetSize.Width()) + "x" + OString::number(targetSize.Height())
- + "_" + bitmap.GetImageKey();
- if (alphaBitmap)
- key += "_" + alphaBitmap->GetAlphaImageKey();
- image = findCachedImage(key);
- if (image)
- {
- assert(image->width() == targetSize.Width() && image->height() == targetSize.Height());
+ return {};
+
+ // Use ready direct image if they are both available, now even the size doesn't matter
+ // (we'll scale as necessary and it's better to scale from the original). Require only
+ // that they are the same size, or that one prefers a shader or doesn't exist
+ // (i.e. avoid two images of different size).
+ bitmapReady = bitmap.GetSkImage(DirectImage::Yes) != nullptr;
+ alphaBitmapReady
+ = alphaBitmap ? alphaBitmap->GetAlphaSkImage(DirectImage::Yes) != nullptr : false;
+ if (bitmapReady && alphaBitmap && !alphaBitmapReady && !alphaBitmap->PreferSkShader())
+ bitmapReady = false;
+ if (alphaBitmapReady && !bitmapReady && bitmap.PreferSkShader())
+ alphaBitmapReady = false;
+
+ DirectImage bitmapType = bitmapReady ? DirectImage::Yes : DirectImage::No;
+ DirectImage alphaBitmapType = alphaBitmapReady ? DirectImage::Yes : DirectImage::No;
+
+ // Try to find a cached result, this time after possible delayed scaling.
+ OString key = makeCachedImageKey(bitmap, alphaBitmap, targetSize, bitmapType, alphaBitmapType);
+ if (sk_sp<SkImage> image = findCachedImage(key))
+ {
+ assert(imageSize(image) == targetSize);
return image;
}
+
+ Size sourceSize;
+ if (bitmapReady)
+ sourceSize = imageSize(bitmap.GetSkImage(DirectImage::Yes));
+ else if (alphaBitmapReady)
+ sourceSize = imageSize(alphaBitmap->GetAlphaSkImage(DirectImage::Yes));
+ else
+ sourceSize = bitmap.GetSize();
+
+ // Generate a new result and cache it.
sk_sp<SkSurface> tmpSurface
= createSkSurface(targetSize, alphaBitmap ? kPremul_SkAlphaType : bitmap.alphaType());
if (!tmpSurface)
@@ -1693,36 +1763,49 @@ sk_sp<SkImage> SkiaSalGraphicsImpl::mergeCacheBitmaps(const SkiaSalBitmap& bitma
SkAutoCanvasRestore autoRestore(canvas, true);
SkPaint paint;
SkSamplingOptions samplingOptions;
- if (targetSize != bitmap.GetSize())
+ if (targetSize != sourceSize)
{
SkMatrix matrix;
- matrix.set(SkMatrix::kMScaleX, 1.0 * targetSize.Width() / bitmap.GetSize().Width());
- matrix.set(SkMatrix::kMScaleY, 1.0 * targetSize.Height() / bitmap.GetSize().Height());
+ matrix.set(SkMatrix::kMScaleX, 1.0 * targetSize.Width() / sourceSize.Width());
+ matrix.set(SkMatrix::kMScaleY, 1.0 * targetSize.Height() / sourceSize.Height());
canvas->concat(matrix);
samplingOptions = makeSamplingOptions(BmpScaleFlag::BestQuality, matrix, 1);
}
if (alphaBitmap != nullptr)
{
canvas->clear(SK_ColorTRANSPARENT);
- paint.setShader(SkShaders::Blend(SkBlendMode::kDstOut, bitmap.GetSkShader(samplingOptions),
- alphaBitmap->GetAlphaSkShader(samplingOptions)));
+ paint.setShader(
+ SkShaders::Blend(SkBlendMode::kDstOut, bitmap.GetSkShader(samplingOptions, bitmapType),
+ alphaBitmap->GetAlphaSkShader(samplingOptions, alphaBitmapType)));
canvas->drawPaint(paint);
}
else if (bitmap.PreferSkShader())
{
- paint.setShader(bitmap.GetSkShader(samplingOptions));
+ paint.setShader(bitmap.GetSkShader(samplingOptions, bitmapType));
canvas->drawPaint(paint);
}
else
- canvas->drawImage(bitmap.GetSkImage(), 0, 0, samplingOptions, &paint);
+ canvas->drawImage(bitmap.GetSkImage(bitmapType), 0, 0, samplingOptions, &paint);
if (isGPU())
SAL_INFO("vcl.skia.trace", "mergecachebitmaps(" << this << "): caching GPU downscaling:"
<< bitmap.GetSize() << "->" << targetSize);
- image = makeCheckedImageSnapshot(tmpSurface);
+ sk_sp<SkImage> image = makeCheckedImageSnapshot(tmpSurface);
addCachedImage(key, image);
return image;
}
+OString SkiaSalGraphicsImpl::makeCachedImageKey(const SkiaSalBitmap& bitmap,
+ const SkiaSalBitmap* alphaBitmap,
+ const Size& targetSize, DirectImage bitmapType,
+ DirectImage alphaBitmapType)
+{
+ OString key = OString::number(targetSize.Width()) + "x" + OString::number(targetSize.Height())
+ + "_" + bitmap.GetImageKey(bitmapType);
+ if (alphaBitmap)
+ key += "_" + alphaBitmap->GetAlphaImageKey(alphaBitmapType);
+ return key;
+}
+
bool SkiaSalGraphicsImpl::drawAlphaBitmap(const SalTwoRect& rPosAry, const SalBitmap& rSourceBitmap,
const SalBitmap& rAlphaBitmap)
{
diff --git a/vcl/skia/salbmp.cxx b/vcl/skia/salbmp.cxx
index dd96e3ecd094..8e1938d15c50 100644
--- a/vcl/skia/salbmp.cxx
+++ b/vcl/skia/salbmp.cxx
@@ -736,11 +736,13 @@ bool SkiaSalBitmap::ConserveMemory() const
&& (mBitCount > 8 || (mBitCount == 8 && mPalette.IsGreyPalette8Bit()));
}
-const sk_sp<SkImage>& SkiaSalBitmap::GetSkImage() const
+const sk_sp<SkImage>& SkiaSalBitmap::GetSkImage(DirectImage direct) const
{
#ifdef DBG_UTIL
assert(mWriteAccessCount == 0);
#endif
+ if (direct == DirectImage::Yes)
+ return mImage;
if (mEraseColorSet)
{
if (mImage)
@@ -812,11 +814,13 @@ const sk_sp<SkImage>& SkiaSalBitmap::GetSkImage() const
return mImage;
}
-const sk_sp<SkImage>& SkiaSalBitmap::GetAlphaSkImage() const
+const sk_sp<SkImage>& SkiaSalBitmap::GetAlphaSkImage(DirectImage direct) const
{
#ifdef DBG_UTIL
assert(mWriteAccessCount == 0);
#endif
+ if (direct == DirectImage::Yes)
+ return mAlphaImage;
if (mEraseColorSet)
{
if (mAlphaImage)
@@ -836,8 +840,8 @@ const sk_sp<SkImage>& SkiaSalBitmap::GetAlphaSkImage() const
}
if (mAlphaImage)
{
- assert(imageSize(mAlphaImage) == mSize); // data has already been scaled if needed
- return mAlphaImage;
+ if (imageSize(mAlphaImage) == mSize)
+ return mAlphaImage;
}
if (mImage)
{
@@ -967,22 +971,41 @@ const sk_sp<SkImage>& SkiaSalBitmap::GetAlphaSkImage() const
return mAlphaImage;
}
+void SkiaSalBitmap::TryDirectConvertToAlphaNoScaling()
+{
+ // This is a bit of a hack. Because of the VCL alpha hack where alpha is stored
+ // separately, we often convert mImage to mAlphaImage to represent the alpha
+ // channel. If code finds out that there is mImage but no mAlphaImage,
+ // this will create it from it, without checking for delayed scaling (i.e.
+ // it is "direct").
+ assert(mImage);
+ assert(!mAlphaImage);
+ // Set wanted size, trigger conversion.
+ Size savedSize = mSize;
+ mSize = imageSize(mImage);
+ GetAlphaSkImage();
+ assert(mAlphaImage);
+ mSize = savedSize;
+}
+
// If the bitmap is to be erased, SkShader with the color set is more efficient
// than creating an image filled with the color.
bool SkiaSalBitmap::PreferSkShader() const { return mEraseColorSet; }
-sk_sp<SkShader> SkiaSalBitmap::GetSkShader(const SkSamplingOptions& samplingOptions) const
+sk_sp<SkShader> SkiaSalBitmap::GetSkShader(const SkSamplingOptions& samplingOptions,
+ DirectImage direct) const
{
if (mEraseColorSet)
return SkShaders::Color(toSkColor(mEraseColor));
- return GetSkImage()->makeShader(samplingOptions);
+ return GetSkImage(direct)->makeShader(samplingOptions);
}
-sk_sp<SkShader> SkiaSalBitmap::GetAlphaSkShader(const SkSamplingOptions& samplingOptions) const
+sk_sp<SkShader> SkiaSalBitmap::GetAlphaSkShader(const SkSamplingOptions& samplingOptions,
+ DirectImage direct) const
{
if (mEraseColorSet)
return SkShaders::Color(fromEraseColorToAlphaImageColor(mEraseColor));
- return GetAlphaSkImage()->makeShader(samplingOptions);
+ return GetAlphaSkImage(direct)->makeShader(samplingOptions);
}
bool SkiaSalBitmap::IsFullyOpaqueAsAlpha() const
@@ -1314,7 +1337,7 @@ void SkiaSalBitmap::ResetPendingScaling()
mAlphaImage.reset();
}
-OString SkiaSalBitmap::GetImageKey() const
+OString SkiaSalBitmap::GetImageKey(DirectImage direct) const
{
if (mEraseColorSet)
{
@@ -1324,10 +1347,11 @@ OString SkiaSalBitmap::GetImageKey() const
<< static_cast<int>(mEraseColor.GetAlpha());
return OString::Concat("E") + ss.str().c_str();
}
- return OString::Concat("I") + OString::number(GetSkImage()->uniqueID());
+ assert(direct == DirectImage::No || mImage);
+ return OString::Concat("I") + OString::number(GetSkImage(direct)->uniqueID());
}
-OString SkiaSalBitmap::GetAlphaImageKey() const
+OString SkiaSalBitmap::GetAlphaImageKey(DirectImage direct) const
{
if (mEraseColorSet)
{
@@ -1336,7 +1360,8 @@ OString SkiaSalBitmap::GetAlphaImageKey() const
<< static_cast<int>(255 - SkColorGetA(fromEraseColorToAlphaImageColor(mEraseColor)));
return OString::Concat("E") + ss.str().c_str();
}
- return OString::Concat("I") + OString::number(GetAlphaSkImage()->uniqueID());
+ assert(direct == DirectImage::No || mAlphaImage);
+ return OString::Concat("I") + OString::number(GetAlphaSkImage(direct)->uniqueID());
}
void SkiaSalBitmap::dump(const char* file) const