diff options
author | Hal Canary <halcanary@google.com> | 2017-07-19 15:48:38 -0400 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2017-07-20 16:23:03 +0000 |
commit | f0f4c0c6d58a00ea2c9008f2686c73dcae46a946 (patch) | |
tree | c1f90186a342582b1803b0cf8824f50b58a89d1c /src/pdf | |
parent | fa486cf4de608e5566b746cfc196e1bb80eb0346 (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')
-rw-r--r-- | src/pdf/SkPDFDevice.cpp | 79 |
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) { |