From 7e872caaf618c8c5fc376515143a3176e09bced2 Mon Sep 17 00:00:00 2001 From: Hal Canary Date: Wed, 19 Jul 2017 15:51:18 -0400 Subject: [PATCH] SkPDF: SkPDFMakeShader takes the paint color. This allows alpha blending and also alpha shaders with color blended in. fixes GMs: composeshader_alpha, composeshader_bitmap Change-Id: I3ab9cbef216f7733798d2e29541b4211c627dab2 Reviewed-on: https://skia-review.googlesource.com/24760 Commit-Queue: Hal Canary Reviewed-by: Ben Wagner --- bench/PDFBench.cpp | 4 +-- src/pdf/SkPDFDevice.cpp | 2 +- src/pdf/SkPDFShader.cpp | 77 +++++++++++++++++++++++++---------------- src/pdf/SkPDFShader.h | 9 +++-- 4 files changed, 57 insertions(+), 35 deletions(-) diff --git a/bench/PDFBench.cpp b/bench/PDFBench.cpp index b3714524aa..5786f5bed4 100644 --- a/bench/PDFBench.cpp +++ b/bench/PDFBench.cpp @@ -216,8 +216,8 @@ struct PDFShaderBench : public Benchmark { SkNullWStream nullStream; SkPDFDocument doc(&nullStream, nullptr, 72, SkDocument::PDFMetadata(), nullptr, false); - sk_sp shader = - SkPDFMakeShader(&doc, fShader.get(), SkMatrix::I(), {0, 0, 400,400}); + sk_sp shader = SkPDFMakeShader(&doc, fShader.get(), SkMatrix::I(), + {0, 0, 400, 400}, SK_ColorBLACK); } } }; diff --git a/src/pdf/SkPDFDevice.cpp b/src/pdf/SkPDFDevice.cpp index 674e3718a5..99136226ec 100644 --- a/src/pdf/SkPDFDevice.cpp +++ b/src/pdf/SkPDFDevice.cpp @@ -2180,7 +2180,7 @@ void SkPDFDevice::populateGraphicStateEntryFromPaint( SkIRect bounds; clipStackBounds.roundOut(&bounds); - pdfShader = SkPDFMakeShader(fDocument, shader, transform, bounds); + pdfShader = SkPDFMakeShader(fDocument, shader, transform, bounds, paint.getColor()); if (pdfShader.get()) { // pdfShader has been canonicalized so we can directly compare diff --git a/src/pdf/SkPDFShader.cpp b/src/pdf/SkPDFShader.cpp index e52fad97de..73a6e6b350 100644 --- a/src/pdf/SkPDFShader.cpp +++ b/src/pdf/SkPDFShader.cpp @@ -19,19 +19,22 @@ #include "SkPDFUtils.h" #include "SkScalar.h" #include "SkStream.h" +#include "SkSurface.h" #include "SkTemplates.h" -static void draw_image_matrix(SkCanvas* canvas, const SkImage* img, const SkMatrix& matrix) { +static void draw_image_matrix(SkCanvas* canvas, const SkImage* img, + const SkMatrix& matrix, const SkPaint& paint) { SkAutoCanvasRestore acr(canvas, true); canvas->concat(matrix); - canvas->drawImage(img, 0, 0); + canvas->drawImage(img, 0, 0, &paint); } -static void draw_bitmap_matrix(SkCanvas* canvas, const SkBitmap& bm, const SkMatrix& matrix) { +static void draw_bitmap_matrix(SkCanvas* canvas, const SkBitmap& bm, + const SkMatrix& matrix, const SkPaint& paint) { SkAutoCanvasRestore acr(canvas, true); canvas->concat(matrix); - canvas->drawBitmap(bm, 0, 0); + canvas->drawBitmap(bm, 0, 0, &paint); } static sk_sp make_image_shader(SkPDFDocument* doc, @@ -87,19 +90,21 @@ static sk_sp make_image_shader(SkPDFDocument* doc, SkScalar width = SkIntToScalar(image->width()); SkScalar height = SkIntToScalar(image->height()); + SkPaint paint; + paint.setColor(key.fPaintColor); // Tiling is implied. First we handle mirroring. if (tileModes[0] == SkShader::kMirror_TileMode) { SkMatrix xMirror; xMirror.setScale(-1, 1); xMirror.postTranslate(2 * width, 0); - draw_image_matrix(&canvas, image, xMirror); + draw_image_matrix(&canvas, image, xMirror, paint); patternBBox.fRight += width; } if (tileModes[1] == SkShader::kMirror_TileMode) { SkMatrix yMirror; yMirror.setScale(SK_Scalar1, -SK_Scalar1); yMirror.postTranslate(0, 2 * height); - draw_image_matrix(&canvas, image, yMirror); + draw_image_matrix(&canvas, image, yMirror, paint); patternBBox.fBottom += height; } if (tileModes[0] == SkShader::kMirror_TileMode && @@ -107,7 +112,7 @@ static sk_sp make_image_shader(SkPDFDocument* doc, SkMatrix mirror; mirror.setScale(-1, -1); mirror.postTranslate(2 * width, 2 * height); - draw_image_matrix(&canvas, image, mirror); + draw_image_matrix(&canvas, image, mirror, paint); } // Then handle Clamping, which requires expanding the pattern canvas to @@ -171,12 +176,12 @@ static sk_sp make_image_shader(SkPDFDocument* doc, SkMatrix leftMatrix; leftMatrix.setScale(-deviceBounds.left(), 1); leftMatrix.postTranslate(deviceBounds.left(), 0); - draw_bitmap_matrix(&canvas, left, leftMatrix); + draw_bitmap_matrix(&canvas, left, leftMatrix, paint); if (tileModes[1] == SkShader::kMirror_TileMode) { leftMatrix.postScale(SK_Scalar1, -SK_Scalar1); leftMatrix.postTranslate(0, 2 * height); - draw_bitmap_matrix(&canvas, left, leftMatrix); + draw_bitmap_matrix(&canvas, left, leftMatrix, paint); } patternBBox.fLeft = 0; } @@ -189,12 +194,12 @@ static sk_sp make_image_shader(SkPDFDocument* doc, SkMatrix rightMatrix; rightMatrix.setScale(deviceBounds.right() - width, 1); rightMatrix.postTranslate(width, 0); - draw_bitmap_matrix(&canvas, right, rightMatrix); + draw_bitmap_matrix(&canvas, right, rightMatrix, paint); if (tileModes[1] == SkShader::kMirror_TileMode) { rightMatrix.postScale(SK_Scalar1, -SK_Scalar1); rightMatrix.postTranslate(0, 2 * height); - draw_bitmap_matrix(&canvas, right, rightMatrix); + draw_bitmap_matrix(&canvas, right, rightMatrix, paint); } patternBBox.fRight = deviceBounds.width(); } @@ -210,12 +215,12 @@ static sk_sp make_image_shader(SkPDFDocument* doc, SkMatrix topMatrix; topMatrix.setScale(SK_Scalar1, -deviceBounds.top()); topMatrix.postTranslate(0, deviceBounds.top()); - draw_bitmap_matrix(&canvas, top, topMatrix); + draw_bitmap_matrix(&canvas, top, topMatrix, paint); if (tileModes[0] == SkShader::kMirror_TileMode) { topMatrix.postScale(-1, 1); topMatrix.postTranslate(2 * width, 0); - draw_bitmap_matrix(&canvas, top, topMatrix); + draw_bitmap_matrix(&canvas, top, topMatrix, paint); } patternBBox.fTop = 0; } @@ -228,12 +233,12 @@ static sk_sp make_image_shader(SkPDFDocument* doc, SkMatrix bottomMatrix; bottomMatrix.setScale(SK_Scalar1, deviceBounds.bottom() - height); bottomMatrix.postTranslate(0, height); - draw_bitmap_matrix(&canvas, bottom, bottomMatrix); + draw_bitmap_matrix(&canvas, bottom, bottomMatrix, paint); if (tileModes[0] == SkShader::kMirror_TileMode) { bottomMatrix.postScale(-1, 1); bottomMatrix.postTranslate(2 * width, 0); - draw_bitmap_matrix(&canvas, bottom, bottomMatrix); + draw_bitmap_matrix(&canvas, bottom, bottomMatrix, paint); } patternBBox.fBottom = deviceBounds.height(); } @@ -252,7 +257,8 @@ static sk_sp make_image_shader(SkPDFDocument* doc, static sk_sp make_fallback_shader(SkPDFDocument* doc, SkShader* shader, const SkMatrix& canvasTransform, - const SkIRect& surfaceBBox) { + const SkIRect& surfaceBBox, + SkColor paintColor) { // TODO(vandebo) This drops SKComposeShader on the floor. We could // handle compose shader by pulling things up to a layer, drawing with // the first shader, applying the xfer mode and drawing again with the @@ -262,7 +268,8 @@ static sk_sp make_fallback_shader(SkPDFDocument* doc, SkMatrix::I(), surfaceBBox, {{0, 0, 0, 0}, 0}, // don't need the key; won't de-dup. - {SkShader::kClamp_TileMode, SkShader::kClamp_TileMode}}; + {SkShader::kClamp_TileMode, SkShader::kClamp_TileMode}, + paintColor}; key.fShaderTransform = shader->getLocalMatrix(); @@ -287,31 +294,40 @@ static sk_sp make_fallback_shader(SkPDFDocument* doc, SkSize scale = {SkIntToScalar(size.width()) / shaderRect.width(), SkIntToScalar(size.height()) / shaderRect.height()}; - SkBitmap bitmap; - bitmap.allocN32Pixels(size.width(), size.height()); - bitmap.eraseColor(SK_ColorTRANSPARENT); + auto surface = SkSurface::MakeRasterN32Premul(size.width(), size.height()); + SkCanvas* canvas = surface->getCanvas(); + canvas->clear(SK_ColorTRANSPARENT); SkPaint p; p.setShader(sk_ref_sp(shader)); + p.setColor(paintColor); - SkCanvas canvas(bitmap); - canvas.scale(scale.width(), scale.height()); - canvas.translate(-shaderRect.x(), -shaderRect.y()); - canvas.drawPaint(p); + canvas->scale(scale.width(), scale.height()); + canvas->translate(-shaderRect.x(), -shaderRect.y()); + canvas->drawPaint(p); key.fShaderTransform.setTranslate(shaderRect.x(), shaderRect.y()); key.fShaderTransform.preScale(1 / scale.width(), 1 / scale.height()); - SkASSERT (!bitmap.isNull()); - bitmap.setImmutable(); - sk_sp image = SkImage::MakeFromBitmap(bitmap); + sk_sp image = surface->makeImageSnapshot(); return make_image_shader(doc, key, image.get()); } +static SkColor adjust_color(SkShader* shader, SkColor paintColor) { + if (SkImage* img = shader->isAImage(nullptr, nullptr)) { + if (img->isAlphaOnly()) { + return paintColor; + } + } + // only preserve the alpha. + return paintColor & SK_ColorBLACK; +} + sk_sp SkPDFMakeShader(SkPDFDocument* doc, SkShader* shader, const SkMatrix& canvasTransform, - const SkIRect& surfaceBBox) { + const SkIRect& surfaceBBox, + SkColor paintColor) { SkASSERT(shader); SkASSERT(doc); if (SkShader::kNone_GradientType != shader->asAGradient(nullptr)) { @@ -326,7 +342,8 @@ sk_sp SkPDFMakeShader(SkPDFDocument* doc, SkMatrix::I(), surfaceBBox, {{0, 0, 0, 0}, 0}, - {SkShader::kClamp_TileMode, SkShader::kClamp_TileMode}}; + {SkShader::kClamp_TileMode, SkShader::kClamp_TileMode}, + adjust_color(shader, paintColor)}; SkASSERT(shader->asAGradient(nullptr) == SkShader::kNone_GradientType) ; if (SkImage* skimg = shader->isAImage(&key.fShaderTransform, key.fImageTileModes)) { @@ -341,5 +358,5 @@ sk_sp SkPDFMakeShader(SkPDFDocument* doc, return pdfShader; } // Don't bother to de-dup fallback shader. - return make_fallback_shader(doc, shader, canvasTransform, surfaceBBox); + return make_fallback_shader(doc, shader, canvasTransform, surfaceBBox, key.fPaintColor); } diff --git a/src/pdf/SkPDFShader.h b/src/pdf/SkPDFShader.h index 09e7738e30..c1a5ef30ab 100644 --- a/src/pdf/SkPDFShader.h +++ b/src/pdf/SkPDFShader.h @@ -34,11 +34,14 @@ struct SkIRect; * positioned, relative to where the page is drawn.) * @param surfceBBox The bounding box of the drawing surface (with matrix * already applied). + * @param paintColor Color+Alpha of the paint. Color is usually ignored, + * unless it is a alpha shader. */ sk_sp SkPDFMakeShader(SkPDFDocument* doc, SkShader* shader, const SkMatrix& ctm, - const SkIRect& surfaceBBox); + const SkIRect& surfaceBBox, + SkColor paintColor); SK_BEGIN_REQUIRE_DENSE struct SkPDFImageShaderKey { @@ -47,6 +50,7 @@ struct SkPDFImageShaderKey { SkIRect fBBox; SkBitmapKey fBitmapKey; SkShader::TileMode fImageTileModes[2]; + SkColor fPaintColor; }; SK_END_REQUIRE_DENSE @@ -58,6 +62,7 @@ inline bool operator==(const SkPDFImageShaderKey& a, const SkPDFImageShaderKey& && a.fBBox == b.fBBox && a.fBitmapKey == b.fBitmapKey && a.fImageTileModes[0] == b.fImageTileModes[0] - && a.fImageTileModes[1] == b.fImageTileModes[1]; + && a.fImageTileModes[1] == b.fImageTileModes[1] + && a.fPaintColor == b.fPaintColor; } #endif