1 /*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "core/components_ng/pattern/canvas/offscreen_canvas_paint_method.h"
17
18 #ifndef ACE_UNITTEST
19 #ifdef USE_NEW_SKIA
20 #include "src/base/SkBase64.h"
21 #else
22 #include "include/utils/SkBase64.h"
23 #endif
24 #include "core/components/common/painter/rosen_decoration_painter.h"
25 #include "core/components/font/constants_converter.h"
26 #include "core/components/font/rosen_font_collection.h"
27 #endif
28
29 #include "base/i18n/localization.h"
30 #include "core/common/container.h"
31 #include "core/components_ng/pattern/canvas/custom_paint_util.h"
32
33 namespace OHOS::Ace::NG {
34 constexpr Dimension DEFAULT_FONT_SIZE = 14.0_px;
OffscreenCanvasPaintMethod(int32_t width,int32_t height)35 OffscreenCanvasPaintMethod::OffscreenCanvasPaintMethod(int32_t width, int32_t height)
36 {
37 antiAlias_ = false;
38 matrix_.Reset();
39 width_ = width;
40 height_ = height;
41 lastLayoutSize_.SetWidth(static_cast<float>(width));
42 lastLayoutSize_.SetHeight(static_cast<float>(height));
43 InitBitmap();
44 // The default value of the font size in canvas is 14px.
45 SetFontSize(DEFAULT_FONT_SIZE);
46 if (apiVersion_ >= static_cast<int32_t>(PlatformVersion::VERSION_EIGHTEEN)) {
47 isPathChanged_ = false;
48 isPath2dChanged_ = false;
49 }
50 }
51
InitBitmap()52 void OffscreenCanvasPaintMethod::InitBitmap()
53 {
54 RSBitmapFormat bitmapFormat = { RSColorType::COLORTYPE_RGBA_8888, RSAlphaType::ALPHATYPE_UNPREMUL };
55 bool ret = bitmap_.Build(width_, height_, bitmapFormat);
56 if (!ret) {
57 TAG_LOGE(AceLogTag::ACE_CANVAS, "The width and height exceed the limit size.");
58 return;
59 }
60 bitmap_.ClearWithColor(RSColor::COLOR_TRANSPARENT);
61 bitmapSize_ = bitmap_.ComputeByteSize();
62 rsCanvas_ = std::make_unique<RSCanvas>();
63 rsCanvas_->Bind(bitmap_);
64 }
65
TransferToImageBitmap()66 RefPtr<PixelMap> OffscreenCanvasPaintMethod::TransferToImageBitmap()
67 {
68 #ifdef PIXEL_MAP_SUPPORTED
69 OHOS::Media::InitializationOptions options;
70 options.alphaType = OHOS::Media::AlphaType::IMAGE_ALPHA_TYPE_PREMUL;
71 options.pixelFormat = OHOS::Media::PixelFormat::RGBA_8888;
72 options.scaleMode = OHOS::Media::ScaleMode::CENTER_CROP;
73 options.size.width = width_;
74 options.size.height = height_;
75 options.editable = true;
76 auto pixelMap = Ace::PixelMap::Create(OHOS::Media::PixelMap::Create(options));
77 CHECK_NULL_RETURN(pixelMap, nullptr);
78 std::shared_ptr<Ace::ImageData> imageData = std::make_shared<Ace::ImageData>();
79 imageData->pixelMap = pixelMap;
80 imageData->dirtyX = 0.0f;
81 imageData->dirtyY = 0.0f;
82 imageData->dirtyWidth = width_;
83 imageData->dirtyHeight = height_;
84 GetImageData(imageData);
85 return pixelMap;
86 #else
87 return nullptr;
88 #endif
89 }
90
Reset()91 void OffscreenCanvasPaintMethod::Reset()
92 {
93 matrix_.Reset();
94 ResetStates();
95 InitBitmap();
96 }
97
GetSystemDirection()98 TextDirection OffscreenCanvasPaintMethod::GetSystemDirection()
99 {
100 return AceApplicationInfo::GetInstance().IsRightToLeft() ? TextDirection::RTL : TextDirection::LTR;
101 }
102
UpdateSize(int32_t width,int32_t height)103 void OffscreenCanvasPaintMethod::UpdateSize(int32_t width, int32_t height)
104 {
105 width_ = width;
106 height_ = height;
107 lastLayoutSize_.SetWidth(static_cast<float>(width));
108 lastLayoutSize_.SetHeight(static_cast<float>(height));
109 Reset();
110 }
111
DrawPixelMap(RefPtr<PixelMap> pixelMap,const Ace::CanvasImage & canvasImage)112 void OffscreenCanvasPaintMethod::DrawPixelMap(RefPtr<PixelMap> pixelMap, const Ace::CanvasImage& canvasImage)
113 {
114 #ifndef ACE_UNITTEST
115 // get Image form pixelMap
116 CHECK_NULL_VOID(pixelMap);
117 auto rsBitmapFormat = Ace::ImageProvider::MakeRSBitmapFormatFromPixelMap(pixelMap);
118 auto rsBitmap = std::make_shared<RSBitmap>();
119 bool ret = rsBitmap->Build(pixelMap->GetWidth(), pixelMap->GetHeight(), rsBitmapFormat, pixelMap->GetRowStride());
120 if (!ret) {
121 TAG_LOGE(AceLogTag::ACE_CANVAS, "The width and height exceed the limit size.");
122 return;
123 }
124 rsBitmap->SetPixels(const_cast<void*>(reinterpret_cast<const void*>(pixelMap->GetPixels())));
125
126 // Step2: Create Image and draw it, using gpu or cpu
127 auto image = std::make_shared<RSImage>();
128 CHECK_NULL_VOID(image->BuildFromBitmap(*rsBitmap));
129 DrawImageInternal(canvasImage, image);
130 #endif
131 }
132
GetImageData(double left,double top,double width,double height)133 std::unique_ptr<Ace::ImageData> OffscreenCanvasPaintMethod::GetImageData(
134 double left, double top, double width, double height)
135 {
136 double dirtyWidth = std::abs(width);
137 double dirtyHeight = std::abs(height);
138 double scaledLeft = left + std::min(width, 0.0);
139 double scaledTop = top + std::min(height, 0.0);
140 // copy the bitmap to tempCanvas
141 RSBitmapFormat format { RSColorType::COLORTYPE_BGRA_8888, RSAlphaType::ALPHATYPE_PREMUL };
142 int32_t size = dirtyWidth * dirtyHeight;
143 auto srcRect =
144 RSRect(scaledLeft, scaledTop, dirtyWidth + scaledLeft, dirtyHeight + scaledTop);
145 auto dstRect = RSRect(0.0, 0.0, dirtyWidth, dirtyHeight);
146 RSBitmap tempCache;
147 tempCache.Build(dirtyWidth, dirtyHeight, format);
148 RSCanvas tempCanvas;
149 tempCanvas.Bind(tempCache);
150 RSImage rsImage;
151 rsImage.BuildFromBitmap(bitmap_);
152 tempCanvas.DrawImageRect(
153 rsImage, srcRect, dstRect, RSSamplingOptions(), RSSrcRectConstraint::FAST_SRC_RECT_CONSTRAINT);
154 // write color
155 uint8_t* pixels = static_cast<uint8_t*>(tempCache.GetPixels());
156 std::unique_ptr<Ace::ImageData> imageData = std::make_unique<Ace::ImageData>();
157 imageData->dirtyWidth = dirtyWidth;
158 imageData->dirtyHeight = dirtyHeight;
159 // a pixel include 4 data blue, green, red, alpha
160 for (int i = 0; i < size * 4; i += 4) {
161 auto blue = pixels[i];
162 auto green = pixels[i + 1];
163 auto red = pixels[i + 2];
164 auto alpha = pixels[i + 3];
165 imageData->data.emplace_back(Color::FromARGB(alpha, red, green, blue).GetValue());
166 }
167 return imageData;
168 }
169
GetImageData(const std::shared_ptr<Ace::ImageData> & imageData)170 void OffscreenCanvasPaintMethod::GetImageData(const std::shared_ptr<Ace::ImageData>& imageData)
171 {
172 int32_t dirtyWidth = std::abs(imageData->dirtyWidth);
173 int32_t dirtyHeight = std::abs(imageData->dirtyHeight);
174 double scaledLeft = imageData->dirtyX + std::min(imageData->dirtyWidth, 0);
175 double scaledTop = imageData->dirtyY + std::min(imageData->dirtyHeight, 0);
176 double dx = std::min(scaledLeft, 0.0);
177 double dy = std::min(scaledTop, 0.0);
178 // copy the bitmap to tempCanvas
179 RSBitmap subBitmap;
180 auto rect = RSRect(scaledLeft, scaledTop, dirtyWidth + scaledLeft, dirtyHeight + scaledTop);
181 bool ret = bitmap_.ExtractSubset(subBitmap, rect);
182 if (!ret) {
183 return;
184 }
185 auto pixelMap = imageData->pixelMap;
186 CHECK_NULL_VOID(pixelMap);
187 auto* rawData = pixelMap->GetWritablePixels();
188 CHECK_NULL_VOID(rawData);
189 RSImageInfo imageInfo =
190 RSImageInfo(dirtyWidth, dirtyHeight, RSColorType::COLORTYPE_RGBA_8888, RSAlphaType::ALPHATYPE_PREMUL);
191 subBitmap.ReadPixels(imageInfo, rawData, dirtyWidth * imageInfo.GetBytesPerPixel(), dx, dy);
192 }
193
ToDataURL(const std::string & type,const double quality)194 std::string OffscreenCanvasPaintMethod::ToDataURL(const std::string& type, const double quality)
195 {
196 #ifndef ACE_UNITTEST
197 std::string mimeType = GetMimeType(type);
198 // Quality needs to be between 0.0 and 1.0 for MimeType jpeg and webp
199 double qua = GetQuality(mimeType, quality);
200 auto imageInfo = SkImageInfo::Make(width_, height_, SkColorType::kBGRA_8888_SkColorType,
201 (mimeType == IMAGE_JPEG) ? SkAlphaType::kOpaque_SkAlphaType : SkAlphaType::kUnpremul_SkAlphaType);
202 RSBitmap tempCache;
203 tempCache.Build(width_, height_,
204 { RSColorType::COLORTYPE_BGRA_8888,
205 (mimeType == IMAGE_JPEG) ? RSAlphaType::ALPHATYPE_OPAQUE : RSAlphaType::ALPHATYPE_UNPREMUL });
206 RSCanvas tempCanvas;
207 tempCanvas.Bind(tempCache);
208 tempCanvas.Clear(RSColor::COLOR_TRANSPARENT);
209 tempCanvas.Scale(1.0, 1.0);
210 tempCanvas.DrawBitmap(bitmap_, 0.0f, 0.0f);
211 RSPixmap rsSrc;
212 bool success = tempCache.PeekPixels(rsSrc);
213 CHECK_NULL_RETURN(success, UNSUPPORTED);
214 SkPixmap src { imageInfo, rsSrc.GetAddr(), rsSrc.GetRowBytes() };
215 SkDynamicMemoryWStream dst;
216 success = EncodeImage(mimeType, qua, src, dst);
217 CHECK_NULL_RETURN(success, UNSUPPORTED);
218 auto result = dst.detachAsData();
219 CHECK_NULL_RETURN(result, UNSUPPORTED);
220 size_t len = SkBase64::Encode(result->data(), result->size(), nullptr);
221 if (len > MAX_LENGTH) {
222 return UNSUPPORTED;
223 }
224 SkString info(len);
225 #ifdef USE_NEW_SKIA
226 SkBase64::Encode(result->data(), result->size(), info.data());
227 #else
228 SkBase64::Encode(result->data(), result->size(), info.writable_str());
229 #endif
230 return std::string(URL_PREFIX).append(mimeType).append(URL_SYMBOL).append(info.c_str());
231 #else
232 return UNSUPPORTED;
233 #endif
234 }
235
GetTransform() const236 TransformParam OffscreenCanvasPaintMethod::GetTransform() const
237 {
238 TransformParam param;
239 CHECK_NULL_RETURN(rsCanvas_, param);
240 RSMatrix matrix = rsCanvas_->GetTotalMatrix();
241 param.scaleX = matrix.Get(RSMatrix::SCALE_X);
242 param.scaleY = matrix.Get(RSMatrix::SCALE_Y);
243 param.skewX = matrix.Get(RSMatrix::SKEW_X);
244 param.skewY = matrix.Get(RSMatrix::SKEW_Y);
245 param.translateX = matrix.Get(RSMatrix::TRANS_X);
246 param.translateY = matrix.Get(RSMatrix::TRANS_Y);
247 return param;
248 }
249
GetLineDash() const250 LineDashParam OffscreenCanvasPaintMethod::GetLineDash() const
251 {
252 return state_.strokeState.GetLineDash();
253 }
254
255 #ifndef ACE_UNITTEST
ConvertTxtStyle(const TextStyle & textStyle,Rosen::TextStyle & txtStyle)256 void OffscreenCanvasPaintMethod::ConvertTxtStyle(const TextStyle& textStyle, Rosen::TextStyle& txtStyle)
257 {
258 Constants::ConvertTxtStyle(textStyle, txtStyle);
259 }
260 #endif
261 } // namespace OHOS::Ace::NG
262