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