Update rive-cpp to 2.0 version
[platform/core/uifw/rive-tizen.git] / submodule / skia / src / image / SkRescaleAndReadPixels.cpp
1 /*
2  * Copyright 2020 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 "include/core/SkBitmap.h"
9 #include "include/core/SkCanvas.h"
10 #include "include/core/SkColorSpace.h"
11 #include "include/core/SkImageInfo.h"
12 #include "include/core/SkPaint.h"
13 #include "include/core/SkRect.h"
14 #include "include/core/SkSurface.h"
15
16 #include <cmath>
17
18 void SkRescaleAndReadPixels(SkBitmap bmp,
19                             const SkImageInfo& resultInfo,
20                             const SkIRect& srcRect,
21                             SkImage::RescaleGamma rescaleGamma,
22                             SkImage::RescaleMode rescaleMode,
23                             SkImage::ReadPixelsCallback callback,
24                             SkImage::ReadPixelsContext context) {
25     int srcW = srcRect.width();
26     int srcH = srcRect.height();
27
28     float sx = (float)resultInfo.width() / srcW;
29     float sy = (float)resultInfo.height() / srcH;
30     // How many bilerp/bicubic steps to do in X and Y. + means upscaling, - means downscaling.
31     int stepsX;
32     int stepsY;
33     if (rescaleMode != SkImage::RescaleMode::kNearest) {
34         stepsX = static_cast<int>((sx > 1.f) ? std::ceil(std::log2f(sx))
35                                              : std::floor(std::log2f(sx)));
36         stepsY = static_cast<int>((sy > 1.f) ? std::ceil(std::log2f(sy))
37                                              : std::floor(std::log2f(sy)));
38     } else {
39         stepsX = sx != 1.f;
40         stepsY = sy != 1.f;
41     }
42
43     SkPaint paint;
44     paint.setBlendMode(SkBlendMode::kSrc);
45     if (stepsX < 0 || stepsY < 0) {
46         // Don't trigger MIP generation. We don't currently have a way to trigger bicubic for
47         // downscaling draws.
48
49         // TODO: should we trigger cubic now that we can?
50         if (rescaleMode != SkImage::RescaleMode::kNearest) {
51             rescaleMode = SkImage::RescaleMode::kRepeatedLinear;
52         }
53     }
54
55     auto rescaling_to_sampling = [](SkImage::RescaleMode rescaleMode) {
56         SkSamplingOptions sampling;
57         if (rescaleMode == SkImage::RescaleMode::kRepeatedLinear) {
58             sampling = SkSamplingOptions(SkFilterMode::kLinear);
59         } else if (rescaleMode == SkImage::RescaleMode::kRepeatedCubic) {
60             sampling = SkSamplingOptions({1.0f/3, 1.0f/3});
61         }
62         return sampling;
63     };
64     SkSamplingOptions sampling = rescaling_to_sampling(rescaleMode);
65
66     sk_sp<SkSurface> tempSurf;
67     sk_sp<SkImage> srcImage;
68     int srcX = srcRect.fLeft;
69     int srcY = srcRect.fTop;
70     SkCanvas::SrcRectConstraint constraint = SkCanvas::kStrict_SrcRectConstraint;
71     // Assume we should ignore the rescale linear request if the surface has no color space since
72     // it's unclear how we'd linearize from an unknown color space.
73     if (rescaleGamma == SkSurface::RescaleGamma::kLinear && bmp.info().colorSpace() &&
74         !bmp.info().colorSpace()->gammaIsLinear()) {
75         auto cs = bmp.info().colorSpace()->makeLinearGamma();
76         // Promote to F16 color type to preserve precision.
77         auto ii = SkImageInfo::Make(srcW, srcH, kRGBA_F16_SkColorType, bmp.info().alphaType(),
78                                     std::move(cs));
79         auto linearSurf = SkSurface::MakeRaster(ii);
80         if (!linearSurf) {
81             callback(context, nullptr);
82             return;
83         }
84         linearSurf->getCanvas()->drawImage(bmp.asImage().get(), -srcX, -srcY, sampling, &paint);
85         tempSurf = std::move(linearSurf);
86         srcImage = tempSurf->makeImageSnapshot();
87         srcX = 0;
88         srcY = 0;
89         constraint = SkCanvas::kFast_SrcRectConstraint;
90     } else {
91         // MakeFromBitmap would trigger a copy if bmp is mutable.
92         srcImage = SkImage::MakeFromRaster(bmp.pixmap(), nullptr, nullptr);
93     }
94     while (stepsX || stepsY) {
95         int nextW = resultInfo.width();
96         int nextH = resultInfo.height();
97         if (stepsX < 0) {
98             nextW = resultInfo.width() << (-stepsX - 1);
99             stepsX++;
100         } else if (stepsX != 0) {
101             if (stepsX > 1) {
102                 nextW = srcW * 2;
103             }
104             --stepsX;
105         }
106         if (stepsY < 0) {
107             nextH = resultInfo.height() << (-stepsY - 1);
108             stepsY++;
109         } else if (stepsY != 0) {
110             if (stepsY > 1) {
111                 nextH = srcH * 2;
112             }
113             --stepsY;
114         }
115         auto ii = srcImage->imageInfo().makeWH(nextW, nextH);
116         if (!stepsX && !stepsY) {
117             // Might as well fold conversion to final info in the last step.
118             ii = resultInfo;
119         }
120         auto next = SkSurface::MakeRaster(ii);
121         if (!next) {
122             callback(context, nullptr);
123             return;
124         }
125         next->getCanvas()->drawImageRect(
126                 srcImage.get(), SkRect::Make(SkIRect::MakeXYWH(srcX, srcY, srcW, srcH)),
127                 SkRect::MakeIWH(nextW, nextH), sampling, &paint, constraint);
128         tempSurf = std::move(next);
129         srcImage = tempSurf->makeImageSnapshot();
130         srcX = srcY = 0;
131         srcW = nextW;
132         srcH = nextH;
133         constraint = SkCanvas::kFast_SrcRectConstraint;
134     }
135
136     size_t rowBytes = resultInfo.minRowBytes();
137     std::unique_ptr<char[]> data(new char[resultInfo.height() * rowBytes]);
138     SkPixmap pm(resultInfo, data.get(), rowBytes);
139     if (srcImage->readPixels(nullptr, pm, srcX, srcY)) {
140         class Result : public SkImage::AsyncReadResult {
141         public:
142             Result(std::unique_ptr<const char[]> data, size_t rowBytes)
143                     : fData(std::move(data)), fRowBytes(rowBytes) {}
144             int count() const override { return 1; }
145             const void* data(int i) const override { return fData.get(); }
146             size_t rowBytes(int i) const override { return fRowBytes; }
147
148         private:
149             std::unique_ptr<const char[]> fData;
150             size_t fRowBytes;
151         };
152         callback(context, std::make_unique<Result>(std::move(data), rowBytes));
153     } else {
154         callback(context, nullptr);
155     }
156 }