aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core/SkPixmap.cpp
diff options
context:
space:
mode:
authorGravatar Mike Klein <mtklein@chromium.org>2018-01-03 10:30:21 -0500
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2018-02-09 14:09:01 +0000
commitc4616804bb407506c6ac1046c7e25e2016911449 (patch)
tree57897464bf5ac351818fad103d387671b823ec46 /src/core/SkPixmap.cpp
parent0ee01901733aa4e1c3a1d1ff6d8d66425dca8402 (diff)
alternate approach to unpremul scalePixels()
We want to keep the clamps in SkImageShader, and keep unpremul scalePixels() happy too. So we extend SkImageShader's internal API to allow specifying an output alpha type, which controls whether we premul or unpremul and how we clamp. scalePixels() uses this to draw instead of a drawBitmap() call. Sort of backwards of usual, we opt our local builds into SK_LEGACY_HIGH_QUALITY_SCALING_CLAMP (and Google3 is already defining this). Then to rebase Chromium we will _define_ this in Chromium's user config, fold it through as if always defined in Skia, then finally remove the definition from Chromium's user config. Change-Id: I38035f0886f79700e7301c3c6042ce362c771d96 Reviewed-on: https://skia-review.googlesource.com/90480 Reviewed-by: Brian Osman <brianosman@google.com> Commit-Queue: Mike Klein <mtklein@chromium.org>
Diffstat (limited to 'src/core/SkPixmap.cpp')
-rw-r--r--src/core/SkPixmap.cpp67
1 files changed, 38 insertions, 29 deletions
diff --git a/src/core/SkPixmap.cpp b/src/core/SkPixmap.cpp
index 42e2c66029..050c6e2ab4 100644
--- a/src/core/SkPixmap.cpp
+++ b/src/core/SkPixmap.cpp
@@ -11,6 +11,7 @@
#include "SkConvertPixels.h"
#include "SkData.h"
#include "SkImageInfoPriv.h"
+#include "SkImageShader.h"
#include "SkHalf.h"
#include "SkMask.h"
#include "SkNx.h"
@@ -229,10 +230,6 @@ bool SkPixmap::erase(const SkColor4f& origColor, const SkIRect* subset) const {
return true;
}
-static void set_alphatype(SkPixmap* dst, const SkPixmap& src, SkAlphaType at) {
- dst->reset(src.info().makeAlphaType(at), src.addr(), src.rowBytes());
-}
-
bool SkPixmap::scalePixels(const SkPixmap& dst, SkFilterQuality quality) const {
// Can't do anthing with empty src or dst
if (this->width() <= 0 || this->height() <= 0 || dst.width() <= 0 || dst.height() <= 0) {
@@ -244,39 +241,51 @@ bool SkPixmap::scalePixels(const SkPixmap& dst, SkFilterQuality quality) const {
return this->readPixels(dst);
}
- // Temp storage in case we need to edit the requested alphatypes
- SkPixmap storage_src, storage_dst;
- const SkPixmap* srcPtr = this;
- const SkPixmap* dstPtr = &dst;
-
- // Trick: if src and dst are both unpremul, we can give the correct result if we change both
- // to premul (or opaque), since the draw will not try to blend or otherwise interpret
- // the pixels' alpha.
- if (srcPtr->alphaType() == kUnpremul_SkAlphaType &&
- dstPtr->alphaType() == kUnpremul_SkAlphaType)
- {
- set_alphatype(&storage_src, *this, kPremul_SkAlphaType);
- set_alphatype(&storage_dst, dst, kPremul_SkAlphaType);
- srcPtr = &storage_src;
- dstPtr = &storage_dst;
- }
-
SkBitmap bitmap;
- if (!bitmap.installPixels(*srcPtr)) {
+ if (!bitmap.installPixels(*this)) {
return false;
}
- bitmap.setIsVolatile(true); // so we don't try to cache it
-
- auto surface(SkSurface::MakeRasterDirect(dstPtr->info(), dstPtr->writable_addr(), dstPtr->rowBytes()));
- if (!surface) {
+ bitmap.setImmutable(); // Don't copy when we create an image.
+ bitmap.setIsVolatile(true); // Disable any caching.
+
+ // We're going to set this up a little oddly so that we can scale unpremul SkPixmaps
+ // to unpremul dsts without ever premultiplying (and potentially throwing away information).
+
+ // 1) Here's the scale matrix between our input pixels and the scaled destination.
+ SkMatrix matrix = SkMatrix::MakeRectToRect(SkRect::Make(this->bounds()),
+ SkRect::Make(dst.bounds()),
+ SkMatrix::kFill_ScaleToFit);
+
+
+ // 2) Instead of just calling drawBitmap(), we'll create a shader that carefully
+ // keeps its output in the alpha type we request, dst.alphaType().
+ sk_sp<SkShader> shader = SkImageShader::Make(SkImage::MakeFromBitmap(bitmap),
+ SkShader::kClamp_TileMode,
+ SkShader::kClamp_TileMode,
+ &matrix,
+ dst.alphaType());
+
+ // 3) No matter what dst's actual alpha type is, we'll construct this surface
+ // as if it were not unpremul. This keeps the rest of the drawing pipeline oblivious
+ // to our trickery here, and prevents it from doing anything like a manual unpremul.
+ SkImageInfo info = dst.info();
+ if (info.alphaType() == kUnpremul_SkAlphaType) {
+ info = info.makeAlphaType(kPremul_SkAlphaType);
+ }
+ sk_sp<SkSurface> surface =
+ SkSurface::MakeRasterDirect(info, dst.writable_addr(), dst.rowBytes());
+ if (!shader || !surface) {
return false;
}
+ // 4) Using SkBlendMode::kSrc means we won't be tempted to try any premul-only blending math.
SkPaint paint;
- paint.setFilterQuality(quality);
paint.setBlendMode(SkBlendMode::kSrc);
- surface->getCanvas()->drawBitmapRect(bitmap, SkRect::MakeIWH(dst.width(), dst.height()),
- &paint);
+ paint.setFilterQuality(quality);
+ paint.setShader(std::move(shader));
+
+ // 5) Draw it!
+ surface->getCanvas()->drawPaint(paint);
return true;
}