• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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