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 <halcanary@google.com>
Reviewed-by: Ben Wagner <bungeman@google.com>
This commit is contained in:
Hal Canary 2017-07-19 15:51:18 -04:00 committed by Skia Commit-Bot
parent b7648a2758
commit 7e872caaf6
4 changed files with 57 additions and 35 deletions

View File

@ -216,8 +216,8 @@ struct PDFShaderBench : public Benchmark {
SkNullWStream nullStream; SkNullWStream nullStream;
SkPDFDocument doc(&nullStream, nullptr, 72, SkPDFDocument doc(&nullStream, nullptr, 72,
SkDocument::PDFMetadata(), nullptr, false); SkDocument::PDFMetadata(), nullptr, false);
sk_sp<SkPDFObject> shader = sk_sp<SkPDFObject> shader = SkPDFMakeShader(&doc, fShader.get(), SkMatrix::I(),
SkPDFMakeShader(&doc, fShader.get(), SkMatrix::I(), {0, 0, 400,400}); {0, 0, 400, 400}, SK_ColorBLACK);
} }
} }
}; };

View File

@ -2180,7 +2180,7 @@ void SkPDFDevice::populateGraphicStateEntryFromPaint(
SkIRect bounds; SkIRect bounds;
clipStackBounds.roundOut(&bounds); clipStackBounds.roundOut(&bounds);
pdfShader = SkPDFMakeShader(fDocument, shader, transform, bounds); pdfShader = SkPDFMakeShader(fDocument, shader, transform, bounds, paint.getColor());
if (pdfShader.get()) { if (pdfShader.get()) {
// pdfShader has been canonicalized so we can directly compare // pdfShader has been canonicalized so we can directly compare

View File

@ -19,19 +19,22 @@
#include "SkPDFUtils.h" #include "SkPDFUtils.h"
#include "SkScalar.h" #include "SkScalar.h"
#include "SkStream.h" #include "SkStream.h"
#include "SkSurface.h"
#include "SkTemplates.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); SkAutoCanvasRestore acr(canvas, true);
canvas->concat(matrix); 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); SkAutoCanvasRestore acr(canvas, true);
canvas->concat(matrix); canvas->concat(matrix);
canvas->drawBitmap(bm, 0, 0); canvas->drawBitmap(bm, 0, 0, &paint);
} }
static sk_sp<SkPDFStream> make_image_shader(SkPDFDocument* doc, static sk_sp<SkPDFStream> make_image_shader(SkPDFDocument* doc,
@ -87,19 +90,21 @@ static sk_sp<SkPDFStream> make_image_shader(SkPDFDocument* doc,
SkScalar width = SkIntToScalar(image->width()); SkScalar width = SkIntToScalar(image->width());
SkScalar height = SkIntToScalar(image->height()); SkScalar height = SkIntToScalar(image->height());
SkPaint paint;
paint.setColor(key.fPaintColor);
// Tiling is implied. First we handle mirroring. // Tiling is implied. First we handle mirroring.
if (tileModes[0] == SkShader::kMirror_TileMode) { if (tileModes[0] == SkShader::kMirror_TileMode) {
SkMatrix xMirror; SkMatrix xMirror;
xMirror.setScale(-1, 1); xMirror.setScale(-1, 1);
xMirror.postTranslate(2 * width, 0); xMirror.postTranslate(2 * width, 0);
draw_image_matrix(&canvas, image, xMirror); draw_image_matrix(&canvas, image, xMirror, paint);
patternBBox.fRight += width; patternBBox.fRight += width;
} }
if (tileModes[1] == SkShader::kMirror_TileMode) { if (tileModes[1] == SkShader::kMirror_TileMode) {
SkMatrix yMirror; SkMatrix yMirror;
yMirror.setScale(SK_Scalar1, -SK_Scalar1); yMirror.setScale(SK_Scalar1, -SK_Scalar1);
yMirror.postTranslate(0, 2 * height); yMirror.postTranslate(0, 2 * height);
draw_image_matrix(&canvas, image, yMirror); draw_image_matrix(&canvas, image, yMirror, paint);
patternBBox.fBottom += height; patternBBox.fBottom += height;
} }
if (tileModes[0] == SkShader::kMirror_TileMode && if (tileModes[0] == SkShader::kMirror_TileMode &&
@ -107,7 +112,7 @@ static sk_sp<SkPDFStream> make_image_shader(SkPDFDocument* doc,
SkMatrix mirror; SkMatrix mirror;
mirror.setScale(-1, -1); mirror.setScale(-1, -1);
mirror.postTranslate(2 * width, 2 * height); 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 // Then handle Clamping, which requires expanding the pattern canvas to
@ -171,12 +176,12 @@ static sk_sp<SkPDFStream> make_image_shader(SkPDFDocument* doc,
SkMatrix leftMatrix; SkMatrix leftMatrix;
leftMatrix.setScale(-deviceBounds.left(), 1); leftMatrix.setScale(-deviceBounds.left(), 1);
leftMatrix.postTranslate(deviceBounds.left(), 0); leftMatrix.postTranslate(deviceBounds.left(), 0);
draw_bitmap_matrix(&canvas, left, leftMatrix); draw_bitmap_matrix(&canvas, left, leftMatrix, paint);
if (tileModes[1] == SkShader::kMirror_TileMode) { if (tileModes[1] == SkShader::kMirror_TileMode) {
leftMatrix.postScale(SK_Scalar1, -SK_Scalar1); leftMatrix.postScale(SK_Scalar1, -SK_Scalar1);
leftMatrix.postTranslate(0, 2 * height); leftMatrix.postTranslate(0, 2 * height);
draw_bitmap_matrix(&canvas, left, leftMatrix); draw_bitmap_matrix(&canvas, left, leftMatrix, paint);
} }
patternBBox.fLeft = 0; patternBBox.fLeft = 0;
} }
@ -189,12 +194,12 @@ static sk_sp<SkPDFStream> make_image_shader(SkPDFDocument* doc,
SkMatrix rightMatrix; SkMatrix rightMatrix;
rightMatrix.setScale(deviceBounds.right() - width, 1); rightMatrix.setScale(deviceBounds.right() - width, 1);
rightMatrix.postTranslate(width, 0); rightMatrix.postTranslate(width, 0);
draw_bitmap_matrix(&canvas, right, rightMatrix); draw_bitmap_matrix(&canvas, right, rightMatrix, paint);
if (tileModes[1] == SkShader::kMirror_TileMode) { if (tileModes[1] == SkShader::kMirror_TileMode) {
rightMatrix.postScale(SK_Scalar1, -SK_Scalar1); rightMatrix.postScale(SK_Scalar1, -SK_Scalar1);
rightMatrix.postTranslate(0, 2 * height); rightMatrix.postTranslate(0, 2 * height);
draw_bitmap_matrix(&canvas, right, rightMatrix); draw_bitmap_matrix(&canvas, right, rightMatrix, paint);
} }
patternBBox.fRight = deviceBounds.width(); patternBBox.fRight = deviceBounds.width();
} }
@ -210,12 +215,12 @@ static sk_sp<SkPDFStream> make_image_shader(SkPDFDocument* doc,
SkMatrix topMatrix; SkMatrix topMatrix;
topMatrix.setScale(SK_Scalar1, -deviceBounds.top()); topMatrix.setScale(SK_Scalar1, -deviceBounds.top());
topMatrix.postTranslate(0, 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) { if (tileModes[0] == SkShader::kMirror_TileMode) {
topMatrix.postScale(-1, 1); topMatrix.postScale(-1, 1);
topMatrix.postTranslate(2 * width, 0); topMatrix.postTranslate(2 * width, 0);
draw_bitmap_matrix(&canvas, top, topMatrix); draw_bitmap_matrix(&canvas, top, topMatrix, paint);
} }
patternBBox.fTop = 0; patternBBox.fTop = 0;
} }
@ -228,12 +233,12 @@ static sk_sp<SkPDFStream> make_image_shader(SkPDFDocument* doc,
SkMatrix bottomMatrix; SkMatrix bottomMatrix;
bottomMatrix.setScale(SK_Scalar1, deviceBounds.bottom() - height); bottomMatrix.setScale(SK_Scalar1, deviceBounds.bottom() - height);
bottomMatrix.postTranslate(0, height); bottomMatrix.postTranslate(0, height);
draw_bitmap_matrix(&canvas, bottom, bottomMatrix); draw_bitmap_matrix(&canvas, bottom, bottomMatrix, paint);
if (tileModes[0] == SkShader::kMirror_TileMode) { if (tileModes[0] == SkShader::kMirror_TileMode) {
bottomMatrix.postScale(-1, 1); bottomMatrix.postScale(-1, 1);
bottomMatrix.postTranslate(2 * width, 0); bottomMatrix.postTranslate(2 * width, 0);
draw_bitmap_matrix(&canvas, bottom, bottomMatrix); draw_bitmap_matrix(&canvas, bottom, bottomMatrix, paint);
} }
patternBBox.fBottom = deviceBounds.height(); patternBBox.fBottom = deviceBounds.height();
} }
@ -252,7 +257,8 @@ static sk_sp<SkPDFStream> make_image_shader(SkPDFDocument* doc,
static sk_sp<SkPDFObject> make_fallback_shader(SkPDFDocument* doc, static sk_sp<SkPDFObject> make_fallback_shader(SkPDFDocument* doc,
SkShader* shader, SkShader* shader,
const SkMatrix& canvasTransform, const SkMatrix& canvasTransform,
const SkIRect& surfaceBBox) { const SkIRect& surfaceBBox,
SkColor paintColor) {
// TODO(vandebo) This drops SKComposeShader on the floor. We could // TODO(vandebo) This drops SKComposeShader on the floor. We could
// handle compose shader by pulling things up to a layer, drawing with // handle compose shader by pulling things up to a layer, drawing with
// the first shader, applying the xfer mode and drawing again with the // the first shader, applying the xfer mode and drawing again with the
@ -262,7 +268,8 @@ static sk_sp<SkPDFObject> make_fallback_shader(SkPDFDocument* doc,
SkMatrix::I(), SkMatrix::I(),
surfaceBBox, surfaceBBox,
{{0, 0, 0, 0}, 0}, // don't need the key; won't de-dup. {{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(); key.fShaderTransform = shader->getLocalMatrix();
@ -287,31 +294,40 @@ static sk_sp<SkPDFObject> make_fallback_shader(SkPDFDocument* doc,
SkSize scale = {SkIntToScalar(size.width()) / shaderRect.width(), SkSize scale = {SkIntToScalar(size.width()) / shaderRect.width(),
SkIntToScalar(size.height()) / shaderRect.height()}; SkIntToScalar(size.height()) / shaderRect.height()};
SkBitmap bitmap; auto surface = SkSurface::MakeRasterN32Premul(size.width(), size.height());
bitmap.allocN32Pixels(size.width(), size.height()); SkCanvas* canvas = surface->getCanvas();
bitmap.eraseColor(SK_ColorTRANSPARENT); canvas->clear(SK_ColorTRANSPARENT);
SkPaint p; SkPaint p;
p.setShader(sk_ref_sp(shader)); p.setShader(sk_ref_sp(shader));
p.setColor(paintColor);
SkCanvas canvas(bitmap); canvas->scale(scale.width(), scale.height());
canvas.scale(scale.width(), scale.height()); canvas->translate(-shaderRect.x(), -shaderRect.y());
canvas.translate(-shaderRect.x(), -shaderRect.y()); canvas->drawPaint(p);
canvas.drawPaint(p);
key.fShaderTransform.setTranslate(shaderRect.x(), shaderRect.y()); key.fShaderTransform.setTranslate(shaderRect.x(), shaderRect.y());
key.fShaderTransform.preScale(1 / scale.width(), 1 / scale.height()); key.fShaderTransform.preScale(1 / scale.width(), 1 / scale.height());
SkASSERT (!bitmap.isNull()); sk_sp<SkImage> image = surface->makeImageSnapshot();
bitmap.setImmutable();
sk_sp<SkImage> image = SkImage::MakeFromBitmap(bitmap);
return make_image_shader(doc, key, image.get()); 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<SkPDFObject> SkPDFMakeShader(SkPDFDocument* doc, sk_sp<SkPDFObject> SkPDFMakeShader(SkPDFDocument* doc,
SkShader* shader, SkShader* shader,
const SkMatrix& canvasTransform, const SkMatrix& canvasTransform,
const SkIRect& surfaceBBox) { const SkIRect& surfaceBBox,
SkColor paintColor) {
SkASSERT(shader); SkASSERT(shader);
SkASSERT(doc); SkASSERT(doc);
if (SkShader::kNone_GradientType != shader->asAGradient(nullptr)) { if (SkShader::kNone_GradientType != shader->asAGradient(nullptr)) {
@ -326,7 +342,8 @@ sk_sp<SkPDFObject> SkPDFMakeShader(SkPDFDocument* doc,
SkMatrix::I(), SkMatrix::I(),
surfaceBBox, surfaceBBox,
{{0, 0, 0, 0}, 0}, {{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) ; SkASSERT(shader->asAGradient(nullptr) == SkShader::kNone_GradientType) ;
if (SkImage* skimg = shader->isAImage(&key.fShaderTransform, key.fImageTileModes)) { if (SkImage* skimg = shader->isAImage(&key.fShaderTransform, key.fImageTileModes)) {
@ -341,5 +358,5 @@ sk_sp<SkPDFObject> SkPDFMakeShader(SkPDFDocument* doc,
return pdfShader; return pdfShader;
} }
// Don't bother to de-dup fallback shader. // 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);
} }

View File

@ -34,11 +34,14 @@ struct SkIRect;
* positioned, relative to where the page is drawn.) * positioned, relative to where the page is drawn.)
* @param surfceBBox The bounding box of the drawing surface (with matrix * @param surfceBBox The bounding box of the drawing surface (with matrix
* already applied). * already applied).
* @param paintColor Color+Alpha of the paint. Color is usually ignored,
* unless it is a alpha shader.
*/ */
sk_sp<SkPDFObject> SkPDFMakeShader(SkPDFDocument* doc, sk_sp<SkPDFObject> SkPDFMakeShader(SkPDFDocument* doc,
SkShader* shader, SkShader* shader,
const SkMatrix& ctm, const SkMatrix& ctm,
const SkIRect& surfaceBBox); const SkIRect& surfaceBBox,
SkColor paintColor);
SK_BEGIN_REQUIRE_DENSE SK_BEGIN_REQUIRE_DENSE
struct SkPDFImageShaderKey { struct SkPDFImageShaderKey {
@ -47,6 +50,7 @@ struct SkPDFImageShaderKey {
SkIRect fBBox; SkIRect fBBox;
SkBitmapKey fBitmapKey; SkBitmapKey fBitmapKey;
SkShader::TileMode fImageTileModes[2]; SkShader::TileMode fImageTileModes[2];
SkColor fPaintColor;
}; };
SK_END_REQUIRE_DENSE SK_END_REQUIRE_DENSE
@ -58,6 +62,7 @@ inline bool operator==(const SkPDFImageShaderKey& a, const SkPDFImageShaderKey&
&& a.fBBox == b.fBBox && a.fBBox == b.fBBox
&& a.fBitmapKey == b.fBitmapKey && a.fBitmapKey == b.fBitmapKey
&& a.fImageTileModes[0] == b.fImageTileModes[0] && a.fImageTileModes[0] == b.fImageTileModes[0]
&& a.fImageTileModes[1] == b.fImageTileModes[1]; && a.fImageTileModes[1] == b.fImageTileModes[1]
&& a.fPaintColor == b.fPaintColor;
} }
#endif #endif