summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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