1 /*
2 * Copyright (c) 2023 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 "pipeline/rs_canvas_drawing_render_node.h"
17
18 #include <memory>
19
20 #include "include/core/SkCanvas.h"
21 #include "src/image/SkImage_Base.h"
22 #ifdef NEW_SKIA
23 #include "include/gpu/GrBackendSurface.h"
24 #include "include/gpu/GrDirectContext.h"
25 #endif
26
27 #include "rs_trace.h"
28
29 #include "common/rs_background_thread.h"
30 #include "common/rs_common_def.h"
31 #include "common/rs_obj_abs_geometry.h"
32 #include "params/rs_canvas_drawing_render_params.h"
33 #include "pipeline/rs_context.h"
34 #include "pipeline/rs_paint_filter_canvas.h"
35 #include "pipeline/rs_recording_canvas.h"
36 #include "pipeline/rs_task_dispatcher.h"
37 #include "pipeline/sk_resource_manager.h"
38 #include "platform/common/rs_log.h"
39 #include "property/rs_properties_painter.h"
40 #include "visitor/rs_node_visitor.h"
41
42
43 namespace OHOS {
44 namespace Rosen {
45 static std::mutex drawingMutex_;
46 namespace {
47 constexpr uint32_t DRAWCMDLIST_COUNT_LIMIT = 50;
48 }
RSCanvasDrawingRenderNode(NodeId id,const std::weak_ptr<RSContext> & context,bool isTextureExportNode)49 RSCanvasDrawingRenderNode::RSCanvasDrawingRenderNode(
50 NodeId id, const std::weak_ptr<RSContext>& context, bool isTextureExportNode)
51 : RSCanvasRenderNode(id, context, isTextureExportNode)
52 {}
53
~RSCanvasDrawingRenderNode()54 RSCanvasDrawingRenderNode::~RSCanvasDrawingRenderNode()
55 {
56 #if (defined(RS_ENABLE_GL) || defined(RS_ENABLE_VK))
57 if (preThreadInfo_.second && surface_) {
58 preThreadInfo_.second(std::move(surface_));
59 }
60 #endif
61 }
62
InitRenderContent()63 void RSCanvasDrawingRenderNode::InitRenderContent()
64 {
65 drawingNodeRenderID = UNI_RENDER_THREAD_INDEX;
66 }
67
68 #if (defined(RS_ENABLE_GL) || defined(RS_ENABLE_VK))
ResetSurfaceWithTexture(int width,int height,RSPaintFilterCanvas & canvas)69 bool RSCanvasDrawingRenderNode::ResetSurfaceWithTexture(int width, int height, RSPaintFilterCanvas& canvas)
70 {
71 if (canvas_ == nullptr) {
72 RS_LOGE("canvas_ is nullptr");
73 return false;
74 }
75 auto preMatrix = canvas_->GetTotalMatrix();
76 auto preSurface = surface_;
77 if (!ResetSurface(width, height, canvas)) {
78 return false;
79 }
80 auto image = preSurface->GetImageSnapshot();
81 if (!image) {
82 return false;
83 }
84 Drawing::TextureOrigin origin = Drawing::TextureOrigin::BOTTOM_LEFT;
85 auto sharedBackendTexture = image->GetBackendTexture(false, &origin);
86 if (!sharedBackendTexture.IsValid()) {
87 RS_LOGE("RSCanvasDrawingRenderNode::ResetSurfaceWithTexture sharedBackendTexture is nullptr");
88 return false;
89 }
90
91 Drawing::BitmapFormat bitmapFormat = { image->GetColorType(), image->GetAlphaType() };
92 auto sharedTexture = std::make_shared<Drawing::Image>();
93 auto context = canvas.GetGPUContext();
94 if (!context || !sharedTexture->BuildFromTexture(*context, sharedBackendTexture.GetTextureInfo(),
95 origin, bitmapFormat, nullptr, SKResourceManager::DeleteSharedTextureContext,
96 new SharedTextureContext(image))) {
97 RS_LOGE("RSCanvasDrawingRenderNode::ResetSurfaceWithTexture sharedTexture is nullptr");
98 return false;
99 }
100 if (RSSystemProperties::GetRecordingEnabled()) {
101 if (sharedTexture->IsTextureBacked()) {
102 RS_LOGI("RSCanvasDrawingRenderNode::ResetSurfaceWithTexture sharedTexture from texture to raster image");
103 sharedTexture = sharedTexture->MakeRasterImage();
104 if (!sharedTexture) {
105 RS_LOGE("RSCanvasDrawingRenderNode::ResetSurfaceWithTexture: MakeRasterImage failed");
106 return false;
107 }
108 }
109 }
110 canvas_->DrawImage(*sharedTexture, 0.f, 0.f, Drawing::SamplingOptions());
111 if (preThreadInfo_.second && preSurface) {
112 preThreadInfo_.second(std::move(preSurface));
113 }
114 preThreadInfo_ = curThreadInfo_;
115 canvas_->SetMatrix(preMatrix);
116 canvas_->Flush();
117 return true;
118 }
119 #endif
120
ProcessRenderContents(RSPaintFilterCanvas & canvas)121 void RSCanvasDrawingRenderNode::ProcessRenderContents(RSPaintFilterCanvas& canvas)
122 {
123 int width = 0;
124 int height = 0;
125 std::lock_guard<std::mutex> lockTask(taskMutex_);
126 if (!GetSizeFromDrawCmdModifiers(width, height)) {
127 return;
128 }
129
130 if (IsNeedResetSurface()) {
131 #if defined(RS_ENABLE_GL) || defined(RS_ENABLE_VK)
132 if (preThreadInfo_.second && surface_) {
133 preThreadInfo_.second(std::move(surface_));
134 }
135 preThreadInfo_ = curThreadInfo_;
136 #endif
137 if (!ResetSurface(width, height, canvas)) {
138 return;
139 }
140 #if defined(RS_ENABLE_GL) || defined(RS_ENABLE_VK)
141 } else if ((isGpuSurface_) && (preThreadInfo_.first != curThreadInfo_.first)) {
142 if (!ResetSurfaceWithTexture(width, height, canvas)) {
143 return;
144 }
145 }
146 #else
147 }
148 #endif
149 if (!surface_) {
150 return;
151 }
152
153 RSModifierContext context = { GetMutableRenderProperties(), canvas_.get() };
154 ApplyDrawCmdModifier(context, RSModifierType::CONTENT_STYLE);
155 isNeedProcess_ = false;
156
157 Rosen::Drawing::Matrix mat;
158 if (RSPropertiesPainter::GetGravityMatrix(
159 GetRenderProperties().GetFrameGravity(), GetRenderProperties().GetFrameRect(), width, height, mat)) {
160 canvas.ConcatMatrix(mat);
161 }
162 if (!recordingCanvas_) {
163 image_ = surface_->GetImageSnapshot();
164 if (image_) {
165 SKResourceManager::Instance().HoldResource(image_);
166 }
167 } else {
168 auto cmds = recordingCanvas_->GetDrawCmdList();
169 if (cmds && !cmds->IsEmpty()) {
170 recordingCanvas_ = std::make_shared<ExtendRecordingCanvas>(width, height, false);
171 canvas_ = std::make_unique<RSPaintFilterCanvas>(recordingCanvas_.get());
172 }
173 }
174 std::lock_guard<std::mutex> lock(imageMutex_);
175 if (!image_) {
176 return;
177 }
178 auto samplingOptions = Drawing::SamplingOptions(Drawing::FilterMode::LINEAR, Drawing::MipmapMode::LINEAR);
179 Drawing::Paint paint;
180 paint.SetStyle(Drawing::Paint::PaintStyle::PAINT_FILL);
181 canvas.AttachPaint(paint);
182 if (canvas.GetRecordingState()) {
183 auto cpuImage = image_->MakeRasterImage();
184 if (!cpuImage) {
185 RS_LOGE("RSCanvasDrawingRenderNode::ProcessRenderContents: MakeRasterImage failed");
186 canvas.DetachPaint();
187 return;
188 }
189 canvas.DrawImage(*cpuImage, 0.f, 0.f, samplingOptions);
190 } else {
191 canvas.DrawImage(*image_, 0.f, 0.f, samplingOptions);
192 }
193 canvas.DetachPaint();
194 }
195
IsNeedProcess() const196 bool RSCanvasDrawingRenderNode::IsNeedProcess() const
197 {
198 if (!renderDrawable_ || !(renderDrawable_->GetRenderParams())) {
199 return false;
200 }
201 return renderDrawable_->GetRenderParams()->IsNeedProcess();
202 }
203
SetNeedProcess(bool needProcess)204 void RSCanvasDrawingRenderNode::SetNeedProcess(bool needProcess)
205 {
206 auto stagingCanvasDrawingParams = static_cast<RSCanvasDrawingRenderParams*>(stagingRenderParams_.get());
207 if (stagingCanvasDrawingParams) {
208 stagingCanvasDrawingParams->SetNeedProcess(needProcess);
209 if (stagingRenderParams_->NeedSync()) {
210 AddToPendingSyncList();
211 }
212 }
213 isNeedProcess_ = needProcess;
214 }
215
PlaybackInCorrespondThread()216 void RSCanvasDrawingRenderNode::PlaybackInCorrespondThread()
217 {
218 auto nodeId = GetId();
219 auto ctx = GetContext().lock();
220 if (ctx == nullptr) {
221 return;
222 }
223 auto task = [nodeId, ctx, this]() {
224 std::lock_guard<std::mutex> lockTask(taskMutex_);
225 auto node = ctx->GetNodeMap().GetRenderNode<RSCanvasDrawingRenderNode>(nodeId);
226 if (!node || !surface_ || !canvas_) {
227 return;
228 }
229 RSModifierContext context = { GetMutableRenderProperties(), canvas_.get() };
230 ApplyDrawCmdModifier(context, RSModifierType::CONTENT_STYLE);
231 isNeedProcess_ = false;
232 };
233 RSTaskDispatcher::GetInstance().PostTask(threadId_, task, false);
234 }
235
ResetSurface(int width,int height,RSPaintFilterCanvas & canvas)236 bool RSCanvasDrawingRenderNode::ResetSurface(int width, int height, RSPaintFilterCanvas& canvas)
237 {
238 Drawing::ImageInfo info =
239 Drawing::ImageInfo { width, height, Drawing::COLORTYPE_RGBA_8888, Drawing::ALPHATYPE_PREMUL };
240
241 #if (defined(RS_ENABLE_GL) || defined(RS_ENABLE_VK))
242 #if (defined(ROSEN_IOS))
243 surface_ = Drawing::Surface::MakeRaster(info);
244 #else
245 auto gpuContext = canvas.GetGPUContext();
246 isGpuSurface_ = true;
247 if (gpuContext == nullptr) {
248 RS_LOGW("RSCanvasDrawingRenderNode::ResetSurface: gpuContext is nullptr, imagesize:[%{public}d, %{public}d],"
249 "id: %{public}" PRIu64"", width, height, GetId());
250 isGpuSurface_ = false;
251 surface_ = Drawing::Surface::MakeRaster(info);
252 } else {
253 surface_ = Drawing::Surface::MakeRenderTarget(gpuContext.get(), false, info);
254 if (!surface_) {
255 isGpuSurface_ = false;
256 surface_ = Drawing::Surface::MakeRaster(info);
257 RS_LOGW("RSCanvasDrawingRenderNode::ResetSurface [%{public}d, %{public}d] %{public}" PRIu64 "",
258 width, height, GetId());
259 if (!surface_) {
260 RS_LOGE("RSCanvasDrawingRenderNode::ResetSurface surface is nullptr");
261 return false;
262 }
263 recordingCanvas_ = std::make_shared<ExtendRecordingCanvas>(width, height, false);
264 canvas_ = std::make_unique<RSPaintFilterCanvas>(recordingCanvas_.get());
265 return true;
266 }
267 }
268 #endif
269 #else
270 surface_ = Drawing::Surface::MakeRaster(info);
271 #endif
272 if (!surface_) {
273 RS_LOGE("RSCanvasDrawingRenderNode::ResetSurface surface is nullptr");
274 return false;
275 }
276 canvas_ = std::make_unique<RSPaintFilterCanvas>(surface_.get());
277 return true;
278 }
279
ApplyDrawCmdModifier(RSModifierContext & context,RSModifierType type)280 void RSCanvasDrawingRenderNode::ApplyDrawCmdModifier(RSModifierContext& context, RSModifierType type)
281 {
282 std::lock_guard<std::mutex> lock(drawCmdListsMutex_);
283 auto it = drawCmdLists_.find(type);
284 if (it == drawCmdLists_.end() || it->second.empty()) {
285 return;
286 }
287 for (const auto& drawCmdList : it->second) {
288 drawCmdList->Playback(*context.canvas_);
289 drawCmdList->ClearOp();
290 }
291 context.canvas_->Flush();
292 it->second.clear();
293 }
294
GetTid() const295 uint32_t RSCanvasDrawingRenderNode::GetTid() const
296 {
297 if (UNI_RENDER_THREAD_INDEX == drawingNodeRenderID) {
298 return drawingNodeRenderID;
299 }
300 return curThreadInfo_.first;
301 }
302
GetBitmap()303 Drawing::Bitmap RSCanvasDrawingRenderNode::GetBitmap()
304 {
305 return GetBitmap(UNI_MAIN_THREAD_INDEX);
306 }
307
WriteSkImageToPixelmap(std::shared_ptr<Drawing::Image> image,Drawing::ImageInfo info,std::shared_ptr<Media::PixelMap> pixelmap,const Drawing::Rect * rect)308 bool WriteSkImageToPixelmap(std::shared_ptr<Drawing::Image> image, Drawing::ImageInfo info,
309 std::shared_ptr<Media::PixelMap> pixelmap, const Drawing::Rect* rect)
310 {
311 return image->ReadPixels(
312 info, pixelmap->GetWritablePixels(), pixelmap->GetRowStride(), rect->GetLeft(), rect->GetTop());
313 }
314
GetImage(const uint64_t tid)315 std::shared_ptr<Drawing::Image> RSCanvasDrawingRenderNode::GetImage(const uint64_t tid)
316 {
317 if (GetTid() != tid) {
318 RS_LOGE("RSCanvasDrawingRenderNode::GetImage: image_ used by multi threads");
319 return nullptr;
320 }
321 if (!image_) {
322 RS_LOGE("RSCanvasDrawingRenderNode::GetImage: image_ is nullptr");
323 }
324 return image_;
325 }
326
GetBitmap(const uint64_t tid)327 Drawing::Bitmap RSCanvasDrawingRenderNode::GetBitmap(const uint64_t tid)
328 {
329 Drawing::Bitmap bitmap;
330 std::lock_guard<std::mutex> lock(drawingMutex_);
331 if (!image_) {
332 RS_LOGE("RSCanvasDrawingRenderNode::GetBitmap: image_ is nullptr");
333 return bitmap;
334 }
335 if (GetTid() != tid) {
336 RS_LOGE("RSCanvasDrawingRenderNode::GetBitmap: image_ used by multi threads");
337 return bitmap;
338 }
339 if (!image_->AsLegacyBitmap(bitmap)) {
340 RS_LOGE("RSCanvasDrawingRenderNode::GetBitmap: asLegacyBitmap failed");
341 }
342 return bitmap;
343 }
344
GetPixelmap(std::shared_ptr<Media::PixelMap> pixelmap,const Drawing::Rect * rect,const uint64_t tid,std::shared_ptr<Drawing::DrawCmdList> drawCmdList)345 bool RSCanvasDrawingRenderNode::GetPixelmap(std::shared_ptr<Media::PixelMap> pixelmap, const Drawing::Rect* rect,
346 const uint64_t tid, std::shared_ptr<Drawing::DrawCmdList> drawCmdList)
347 {
348 std::lock_guard<std::mutex> lock(drawingMutex_);
349 if (!pixelmap || !rect) {
350 RS_LOGE("RSCanvasDrawingRenderNode::GetPixelmap: pixelmap is nullptr");
351 return false;
352 }
353
354 if (!surface_) {
355 RS_LOGE("RSCanvasDrawingRenderNode::GetPixelmap: surface is nullptr");
356 return false;
357 }
358
359 auto image = surface_->GetImageSnapshot();
360 if (image == nullptr) {
361 RS_LOGE("RSCanvasDrawingRenderNode::GetPixelmap: GetImageSnapshot failed");
362 return false;
363 }
364
365 if (GetTid() != tid) {
366 RS_LOGE("RSCanvasDrawingRenderNode::GetPixelmap: surface used by multi threads");
367 return false;
368 }
369
370 Drawing::ImageInfo info = Drawing::ImageInfo { pixelmap->GetWidth(), pixelmap->GetHeight(),
371 Drawing::COLORTYPE_RGBA_8888, Drawing::ALPHATYPE_PREMUL };
372 if (!drawCmdList) {
373 if (!WriteSkImageToPixelmap(image, info, pixelmap, rect)) {
374 RS_LOGE("RSCanvasDrawingRenderNode::GetPixelmap: readPixels failed");
375 return false;
376 }
377 return true;
378 }
379 std::shared_ptr<Drawing::Surface> surface;
380 std::unique_ptr<RSPaintFilterCanvas> canvas;
381 #if (defined(RS_ENABLE_GL) || defined(RS_ENABLE_VK))
382 if (!canvas_) {
383 return false;
384 }
385 auto gpuContext = canvas_->GetGPUContext();
386 if (gpuContext == nullptr) {
387 if (!WriteSkImageToPixelmap(image, info, pixelmap, rect)) {
388 RS_LOGE("RSCanvasDrawingRenderNode::GetPixelmap: readPixels failed");
389 }
390 return false;
391 } else {
392 Drawing::ImageInfo newInfo = Drawing::ImageInfo{ image->GetWidth(), image->GetHeight(),
393 Drawing::COLORTYPE_RGBA_8888, Drawing::ALPHATYPE_PREMUL };
394 surface = Drawing::Surface::MakeRenderTarget(gpuContext.get(), false, newInfo);
395 if (!surface) {
396 if (!WriteSkImageToPixelmap(image, info, pixelmap, rect)) {
397 RS_LOGE("RSCanvasDrawingRenderNode::GetPixelmap: readPixels failed");
398 }
399 return false;
400 }
401 canvas = std::make_unique<RSPaintFilterCanvas>(surface.get());
402 }
403 #else
404 if (!WriteSkImageToPixelmap(image, info, pixelmap, rect)) {
405 RS_LOGE("RSCanvasDrawingRenderNode::GetPixelmap: readPixels failed");
406 }
407 return false;
408 #endif
409 canvas->DrawImage(*image, 0, 0, Drawing::SamplingOptions());
410 drawCmdList->Playback(*canvas, rect);
411 auto pixelmapImage = surface->GetImageSnapshot();
412 if (!pixelmapImage) {
413 return false;
414 }
415 if (!WriteSkImageToPixelmap(pixelmapImage, info, pixelmap, rect)) {
416 RS_LOGE("RSCanvasDrawingRenderNode::GetPixelmap: readPixels failed");
417 return false;
418 }
419 return true;
420 }
421
GetSizeFromDrawCmdModifiers(int & width,int & height)422 bool RSCanvasDrawingRenderNode::GetSizeFromDrawCmdModifiers(int& width, int& height)
423 {
424 auto it = GetDrawCmdModifiers().find(RSModifierType::CONTENT_STYLE);
425 if (it == GetDrawCmdModifiers().end() || it->second.empty()) {
426 return false;
427 }
428 for (const auto& modifier : it->second) {
429 auto prop = modifier->GetProperty();
430 if (auto cmd = std::static_pointer_cast<RSRenderProperty<Drawing::DrawCmdListPtr>>(prop)->Get()) {
431 width = std::max(width, cmd->GetWidth());
432 height = std::max(height, cmd->GetHeight());
433 }
434 }
435 if (width <= 0 || height <= 0) {
436 RS_LOGE("RSCanvasDrawingRenderNode::GetSizeFromDrawCmdModifiers: The width or height of the canvas is less "
437 "than or equal to 0");
438 return false;
439 }
440 return true;
441 }
442
IsNeedResetSurface() const443 bool RSCanvasDrawingRenderNode::IsNeedResetSurface() const
444 {
445 if (!surface_ || !surface_->GetCanvas()) {
446 return true;
447 }
448 return false;
449 }
450
InitRenderParams()451 void RSCanvasDrawingRenderNode::InitRenderParams()
452 {
453 stagingRenderParams_ = std::make_unique<RSCanvasDrawingRenderParams>(GetId());
454 DrawableV2::RSRenderNodeDrawableAdapter::OnGenerate(shared_from_this());
455 if (renderDrawable_ == nullptr) {
456 RS_LOGE("RSCanvasDrawingRenderNode::InitRenderParams failed");
457 return;
458 }
459 }
460
AddDirtyType(RSModifierType modifierType)461 void RSCanvasDrawingRenderNode::AddDirtyType(RSModifierType modifierType)
462 {
463 dirtyTypes_.set(static_cast<int>(modifierType), true);
464 std::lock_guard<std::mutex> lock(drawCmdListsMutex_);
465 for (auto& [type, list]: GetDrawCmdModifiers()) {
466 if (modifierType != type || list.empty()) {
467 continue;
468 }
469 for (const auto& modifier : list) {
470 if (modifier == nullptr) {
471 continue;
472 }
473 auto prop = modifier->GetProperty();
474 if (prop == nullptr) {
475 continue;
476 }
477 auto cmd = std::static_pointer_cast<RSRenderProperty<Drawing::DrawCmdListPtr>>(prop)->Get();
478 if (cmd == nullptr) {
479 continue;
480 }
481 //only content_style allowed multi-drawcmdlist, others modifier same as canvas_node
482 if (type != RSModifierType::CONTENT_STYLE) {
483 drawCmdLists_[type].clear();
484 }
485 drawCmdLists_[type].emplace_back(cmd);
486 SetNeedProcess(true);
487 }
488 bool overflow = drawCmdLists_[type].size() > DRAWCMDLIST_COUNT_LIMIT;
489 if (overflow && lastOverflowStatus_ != overflow) {
490 RS_LOGE("drawcmdlist overflow, This Node[%{public}" PRIu64 "] with Modifier[%{public}hd]"
491 " have drawcmdlist:%{public}zu", GetId(), type, drawCmdLists_[type].size());
492 }
493 lastOverflowStatus_ = overflow;
494 // If such nodes are not drawn, The drawcmdlists don't clearOp during recording, As a result, there are
495 // too many drawOp, so we need to add the limit of drawcmdlists.
496 while ((GetOldDirtyInSurface().IsEmpty() || !IsDirty() || renderDrawable_) &&
497 drawCmdLists_[type].size() > DRAWCMDLIST_COUNT_LIMIT) {
498 RS_LOGD("This Node[%{public}" PRIu64 "] with Modifier[%{public}hd] have drawcmdlist:%{public}zu", GetId(),
499 type, drawCmdLists_[type].size());
500 drawCmdLists_[type].pop_front();
501 }
502 }
503 }
504
ClearOp()505 void RSCanvasDrawingRenderNode::ClearOp()
506 {
507 std::lock_guard<std::mutex> lock(drawCmdListsMutex_);
508 drawCmdLists_.clear();
509 }
510
ResetSurface(int width,int height)511 void RSCanvasDrawingRenderNode::ResetSurface(int width, int height)
512 {
513 std::lock_guard<std::mutex> lockTask(taskMutex_);
514 if (preThreadInfo_.second && surface_) {
515 preThreadInfo_.second(std::move(surface_));
516 }
517 surface_ = nullptr;
518 recordingCanvas_ = nullptr;
519 stagingRenderParams_->SetCanvasDrawingSurfaceChanged(true);
520 stagingRenderParams_->SetCanvasDrawingSurfaceParams(width, height);
521 }
522
GetDrawCmdLists() const523 const std::map<RSModifierType, std::list<Drawing::DrawCmdListPtr>>& RSCanvasDrawingRenderNode::GetDrawCmdLists() const
524 {
525 return drawCmdLists_;
526 }
527
ClearResource()528 void RSCanvasDrawingRenderNode::ClearResource()
529 {
530 if (renderDrawable_ && renderDrawable_->IsDrawCmdListsVisited()) {
531 std::lock_guard<std::mutex> lock(drawCmdListsMutex_);
532 drawCmdLists_.clear();
533 renderDrawable_->SetDrawCmdListsVisited(false);
534 }
535 }
536
537 } // namespace Rosen
538 } // namespace OHOS