1 /*
2 * Copyright 2023 Google LLC
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "src/image/SkImage_Picture.h"
9
10 #include "include/core/SkCanvas.h"
11 #include "include/core/SkColor.h"
12 #include "include/core/SkColorSpace.h"
13 #include "include/core/SkColorType.h"
14 #include "include/core/SkImage.h"
15 #include "include/core/SkImageGenerator.h"
16 #include "include/core/SkImageInfo.h"
17 #include "include/core/SkMatrix.h"
18 #include "include/core/SkPicture.h"
19 #include "include/core/SkSurfaceProps.h"
20 #include "include/private/base/SkAssert.h"
21 #include "include/private/base/SkMutex.h"
22 #include "include/private/base/SkTFitsIn.h"
23 #include "src/base/SkTLazy.h"
24 #include "src/image/SkImageGeneratorPriv.h"
25 #include "src/image/SkImage_Lazy.h"
26 #include "src/image/SkPictureImageGenerator.h"
27
28 #include <cstring>
29 #include <memory>
30 #include <utility>
31
32 class SkPaint;
33 struct SkISize;
34
Make(sk_sp<SkPicture> picture,const SkISize & dimensions,const SkMatrix * matrix,const SkPaint * paint,SkImages::BitDepth bitDepth,sk_sp<SkColorSpace> colorSpace,SkSurfaceProps props)35 sk_sp<SkImage> SkImage_Picture::Make(sk_sp<SkPicture> picture, const SkISize& dimensions,
36 const SkMatrix* matrix, const SkPaint* paint,
37 SkImages::BitDepth bitDepth, sk_sp<SkColorSpace> colorSpace,
38 SkSurfaceProps props) {
39 auto gen = SkImageGenerators::MakeFromPicture(dimensions, std::move(picture), matrix, paint,
40 bitDepth, std::move(colorSpace), props);
41
42 SkImage_Lazy::Validator validator(
43 SharedGenerator::Make(std::move(gen)), nullptr, nullptr);
44
45 return validator ? sk_make_sp<SkImage_Picture>(&validator) : nullptr;
46 }
47
props() const48 const SkSurfaceProps* SkImage_Picture::props() const {
49 auto pictureIG = static_cast<SkPictureImageGenerator*>(this->generator()->fGenerator.get());
50 return &pictureIG->fProps;
51 }
52
replay(SkCanvas * canvas) const53 void SkImage_Picture::replay(SkCanvas* canvas) const {
54 auto sharedGenerator = this->generator();
55 SkAutoMutexExclusive mutex(sharedGenerator->fMutex);
56
57 auto pictureIG = static_cast<SkPictureImageGenerator*>(sharedGenerator->fGenerator.get());
58 canvas->clear(SkColors::kTransparent);
59 canvas->drawPicture(pictureIG->fPicture,
60 &pictureIG->fMatrix,
61 pictureIG->fPaint.getMaybeNull());
62 }
63
getImageKeyValues(uint32_t keyValues[SkTiledImageUtils::kNumImageKeyValues]) const64 bool SkImage_Picture::getImageKeyValues(
65 uint32_t keyValues[SkTiledImageUtils::kNumImageKeyValues]) const {
66
67 auto sharedGenerator = this->generator();
68 SkAutoMutexExclusive mutex(sharedGenerator->fMutex);
69
70 auto pictureIG = static_cast<SkPictureImageGenerator*>(sharedGenerator->fGenerator.get());
71 if (pictureIG->fPaint.getMaybeNull()) {
72 // A full paint complicates the potential key too much.
73 return false;
74 }
75
76 const SkImageInfo& ii = sharedGenerator->getInfo();
77 if (!ii.colorSpace()->isSRGB()) {
78 // We only return key values if the colorSpace is sRGB.
79 return false;
80 }
81
82 const SkMatrix& m = pictureIG->fMatrix;
83 if (!m.isIdentity() && !m.isTranslate()) {
84 // To keep the key small we only cache simple (<= translation) matrices
85 return false;
86 }
87
88 bool isU8 = ii.colorType() != kRGBA_F16_SkColorType;
89 uint32_t pixelGeometry = this->props()->pixelGeometry();
90 uint32_t surfacePropFlags = this->props()->flags();
91 int width = ii.width();
92 int height = ii.height();
93 float transX = m.getTranslateX();
94 float transY = m.getTranslateY();
95
96 SkASSERT(pixelGeometry <= 4);
97 SkASSERT(surfacePropFlags < 8);
98 SkASSERT(SkTFitsIn<uint32_t>(width));
99 SkASSERT(SkTFitsIn<uint32_t>(height));
100 SkASSERT(sizeof(float) == sizeof(uint32_t));
101
102 // The 0th slot usually holds either the SkBitmap's ID or the image's. In those two cases
103 // slot #1 is zero so we can reuse the 0th slot here.
104 keyValues[0] = (isU8 ? 0x1 : 0x0) | // 1 bit
105 (pixelGeometry << 1) | // 3 bits
106 (surfacePropFlags << 4); // 3 bits
107 keyValues[1] = pictureIG->fPicture->uniqueID();
108 SkASSERT(keyValues[1] != 0); // Double check we don't collide w/ bitmap or image keys
109 keyValues[2] = width;
110 keyValues[3] = height;
111 memcpy(&keyValues[4], &transX, sizeof(uint32_t));
112 memcpy(&keyValues[5], &transY, sizeof(uint32_t));
113 return true;
114 }
115