1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2011 Google Inc.
3cb93a386Sopenharmony_ci *
4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be
5cb93a386Sopenharmony_ci * found in the LICENSE file.
6cb93a386Sopenharmony_ci */
7cb93a386Sopenharmony_ci
8cb93a386Sopenharmony_ci#include "src/pdf/SkPDFShader.h"
9cb93a386Sopenharmony_ci
10cb93a386Sopenharmony_ci#include "include/core/SkData.h"
11cb93a386Sopenharmony_ci#include "include/core/SkMath.h"
12cb93a386Sopenharmony_ci#include "include/core/SkScalar.h"
13cb93a386Sopenharmony_ci#include "include/core/SkStream.h"
14cb93a386Sopenharmony_ci#include "include/core/SkSurface.h"
15cb93a386Sopenharmony_ci#include "include/docs/SkPDFDocument.h"
16cb93a386Sopenharmony_ci#include "include/private/SkTPin.h"
17cb93a386Sopenharmony_ci#include "include/private/SkTemplates.h"
18cb93a386Sopenharmony_ci#include "src/pdf/SkPDFDevice.h"
19cb93a386Sopenharmony_ci#include "src/pdf/SkPDFDocumentPriv.h"
20cb93a386Sopenharmony_ci#include "src/pdf/SkPDFFormXObject.h"
21cb93a386Sopenharmony_ci#include "src/pdf/SkPDFGradientShader.h"
22cb93a386Sopenharmony_ci#include "src/pdf/SkPDFGraphicState.h"
23cb93a386Sopenharmony_ci#include "src/pdf/SkPDFResourceDict.h"
24cb93a386Sopenharmony_ci#include "src/pdf/SkPDFUtils.h"
25cb93a386Sopenharmony_ci
26cb93a386Sopenharmony_cistatic void draw(SkCanvas* canvas, const SkImage* image, SkColor4f paintColor) {
27cb93a386Sopenharmony_ci    SkPaint paint(paintColor);
28cb93a386Sopenharmony_ci    canvas->drawImage(image, 0, 0, SkSamplingOptions(), &paint);
29cb93a386Sopenharmony_ci}
30cb93a386Sopenharmony_ci
31cb93a386Sopenharmony_cistatic SkBitmap to_bitmap(const SkImage* image) {
32cb93a386Sopenharmony_ci    SkBitmap bitmap;
33cb93a386Sopenharmony_ci    if (!SkPDFUtils::ToBitmap(image, &bitmap)) {
34cb93a386Sopenharmony_ci        bitmap.allocN32Pixels(image->width(), image->height());
35cb93a386Sopenharmony_ci        bitmap.eraseColor(0x00000000);
36cb93a386Sopenharmony_ci    }
37cb93a386Sopenharmony_ci    return bitmap;
38cb93a386Sopenharmony_ci}
39cb93a386Sopenharmony_ci
40cb93a386Sopenharmony_cistatic void draw_matrix(SkCanvas* canvas, const SkImage* image,
41cb93a386Sopenharmony_ci                        const SkMatrix& matrix, SkColor4f paintColor) {
42cb93a386Sopenharmony_ci    SkAutoCanvasRestore acr(canvas, true);
43cb93a386Sopenharmony_ci    canvas->concat(matrix);
44cb93a386Sopenharmony_ci    draw(canvas, image, paintColor);
45cb93a386Sopenharmony_ci}
46cb93a386Sopenharmony_ci
47cb93a386Sopenharmony_cistatic void draw_bitmap_matrix(SkCanvas* canvas, const SkBitmap& bm,
48cb93a386Sopenharmony_ci                               const SkMatrix& matrix, SkColor4f paintColor) {
49cb93a386Sopenharmony_ci    SkAutoCanvasRestore acr(canvas, true);
50cb93a386Sopenharmony_ci    canvas->concat(matrix);
51cb93a386Sopenharmony_ci    SkPaint paint(paintColor);
52cb93a386Sopenharmony_ci    canvas->drawImage(bm.asImage(), 0, 0, SkSamplingOptions(), &paint);
53cb93a386Sopenharmony_ci}
54cb93a386Sopenharmony_ci
55cb93a386Sopenharmony_cistatic void fill_color_from_bitmap(SkCanvas* canvas,
56cb93a386Sopenharmony_ci                                   float left, float top, float right, float bottom,
57cb93a386Sopenharmony_ci                                   const SkBitmap& bitmap, int x, int y, float alpha) {
58cb93a386Sopenharmony_ci    SkRect rect{left, top, right, bottom};
59cb93a386Sopenharmony_ci    if (!rect.isEmpty()) {
60cb93a386Sopenharmony_ci        SkColor4f color = SkColor4f::FromColor(bitmap.getColor(x, y));
61cb93a386Sopenharmony_ci        SkPaint paint(SkColor4f{color.fR, color.fG, color.fB, alpha * color.fA});
62cb93a386Sopenharmony_ci        canvas->drawRect(rect, paint);
63cb93a386Sopenharmony_ci    }
64cb93a386Sopenharmony_ci}
65cb93a386Sopenharmony_ci
66cb93a386Sopenharmony_cistatic SkMatrix scale_translate(SkScalar sx, SkScalar sy, SkScalar tx, SkScalar ty) {
67cb93a386Sopenharmony_ci    SkMatrix m;
68cb93a386Sopenharmony_ci    m.setScaleTranslate(sx, sy, tx, ty);
69cb93a386Sopenharmony_ci    return m;
70cb93a386Sopenharmony_ci}
71cb93a386Sopenharmony_ci
72cb93a386Sopenharmony_cistatic bool is_tiled(SkTileMode m) { return SkTileMode::kMirror == m || SkTileMode::kRepeat == m; }
73cb93a386Sopenharmony_ci
74cb93a386Sopenharmony_cistatic SkPDFIndirectReference make_image_shader(SkPDFDocument* doc,
75cb93a386Sopenharmony_ci                                                SkMatrix finalMatrix,
76cb93a386Sopenharmony_ci                                                SkTileMode tileModesX,
77cb93a386Sopenharmony_ci                                                SkTileMode tileModesY,
78cb93a386Sopenharmony_ci                                                SkRect bBox,
79cb93a386Sopenharmony_ci                                                const SkImage* image,
80cb93a386Sopenharmony_ci                                                SkColor4f paintColor) {
81cb93a386Sopenharmony_ci    // The image shader pattern cell will be drawn into a separate device
82cb93a386Sopenharmony_ci    // in pattern cell space (no scaling on the bitmap, though there may be
83cb93a386Sopenharmony_ci    // translations so that all content is in the device, coordinates > 0).
84cb93a386Sopenharmony_ci
85cb93a386Sopenharmony_ci    // Map clip bounds to shader space to ensure the device is large enough
86cb93a386Sopenharmony_ci    // to handle fake clamping.
87cb93a386Sopenharmony_ci
88cb93a386Sopenharmony_ci    SkRect deviceBounds = bBox;
89cb93a386Sopenharmony_ci    if (!SkPDFUtils::InverseTransformBBox(finalMatrix, &deviceBounds)) {
90cb93a386Sopenharmony_ci        return SkPDFIndirectReference();
91cb93a386Sopenharmony_ci    }
92cb93a386Sopenharmony_ci
93cb93a386Sopenharmony_ci    SkRect bitmapBounds = SkRect::MakeSize(SkSize::Make(image->dimensions()));
94cb93a386Sopenharmony_ci
95cb93a386Sopenharmony_ci    // For tiling modes, the bounds should be extended to include the bitmap,
96cb93a386Sopenharmony_ci    // otherwise the bitmap gets clipped out and the shader is empty and awful.
97cb93a386Sopenharmony_ci    // For clamp modes, we're only interested in the clip region, whether
98cb93a386Sopenharmony_ci    // or not the main bitmap is in it.
99cb93a386Sopenharmony_ci    if (is_tiled(tileModesX) || is_tiled(tileModesY)) {
100cb93a386Sopenharmony_ci        deviceBounds.join(bitmapBounds);
101cb93a386Sopenharmony_ci    }
102cb93a386Sopenharmony_ci
103cb93a386Sopenharmony_ci    SkISize patternDeviceSize = {SkScalarCeilToInt(deviceBounds.width()),
104cb93a386Sopenharmony_ci                                 SkScalarCeilToInt(deviceBounds.height())};
105cb93a386Sopenharmony_ci    auto patternDevice = sk_make_sp<SkPDFDevice>(patternDeviceSize, doc);
106cb93a386Sopenharmony_ci    SkCanvas canvas(patternDevice);
107cb93a386Sopenharmony_ci
108cb93a386Sopenharmony_ci    SkRect patternBBox = SkRect::MakeSize(SkSize::Make(image->dimensions()));
109cb93a386Sopenharmony_ci    SkScalar width = patternBBox.width();
110cb93a386Sopenharmony_ci    SkScalar height = patternBBox.height();
111cb93a386Sopenharmony_ci
112cb93a386Sopenharmony_ci    // Translate the canvas so that the bitmap origin is at (0, 0).
113cb93a386Sopenharmony_ci    canvas.translate(-deviceBounds.left(), -deviceBounds.top());
114cb93a386Sopenharmony_ci    patternBBox.offset(-deviceBounds.left(), -deviceBounds.top());
115cb93a386Sopenharmony_ci    // Undo the translation in the final matrix
116cb93a386Sopenharmony_ci    finalMatrix.preTranslate(deviceBounds.left(), deviceBounds.top());
117cb93a386Sopenharmony_ci
118cb93a386Sopenharmony_ci    // If the bitmap is out of bounds (i.e. clamp mode where we only see the
119cb93a386Sopenharmony_ci    // stretched sides), canvas will clip this out and the extraneous data
120cb93a386Sopenharmony_ci    // won't be saved to the PDF.
121cb93a386Sopenharmony_ci    draw(&canvas, image, paintColor);
122cb93a386Sopenharmony_ci
123cb93a386Sopenharmony_ci    // Tiling is implied.  First we handle mirroring.
124cb93a386Sopenharmony_ci    if (tileModesX == SkTileMode::kMirror) {
125cb93a386Sopenharmony_ci        draw_matrix(&canvas, image, scale_translate(-1, 1, 2 * width, 0), paintColor);
126cb93a386Sopenharmony_ci        patternBBox.fRight += width;
127cb93a386Sopenharmony_ci    }
128cb93a386Sopenharmony_ci    if (tileModesY == SkTileMode::kMirror) {
129cb93a386Sopenharmony_ci        draw_matrix(&canvas, image, scale_translate(1, -1, 0, 2 * height), paintColor);
130cb93a386Sopenharmony_ci        patternBBox.fBottom += height;
131cb93a386Sopenharmony_ci    }
132cb93a386Sopenharmony_ci    if (tileModesX == SkTileMode::kMirror && tileModesY == SkTileMode::kMirror) {
133cb93a386Sopenharmony_ci        draw_matrix(&canvas, image, scale_translate(-1, -1, 2 * width, 2 * height), paintColor);
134cb93a386Sopenharmony_ci    }
135cb93a386Sopenharmony_ci
136cb93a386Sopenharmony_ci    // Then handle Clamping, which requires expanding the pattern canvas to
137cb93a386Sopenharmony_ci    // cover the entire surfaceBBox.
138cb93a386Sopenharmony_ci
139cb93a386Sopenharmony_ci    SkBitmap bitmap;
140cb93a386Sopenharmony_ci    if (tileModesX == SkTileMode::kClamp || tileModesY == SkTileMode::kClamp) {
141cb93a386Sopenharmony_ci        // For now, the easiest way to access the colors in the corners and sides is
142cb93a386Sopenharmony_ci        // to just make a bitmap from the image.
143cb93a386Sopenharmony_ci        bitmap = to_bitmap(image);
144cb93a386Sopenharmony_ci    }
145cb93a386Sopenharmony_ci
146cb93a386Sopenharmony_ci    // If both x and y are in clamp mode, we start by filling in the corners.
147cb93a386Sopenharmony_ci    // (Which are just a rectangles of the corner colors.)
148cb93a386Sopenharmony_ci    if (tileModesX == SkTileMode::kClamp && tileModesY == SkTileMode::kClamp) {
149cb93a386Sopenharmony_ci        SkASSERT(!bitmap.drawsNothing());
150cb93a386Sopenharmony_ci
151cb93a386Sopenharmony_ci        fill_color_from_bitmap(&canvas, deviceBounds.left(), deviceBounds.top(), 0, 0,
152cb93a386Sopenharmony_ci                               bitmap, 0, 0, paintColor.fA);
153cb93a386Sopenharmony_ci
154cb93a386Sopenharmony_ci        fill_color_from_bitmap(&canvas, width, deviceBounds.top(), deviceBounds.right(), 0,
155cb93a386Sopenharmony_ci                               bitmap, bitmap.width() - 1, 0, paintColor.fA);
156cb93a386Sopenharmony_ci
157cb93a386Sopenharmony_ci        fill_color_from_bitmap(&canvas, width, height, deviceBounds.right(), deviceBounds.bottom(),
158cb93a386Sopenharmony_ci                               bitmap, bitmap.width() - 1, bitmap.height() - 1, paintColor.fA);
159cb93a386Sopenharmony_ci
160cb93a386Sopenharmony_ci        fill_color_from_bitmap(&canvas, deviceBounds.left(), height, 0, deviceBounds.bottom(),
161cb93a386Sopenharmony_ci                               bitmap, 0, bitmap.height() - 1, paintColor.fA);
162cb93a386Sopenharmony_ci    }
163cb93a386Sopenharmony_ci
164cb93a386Sopenharmony_ci    // Then expand the left, right, top, then bottom.
165cb93a386Sopenharmony_ci    if (tileModesX == SkTileMode::kClamp) {
166cb93a386Sopenharmony_ci        SkASSERT(!bitmap.drawsNothing());
167cb93a386Sopenharmony_ci        SkIRect subset = SkIRect::MakeXYWH(0, 0, 1, bitmap.height());
168cb93a386Sopenharmony_ci        if (deviceBounds.left() < 0) {
169cb93a386Sopenharmony_ci            SkBitmap left;
170cb93a386Sopenharmony_ci            SkAssertResult(bitmap.extractSubset(&left, subset));
171cb93a386Sopenharmony_ci
172cb93a386Sopenharmony_ci            SkMatrix leftMatrix = scale_translate(-deviceBounds.left(), 1, deviceBounds.left(), 0);
173cb93a386Sopenharmony_ci            draw_bitmap_matrix(&canvas, left, leftMatrix, paintColor);
174cb93a386Sopenharmony_ci
175cb93a386Sopenharmony_ci            if (tileModesY == SkTileMode::kMirror) {
176cb93a386Sopenharmony_ci                leftMatrix.postScale(SK_Scalar1, -SK_Scalar1);
177cb93a386Sopenharmony_ci                leftMatrix.postTranslate(0, 2 * height);
178cb93a386Sopenharmony_ci                draw_bitmap_matrix(&canvas, left, leftMatrix, paintColor);
179cb93a386Sopenharmony_ci            }
180cb93a386Sopenharmony_ci            patternBBox.fLeft = 0;
181cb93a386Sopenharmony_ci        }
182cb93a386Sopenharmony_ci
183cb93a386Sopenharmony_ci        if (deviceBounds.right() > width) {
184cb93a386Sopenharmony_ci            SkBitmap right;
185cb93a386Sopenharmony_ci            subset.offset(bitmap.width() - 1, 0);
186cb93a386Sopenharmony_ci            SkAssertResult(bitmap.extractSubset(&right, subset));
187cb93a386Sopenharmony_ci
188cb93a386Sopenharmony_ci            SkMatrix rightMatrix = scale_translate(deviceBounds.right() - width, 1, width, 0);
189cb93a386Sopenharmony_ci            draw_bitmap_matrix(&canvas, right, rightMatrix, paintColor);
190cb93a386Sopenharmony_ci
191cb93a386Sopenharmony_ci            if (tileModesY == SkTileMode::kMirror) {
192cb93a386Sopenharmony_ci                rightMatrix.postScale(SK_Scalar1, -SK_Scalar1);
193cb93a386Sopenharmony_ci                rightMatrix.postTranslate(0, 2 * height);
194cb93a386Sopenharmony_ci                draw_bitmap_matrix(&canvas, right, rightMatrix, paintColor);
195cb93a386Sopenharmony_ci            }
196cb93a386Sopenharmony_ci            patternBBox.fRight = deviceBounds.width();
197cb93a386Sopenharmony_ci        }
198cb93a386Sopenharmony_ci    }
199cb93a386Sopenharmony_ci    if (tileModesX == SkTileMode::kDecal) {
200cb93a386Sopenharmony_ci        if (deviceBounds.left() < 0) {
201cb93a386Sopenharmony_ci            patternBBox.fLeft = 0;
202cb93a386Sopenharmony_ci        }
203cb93a386Sopenharmony_ci        if (deviceBounds.right() > width) {
204cb93a386Sopenharmony_ci            patternBBox.fRight = deviceBounds.width();
205cb93a386Sopenharmony_ci        }
206cb93a386Sopenharmony_ci    }
207cb93a386Sopenharmony_ci
208cb93a386Sopenharmony_ci    if (tileModesY == SkTileMode::kClamp) {
209cb93a386Sopenharmony_ci        SkASSERT(!bitmap.drawsNothing());
210cb93a386Sopenharmony_ci        SkIRect subset = SkIRect::MakeXYWH(0, 0, bitmap.width(), 1);
211cb93a386Sopenharmony_ci        if (deviceBounds.top() < 0) {
212cb93a386Sopenharmony_ci            SkBitmap top;
213cb93a386Sopenharmony_ci            SkAssertResult(bitmap.extractSubset(&top, subset));
214cb93a386Sopenharmony_ci
215cb93a386Sopenharmony_ci            SkMatrix topMatrix = scale_translate(1, -deviceBounds.top(), 0, deviceBounds.top());
216cb93a386Sopenharmony_ci            draw_bitmap_matrix(&canvas, top, topMatrix, paintColor);
217cb93a386Sopenharmony_ci
218cb93a386Sopenharmony_ci            if (tileModesX == SkTileMode::kMirror) {
219cb93a386Sopenharmony_ci                topMatrix.postScale(-1, 1);
220cb93a386Sopenharmony_ci                topMatrix.postTranslate(2 * width, 0);
221cb93a386Sopenharmony_ci                draw_bitmap_matrix(&canvas, top, topMatrix, paintColor);
222cb93a386Sopenharmony_ci            }
223cb93a386Sopenharmony_ci            patternBBox.fTop = 0;
224cb93a386Sopenharmony_ci        }
225cb93a386Sopenharmony_ci
226cb93a386Sopenharmony_ci        if (deviceBounds.bottom() > height) {
227cb93a386Sopenharmony_ci            SkBitmap bottom;
228cb93a386Sopenharmony_ci            subset.offset(0, bitmap.height() - 1);
229cb93a386Sopenharmony_ci            SkAssertResult(bitmap.extractSubset(&bottom, subset));
230cb93a386Sopenharmony_ci
231cb93a386Sopenharmony_ci            SkMatrix bottomMatrix = scale_translate(1, deviceBounds.bottom() - height, 0, height);
232cb93a386Sopenharmony_ci            draw_bitmap_matrix(&canvas, bottom, bottomMatrix, paintColor);
233cb93a386Sopenharmony_ci
234cb93a386Sopenharmony_ci            if (tileModesX == SkTileMode::kMirror) {
235cb93a386Sopenharmony_ci                bottomMatrix.postScale(-1, 1);
236cb93a386Sopenharmony_ci                bottomMatrix.postTranslate(2 * width, 0);
237cb93a386Sopenharmony_ci                draw_bitmap_matrix(&canvas, bottom, bottomMatrix, paintColor);
238cb93a386Sopenharmony_ci            }
239cb93a386Sopenharmony_ci            patternBBox.fBottom = deviceBounds.height();
240cb93a386Sopenharmony_ci        }
241cb93a386Sopenharmony_ci    }
242cb93a386Sopenharmony_ci    if (tileModesY == SkTileMode::kDecal) {
243cb93a386Sopenharmony_ci        if (deviceBounds.top() < 0) {
244cb93a386Sopenharmony_ci            patternBBox.fTop = 0;
245cb93a386Sopenharmony_ci        }
246cb93a386Sopenharmony_ci        if (deviceBounds.bottom() > height) {
247cb93a386Sopenharmony_ci            patternBBox.fBottom = deviceBounds.height();
248cb93a386Sopenharmony_ci        }
249cb93a386Sopenharmony_ci    }
250cb93a386Sopenharmony_ci
251cb93a386Sopenharmony_ci    auto imageShader = patternDevice->content();
252cb93a386Sopenharmony_ci    std::unique_ptr<SkPDFDict> resourceDict = patternDevice->makeResourceDict();
253cb93a386Sopenharmony_ci    std::unique_ptr<SkPDFDict> dict = SkPDFMakeDict();
254cb93a386Sopenharmony_ci    SkPDFUtils::PopulateTilingPatternDict(dict.get(), patternBBox,
255cb93a386Sopenharmony_ci                                          std::move(resourceDict), finalMatrix);
256cb93a386Sopenharmony_ci    return SkPDFStreamOut(std::move(dict), std::move(imageShader), doc);
257cb93a386Sopenharmony_ci}
258cb93a386Sopenharmony_ci
259cb93a386Sopenharmony_ci// Generic fallback for unsupported shaders:
260cb93a386Sopenharmony_ci//  * allocate a surfaceBBox-sized bitmap
261cb93a386Sopenharmony_ci//  * shade the whole area
262cb93a386Sopenharmony_ci//  * use the result as a bitmap shader
263cb93a386Sopenharmony_cistatic SkPDFIndirectReference make_fallback_shader(SkPDFDocument* doc,
264cb93a386Sopenharmony_ci                                                   SkShader* shader,
265cb93a386Sopenharmony_ci                                                   const SkMatrix& canvasTransform,
266cb93a386Sopenharmony_ci                                                   const SkIRect& surfaceBBox,
267cb93a386Sopenharmony_ci                                                   SkColor4f paintColor) {
268cb93a386Sopenharmony_ci    // TODO(vandebo) This drops SKComposeShader on the floor.  We could
269cb93a386Sopenharmony_ci    // handle compose shader by pulling things up to a layer, drawing with
270cb93a386Sopenharmony_ci    // the first shader, applying the xfer mode and drawing again with the
271cb93a386Sopenharmony_ci    // second shader, then applying the layer to the original drawing.
272cb93a386Sopenharmony_ci
273cb93a386Sopenharmony_ci    SkMatrix shaderTransform = as_SB(shader)->getLocalMatrix();
274cb93a386Sopenharmony_ci
275cb93a386Sopenharmony_ci    // surfaceBBox is in device space. While that's exactly what we
276cb93a386Sopenharmony_ci    // want for sizing our bitmap, we need to map it into
277cb93a386Sopenharmony_ci    // shader space for adjustments (to match
278cb93a386Sopenharmony_ci    // MakeImageShader's behavior).
279cb93a386Sopenharmony_ci    SkRect shaderRect = SkRect::Make(surfaceBBox);
280cb93a386Sopenharmony_ci    if (!SkPDFUtils::InverseTransformBBox(canvasTransform, &shaderRect)) {
281cb93a386Sopenharmony_ci        return SkPDFIndirectReference();
282cb93a386Sopenharmony_ci    }
283cb93a386Sopenharmony_ci    // Clamp the bitmap size to about 1M pixels
284cb93a386Sopenharmony_ci    static const int kMaxBitmapArea = 1024 * 1024;
285cb93a386Sopenharmony_ci    SkScalar bitmapArea = (float)surfaceBBox.width() * (float)surfaceBBox.height();
286cb93a386Sopenharmony_ci    SkScalar rasterScale = 1.0f;
287cb93a386Sopenharmony_ci    if (bitmapArea > (float)kMaxBitmapArea) {
288cb93a386Sopenharmony_ci        rasterScale *= SkScalarSqrt((float)kMaxBitmapArea / bitmapArea);
289cb93a386Sopenharmony_ci    }
290cb93a386Sopenharmony_ci
291cb93a386Sopenharmony_ci    SkISize size = {
292cb93a386Sopenharmony_ci        SkTPin(SkScalarCeilToInt(rasterScale * surfaceBBox.width()),  1, kMaxBitmapArea),
293cb93a386Sopenharmony_ci        SkTPin(SkScalarCeilToInt(rasterScale * surfaceBBox.height()), 1, kMaxBitmapArea)};
294cb93a386Sopenharmony_ci    SkSize scale = {SkIntToScalar(size.width()) / shaderRect.width(),
295cb93a386Sopenharmony_ci                    SkIntToScalar(size.height()) / shaderRect.height()};
296cb93a386Sopenharmony_ci
297cb93a386Sopenharmony_ci    auto surface = SkSurface::MakeRasterN32Premul(size.width(), size.height());
298cb93a386Sopenharmony_ci    SkASSERT(surface);
299cb93a386Sopenharmony_ci    SkCanvas* canvas = surface->getCanvas();
300cb93a386Sopenharmony_ci    canvas->clear(SK_ColorTRANSPARENT);
301cb93a386Sopenharmony_ci
302cb93a386Sopenharmony_ci    SkPaint p(paintColor);
303cb93a386Sopenharmony_ci    p.setShader(sk_ref_sp(shader));
304cb93a386Sopenharmony_ci
305cb93a386Sopenharmony_ci    canvas->scale(scale.width(), scale.height());
306cb93a386Sopenharmony_ci    canvas->translate(-shaderRect.x(), -shaderRect.y());
307cb93a386Sopenharmony_ci    canvas->drawPaint(p);
308cb93a386Sopenharmony_ci
309cb93a386Sopenharmony_ci    shaderTransform.setTranslate(shaderRect.x(), shaderRect.y());
310cb93a386Sopenharmony_ci    shaderTransform.preScale(1 / scale.width(), 1 / scale.height());
311cb93a386Sopenharmony_ci
312cb93a386Sopenharmony_ci    sk_sp<SkImage> image = surface->makeImageSnapshot();
313cb93a386Sopenharmony_ci    SkASSERT(image);
314cb93a386Sopenharmony_ci    return make_image_shader(doc,
315cb93a386Sopenharmony_ci                             SkMatrix::Concat(canvasTransform, shaderTransform),
316cb93a386Sopenharmony_ci                             SkTileMode::kClamp, SkTileMode::kClamp,
317cb93a386Sopenharmony_ci                             SkRect::Make(surfaceBBox),
318cb93a386Sopenharmony_ci                             image.get(),
319cb93a386Sopenharmony_ci                             paintColor);
320cb93a386Sopenharmony_ci}
321cb93a386Sopenharmony_ci
322cb93a386Sopenharmony_cistatic SkColor4f adjust_color(SkShader* shader, SkColor4f paintColor) {
323cb93a386Sopenharmony_ci    if (SkImage* img = shader->isAImage(nullptr, (SkTileMode*)nullptr)) {
324cb93a386Sopenharmony_ci        if (img->isAlphaOnly()) {
325cb93a386Sopenharmony_ci            return paintColor;
326cb93a386Sopenharmony_ci        }
327cb93a386Sopenharmony_ci    }
328cb93a386Sopenharmony_ci    return SkColor4f{0, 0, 0, paintColor.fA};  // only preserve the alpha.
329cb93a386Sopenharmony_ci}
330cb93a386Sopenharmony_ci
331cb93a386Sopenharmony_ciSkPDFIndirectReference SkPDFMakeShader(SkPDFDocument* doc,
332cb93a386Sopenharmony_ci                                       SkShader* shader,
333cb93a386Sopenharmony_ci                                       const SkMatrix& canvasTransform,
334cb93a386Sopenharmony_ci                                       const SkIRect& surfaceBBox,
335cb93a386Sopenharmony_ci                                       SkColor4f paintColor) {
336cb93a386Sopenharmony_ci    SkASSERT(shader);
337cb93a386Sopenharmony_ci    SkASSERT(doc);
338cb93a386Sopenharmony_ci    if (SkShader::kNone_GradientType != shader->asAGradient(nullptr)) {
339cb93a386Sopenharmony_ci        return SkPDFGradientShader::Make(doc, shader, canvasTransform, surfaceBBox);
340cb93a386Sopenharmony_ci    }
341cb93a386Sopenharmony_ci    if (surfaceBBox.isEmpty()) {
342cb93a386Sopenharmony_ci        return SkPDFIndirectReference();
343cb93a386Sopenharmony_ci    }
344cb93a386Sopenharmony_ci    SkBitmap image;
345cb93a386Sopenharmony_ci
346cb93a386Sopenharmony_ci    SkASSERT(shader->asAGradient(nullptr) == SkShader::kNone_GradientType) ;
347cb93a386Sopenharmony_ci
348cb93a386Sopenharmony_ci    paintColor = adjust_color(shader, paintColor);
349cb93a386Sopenharmony_ci    SkMatrix shaderTransform;
350cb93a386Sopenharmony_ci    SkTileMode imageTileModes[2];
351cb93a386Sopenharmony_ci    if (SkImage* skimg = shader->isAImage(&shaderTransform, imageTileModes)) {
352cb93a386Sopenharmony_ci        SkMatrix finalMatrix = SkMatrix::Concat(canvasTransform, shaderTransform);
353cb93a386Sopenharmony_ci        SkPDFImageShaderKey key = {
354cb93a386Sopenharmony_ci            finalMatrix,
355cb93a386Sopenharmony_ci            surfaceBBox,
356cb93a386Sopenharmony_ci            SkBitmapKeyFromImage(skimg),
357cb93a386Sopenharmony_ci            {imageTileModes[0], imageTileModes[1]},
358cb93a386Sopenharmony_ci            paintColor};
359cb93a386Sopenharmony_ci        SkPDFIndirectReference* shaderPtr = doc->fImageShaderMap.find(key);
360cb93a386Sopenharmony_ci        if (shaderPtr) {
361cb93a386Sopenharmony_ci            return *shaderPtr;
362cb93a386Sopenharmony_ci        }
363cb93a386Sopenharmony_ci        SkPDFIndirectReference pdfShader =
364cb93a386Sopenharmony_ci                make_image_shader(doc,
365cb93a386Sopenharmony_ci                                  finalMatrix,
366cb93a386Sopenharmony_ci                                  imageTileModes[0],
367cb93a386Sopenharmony_ci                                  imageTileModes[1],
368cb93a386Sopenharmony_ci                                  SkRect::Make(surfaceBBox),
369cb93a386Sopenharmony_ci                                  skimg,
370cb93a386Sopenharmony_ci                                  paintColor);
371cb93a386Sopenharmony_ci        doc->fImageShaderMap.set(std::move(key), pdfShader);
372cb93a386Sopenharmony_ci        return pdfShader;
373cb93a386Sopenharmony_ci    }
374cb93a386Sopenharmony_ci    // Don't bother to de-dup fallback shader.
375cb93a386Sopenharmony_ci    return make_fallback_shader(doc, shader, canvasTransform, surfaceBBox, paintColor);
376cb93a386Sopenharmony_ci}
377