• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "core/components_ng/render/adapter/component_snapshot.h"
17 
18 #include "transaction/rs_interfaces.h"
19 #include "base/log/ace_trace.h"
20 #include "bridge/common/utils/utils.h"
21 #include "core/components_ng/base/inspector.h"
22 #include "core/components_ng/pattern/image/image_pattern.h"
23 #include "core/components_ng/pattern/stack/stack_pattern.h"
24 #include "core/components_ng/render/adapter/rosen_render_context.h"
25 
26 namespace OHOS::Ace::NG {
27 namespace {
28 
29 constexpr std::chrono::duration<int, std::milli> SNAPSHOT_TIMEOUT_DURATION(3000);
30 constexpr std::chrono::duration<int, std::milli> CREATE_SNAPSHOT_TIMEOUT_DURATION(80);
31 
32 class CustomizedCallback : public Rosen::SurfaceCaptureCallback {
33 public:
CustomizedCallback(ComponentSnapshot::JsCallback && jsCallback,WeakPtr<FrameNode> node)34     CustomizedCallback(ComponentSnapshot::JsCallback&& jsCallback, WeakPtr<FrameNode> node)
35         : callback_(std::move(jsCallback)), node_(std::move(node))
36     {}
37     ~CustomizedCallback() override = default;
OnSurfaceCapture(std::shared_ptr<Media::PixelMap> pixelMap)38     void OnSurfaceCapture(std::shared_ptr<Media::PixelMap> pixelMap) override
39     {
40         if (callback_ == nullptr) {
41             TAG_LOGW(AceLogTag::ACE_COMPONENT_SNAPSHOT, "Internal error! The callback_ is null");
42             auto node = node_.Upgrade();
43             CHECK_NULL_VOID(node);
44             Inspector::RemoveOffscreenNode(node);
45             return;
46         }
47         if (!pixelMap) {
48             TAG_LOGW(AceLogTag::ACE_COMPONENT_SNAPSHOT, "Internal error! The pixelmap returned by the system is null");
49             callback_(nullptr, ERROR_CODE_INTERNAL_ERROR, [node = node_]() {
50                 auto frameNode = node.Upgrade();
51                 CHECK_NULL_VOID(frameNode);
52                 Inspector::RemoveOffscreenNode(frameNode);
53             });
54         } else {
55             TAG_LOGI(AceLogTag::ACE_COMPONENT_SNAPSHOT,
56                 "ComponentSnapshot successful! pixelMap.width=%{public}d pixelMap.height=%{public}d",
57                 pixelMap->GetWidth(), pixelMap->GetHeight());
58             callback_(pixelMap, ERROR_CODE_NO_ERROR, [node = node_]() {
59                 auto frameNode = node.Upgrade();
60                 CHECK_NULL_VOID(frameNode);
61                 Inspector::RemoveOffscreenNode(frameNode);
62             });
63         }
64     }
65 
66 private:
67     ComponentSnapshot::JsCallback callback_;
68     WeakPtr<FrameNode> node_;
69 };
70 
71 class NormalCaptureCallback : public Rosen::SurfaceCaptureCallback {
72 public:
NormalCaptureCallback(ComponentSnapshot::NormalCallback && callback)73     explicit NormalCaptureCallback(ComponentSnapshot::NormalCallback&& callback) : callback_(std::move(callback)) {}
74     ~NormalCaptureCallback() override = default;
OnSurfaceCapture(std::shared_ptr<Media::PixelMap> pixelMap)75     void OnSurfaceCapture(std::shared_ptr<Media::PixelMap> pixelMap) override
76     {
77         CHECK_NULL_VOID(callback_);
78         callback_(pixelMap);
79     }
80 
81 private:
82     ComponentSnapshot::NormalCallback callback_;
83 };
84 
85 class SyncCustomizedCallback : public Rosen::SurfaceCaptureCallback {
86 public:
87     SyncCustomizedCallback() = default;
88     ~SyncCustomizedCallback() override = default;
OnSurfaceCapture(std::shared_ptr<Media::PixelMap> pixelMap)89     void OnSurfaceCapture(std::shared_ptr<Media::PixelMap> pixelMap) override
90     {
91         if (!pixelMap) {
92             TAG_LOGW(AceLogTag::ACE_COMPONENT_SNAPSHOT, "Internal error! The pixelmap returned by the system is null");
93             pixelMap_ = nullptr;
94         } else {
95             TAG_LOGI(AceLogTag::ACE_COMPONENT_SNAPSHOT,
96                 "ComponentSnapshot successful! pixelMap.width=%{public}d pixelMap.height=%{public}d",
97                 pixelMap->GetWidth(), pixelMap->GetHeight());
98             pixelMap_ = pixelMap;
99         }
100         std::unique_lock<std::mutex> lock(mutex_);
101         cv_.notify_all();
102     }
103 
GetPixelMap(std::chrono::duration<int,std::milli> timeout)104     std::pair<int32_t, std::shared_ptr<Media::PixelMap>> GetPixelMap(std::chrono::duration<int, std::milli> timeout)
105     {
106         std::pair<int32_t, std::shared_ptr<Media::PixelMap>> result(ERROR_CODE_INTERNAL_ERROR, nullptr);
107         std::unique_lock<std::mutex> lock(mutex_);
108         auto status = cv_.wait_for(lock, timeout);
109         if (status == std::cv_status::timeout) {
110             return { ERROR_CODE_COMPONENT_SNAPSHOT_TIMEOUT, nullptr };
111         }
112         if (pixelMap_) {
113             result = { ERROR_CODE_NO_ERROR, pixelMap_ };
114         }
115         return result;
116     }
117 
118 private:
119     mutable std::mutex mutex_;
120     std::condition_variable cv_;
121     std::shared_ptr<Media::PixelMap> pixelMap_;
122 };
123 } // namespace
124 
IsSnapshotRegionValid(LocalizedSnapshotRegion & snapshotRegion)125 bool IsSnapshotRegionValid(LocalizedSnapshotRegion& snapshotRegion)
126 {
127     if (snapshotRegion.start < 0 || snapshotRegion.end < 0 || snapshotRegion.top < 0 ||
128         snapshotRegion.bottom < 0) {
129         TAG_LOGW(AceLogTag::ACE_COMPONENT_SNAPSHOT, "Snapshot reigon is invalid.");
130         return false;
131     }
132     return true;
133 }
134 
IsSnapshotRegionInRange(LocalizedSnapshotRegion & snapshotRegion,float & nodeWidth,float & nodeHeight)135 bool IsSnapshotRegionInRange(LocalizedSnapshotRegion& snapshotRegion, float& nodeWidth, float& nodeHeight)
136 {
137     if (snapshotRegion.start > nodeWidth || snapshotRegion.end > nodeWidth || snapshotRegion.top > nodeHeight ||
138         snapshotRegion.bottom > nodeHeight) {
139         TAG_LOGW(AceLogTag::ACE_COMPONENT_SNAPSHOT, "Snapshot reigon out of range.");
140         return false;
141     }
142     return true;
143 }
144 
SetCaptureReigon(const RefPtr<FrameNode> & node,const SnapshotOptions & options,Rosen::Drawing::Rect & specifiedAreaRect)145 bool SetCaptureReigon(const RefPtr<FrameNode>& node, const SnapshotOptions& options,
146     Rosen::Drawing::Rect& specifiedAreaRect)
147 {
148     RectF nodeRect = node->GetGeometryNode()->GetFrameRect();
149     float nodeWidth = nodeRect.Width();
150     float nodeHeight = nodeRect.Height();
151     if (options.regionMode == NG::SnapshotRegionMode::NO_REGION) {
152         specifiedAreaRect = Rosen::Drawing::Rect(
153             0.0f,
154             0.0f,
155             nodeWidth,
156             nodeHeight);
157         return true;
158     }
159 
160     LocalizedSnapshotRegion snapshotRegion = options.snapshotRegion;
161     if (!IsSnapshotRegionValid(snapshotRegion) || !IsSnapshotRegionInRange(snapshotRegion, nodeWidth, nodeHeight)) {
162         return false;
163     }
164 
165     auto nodeLayoutProperty = node->GetLayoutProperty();
166     if (!nodeLayoutProperty) {
167         TAG_LOGW(AceLogTag::ACE_COMPONENT_SNAPSHOT, "Can't get the layout property of target node.");
168         return false;
169     }
170 
171     TextDirection layoutDirection = nodeLayoutProperty->GetLayoutDirection();
172     if (layoutDirection == TextDirection::AUTO || layoutDirection == TextDirection::INHERIT) {
173         layoutDirection = AceApplicationInfo::GetInstance().IsRightToLeft() ? TextDirection::RTL : TextDirection::LTR;
174     }
175     bool isRegionMirror = NG::SnapshotRegionMode::LOCALIZED && layoutDirection == TextDirection::RTL;
176 
177     specifiedAreaRect = Rosen::Drawing::Rect(
178         isRegionMirror ? nodeWidth - snapshotRegion.end : snapshotRegion.start,
179         snapshotRegion.top,
180         isRegionMirror ? nodeWidth - snapshotRegion.start : snapshotRegion.end,
181         snapshotRegion.bottom);
182     return true;
183 }
184 
ProcessImageNode(const RefPtr<UINode> & node)185 void ProcessImageNode(const RefPtr<UINode>& node)
186 {
187     if (node->GetTag() == V2::IMAGE_ETS_TAG) {
188         auto imageNode = AceType::DynamicCast<FrameNode>(node);
189         if (imageNode && AceType::DynamicCast<ImagePattern>(imageNode->GetPattern())) {
190             auto imagePattern = AceType::DynamicCast<ImagePattern>(imageNode->GetPattern());
191             imagePattern->SetIsComponentSnapshotNode();
192             imagePattern->OnVisibleAreaChange(true);
193         }
194     }
195     auto children = node->GetChildren();
196     for (const auto& child : children) {
197         ProcessImageNode(child);
198     }
199 }
200 
CheckImageSuccessfullyLoad(const RefPtr<UINode> & node,int32_t & imageCount)201 bool CheckImageSuccessfullyLoad(const RefPtr<UINode>& node, int32_t& imageCount)
202 {
203     CHECK_NULL_RETURN(node, false);
204     auto frameNode = AceType::DynamicCast<FrameNode>(node);
205     if (frameNode && !frameNode->IsVisible()) {
206         return true;
207     }
208     if (node->GetTag() == V2::IMAGE_ETS_TAG) {
209         imageCount++;
210         auto imageNode = AceType::DynamicCast<FrameNode>(node);
211         CHECK_NULL_RETURN(imageNode, false);
212         auto imagePattern = AceType::DynamicCast<ImagePattern>(imageNode->GetPattern());
213         CHECK_NULL_RETURN(imagePattern, false);
214         auto imageLoadContext = imagePattern->GetImageLoadingContext().Upgrade();
215         CHECK_NULL_RETURN(imageLoadContext, false);
216         auto imageStateManger = imageLoadContext->GetStateManger();
217         CHECK_NULL_RETURN(imageStateManger, false);
218 
219         auto result = imageStateManger->GetCurrentState() == ImageLoadingState::LOAD_SUCCESS;
220         if (!result) {
221             TAG_LOGW(AceLogTag::ACE_COMPONENT_SNAPSHOT,
222                 "Image loading failed! ImageId=%{public}d ImageState=%{public}d ImageKey=%{public}s",
223                 imageNode->GetId(), static_cast<int32_t>(imageStateManger->GetCurrentState()),
224                 imageNode->GetInspectorId().value_or("").c_str());
225         }
226         return result;
227     }
228 
229     auto children = node->GetChildren();
230     for (const auto& child : children) {
231         if (!CheckImageSuccessfullyLoad(child, imageCount)) {
232             return false;
233         }
234     }
235     return true;
236 }
237 
GetTaskExecutor(const RefPtr<AceType> & customNode,RefPtr<PipelineContext> & pipeline,RefPtr<TaskExecutor> & executor)238 bool GetTaskExecutor(const RefPtr<AceType>& customNode, RefPtr<PipelineContext>& pipeline,
239     RefPtr<TaskExecutor>& executor)
240 {
241     auto uiNode = AceType::DynamicCast<UINode>(customNode);
242     if (!uiNode) {
243         TAG_LOGW(AceLogTag::ACE_COMPONENT_SNAPSHOT, "Internal error! uiNode is nullptr, "
244         "because customNode is type of %{public}s", AceType::TypeName(customNode));
245         return false;
246     }
247     pipeline = uiNode->GetContextRefPtr();
248     if (!pipeline) {
249         TAG_LOGW(AceLogTag::ACE_COMPONENT_SNAPSHOT, "Internal error! can't get pipeline");
250         return false;
251     }
252     executor = pipeline->GetTaskExecutor();
253     if (!executor) {
254         TAG_LOGW(AceLogTag::ACE_COMPONENT_SNAPSHOT, "Internal error! can't get executor");
255         return false;
256     }
257 
258     return true;
259 }
260 
GetRsNode(const RefPtr<FrameNode> & node)261 std::shared_ptr<Rosen::RSNode> ComponentSnapshot::GetRsNode(const RefPtr<FrameNode>& node)
262 {
263     CHECK_NULL_RETURN(node, nullptr);
264     auto context = AceType::DynamicCast<RosenRenderContext>(node->GetRenderContext());
265     CHECK_NULL_RETURN(context, nullptr);
266     auto rsNode = context->GetRSNode();
267     return rsNode;
268 }
269 
Get(const std::string & componentId,JsCallback && callback,const SnapshotOptions & options)270 void ComponentSnapshot::Get(const std::string& componentId, JsCallback&& callback, const SnapshotOptions& options)
271 {
272     auto node = Inspector::GetFrameNodeByKey(componentId);
273     if (!node) {
274         callback(nullptr, ERROR_CODE_INTERNAL_ERROR, nullptr);
275         TAG_LOGW(AceLogTag::ACE_COMPONENT_SNAPSHOT,
276             "Can't find a component that id or key are " SEC_PLD(%{public}s)
277             ", Please check your parameters are correct",
278             SEC_PARAM(componentId.c_str()));
279         return;
280     }
281 
282     auto rsNode = GetRsNode(node);
283 
284     if (node->GetIsLayoutNode()) {
285         std::list<RefPtr<FrameNode>> children;
286         node->GetOneDepthVisibleFrame(children);
287         if (children.empty()) {
288             callback(nullptr, ERROR_CODE_INTERNAL_ERROR, nullptr);
289             TAG_LOGW(AceLogTag::ACE_COMPONENT_SNAPSHOT,
290                 "Children is empty from FrameNode(Id=" SEC_PLD(%{public}d) ",Depth=%{public}d,Tag=%{public}s)",
291                 SEC_PARAM(node->GetId()), node->GetDepth(), node->GetTag().c_str());
292             return;
293         }
294         node = children.front();
295         rsNode = GetRsNode(children.front());
296     }
297 
298     if (!rsNode) {
299         callback(nullptr, ERROR_CODE_INTERNAL_ERROR, nullptr);
300         TAG_LOGW(AceLogTag::ACE_COMPONENT_SNAPSHOT,
301             "RsNode is null from FrameNode(Id=" SEC_PLD(%{public}d) ",Depth=%{public}d,Tag=%{public}s)",
302             SEC_PARAM(node->GetId()), node->GetDepth(), node->GetTag().c_str());
303         return;
304     }
305     int32_t imageCount = 0;
306     bool checkImage = CheckImageSuccessfullyLoad(node, imageCount);
307     TAG_LOGI(AceLogTag::ACE_COMPONENT_SNAPSHOT,
308         "Get ComponentSnapshot options=%{public}s Id=" SEC_PLD(%{public}d) " Depth=%{public}d Tag=%{public}s "
309         "imageCount=%{public}d checkImage=%{public}d RsNodeId=%{public}" PRIu64 "",
310         options.ToString().c_str(), SEC_PARAM(node->GetId()), node->GetDepth(), node->GetTag().c_str(),
311         imageCount, checkImage, rsNode->GetId());
312     auto& rsInterface = Rosen::RSInterfaces::GetInstance();
313     Rosen::Drawing::Rect specifiedAreaRect = {};
314     bool isSetReigon = SetCaptureReigon(node, options, specifiedAreaRect);
315     if (!isSetReigon) {
316         callback(nullptr, ERROR_CODE_PARAM_INVALID, nullptr);
317         return;
318     }
319     rsInterface.TakeSurfaceCaptureForUI(rsNode, std::make_shared<CustomizedCallback>(std::move(callback), nullptr),
320         options.scale, options.scale, options.waitUntilRenderFinished, specifiedAreaRect);
321 }
322 
GetByUniqueId(int32_t uniqueId,JsCallback && callback,const SnapshotOptions & options)323 void ComponentSnapshot::GetByUniqueId(int32_t uniqueId, JsCallback&& callback, const SnapshotOptions& options)
324 {
325     auto node = AceType::DynamicCast<FrameNode>(OHOS::Ace::ElementRegister::GetInstance()->GetNodeById(uniqueId));
326     if (!node) {
327         callback(nullptr, ERROR_CODE_INTERNAL_ERROR, nullptr);
328         TAG_LOGW(AceLogTag::ACE_COMPONENT_SNAPSHOT,
329             "Can't find a component that uniqueId is %{public}d, Please check your parameters are correct",
330             uniqueId);
331         return;
332     }
333 
334     auto rsNode = GetRsNode(node);
335 
336     if (node->GetIsLayoutNode()) {
337         std::list<RefPtr<FrameNode>> children;
338         node->GetOneDepthVisibleFrame(children);
339         if (children.empty()) {
340             callback(nullptr, ERROR_CODE_INTERNAL_ERROR, nullptr);
341             TAG_LOGW(AceLogTag::ACE_COMPONENT_SNAPSHOT,
342                 "Children is empty from FrameNode(Id=%{public}d,Tag=%{public}s)",
343                 node->GetId(), node->GetTag().c_str());
344             return;
345         }
346         node = children.front();
347         rsNode = GetRsNode(children.front());
348     }
349 
350     if (!rsNode) {
351         callback(nullptr, ERROR_CODE_INTERNAL_ERROR, nullptr);
352         TAG_LOGW(AceLogTag::ACE_COMPONENT_SNAPSHOT,
353             "RsNode is null from FrameNode(Id=%{public}d,Tag=%{public}s)",
354             node->GetId(), node->GetTag().c_str());
355         return;
356     }
357     ACE_SCOPED_TRACE("ComponentSnapshot::GetByUniqueId_Id=%d_RsId=%" PRIu64 "", node->GetId(), rsNode->GetId());
358     int32_t imageCount = 0;
359     bool checkImage = CheckImageSuccessfullyLoad(node, imageCount);
360     TAG_LOGI(AceLogTag::ACE_COMPONENT_SNAPSHOT,
361         "GetByUniqueId ComponentSnapshot options=%{public}s Id=%{public}d Tag=%{public}s imageCount=%{public}d "
362         "checkImage=%{public}d RsNodeId=%{public}" PRIu64 "",
363         options.ToString().c_str(), node->GetId(), node->GetTag().c_str(), imageCount, checkImage, rsNode->GetId());
364     auto& rsInterface = Rosen::RSInterfaces::GetInstance();
365     Rosen::Drawing::Rect specifiedAreaRect = {};
366     bool isSetReigon = SetCaptureReigon(node, options, specifiedAreaRect);
367     if (!isSetReigon) {
368         callback(nullptr, ERROR_CODE_PARAM_INVALID, nullptr);
369         return;
370     }
371     rsInterface.TakeSurfaceCaptureForUI(rsNode, std::make_shared<CustomizedCallback>(std::move(callback), nullptr),
372         options.scale, options.scale, options.waitUntilRenderFinished, specifiedAreaRect);
373 }
374 
Create(const RefPtr<AceType> & customNode,JsCallback && callback,bool enableInspector,const SnapshotParam & param,bool flag)375 void ComponentSnapshot::Create(
376     const RefPtr<AceType>& customNode, JsCallback&& callback, bool enableInspector, const SnapshotParam& param,
377     bool flag)
378 {
379     if (!customNode) {
380         callback(nullptr, ERROR_CODE_INTERNAL_ERROR, nullptr);
381         TAG_LOGW(AceLogTag::ACE_COMPONENT_SNAPSHOT, "Internal error! customNode is nullptr");
382         return;
383     }
384     auto* stack = ViewStackProcessor::GetInstance();
385     auto nodeId = stack->ClaimNodeId();
386     auto stackNode = FrameNode::CreateFrameNode(V2::STACK_ETS_TAG, nodeId, AceType::MakeRefPtr<StackPattern>());
387     RefPtr<PipelineContext> pipeline = nullptr;
388     RefPtr<TaskExecutor> executor = nullptr;
389     if (!GetTaskExecutor(customNode, pipeline, executor)) {
390         callback(nullptr, ERROR_CODE_INTERNAL_ERROR, nullptr);
391         return;
392     }
393     auto node = AceType::DynamicCast<FrameNode>(customNode);
394     if (!node) {
395         RefPtr<UINode> uiNode = AceType::DynamicCast<UINode>(customNode);
396         stackNode->AddChild(uiNode);
397         node = stackNode;
398     }
399     FrameNode::ProcessOffscreenNode(node);
400     TAG_LOGI(AceLogTag::ACE_COMPONENT_SNAPSHOT,
401         "Process off screen Node finished, root size = %{public}s Id=%{public}d Tag=%{public}s InspectorId=%{public}s "
402         "enableInspector=%{public}d",
403         node->GetGeometryNode()->GetFrameSize().ToString().c_str(), node->GetId(), node->GetTag().c_str(),
404         node->GetInspectorId().value_or("").c_str(), enableInspector);
405 
406     ProcessImageNode(node);
407 
408     if (enableInspector) {
409         Inspector::AddOffscreenNode(node);
410     }
411 
412     if (flag) {
413         executor->PostTask(
414             [node]() {
415                 auto pipeline = node->GetContext();
416                 CHECK_NULL_VOID(pipeline);
417                 pipeline->FlushUITasks();
418                 pipeline->FlushMessages();
419             },
420             TaskExecutor::TaskType::UI, "ArkUIComponentSnapshotFlushUITasks", PriorityType::VIP);
421     }
422     PostDelayedTaskOfBuiler(executor, std::move(callback), node, enableInspector, pipeline, param);
423 }
424 
GetNormalCapture(const RefPtr<FrameNode> & frameNode,NormalCallback && callback)425 void ComponentSnapshot::GetNormalCapture(const RefPtr<FrameNode>& frameNode, NormalCallback&& callback)
426 {
427     auto rsNode = GetRsNode(frameNode);
428     auto& rsInterface = Rosen::RSInterfaces::GetInstance();
429     rsInterface.TakeSurfaceCaptureForUI(rsNode, std::make_shared<NormalCaptureCallback>(std::move(callback)));
430 }
431 
PostDelayedTaskOfBuiler(const RefPtr<TaskExecutor> & executor,JsCallback && callback,const RefPtr<FrameNode> & node,bool enableInspector,const RefPtr<PipelineContext> & pipeline,const SnapshotParam & param)432 void ComponentSnapshot::PostDelayedTaskOfBuiler(const RefPtr<TaskExecutor>& executor, JsCallback&& callback,
433     const RefPtr<FrameNode>& node, bool enableInspector, const RefPtr<PipelineContext>& pipeline,
434     const SnapshotParam& param)
435 {
436     executor->PostDelayedTask(
437         [callback, node, enableInspector, pipeline, param]() mutable {
438             BuilerTask(std::move(callback), node, enableInspector, pipeline, param);
439         },
440         TaskExecutor::TaskType::UI, param.delay, "ArkUIComponentSnapshotCreateCapture", PriorityType::VIP);
441 }
442 
BuilerTask(JsCallback && callback,const RefPtr<FrameNode> & node,bool enableInspector,const RefPtr<PipelineContext> & pipeline,const SnapshotParam & param)443 void ComponentSnapshot::BuilerTask(JsCallback&& callback, const RefPtr<FrameNode>& node, bool enableInspector,
444     const RefPtr<PipelineContext>& pipeline, const SnapshotParam& param)
445 {
446     int32_t imageCount = 0;
447     if (param.checkImageStatus && !CheckImageSuccessfullyLoad(node, imageCount)) {
448         TAG_LOGW(AceLogTag::ACE_COMPONENT_SNAPSHOT,
449             "Image loading failed! rootId=%{public}d rootNode=%{public}s InspectorId=%{public}s",
450             node->GetId(), node->GetTag().c_str(), node->GetInspectorId().value_or("").c_str());
451         Inspector::RemoveOffscreenNode(node);
452         callback(nullptr, ERROR_CODE_COMPONENT_SNAPSHOT_IMAGE_LOAD_ERROR, nullptr);
453         return;
454     }
455     if (param.options.waitUntilRenderFinished) {
456         pipeline->FlushUITasks();
457         pipeline->FlushMessages();
458     }
459     auto rsNode = GetRsNode(node);
460     auto& rsInterface = Rosen::RSInterfaces::GetInstance();
461     TAG_LOGI(AceLogTag::ACE_COMPONENT_SNAPSHOT,
462         "Begin to take surfaceCapture for ui, rootId=" SEC_PLD(%{public}d) " depth=%{public}d param=%{public}s "
463         "imageCount=%{public}d",
464         SEC_PARAM(node->GetId()), node->GetDepth(), param.ToString().c_str(), imageCount);
465     Rosen::Drawing::Rect specifiedAreaRect = {};
466     bool isSetReigon = SetCaptureReigon(node, param.options, specifiedAreaRect);
467     if (!isSetReigon) {
468         callback(nullptr, ERROR_CODE_PARAM_INVALID, nullptr);
469         return;
470     }
471     rsInterface.TakeSurfaceCaptureForUI(
472         rsNode,
473         std::make_shared<CustomizedCallback>(std::move(callback), enableInspector ? node : nullptr),
474         param.options.scale, param.options.scale, param.options.waitUntilRenderFinished, specifiedAreaRect);
475 }
476 
GetSync(RefPtr<FrameNode> & node,const SnapshotOptions & options)477 std::pair<int32_t, std::shared_ptr<Media::PixelMap>> ComponentSnapshot::GetSync(
478     RefPtr<FrameNode>& node, const SnapshotOptions& options)
479 {
480     CHECK_RUN_ON(UI);
481     ACE_SCOPED_TRACE("ComponentSnapshot::GetSyncStart_%s", node->GetInspectorIdValue("").c_str());
482     std::pair<int32_t, std::shared_ptr<Media::PixelMap>> result(ERROR_CODE_INTERNAL_ERROR, nullptr);
483     CHECK_NULL_RETURN(node, result);
484     auto rsNode = GetRsNode(node);
485 
486     if (node->GetIsLayoutNode()) {
487         std::list<RefPtr<FrameNode>> children;
488         node->GetOneDepthVisibleFrame(children);
489         if (children.empty()) {
490             TAG_LOGW(AceLogTag::ACE_COMPONENT_SNAPSHOT,
491                 "Children is empty from FrameNode(Id=" SEC_PLD(%{public}d) ",Depth=%{public}d,Tag=%{public}s)",
492                 SEC_PARAM(node->GetId()), node->GetDepth(), node->GetTag().c_str());
493             return result;
494         }
495         node = children.front();
496         rsNode = GetRsNode(children.front());
497     }
498     std::pair<int32_t, std::shared_ptr<Media::PixelMap>> regionResult(ERROR_CODE_PARAM_INVALID, nullptr);
499 
500     if (!rsNode) {
501         TAG_LOGW(AceLogTag::ACE_COMPONENT_SNAPSHOT,
502             "RsNode is null from FrameNode(Id=" SEC_PLD(%{public}d) ",Depth=%{public}d,Tag=%{public}s)",
503             SEC_PARAM(node->GetId()), node->GetDepth(), node->GetTag().c_str());
504         return result;
505     }
506     TAG_LOGI(AceLogTag::ACE_COMPONENT_SNAPSHOT,
507         "GetSync ComponentSnapshot options=%{public}s Id=" SEC_PLD(%{public}d) " Depth=%{public}d Tag=%{public}s "
508         "RsNodeId=%{public}" PRIu64 "",
509         options.ToString().c_str(), SEC_PARAM(node->GetId()), node->GetDepth(), node->GetTag().c_str(),
510         rsNode->GetId());
511     auto& rsInterface = Rosen::RSInterfaces::GetInstance();
512     auto syncCallback = std::make_shared<SyncCustomizedCallback>();
513     {
514         ACE_SCOPED_TRACE("ComponentSnapshot::GetSync_TakeSurfaceCaptureForUI_%s_%d_%" PRIu64 "",
515             node->GetInspectorIdValue("").c_str(), node->GetId(), rsNode->GetId());
516     }
517     Rosen::Drawing::Rect specifiedAreaRect = {};
518     bool isSetReigon = SetCaptureReigon(node, options, specifiedAreaRect);
519     if (!isSetReigon) {
520         return regionResult;
521     }
522     rsInterface.TakeSurfaceCaptureForUI(rsNode, syncCallback,
523         options.scale, options.scale, options.waitUntilRenderFinished);
524     return syncCallback->GetPixelMap(SNAPSHOT_TIMEOUT_DURATION);
525 }
526 
GetSync(const std::string & componentId,const SnapshotOptions & options)527 std::pair<int32_t, std::shared_ptr<Media::PixelMap>> ComponentSnapshot::GetSync(const std::string& componentId,
528     const SnapshotOptions& options)
529 {
530     CHECK_RUN_ON(UI);
531     ACE_SCOPED_TRACE("ComponentSnapshot::GetSyncStart_%s", componentId.c_str());
532     std::pair<int32_t, std::shared_ptr<Media::PixelMap>> result(ERROR_CODE_INTERNAL_ERROR, nullptr);
533     auto node = Inspector::GetFrameNodeByKey(componentId);
534     if (!node) {
535         TAG_LOGW(AceLogTag::ACE_COMPONENT_SNAPSHOT,
536             "Can't find a component that id or key are " SEC_PLD(%{public}s)
537             ", Please check your parameters are correct",
538             SEC_PARAM(componentId.c_str()));
539         return result;
540     }
541 
542     return GetSync(node, options);
543 }
544 
GetSyncByUniqueId(int32_t uniqueId,const SnapshotOptions & options)545 std::pair<int32_t, std::shared_ptr<Media::PixelMap>> ComponentSnapshot::GetSyncByUniqueId(int32_t uniqueId,
546     const SnapshotOptions& options)
547 {
548     CHECK_RUN_ON(UI);
549     ACE_SCOPED_TRACE("ComponentSnapshot::GetSyncByUniqueId_%d", uniqueId);
550     std::pair<int32_t, std::shared_ptr<Media::PixelMap>> result(ERROR_CODE_INTERNAL_ERROR, nullptr);
551     std::pair<int32_t, std::shared_ptr<Media::PixelMap>> regionResult(ERROR_CODE_PARAM_INVALID, nullptr);
552     auto node = AceType::DynamicCast<FrameNode>(OHOS::Ace::ElementRegister::GetInstance()->GetNodeById(uniqueId));
553     if (!node) {
554         TAG_LOGW(AceLogTag::ACE_COMPONENT_SNAPSHOT,
555             "Can't find a component that uniqueId is %{public}d, Please check your parameters are correct", uniqueId);
556         return result;
557     }
558 
559     auto rsNode = GetRsNode(node);
560 
561     if (node->GetIsLayoutNode()) {
562         std::list<RefPtr<FrameNode>> children;
563         node->GetOneDepthVisibleFrame(children);
564         if (children.empty()) {
565             TAG_LOGW(AceLogTag::ACE_COMPONENT_SNAPSHOT,
566                 "Children is empty from FrameNode(Id=%{public}d,Tag=%{public}s)",
567                 node->GetId(), node->GetTag().c_str());
568             return result;
569         }
570         node = children.front();
571         rsNode = GetRsNode(children.front());
572     }
573 
574     if (!rsNode) {
575         TAG_LOGW(AceLogTag::ACE_COMPONENT_SNAPSHOT,
576             "RsNode is null from FrameNode(Id=%{public}d,Tag=%{public}s)",
577             node->GetId(), node->GetTag().c_str());
578         return result;
579     }
580     TAG_LOGI(AceLogTag::ACE_COMPONENT_SNAPSHOT,
581         "GetSyncByUniqueId ComponentSnapshot options=%{public}s Id=%{public}d Tag=%{public}s "
582         "RsNodeId=%{public}" PRIu64 "",
583         options.ToString().c_str(), node->GetId(), node->GetTag().c_str(), rsNode->GetId());
584     auto& rsInterface = Rosen::RSInterfaces::GetInstance();
585     auto syncCallback = std::make_shared<SyncCustomizedCallback>();
586     {
587         ACE_SCOPED_TRACE("ComponentSnapshot::GetSyncByUniqueId_TakeSurfaceCaptureForUI_%d_%" PRIu64 "",
588             node->GetId(), rsNode->GetId());
589     }
590     Rosen::Drawing::Rect specifiedAreaRect = {};
591     bool isSetReigon = SetCaptureReigon(node, options, specifiedAreaRect);
592     if (!isSetReigon) {
593         return regionResult;
594     }
595     rsInterface.TakeSurfaceCaptureForUI(rsNode, syncCallback,
596         options.scale, options.scale, options.waitUntilRenderFinished, specifiedAreaRect);
597     return syncCallback->GetPixelMap(SNAPSHOT_TIMEOUT_DURATION);
598 }
599 
600 // Note: do not use this method, it's only called in drag procedure process.
CreateSync(const RefPtr<AceType> & customNode,const SnapshotParam & param)601 std::shared_ptr<Media::PixelMap> ComponentSnapshot::CreateSync(
602     const RefPtr<AceType>& customNode, const SnapshotParam& param)
603 {
604     if (!customNode) {
605         TAG_LOGW(AceLogTag::ACE_COMPONENT_SNAPSHOT, "CreateSync Internal error! customNode is nullptr");
606         return nullptr;
607     }
608     auto* stack = ViewStackProcessor::GetInstance();
609     auto nodeId = stack->ClaimNodeId();
610     auto stackNode = FrameNode::CreateFrameNode(V2::STACK_ETS_TAG, nodeId, AceType::MakeRefPtr<StackPattern>());
611     RefPtr<PipelineContext> pipeline = nullptr;
612     RefPtr<TaskExecutor> executor = nullptr;
613     if (!GetTaskExecutor(customNode, pipeline, executor)) {
614         TAG_LOGW(AceLogTag::ACE_COMPONENT_SNAPSHOT, "Internal error! Can't get TaskExecutor!");
615         return nullptr;
616     }
617     auto node = AceType::DynamicCast<FrameNode>(customNode);
618     if (!node) {
619         RefPtr<UINode> uiNode = AceType::DynamicCast<UINode>(customNode);
620         stackNode->AddChild(uiNode);
621         node = stackNode;
622     }
623     FrameNode::ProcessOffscreenNode(node);
624     TAG_LOGI(AceLogTag::ACE_COMPONENT_SNAPSHOT,
625         "Process off screen Node finished, root size = %{public}s Id=" SEC_PLD(%{public}d) " Tag=%{public}s "
626         "InspectorId=" SEC_PLD(%{public}s), node->GetGeometryNode()->GetFrameSize().ToString().c_str(),
627         SEC_PARAM(node->GetId()), node->GetTag().c_str(), SEC_PARAM(node->GetInspectorId().value_or("").c_str()));
628 
629     ProcessImageNode(node);
630     pipeline->FlushUITasks();
631     pipeline->FlushMessages();
632     int32_t imageCount = 0;
633     bool checkImage = CheckImageSuccessfullyLoad(node, imageCount);
634     if (!checkImage) {
635         TAG_LOGW(AceLogTag::ACE_COMPONENT_SNAPSHOT,
636             "Image loading failed! rootId=" SEC_PLD(%{public}d) " depth=%{public}d rootNode=%{public}s",
637             SEC_PARAM(node->GetId()), node->GetDepth(), node->GetTag().c_str());
638         return nullptr;
639     }
640     auto rsNode = GetRsNode(node);
641     if (!rsNode) {
642         TAG_LOGW(AceLogTag::ACE_COMPONENT_SNAPSHOT,
643             "Can't get RsNode! rootId=" SEC_PLD(%{public}d) " depth=%{public}d rootNode=%{public}s",
644             SEC_PARAM(node->GetId()), node->GetDepth(), node->GetTag().c_str());
645         return nullptr;
646     }
647     auto& rsInterface = Rosen::RSInterfaces::GetInstance();
648     auto syncCallback = std::make_shared<SyncCustomizedCallback>();
649     rsInterface.TakeSurfaceCaptureForUI(rsNode, syncCallback,
650         1.f, 1.f, true);
651     return syncCallback->GetPixelMap(CREATE_SNAPSHOT_TIMEOUT_DURATION).second;
652 }
653 } // namespace OHOS::Ace::NG
654