blob: 44cc27b0a9b91e953b5105b227b5fd2bf6049364 [file] [log] [blame]
vandebo@chromium.orgda912d62011-03-08 18:31:02 +00001/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00002 * Copyright 2011 Google Inc.
vandebo@chromium.orgda912d62011-03-08 18:31:02 +00003 *
epoger@google.comec3ed6a2011-07-28 14:26:00 +00004 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
vandebo@chromium.orgda912d62011-03-08 18:31:02 +00006 */
7
epoger@google.comec3ed6a2011-07-28 14:26:00 +00008
vandebo@chromium.orgda912d62011-03-08 18:31:02 +00009#include "SkPDFShader.h"
10
vandebo@chromium.org421d6442011-07-20 17:39:01 +000011#include "SkData.h"
halcanaryfb62b3d2015-01-21 09:59:14 -080012#include "SkPDFCanon.h"
vandebo@chromium.orgda912d62011-03-08 18:31:02 +000013#include "SkPDFDevice.h"
halcanary989da4a2016-03-21 14:33:17 -070014#include "SkPDFDocument.h"
commit-bot@chromium.org93a2e212013-07-23 23:16:03 +000015#include "SkPDFFormXObject.h"
Hal Canary94fd66c2017-07-05 11:25:42 -040016#include "SkPDFGradientShader.h"
commit-bot@chromium.org93a2e212013-07-23 23:16:03 +000017#include "SkPDFGraphicState.h"
commit-bot@chromium.org47401352013-07-23 21:49:29 +000018#include "SkPDFResourceDict.h"
vandebo@chromium.orgda912d62011-03-08 18:31:02 +000019#include "SkPDFUtils.h"
20#include "SkScalar.h"
21#include "SkStream.h"
twiz@google.com316338a2011-03-09 23:14:04 +000022#include "SkTemplates.h"
vandebo@chromium.orgda912d62011-03-08 18:31:02 +000023
vandebo@chromium.orgda912d62011-03-08 18:31:02 +000024
Hal Canary94fd66c2017-07-05 11:25:42 -040025static void draw_bitmap_matrix(SkCanvas* canvas, const SkBitmap& bm, const SkMatrix& matrix) {
Florin Malitac54d8db2014-12-10 12:02:16 -050026 SkAutoCanvasRestore acr(canvas, true);
27 canvas->concat(matrix);
28 canvas->drawBitmap(bm, 0, 0);
29}
30
halcanarydabd4f02016-08-03 11:16:56 -070031static sk_sp<SkPDFStream> make_image_shader(SkPDFDocument* doc,
halcanarydabd4f02016-08-03 11:16:56 -070032 const SkPDFShader::State& state,
33 SkBitmap image) {
Hal Canaryf50ff392016-09-30 10:25:39 -040034 SkASSERT(state.fBitmapKey ==
35 (SkBitmapKey{image.getSubset(), image.getGenerationID()}));
vandebo@chromium.orgda912d62011-03-08 18:31:02 +000036
commit-bot@chromium.orge324cc62013-08-21 23:10:45 +000037 // The image shader pattern cell will be drawn into a separate device
38 // in pattern cell space (no scaling on the bitmap, though there may be
39 // translations so that all content is in the device, coordinates > 0).
40
41 // Map clip bounds to shader space to ensure the device is large enough
42 // to handle fake clamping.
halcanarybc59ac62015-01-23 04:18:53 -080043 SkMatrix finalMatrix = state.fCanvasTransform;
44 finalMatrix.preConcat(state.fShaderTransform);
commit-bot@chromium.orge324cc62013-08-21 23:10:45 +000045 SkRect deviceBounds;
halcanarybc59ac62015-01-23 04:18:53 -080046 deviceBounds.set(state.fBBox);
Hal Canary94fd66c2017-07-05 11:25:42 -040047 if (!SkPDFUtils::InverseTransformBBox(finalMatrix, &deviceBounds)) {
halcanary96fcdcc2015-08-27 07:41:13 -070048 return nullptr;
vandebo@chromium.org386dfc02012-04-17 22:31:52 +000049 }
vandebo@chromium.orgda912d62011-03-08 18:31:02 +000050
commit-bot@chromium.orge324cc62013-08-21 23:10:45 +000051 SkRect bitmapBounds;
halcanarydabd4f02016-08-03 11:16:56 -070052 image.getBounds(&bitmapBounds);
commit-bot@chromium.orge324cc62013-08-21 23:10:45 +000053
54 // For tiling modes, the bounds should be extended to include the bitmap,
55 // otherwise the bitmap gets clipped out and the shader is empty and awful.
56 // For clamp modes, we're only interested in the clip region, whether
57 // or not the main bitmap is in it.
vandebo@chromium.orgda912d62011-03-08 18:31:02 +000058 SkShader::TileMode tileModes[2];
halcanarybc59ac62015-01-23 04:18:53 -080059 tileModes[0] = state.fImageTileModes[0];
60 tileModes[1] = state.fImageTileModes[1];
commit-bot@chromium.orge324cc62013-08-21 23:10:45 +000061 if (tileModes[0] != SkShader::kClamp_TileMode ||
62 tileModes[1] != SkShader::kClamp_TileMode) {
63 deviceBounds.join(bitmapBounds);
64 }
vandebo@chromium.orgda912d62011-03-08 18:31:02 +000065
reed@google.come1ca7052013-12-17 19:22:07 +000066 SkISize size = SkISize::Make(SkScalarRoundToInt(deviceBounds.width()),
67 SkScalarRoundToInt(deviceBounds.height()));
Hal Canarya0622582017-06-29 18:51:35 -040068 auto patternDevice = sk_make_sp<SkPDFDevice>(size, doc);
halcanarya1f1ee92015-02-20 06:17:26 -080069 SkCanvas canvas(patternDevice.get());
commit-bot@chromium.orge324cc62013-08-21 23:10:45 +000070
71 SkRect patternBBox;
halcanarydabd4f02016-08-03 11:16:56 -070072 image.getBounds(&patternBBox);
commit-bot@chromium.orge324cc62013-08-21 23:10:45 +000073
74 // Translate the canvas so that the bitmap origin is at (0, 0).
75 canvas.translate(-deviceBounds.left(), -deviceBounds.top());
76 patternBBox.offset(-deviceBounds.left(), -deviceBounds.top());
77 // Undo the translation in the final matrix
78 finalMatrix.preTranslate(deviceBounds.left(), deviceBounds.top());
79
80 // If the bitmap is out of bounds (i.e. clamp mode where we only see the
81 // stretched sides), canvas will clip this out and the extraneous data
82 // won't be saved to the PDF.
halcanarydabd4f02016-08-03 11:16:56 -070083 canvas.drawBitmap(image, 0, 0);
commit-bot@chromium.orge324cc62013-08-21 23:10:45 +000084
halcanarydabd4f02016-08-03 11:16:56 -070085 SkScalar width = SkIntToScalar(image.width());
86 SkScalar height = SkIntToScalar(image.height());
vandebo@chromium.orgda912d62011-03-08 18:31:02 +000087
88 // Tiling is implied. First we handle mirroring.
89 if (tileModes[0] == SkShader::kMirror_TileMode) {
90 SkMatrix xMirror;
91 xMirror.setScale(-1, 1);
92 xMirror.postTranslate(2 * width, 0);
Hal Canary94fd66c2017-07-05 11:25:42 -040093 draw_bitmap_matrix(&canvas, image, xMirror);
vandebo@chromium.orgda912d62011-03-08 18:31:02 +000094 patternBBox.fRight += width;
95 }
96 if (tileModes[1] == SkShader::kMirror_TileMode) {
97 SkMatrix yMirror;
vandebo@chromium.org663515b2012-01-05 18:45:27 +000098 yMirror.setScale(SK_Scalar1, -SK_Scalar1);
vandebo@chromium.orgda912d62011-03-08 18:31:02 +000099 yMirror.postTranslate(0, 2 * height);
Hal Canary94fd66c2017-07-05 11:25:42 -0400100 draw_bitmap_matrix(&canvas, image, yMirror);
vandebo@chromium.orgda912d62011-03-08 18:31:02 +0000101 patternBBox.fBottom += height;
102 }
103 if (tileModes[0] == SkShader::kMirror_TileMode &&
104 tileModes[1] == SkShader::kMirror_TileMode) {
105 SkMatrix mirror;
106 mirror.setScale(-1, -1);
107 mirror.postTranslate(2 * width, 2 * height);
Hal Canary94fd66c2017-07-05 11:25:42 -0400108 draw_bitmap_matrix(&canvas, image, mirror);
vandebo@chromium.orgda912d62011-03-08 18:31:02 +0000109 }
110
111 // Then handle Clamping, which requires expanding the pattern canvas to
112 // cover the entire surfaceBBox.
113
114 // If both x and y are in clamp mode, we start by filling in the corners.
115 // (Which are just a rectangles of the corner colors.)
116 if (tileModes[0] == SkShader::kClamp_TileMode &&
117 tileModes[1] == SkShader::kClamp_TileMode) {
118 SkPaint paint;
119 SkRect rect;
commit-bot@chromium.orge324cc62013-08-21 23:10:45 +0000120 rect = SkRect::MakeLTRB(deviceBounds.left(), deviceBounds.top(), 0, 0);
vandebo@chromium.orgda912d62011-03-08 18:31:02 +0000121 if (!rect.isEmpty()) {
halcanarydabd4f02016-08-03 11:16:56 -0700122 paint.setColor(image.getColor(0, 0));
vandebo@chromium.orgda912d62011-03-08 18:31:02 +0000123 canvas.drawRect(rect, paint);
124 }
125
commit-bot@chromium.orge324cc62013-08-21 23:10:45 +0000126 rect = SkRect::MakeLTRB(width, deviceBounds.top(),
127 deviceBounds.right(), 0);
vandebo@chromium.orgda912d62011-03-08 18:31:02 +0000128 if (!rect.isEmpty()) {
halcanarydabd4f02016-08-03 11:16:56 -0700129 paint.setColor(image.getColor(image.width() - 1, 0));
vandebo@chromium.orgda912d62011-03-08 18:31:02 +0000130 canvas.drawRect(rect, paint);
131 }
132
commit-bot@chromium.orge324cc62013-08-21 23:10:45 +0000133 rect = SkRect::MakeLTRB(width, height,
134 deviceBounds.right(), deviceBounds.bottom());
vandebo@chromium.orgda912d62011-03-08 18:31:02 +0000135 if (!rect.isEmpty()) {
halcanarydabd4f02016-08-03 11:16:56 -0700136 paint.setColor(image.getColor(image.width() - 1,
137 image.height() - 1));
vandebo@chromium.orgda912d62011-03-08 18:31:02 +0000138 canvas.drawRect(rect, paint);
139 }
140
commit-bot@chromium.orge324cc62013-08-21 23:10:45 +0000141 rect = SkRect::MakeLTRB(deviceBounds.left(), height,
142 0, deviceBounds.bottom());
vandebo@chromium.orgda912d62011-03-08 18:31:02 +0000143 if (!rect.isEmpty()) {
halcanarydabd4f02016-08-03 11:16:56 -0700144 paint.setColor(image.getColor(0, image.height() - 1));
vandebo@chromium.orgda912d62011-03-08 18:31:02 +0000145 canvas.drawRect(rect, paint);
146 }
147 }
148
149 // Then expand the left, right, top, then bottom.
150 if (tileModes[0] == SkShader::kClamp_TileMode) {
halcanarydabd4f02016-08-03 11:16:56 -0700151 SkIRect subset = SkIRect::MakeXYWH(0, 0, 1, image.height());
commit-bot@chromium.orge324cc62013-08-21 23:10:45 +0000152 if (deviceBounds.left() < 0) {
vandebo@chromium.orgda912d62011-03-08 18:31:02 +0000153 SkBitmap left;
halcanarydabd4f02016-08-03 11:16:56 -0700154 SkAssertResult(image.extractSubset(&left, subset));
vandebo@chromium.orgda912d62011-03-08 18:31:02 +0000155
156 SkMatrix leftMatrix;
commit-bot@chromium.orge324cc62013-08-21 23:10:45 +0000157 leftMatrix.setScale(-deviceBounds.left(), 1);
158 leftMatrix.postTranslate(deviceBounds.left(), 0);
Hal Canary94fd66c2017-07-05 11:25:42 -0400159 draw_bitmap_matrix(&canvas, left, leftMatrix);
vandebo@chromium.orgda912d62011-03-08 18:31:02 +0000160
161 if (tileModes[1] == SkShader::kMirror_TileMode) {
vandebo@chromium.org663515b2012-01-05 18:45:27 +0000162 leftMatrix.postScale(SK_Scalar1, -SK_Scalar1);
vandebo@chromium.orgda912d62011-03-08 18:31:02 +0000163 leftMatrix.postTranslate(0, 2 * height);
Hal Canary94fd66c2017-07-05 11:25:42 -0400164 draw_bitmap_matrix(&canvas, left, leftMatrix);
vandebo@chromium.orgda912d62011-03-08 18:31:02 +0000165 }
vandebo@chromium.orgbe2048a2011-05-02 15:24:01 +0000166 patternBBox.fLeft = 0;
vandebo@chromium.orgda912d62011-03-08 18:31:02 +0000167 }
168
commit-bot@chromium.orge324cc62013-08-21 23:10:45 +0000169 if (deviceBounds.right() > width) {
vandebo@chromium.orgda912d62011-03-08 18:31:02 +0000170 SkBitmap right;
halcanarydabd4f02016-08-03 11:16:56 -0700171 subset.offset(image.width() - 1, 0);
172 SkAssertResult(image.extractSubset(&right, subset));
vandebo@chromium.orgda912d62011-03-08 18:31:02 +0000173
174 SkMatrix rightMatrix;
commit-bot@chromium.orge324cc62013-08-21 23:10:45 +0000175 rightMatrix.setScale(deviceBounds.right() - width, 1);
vandebo@chromium.orgda912d62011-03-08 18:31:02 +0000176 rightMatrix.postTranslate(width, 0);
Hal Canary94fd66c2017-07-05 11:25:42 -0400177 draw_bitmap_matrix(&canvas, right, rightMatrix);
vandebo@chromium.orgda912d62011-03-08 18:31:02 +0000178
179 if (tileModes[1] == SkShader::kMirror_TileMode) {
vandebo@chromium.org663515b2012-01-05 18:45:27 +0000180 rightMatrix.postScale(SK_Scalar1, -SK_Scalar1);
vandebo@chromium.orgda912d62011-03-08 18:31:02 +0000181 rightMatrix.postTranslate(0, 2 * height);
Hal Canary94fd66c2017-07-05 11:25:42 -0400182 draw_bitmap_matrix(&canvas, right, rightMatrix);
vandebo@chromium.orgda912d62011-03-08 18:31:02 +0000183 }
commit-bot@chromium.orge324cc62013-08-21 23:10:45 +0000184 patternBBox.fRight = deviceBounds.width();
vandebo@chromium.orgda912d62011-03-08 18:31:02 +0000185 }
186 }
187
188 if (tileModes[1] == SkShader::kClamp_TileMode) {
halcanarydabd4f02016-08-03 11:16:56 -0700189 SkIRect subset = SkIRect::MakeXYWH(0, 0, image.width(), 1);
commit-bot@chromium.orge324cc62013-08-21 23:10:45 +0000190 if (deviceBounds.top() < 0) {
vandebo@chromium.orgda912d62011-03-08 18:31:02 +0000191 SkBitmap top;
halcanarydabd4f02016-08-03 11:16:56 -0700192 SkAssertResult(image.extractSubset(&top, subset));
vandebo@chromium.orgda912d62011-03-08 18:31:02 +0000193
194 SkMatrix topMatrix;
commit-bot@chromium.orge324cc62013-08-21 23:10:45 +0000195 topMatrix.setScale(SK_Scalar1, -deviceBounds.top());
196 topMatrix.postTranslate(0, deviceBounds.top());
Hal Canary94fd66c2017-07-05 11:25:42 -0400197 draw_bitmap_matrix(&canvas, top, topMatrix);
vandebo@chromium.orgda912d62011-03-08 18:31:02 +0000198
199 if (tileModes[0] == SkShader::kMirror_TileMode) {
200 topMatrix.postScale(-1, 1);
201 topMatrix.postTranslate(2 * width, 0);
Hal Canary94fd66c2017-07-05 11:25:42 -0400202 draw_bitmap_matrix(&canvas, top, topMatrix);
vandebo@chromium.orgda912d62011-03-08 18:31:02 +0000203 }
vandebo@chromium.orgbe2048a2011-05-02 15:24:01 +0000204 patternBBox.fTop = 0;
vandebo@chromium.orgda912d62011-03-08 18:31:02 +0000205 }
206
commit-bot@chromium.orge324cc62013-08-21 23:10:45 +0000207 if (deviceBounds.bottom() > height) {
vandebo@chromium.orgda912d62011-03-08 18:31:02 +0000208 SkBitmap bottom;
halcanarydabd4f02016-08-03 11:16:56 -0700209 subset.offset(0, image.height() - 1);
210 SkAssertResult(image.extractSubset(&bottom, subset));
vandebo@chromium.orgda912d62011-03-08 18:31:02 +0000211
212 SkMatrix bottomMatrix;
commit-bot@chromium.orge324cc62013-08-21 23:10:45 +0000213 bottomMatrix.setScale(SK_Scalar1, deviceBounds.bottom() - height);
vandebo@chromium.orgda912d62011-03-08 18:31:02 +0000214 bottomMatrix.postTranslate(0, height);
Hal Canary94fd66c2017-07-05 11:25:42 -0400215 draw_bitmap_matrix(&canvas, bottom, bottomMatrix);
vandebo@chromium.orgda912d62011-03-08 18:31:02 +0000216
217 if (tileModes[0] == SkShader::kMirror_TileMode) {
218 bottomMatrix.postScale(-1, 1);
219 bottomMatrix.postTranslate(2 * width, 0);
Hal Canary94fd66c2017-07-05 11:25:42 -0400220 draw_bitmap_matrix(&canvas, bottom, bottomMatrix);
vandebo@chromium.orgda912d62011-03-08 18:31:02 +0000221 }
commit-bot@chromium.orge324cc62013-08-21 23:10:45 +0000222 patternBBox.fBottom = deviceBounds.height();
vandebo@chromium.orgda912d62011-03-08 18:31:02 +0000223 }
224 }
225
halcanarydabd4f02016-08-03 11:16:56 -0700226 auto imageShader = sk_make_sp<SkPDFStream>(patternDevice->content());
Hal Canary94fd66c2017-07-05 11:25:42 -0400227 SkPDFUtils::PopulateTilingPatternDict(imageShader->dict(), patternBBox,
halcanarydabd4f02016-08-03 11:16:56 -0700228 patternDevice->makeResourceDict(), finalMatrix);
halcanarybc59ac62015-01-23 04:18:53 -0800229 return imageShader;
vandebo@chromium.orgda912d62011-03-08 18:31:02 +0000230}
231
Hal Canary94fd66c2017-07-05 11:25:42 -0400232// Generic fallback for unsupported shaders:
233// * allocate a surfaceBBox-sized bitmap
234// * shade the whole area
235// * use the result as a bitmap shader
236static sk_sp<SkPDFObject> make_fallback_shader(SkPDFDocument* doc,
237 SkShader* shader,
238 const SkMatrix& canvasTransform,
239 const SkIRect& surfaceBBox) {
240 // TODO(vandebo) This drops SKComposeShader on the floor. We could
241 // handle compose shader by pulling things up to a layer, drawing with
242 // the first shader, applying the xfer mode and drawing again with the
243 // second shader, then applying the layer to the original drawing.
244 SkPDFShader::State state = {
245 canvasTransform,
246 SkMatrix::I(),
247 surfaceBBox,
248 {{0, 0, 0, 0}, 0},
249 {SkShader::kClamp_TileMode, SkShader::kClamp_TileMode}};
vandebo@chromium.orgda912d62011-03-08 18:31:02 +0000250
Hal Canary94fd66c2017-07-05 11:25:42 -0400251 state.fShaderTransform = shader->getLocalMatrix();
vandebo@chromium.orgda912d62011-03-08 18:31:02 +0000252
Hal Canary94fd66c2017-07-05 11:25:42 -0400253 // surfaceBBox is in device space. While that's exactly what we
Hal Canary47bf4c02016-09-28 11:53:33 -0400254 // want for sizing our bitmap, we need to map it into
255 // shader space for adjustments (to match
256 // MakeImageShader's behavior).
Hal Canary94fd66c2017-07-05 11:25:42 -0400257 SkRect shaderRect = SkRect::Make(surfaceBBox);
258 if (!SkPDFUtils::InverseTransformBBox(canvasTransform, &shaderRect)) {
259 return nullptr;
Hal Canary47bf4c02016-09-28 11:53:33 -0400260 }
Hal Canary47bf4c02016-09-28 11:53:33 -0400261 // Clamp the bitmap size to about 1M pixels
262 static const SkScalar kMaxBitmapArea = 1024 * 1024;
Hal Canary94fd66c2017-07-05 11:25:42 -0400263 SkScalar rasterScale = SkIntToScalar(doc->rasterDpi()) / SkPDFUtils::kDpiForRasterScaleOne;
264 SkScalar bitmapArea = rasterScale * surfaceBBox.width() * rasterScale * surfaceBBox.height();
Hal Canary47bf4c02016-09-28 11:53:33 -0400265 if (bitmapArea > kMaxBitmapArea) {
266 rasterScale *= SkScalarSqrt(kMaxBitmapArea / bitmapArea);
267 }
268
Hal Canary94fd66c2017-07-05 11:25:42 -0400269 SkISize size = {SkScalarRoundToInt(rasterScale * surfaceBBox.width()),
270 SkScalarRoundToInt(rasterScale * surfaceBBox.height())};
Hal Canaryfafe1352017-04-11 12:12:02 -0400271 SkSize scale = {SkIntToScalar(size.width()) / shaderRect.width(),
272 SkIntToScalar(size.height()) / shaderRect.height()};
Hal Canary47bf4c02016-09-28 11:53:33 -0400273
Hal Canary94fd66c2017-07-05 11:25:42 -0400274 SkBitmap image;
275 image.allocN32Pixels(size.width(), size.height());
276 image.eraseColor(SK_ColorTRANSPARENT);
Hal Canary47bf4c02016-09-28 11:53:33 -0400277
278 SkPaint p;
279 p.setShader(sk_ref_sp(shader));
280
Hal Canary94fd66c2017-07-05 11:25:42 -0400281 SkCanvas canvas(image);
Hal Canary47bf4c02016-09-28 11:53:33 -0400282 canvas.scale(scale.width(), scale.height());
283 canvas.translate(-shaderRect.x(), -shaderRect.y());
284 canvas.drawPaint(p);
285
Hal Canary94fd66c2017-07-05 11:25:42 -0400286 state.fShaderTransform.setTranslate(shaderRect.x(), shaderRect.y());
287 state.fShaderTransform.preScale(1 / scale.width(), 1 / scale.height());
288 state.fBitmapKey = SkBitmapKey{image.getSubset(), image.getGenerationID()};
289 SkASSERT (!image.isNull());
290 return make_image_shader(doc, state, std::move(image));
vandebo@chromium.orgda912d62011-03-08 18:31:02 +0000291}
commit-bot@chromium.org93a2e212013-07-23 23:16:03 +0000292
Hal Canary94fd66c2017-07-05 11:25:42 -0400293sk_sp<SkPDFObject> SkPDFShader::GetPDFShader(SkPDFDocument* doc,
294 SkShader* shader,
295 const SkMatrix& canvasTransform,
296 const SkIRect& surfaceBBox) {
297 SkASSERT(shader);
298 SkASSERT(doc);
299 if (SkShader::kNone_GradientType != shader->asAGradient(nullptr)) {
300 return SkPDFGradientShader::Make(doc, shader, canvasTransform, surfaceBBox);
301 }
302 if (surfaceBBox.isEmpty()) {
303 return nullptr;
304 }
305 SkBitmap image;
306 SkPDFShader::State state = {
307 canvasTransform,
308 SkMatrix::I(),
309 surfaceBBox,
310 {{0, 0, 0, 0}, 0},
311 {SkShader::kClamp_TileMode, SkShader::kClamp_TileMode}};
commit-bot@chromium.org93a2e212013-07-23 23:16:03 +0000312
Hal Canary94fd66c2017-07-05 11:25:42 -0400313 SkASSERT(shader->asAGradient(nullptr) == SkShader::kNone_GradientType) ;
314 SkImage* skimg;
315 if ((skimg = shader->isAImage(&state.fShaderTransform, state.fImageTileModes))
316 && skimg->asLegacyBitmap(&image, SkImage::kRO_LegacyBitmapMode)) {
317 // TODO(halcanary): delay converting to bitmap.
318 state.fBitmapKey = SkBitmapKey{image.getSubset(), image.getGenerationID()};
319 if (image.isNull()) {
320 return nullptr;
commit-bot@chromium.org93a2e212013-07-23 23:16:03 +0000321 }
Hal Canary94fd66c2017-07-05 11:25:42 -0400322 SkPDFCanon* canon = doc->canon();
323 sk_sp<SkPDFObject>* shaderPtr = canon->fImageShaderMap.find(state);
324 if (shaderPtr) {
325 return *shaderPtr;
commit-bot@chromium.org93a2e212013-07-23 23:16:03 +0000326 }
Hal Canary94fd66c2017-07-05 11:25:42 -0400327 sk_sp<SkPDFObject> pdfShader = make_image_shader(doc, state, std::move(image));
328 canon->fImageShaderMap.set(std::move(state), pdfShader);
329 return pdfShader;
commit-bot@chromium.org93a2e212013-07-23 23:16:03 +0000330 }
Hal Canary94fd66c2017-07-05 11:25:42 -0400331 // Don't bother to de-dup fallback shader.
332 return make_fallback_shader(doc, shader, canvasTransform, surfaceBBox);
commit-bot@chromium.org93a2e212013-07-23 23:16:03 +0000333}