aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/pdf/SkPDFDevice.cpp
diff options
context:
space:
mode:
authorGravatar Hal Canary <halcanary@google.com>2017-07-19 15:48:38 -0400
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2017-07-20 16:23:03 +0000
commitf0f4c0c6d58a00ea2c9008f2686c73dcae46a946 (patch)
treec1f90186a342582b1803b0cf8824f50b58a89d1c /src/pdf/SkPDFDevice.cpp
parentfa486cf4de608e5566b746cfc196e1bb80eb0346 (diff)
SkPDF: Support alpha-only images with maskfilters
- Handle alpha-only images with maskfilters - No longer apply color-filter to alpha-only images (it should apply to the paint color/shader composed with the alpha image instead). - Alpha-only images without maskfilters do sub-pixel clipping. - Non-alpha-only drawImages with maskfilters do sub-pixel clipping. * Fixes `alpha_image` GM (output now matches GPU backend). * Improves GMs `imagemasksubset` and `shadows`. BUG=skia:6735 Change-Id: I62a82b4133ae0eb42d6315785bc3d2cb834bd352 Reviewed-on: https://skia-review.googlesource.com/24820 Reviewed-by: Ben Wagner <bungeman@google.com> Commit-Queue: Hal Canary <halcanary@google.com>
Diffstat (limited to 'src/pdf/SkPDFDevice.cpp')
-rw-r--r--src/pdf/SkPDFDevice.cpp79
1 files changed, 49 insertions, 30 deletions
diff --git a/src/pdf/SkPDFDevice.cpp b/src/pdf/SkPDFDevice.cpp
index 39209842b0..e4ab92850a 100644
--- a/src/pdf/SkPDFDevice.cpp
+++ b/src/pdf/SkPDFDevice.cpp
@@ -2286,11 +2286,8 @@ void SkPDFDevice::internalDrawImageRect(SkKeyedImage imageSubset,
return;
}
+ // First, figure out the src->dst transform and subset the image if needed.
SkIRect bounds = imageSubset.image()->bounds();
- SkPaint paint = srcPaint;
- if (imageSubset.image()->isOpaque()) {
- replace_srcmode_on_opaque_paint(&paint);
- }
SkRect srcRect = src ? *src : SkRect::Make(bounds);
SkMatrix transform;
transform.setRectToRect(srcRect, dst, SkMatrix::kFill_ScaleToFit);
@@ -2309,21 +2306,36 @@ void SkPDFDevice::internalDrawImageRect(SkKeyedImage imageSubset,
}
}
- // TODO(halcanary) support isAlphaOnly & getMaskFilter.
- bool imageAlphaOnly = imageSubset.image()->isAlphaOnly() && !paint.getMaskFilter();
- if (imageAlphaOnly) {
- if (SkColorFilter* colorFilter = paint.getColorFilter()) {
- sk_sp<SkImage> img = color_filter(imageSubset.image().get(), colorFilter);
- paint.setColorFilter(nullptr);
- imageSubset = SkKeyedImage(std::move(img));
- if (!imageSubset) {
- return;
- }
- imageAlphaOnly = imageSubset.image()->isAlphaOnly();
- // The colorfilter can make a alphonly image no longer be alphaonly.
- }
+ // If the image is opaque and the paint's alpha is too, replace
+ // kSrc blendmode with kSrcOver.
+ SkPaint paint = srcPaint;
+ if (imageSubset.image()->isOpaque()) {
+ replace_srcmode_on_opaque_paint(&paint);
}
- if (imageAlphaOnly) {
+
+ // Alpha-only images need to get their color from the shader, before
+ // applying the colorfilter.
+ if (imageSubset.image()->isAlphaOnly() && paint.getColorFilter()) {
+ // must blend alpha image and shader before applying colorfilter.
+ auto surface =
+ SkSurface::MakeRaster(SkImageInfo::MakeN32Premul(imageSubset.image()->dimensions()));
+ SkCanvas* canvas = surface->getCanvas();
+ SkPaint tmpPaint;
+ // In the case of alpha images with shaders, the shader's coordinate
+ // system is the image's coordiantes.
+ tmpPaint.setShader(sk_ref_sp(paint.getShader()));
+ tmpPaint.setColor(paint.getColor());
+ canvas->clear(0x00000000);
+ canvas->drawImage(imageSubset.image().get(), 0, 0, &tmpPaint);
+ paint.setShader(nullptr);
+ imageSubset = SkKeyedImage(surface->makeImageSnapshot());
+ SkASSERT(!imageSubset.image()->isAlphaOnly());
+ }
+
+ if (imageSubset.image()->isAlphaOnly()) {
+ // The ColorFilter applies to the paint color/shader, not the alpha layer.
+ SkASSERT(nullptr == paint.getColorFilter());
+
sk_sp<SkImage> mask = alpha_image_to_greyscale_image(imageSubset.image().get());
if (!mask) {
return;
@@ -2333,12 +2345,24 @@ void SkPDFDevice::internalDrawImageRect(SkKeyedImage imageSubset,
sk_sp<SkPDFDevice> maskDevice = this->makeCongruentDevice();
{
SkCanvas canvas(maskDevice.get());
- canvas.concat(transform);
- canvas.concat(ctm);
- // TODO(halcanary): investigate sub-pixel clipping.
- canvas.drawImage(mask, 0, 0);
+ if (paint.getMaskFilter()) {
+ // This clip prevents the mask image shader from covering
+ // entire device if unnecessary.
+ canvas.clipRect(this->cs().bounds(this->bounds()));
+ canvas.concat(ctm);
+ SkPaint tmpPaint;
+ tmpPaint.setShader(mask->makeShader(&transform));
+ tmpPaint.setMaskFilter(sk_ref_sp(paint.getMaskFilter()));
+ canvas.drawRect(dst, tmpPaint);
+ } else {
+ canvas.concat(ctm);
+ if (src && !is_integral(*src)) {
+ canvas.clipRect(dst);
+ }
+ canvas.concat(transform);
+ canvas.drawImage(mask, 0, 0);
+ }
}
- remove_color_filter(&paint);
if (!ctm.isIdentity() && paint.getShader()) {
transform_shader(&paint, ctm); // Since we are using identity matrix.
}
@@ -2355,8 +2379,8 @@ void SkPDFDevice::internalDrawImageRect(SkKeyedImage imageSubset,
if (paint.getMaskFilter()) {
paint.setShader(imageSubset.image()->makeShader(&transform));
SkPath path;
- path.addRect(SkRect::Make(imageSubset.image()->bounds()));
- this->internalDrawPath(this->cs(), this->ctm(), path, paint, &transform, true);
+ path.addRect(dst); // handles non-integral clipping.
+ this->internalDrawPath(this->cs(), this->ctm(), path, paint, nullptr, true);
return;
}
transform.postConcat(ctm);
@@ -2471,11 +2495,6 @@ void SkPDFDevice::internalDrawImageRect(SkKeyedImage imageSubset,
}
if (SkColorFilter* colorFilter = paint.getColorFilter()) {
- // TODO(https://bug.skia.org/4378): implement colorfilter on other
- // draw calls. This code here works for all
- // drawBitmap*()/drawImage*() calls amd ImageFilters (which
- // rasterize a layer on this backend). Fortuanely, this seems
- // to be how Chromium impements most color-filters.
sk_sp<SkImage> img = color_filter(imageSubset.image().get(), colorFilter);
imageSubset = SkKeyedImage(std::move(img));
if (!imageSubset) {