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 * This file contains implementations of SkPixmap methods which require the CPU backend.
8 */
9
10 #include "include/core/SkAlphaType.h"
11 #include "include/core/SkBitmap.h"
12 #include "include/core/SkBlendMode.h"
13 #include "include/core/SkCanvas.h"
14 #include "include/core/SkColor.h"
15 #include "include/core/SkImageInfo.h"
16 #include "include/core/SkMatrix.h"
17 #include "include/core/SkPaint.h"
18 #include "include/core/SkPixmap.h"
19 #include "include/core/SkRect.h"
20 #include "include/core/SkRefCnt.h"
21 #include "include/core/SkShader.h"
22 #include "include/core/SkSurface.h"
23 #include "include/core/SkTileMode.h"
24 #include "src/core/SkDraw.h"
25 #include "src/core/SkMatrixProvider.h"
26 #include "src/core/SkRasterClip.h"
27 #include "src/shaders/SkImageShader.h"
28
29 #include <utility>
30
31 class SkColorSpace;
32 struct SkSamplingOptions;
33
erase(SkColor color,const SkIRect & subset) const34 bool SkPixmap::erase(SkColor color, const SkIRect& subset) const {
35 return this->erase(SkColor4f::FromColor(color), &subset);
36 }
37
erase(const SkColor4f & color,SkColorSpace * cs,const SkIRect * subset) const38 bool SkPixmap::erase(const SkColor4f& color, SkColorSpace* cs, const SkIRect* subset) const {
39 SkPaint paint;
40 paint.setBlendMode(SkBlendMode::kSrc);
41 paint.setColor4f(color, cs);
42
43 SkIRect clip = this->bounds();
44 if (subset && !clip.intersect(*subset)) {
45 return false;
46 }
47 SkRasterClip rc{clip};
48
49 SkDraw draw;
50 SkMatrixProvider matrixProvider(SkMatrix::I());
51 draw.fDst = *this;
52 draw.fMatrixProvider = &matrixProvider;
53 draw.fRC = &rc;
54
55 draw.drawPaint(paint);
56 return true;
57 }
58
scalePixels(const SkPixmap & actualDst,const SkSamplingOptions & sampling) const59 bool SkPixmap::scalePixels(const SkPixmap& actualDst, const SkSamplingOptions& sampling) const {
60 // We may need to tweak how we interpret these just a little below, so we make copies.
61 SkPixmap src = *this,
62 dst = actualDst;
63
64 // Can't do anthing with empty src or dst
65 if (src.width() <= 0 || src.height() <= 0 ||
66 dst.width() <= 0 || dst.height() <= 0) {
67 return false;
68 }
69
70 // no scaling involved?
71 if (src.width() == dst.width() && src.height() == dst.height()) {
72 return src.readPixels(dst);
73 }
74
75 // If src and dst are both unpremul, we'll fake the source out to appear as if premul,
76 // and mark the destination as opaque. This odd combination allows us to scale unpremul
77 // pixels without ever premultiplying them (perhaps losing information in the color channels).
78 // This is an idiosyncratic feature of scalePixels(), and is tested by scalepixels_unpremul GM.
79 bool clampAsIfUnpremul = false;
80 if (src.alphaType() == kUnpremul_SkAlphaType &&
81 dst.alphaType() == kUnpremul_SkAlphaType) {
82 src.reset(src.info().makeAlphaType(kPremul_SkAlphaType), src.addr(), src.rowBytes());
83 dst.reset(dst.info().makeAlphaType(kOpaque_SkAlphaType), dst.addr(), dst.rowBytes());
84
85 // We'll need to tell the image shader to clamp to [0,1] instead of the
86 // usual [0,a] when using a bicubic scaling (kHigh_SkFilterQuality).
87 clampAsIfUnpremul = true;
88 }
89
90 SkBitmap bitmap;
91 if (!bitmap.installPixels(src)) {
92 return false;
93 }
94 bitmap.setImmutable(); // Don't copy when we create an image.
95
96 SkMatrix scale = SkMatrix::RectToRect(SkRect::Make(src.bounds()), SkRect::Make(dst.bounds()));
97
98 sk_sp<SkShader> shader = SkImageShader::Make(bitmap.asImage(),
99 SkTileMode::kClamp,
100 SkTileMode::kClamp,
101 sampling,
102 &scale,
103 clampAsIfUnpremul);
104
105 sk_sp<SkSurface> surface = SkSurface::MakeRasterDirect(dst.info(),
106 dst.writable_addr(),
107 dst.rowBytes());
108 if (!shader || !surface) {
109 return false;
110 }
111
112 SkPaint paint;
113 paint.setBlendMode(SkBlendMode::kSrc);
114 paint.setShader(std::move(shader));
115 surface->getCanvas()->drawPaint(paint);
116 return true;
117 }
118