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