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/canvas_paint_method.h"
17
18 #include "base/log/ace_trace.h"
19 #include "core/components_ng/pattern/canvas/custom_paint_util.h"
20
21 #ifndef ACE_UNITTEST
22 #include "include/utils/SkBase64.h"
23 #include "core/components/common/painter/rosen_decoration_painter.h"
24 #include "core/components/font/constants_converter.h"
25 #include "core/components/font/rosen_font_collection.h"
26 #include "core/components_ng/render/adapter/rosen_render_context.h"
27 #include "core/image/sk_image_cache.h"
28 #endif
29
30 #include "base/i18n/localization.h"
31 #include "base/image/pixel_map.h"
32 #include "base/utils/utils.h"
33 #include "core/common/container.h"
34 #include "core/components_ng/image_provider/image_object.h"
35 #include "core/components_ng/pattern/canvas/canvas_paint_op.h"
36 #include "core/components_ng/render/drawing.h"
37
38 namespace OHOS::Ace::NG {
39 constexpr Dimension DEFAULT_FONT_SIZE = 14.0_px;
CanvasPaintMethod(RefPtr<CanvasModifier> contentModifier,const RefPtr<FrameNode> & frameNode)40 CanvasPaintMethod::CanvasPaintMethod(RefPtr<CanvasModifier> contentModifier, const RefPtr<FrameNode>& frameNode)
41 : frameNode_(frameNode)
42 {
43 matrix_.Reset();
44 context_ = frameNode ? frameNode->GetContextRefPtr() : nullptr;
45 imageShadow_ = std::make_unique<Shadow>();
46 contentModifier_ = contentModifier;
47 // The initial value of the font size in canvas is 14px.
48 SetFontSize(DEFAULT_FONT_SIZE);
49 }
50
51 #ifndef USE_FAST_TASKPOOL
PushTask(const TaskFunc & task)52 void CanvasPaintMethod::PushTask(const TaskFunc& task)
53 {
54 static constexpr uint32_t suggestSize = 100000;
55 tasks_.emplace_back(task);
56 if (tasks_.size() >= suggestSize && tasks_.size() % suggestSize == 0) {
57 TAG_LOGI(AceLogTag::ACE_CANVAS, "[%{public}s] Canvas task size: %{public}zu", customNodeName_.c_str(),
58 tasks_.size());
59 }
60 CHECK_EQUAL_VOID(needMarkDirty_, false);
61 needMarkDirty_ = false;
62 auto host = frameNode_.Upgrade();
63 CHECK_NULL_VOID(host);
64 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
65 }
66 #endif
67
HasTask() const68 bool CanvasPaintMethod::HasTask() const
69 {
70 #ifndef USE_FAST_TASKPOOL
71 return !tasks_.empty();
72 #else
73 return fastTaskPool_ && !fastTaskPool_->Empty();
74 #endif
75 }
76
FlushTask()77 void CanvasPaintMethod::FlushTask()
78 {
79 #ifndef USE_FAST_TASKPOOL
80 ACE_SCOPED_TRACE("Canvas tasks count: %zu.", tasks_.size());
81 for (auto& task : tasks_) {
82 task(*this);
83 }
84 tasks_.clear();
85 #else
86 CHECK_NULL_VOID(fastTaskPool_);
87 fastTaskPool_->Draw(this);
88 fastTaskPool_->Reset();
89 #endif
90 needMarkDirty_ = true;
91 }
92
UpdateContentModifier(PaintWrapper * paintWrapper)93 void CanvasPaintMethod::UpdateContentModifier(PaintWrapper* paintWrapper)
94 {
95 ACE_SCOPED_TRACE("CanvasPaintMethod::UpdateContentModifier");
96 auto host = frameNode_.Upgrade();
97 CHECK_NULL_VOID(host);
98 auto geometryNode = host->GetGeometryNode();
99 CHECK_NULL_VOID(geometryNode);
100 auto pixelGridRoundSize = geometryNode->GetPixelGridRoundSize();
101 lastLayoutSize_.SetSizeT(pixelGridRoundSize);
102 auto recordingCanvas = std::static_pointer_cast<RSRecordingCanvas>(rsCanvas_);
103 CHECK_NULL_VOID(recordingCanvas);
104 auto context = context_.Upgrade();
105 CHECK_NULL_VOID(context);
106 auto fontManager = context->GetFontManager();
107 if (fontManager) {
108 recordingCanvas->SetIsCustomTextType(fontManager->IsDefaultFontChanged());
109 }
110
111 if (!HasTask()) {
112 return;
113 }
114
115 FireOnModifierUpdateFunc();
116 recordingCanvas->Scale(1.0, 1.0);
117 FlushTask();
118 CHECK_NULL_VOID(contentModifier_);
119 contentModifier_->MarkModifierDirty();
120 }
121
UpdateRecordingCanvas(float width,float height)122 void CanvasPaintMethod::UpdateRecordingCanvas(float width, float height)
123 {
124 rsCanvas_ = std::make_shared<RSRecordingCanvas>(width, height);
125 contentModifier_->UpdateCanvas(std::static_pointer_cast<RSRecordingCanvas>(rsCanvas_));
126 CHECK_NULL_VOID(rsCanvas_);
127 rsCanvas_->Save();
128 FireRSCanvasCallback(width, height);
129 if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_THIRTEEN)) {
130 ResetStates();
131 }
132 needMarkDirty_ = true;
133 }
134
DrawPixelMap(RefPtr<PixelMap> pixelMap,const Ace::CanvasImage & canvasImage)135 void CanvasPaintMethod::DrawPixelMap(RefPtr<PixelMap> pixelMap, const Ace::CanvasImage& canvasImage)
136 {
137 #ifndef ACE_UNITTEST
138 InitImagePaint(nullptr, &imageBrush_, sampleOptions_);
139 imageBrush_.SetAntiAlias(antiAlias_);
140 RSBrush compositeOperationpBrush;
141 InitPaintBlend(compositeOperationpBrush);
142 RSSaveLayerOps layerOps(nullptr, &compositeOperationpBrush);
143 if (state_.globalState.GetType() != CompositeOperation::SOURCE_OVER) {
144 rsCanvas_->SaveLayer(layerOps);
145 }
146
147 if (state_.globalState.HasGlobalAlpha()) {
148 imageBrush_.SetAlphaF(state_.globalState.GetAlpha());
149 }
150
151 if (HasShadow()) {
152 RSRect rec = RSRect(
153 canvasImage.dx, canvasImage.dy, canvasImage.dx + canvasImage.dWidth, canvasImage.dy + canvasImage.dHeight);
154 RSPath path;
155 path.AddRect(rec);
156 PaintImageShadow(path, state_.shadow, &imageBrush_, nullptr,
157 (state_.globalState.GetType() != CompositeOperation::SOURCE_OVER) ? &layerOps : nullptr);
158 }
159 DrawPixelMapInternal(pixelMap, canvasImage);
160 if (state_.globalState.GetType() != CompositeOperation::SOURCE_OVER) {
161 rsCanvas_->Restore();
162 }
163 #endif
164 }
165
DrawPixelMapInternal(RefPtr<PixelMap> pixelMap,const Ace::CanvasImage & canvasImage)166 void CanvasPaintMethod::DrawPixelMapInternal(RefPtr<PixelMap> pixelMap, const Ace::CanvasImage& canvasImage)
167 {
168 #ifndef ACE_UNITTEST
169 const std::shared_ptr<Media::PixelMap> tempPixelMap = pixelMap->GetPixelMapSharedPtr();
170 CHECK_NULL_VOID(tempPixelMap);
171 RSRect srcRect;
172 RSRect dstRect;
173 switch (canvasImage.flag) {
174 case DrawImageType::THREE_PARAMS: {
175 srcRect = RSRect(0, 0, tempPixelMap->GetWidth(), tempPixelMap->GetHeight());
176 dstRect = RSRect(canvasImage.dx, canvasImage.dy, canvasImage.dx + tempPixelMap->GetWidth(),
177 canvasImage.dy + tempPixelMap->GetHeight());
178 break;
179 }
180 case DrawImageType::FIVE_PARAMS: {
181 srcRect = RSRect(0, 0, tempPixelMap->GetWidth(), tempPixelMap->GetHeight());
182 dstRect = RSRect(canvasImage.dx, canvasImage.dy, canvasImage.dx + canvasImage.dWidth,
183 canvasImage.dy + canvasImage.dHeight);
184 break;
185 }
186 case DrawImageType::NINE_PARAMS: {
187 srcRect = RSRect(canvasImage.sx, canvasImage.sy, canvasImage.sx + canvasImage.sWidth,
188 canvasImage.sy + canvasImage.sHeight);
189 dstRect = RSRect(canvasImage.dx, canvasImage.dy, canvasImage.dx + canvasImage.dWidth,
190 canvasImage.dy + canvasImage.dHeight);
191 break;
192 }
193 default:
194 break;
195 }
196 auto recordingCanvas = std::static_pointer_cast<RSRecordingCanvas>(rsCanvas_);
197 CHECK_NULL_VOID(recordingCanvas);
198 recordingCanvas->AttachBrush(imageBrush_);
199 recordingCanvas->DrawPixelMapRect(tempPixelMap, srcRect, dstRect, sampleOptions_);
200 recordingCanvas->DetachBrush();
201 #endif
202 }
203
CloseImageBitmap(const std::string & src)204 void CanvasPaintMethod::CloseImageBitmap(const std::string& src)
205 {
206 #ifndef ACE_UNITTEST
207 CHECK_NULL_VOID(imageCache_);
208 auto cacheImage = imageCache_->GetCacheImage(src);
209 CHECK_NULL_VOID(cacheImage);
210 CHECK_NULL_VOID(cacheImage->imagePtr);
211 imageCache_->ClearCacheImage(src);
212 #endif
213 }
214
GetImageData(double left,double top,double width,double height)215 std::unique_ptr<Ace::ImageData> CanvasPaintMethod::GetImageData(
216 double left, double top, double width, double height)
217 {
218 auto host = frameNode_.Upgrade();
219 CHECK_NULL_RETURN(host, nullptr);
220 auto renderContext = host->GetRenderContext();
221 CHECK_NULL_RETURN(renderContext, nullptr);
222 double dirtyWidth = std::abs(width);
223 double dirtyHeight = std::abs(height);
224 double scaledLeft = left + std::min(width, 0.0);
225 double scaledTop = top + std::min(height, 0.0);
226
227 // copy the bitmap to tempCanvas
228 RSBitmap currentBitmap;
229 if (!DrawBitmap(renderContext, currentBitmap)) {
230 return nullptr;
231 }
232
233 RSBitmapFormat format { RSColorType::COLORTYPE_BGRA_8888, RSAlphaType::ALPHATYPE_OPAQUE };
234 RSBitmap tempCache;
235 tempCache.Build(dirtyWidth, dirtyHeight, format);
236 int32_t size = dirtyWidth * dirtyHeight;
237
238 RSCanvas tempCanvas;
239 tempCanvas.Bind(tempCache);
240 auto srcRect = RSRect(scaledLeft, scaledTop, dirtyWidth + scaledLeft, dirtyHeight + scaledTop);
241 auto dstRect = RSRect(0.0, 0.0, dirtyWidth, dirtyHeight);
242 RSImage rsImage;
243 rsImage.BuildFromBitmap(currentBitmap);
244 tempCanvas.DrawImageRect(rsImage, srcRect, dstRect, RSSamplingOptions());
245 const uint8_t* pixels = static_cast<const uint8_t*>(tempCache.GetPixels());
246 CHECK_NULL_RETURN(pixels, nullptr);
247 std::unique_ptr<Ace::ImageData> imageData = std::make_unique<Ace::ImageData>();
248 imageData->dirtyWidth = dirtyWidth;
249 imageData->dirtyHeight = dirtyHeight;
250 // a pixel include 4 data(blue, green, red, alpha)
251 for (int i = 0; i < size * 4; i += 4) {
252 auto blue = pixels[i];
253 auto green = pixels[i + 1];
254 auto red = pixels[i + 2];
255 auto alpha = pixels[i + 3];
256 imageData->data.emplace_back(Color::FromARGB(alpha, red, green, blue).GetValue());
257 }
258 return imageData;
259 }
260
GetImageData(const std::shared_ptr<Ace::ImageData> & imageData)261 void CanvasPaintMethod::GetImageData(
262 const std::shared_ptr<Ace::ImageData>& imageData)
263 {
264 #ifndef ACE_UNITTEST
265 auto host = frameNode_.Upgrade();
266 CHECK_NULL_VOID(host);
267 auto renderContext = host->GetRenderContext();
268 auto rosenRenderContext = AceType::DynamicCast<RosenRenderContext>(renderContext);
269 CHECK_NULL_VOID(rosenRenderContext);
270 CHECK_NULL_VOID(imageData);
271 auto dirtyWidth = std::abs(imageData->dirtyWidth);
272 auto dirtyHeight = std::abs(imageData->dirtyHeight);
273 auto scaledLeft = imageData->dirtyX + std::min(imageData->dirtyWidth, 0);
274 auto scaledTop = imageData->dirtyY + std::min(imageData->dirtyHeight, 0);
275
276 auto recordingCanvas = std::static_pointer_cast<RSRecordingCanvas>(rsCanvas_);
277 CHECK_NULL_VOID(recordingCanvas);
278 auto drawCmdList = recordingCanvas->GetDrawCmdList();
279 auto rect = RSRect(scaledLeft, scaledTop, dirtyWidth + scaledLeft, dirtyHeight + scaledTop);
280 auto pixelMap = imageData->pixelMap;
281 CHECK_NULL_VOID(pixelMap);
282 auto sharedPixelMap = pixelMap->GetPixelMapSharedPtr();
283 auto ret = rosenRenderContext->GetPixelMap(sharedPixelMap, drawCmdList, &rect);
284 if (!ret) {
285 if (!drawCmdList || drawCmdList->IsEmpty()) {
286 return;
287 }
288 RSBitmap bitmap;
289 RSImageInfo info = RSImageInfo(rect.GetWidth(), rect.GetHeight(),
290 RSColorType::COLORTYPE_RGBA_8888, RSAlphaType::ALPHATYPE_PREMUL);
291 bitmap.InstallPixels(info, pixelMap->GetWritablePixels(), pixelMap->GetRowBytes());
292 RSCanvas canvas;
293 canvas.Bind(bitmap);
294 canvas.Translate(-rect.GetLeft(), -rect.GetTop());
295 drawCmdList->Playback(canvas, &rect);
296 }
297 #endif
298 }
299
300 #ifdef PIXEL_MAP_SUPPORTED
TransferFromImageBitmap(const RefPtr<PixelMap> & pixelMap)301 void CanvasPaintMethod::TransferFromImageBitmap(const RefPtr<PixelMap>& pixelMap)
302 {
303 CHECK_NULL_VOID(pixelMap);
304 InitImagePaint(nullptr, &imageBrush_, sampleOptions_);
305 auto recordingCanvas = std::static_pointer_cast<RSRecordingCanvas>(rsCanvas_);
306 CHECK_NULL_VOID(recordingCanvas);
307 const std::shared_ptr<Media::PixelMap> tempPixelMap = pixelMap->GetPixelMapSharedPtr();
308 CHECK_NULL_VOID(tempPixelMap);
309 RSRect srcRect = RSRect(0, 0, tempPixelMap->GetWidth(), tempPixelMap->GetHeight());
310 RSRect dstRect = RSRect(0, 0, tempPixelMap->GetWidth(), tempPixelMap->GetHeight());
311 recordingCanvas->AttachBrush(imageBrush_);
312 recordingCanvas->DrawPixelMapRect(tempPixelMap, srcRect, dstRect, sampleOptions_);
313 recordingCanvas->DetachBrush();
314 }
315 #endif
316
ToDataURL(const std::string & type,const double quality)317 std::string CanvasPaintMethod::ToDataURL(const std::string& type, const double quality)
318 {
319 #ifndef ACE_UNITTEST
320 auto host = frameNode_.Upgrade();
321 CHECK_NULL_RETURN(host, UNSUPPORTED);
322 auto renderContext = host->GetRenderContext();
323 CHECK_NULL_RETURN(renderContext, UNSUPPORTED);
324 std::string mimeType = GetMimeType(type);
325 // Quality needs to be between 0.0 and 1.0 for MimeType jpeg and webp
326 double qua = GetQuality(mimeType, quality);
327 double width = lastLayoutSize_.Width();
328 double height = lastLayoutSize_.Height();
329 auto imageInfo = SkImageInfo::Make(width, height, SkColorType::kBGRA_8888_SkColorType,
330 (mimeType == IMAGE_JPEG) ? SkAlphaType::kOpaque_SkAlphaType : SkAlphaType::kUnpremul_SkAlphaType);
331 RSBitmapFormat format { RSColorType::COLORTYPE_BGRA_8888,
332 (mimeType == IMAGE_JPEG) ? RSAlphaType::ALPHATYPE_OPAQUE : RSAlphaType::ALPHATYPE_UNPREMUL };
333 RSBitmap tempCache;
334 tempCache.Build(width, height, format);
335 RSBitmap currentBitmap;
336 if (!DrawBitmap(renderContext, currentBitmap)) {
337 return UNSUPPORTED;
338 }
339 bool success = currentBitmap.GetPixmap().ScalePixels(
340 tempCache.GetPixmap(), RSSamplingOptions(RSCubicResampler { 1 / 3.0f, 1 / 3.0f }));
341 CHECK_NULL_RETURN(success, UNSUPPORTED);
342 RSPixmap rsSrc = tempCache.GetPixmap();
343 SkPixmap src { imageInfo, rsSrc.GetAddr(), rsSrc.GetRowBytes() };
344 SkDynamicMemoryWStream dst;
345 success = EncodeImage(mimeType, qua, src, dst);
346 CHECK_NULL_RETURN(success, UNSUPPORTED);
347 auto result = dst.detachAsData();
348 CHECK_NULL_RETURN(result, UNSUPPORTED);
349 size_t len = SkBase64::Encode(result->data(), result->size(), nullptr);
350 if (len > MAX_LENGTH) {
351 return UNSUPPORTED;
352 }
353 SkString info(len);
354 SkBase64::Encode(result->data(), result->size(), info.writable_str());
355 return std::string(URL_PREFIX).append(mimeType).append(URL_SYMBOL).append(info.c_str());
356 #else
357 return UNSUPPORTED;
358 #endif
359 }
360
DrawBitmap(RefPtr<RenderContext> renderContext,RSBitmap & currentBitmap)361 bool CanvasPaintMethod::DrawBitmap(RefPtr<RenderContext> renderContext, RSBitmap& currentBitmap)
362 {
363 #ifndef ACE_UNITTEST
364 auto recordingCanvas = std::static_pointer_cast<RSRecordingCanvas>(rsCanvas_);
365 CHECK_NULL_RETURN(recordingCanvas, false);
366 auto rosenRenderContext = AceType::DynamicCast<RosenRenderContext>(renderContext);
367 CHECK_NULL_RETURN(rosenRenderContext, false);
368 auto drawCmdList = recordingCanvas->GetDrawCmdList();
369 CHECK_NULL_RETURN(drawCmdList, false);
370 bool res = rosenRenderContext->GetBitmap(currentBitmap, drawCmdList);
371 if (res) {
372 return true;
373 }
374 if (drawCmdList->IsEmpty()) {
375 return false;
376 }
377 currentBitmap.Free();
378 RSBitmapFormat format;
379 if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_FOURTEEN)) {
380 format = { RSColorType::COLORTYPE_BGRA_8888, RSAlphaType::ALPHATYPE_PREMUL };
381 } else {
382 format = { RSColorType::COLORTYPE_BGRA_8888, RSAlphaType::ALPHATYPE_OPAQUE };
383 }
384 currentBitmap.Build(lastLayoutSize_.Width(), lastLayoutSize_.Height(), format);
385
386 RSCanvas currentCanvas;
387 currentCanvas.Bind(currentBitmap);
388 drawCmdList->Playback(currentCanvas);
389 return true;
390 #else
391 return false;
392 #endif
393 }
394
GetJsonData(const std::string & path)395 std::string CanvasPaintMethod::GetJsonData(const std::string& path)
396 {
397 #ifndef ACE_UNITTEST
398 AssetImageLoader imageLoader;
399 return imageLoader.LoadJsonData(path, context_);
400 #else
401 return "";
402 #endif
403 }
404
Reset()405 void CanvasPaintMethod::Reset()
406 {
407 ResetStates();
408 CHECK_NULL_VOID(rsCanvas_);
409 if (rsCanvas_->GetSaveCount() >= DEFAULT_SAVE_COUNT) {
410 rsCanvas_->RestoreToCount(0);
411 }
412 rsCanvas_->ResetMatrix();
413 rsCanvas_->Clear(RSColor::COLOR_TRANSPARENT);
414 rsCanvas_->Save();
415 }
416 #ifndef ACE_UNITTEST
ConvertTxtStyle(const TextStyle & textStyle,Rosen::TextStyle & txtStyle)417 void CanvasPaintMethod::ConvertTxtStyle(const TextStyle& textStyle, Rosen::TextStyle& txtStyle)
418 {
419 Constants::ConvertTxtStyle(textStyle, context_, txtStyle);
420 }
421 #endif
422
GetDumpInfo()423 std::string CanvasPaintMethod::GetDumpInfo()
424 {
425 CHECK_NULL_RETURN(rsCanvas_, "Canvas is nullptr");
426 // translate
427 std::string trans = "TRANS: " + std::to_string(rsCanvas_->GetTotalMatrix().Get(RSMatrix::TRANS_X)) + ", " +
428 std::to_string(rsCanvas_->GetTotalMatrix().Get(RSMatrix::TRANS_Y)) + "; ";
429 // scale
430 std::string scale = "SCALE: " + std::to_string(rsCanvas_->GetTotalMatrix().Get(RSMatrix::SCALE_X)) + ", " +
431 std::to_string(rsCanvas_->GetTotalMatrix().Get(RSMatrix::SCALE_Y)) + "; ";
432 // rotate
433 std::string skew = "SKEW: " + std::to_string(rsCanvas_->GetTotalMatrix().Get(RSMatrix::SKEW_X)) + ", " +
434 std::to_string(rsCanvas_->GetTotalMatrix().Get(RSMatrix::SKEW_Y)) + "; ";
435 return trans.append(scale).append(skew);
436 }
437
SetHostCustomNodeName()438 void CanvasPaintMethod::SetHostCustomNodeName()
439 {
440 auto frameNode = frameNode_.Upgrade();
441 CHECK_NULL_VOID(frameNode);
442 auto customNode = frameNode->GetParentCustomNode();
443 CHECK_NULL_VOID(customNode);
444 customNodeName_ = customNode->GetJSViewName();
445 }
446
GetSimplifyDumpInfo(std::unique_ptr<JsonValue> & json)447 void CanvasPaintMethod::GetSimplifyDumpInfo(std::unique_ptr<JsonValue>& json)
448 {
449 CHECK_NULL_VOID(rsCanvas_);
450 auto matrix = rsCanvas_->GetTotalMatrix();
451 json->Put("Trans",
452 (std::to_string(matrix.Get(RSMatrix::TRANS_X)) + "," + std::to_string(matrix.Get(RSMatrix::TRANS_Y))).c_str());
453 json->Put("Scale",
454 (std::to_string(matrix.Get(RSMatrix::SCALE_X)) + "," + std::to_string(matrix.Get(RSMatrix::SCALE_Y))).c_str());
455 json->Put("Skew",
456 (std::to_string(matrix.Get(RSMatrix::SKEW_X)) + "," + std::to_string(matrix.Get(RSMatrix::SKEW_Y))).c_str());
457 }
458 } // namespace OHOS::Ace::NG
459