diff --git a/frameworks/base/error/error_code.h b/frameworks/base/error/error_code.h index 02002762a81..17bfabd2c6d 100644 --- a/frameworks/base/error/error_code.h +++ b/frameworks/base/error/error_code.h @@ -105,6 +105,7 @@ constexpr int32_t ERROR_CODE_NON_EXIST = 150003; // ComponentSnapshot error code constexpr int32_t ERROR_CODE_COMPONENT_SNAPSHOT_IMAGE_LOAD_ERROR = 160001; +constexpr int32_t ERROR_CODE_COMPONENT_SNAPSHOT_TIMEOUT = 160002; // FromHtml error code constexpr int32_t ERROR_CODE_FROM_HTML_CONVERT_ERROR = 170001; diff --git a/frameworks/bridge/declarative_frontend/engine/jsUIContext.js b/frameworks/bridge/declarative_frontend/engine/jsUIContext.js index 504a148bd15..6b0f89b0a7f 100644 --- a/frameworks/bridge/declarative_frontend/engine/jsUIContext.js +++ b/frameworks/bridge/declarative_frontend/engine/jsUIContext.js @@ -110,6 +110,12 @@ class ComponentSnapshot { __JSScopeUtil__.restoreInstanceId(); } } + getSync(id, options) { + __JSScopeUtil__.syncInstanceId(this.instanceId_); + let pixelmap = this.ohos_componentSnapshot.getSync(id, options); + __JSScopeUtil__.restoreInstanceId(); + return pixelmap; + } } class DragController { diff --git a/frameworks/bridge/declarative_frontend/frontend_delegate_declarative.cpp b/frameworks/bridge/declarative_frontend/frontend_delegate_declarative.cpp index e8632676ef7..eed467b5818 100644 --- a/frameworks/bridge/declarative_frontend/frontend_delegate_declarative.cpp +++ b/frameworks/bridge/declarative_frontend/frontend_delegate_declarative.cpp @@ -3366,6 +3366,15 @@ void FrontendDelegateDeclarative::GetSnapshot( #endif } +std::pair> FrontendDelegateDeclarative::GetSyncSnapshot( + const std::string& componentId, const NG::SnapshotOptions& options) +{ +#ifdef ENABLE_ROSEN_BACKEND + return NG::ComponentSnapshot::GetSync(componentId, options); +#endif + return {ERROR_CODE_INTERNAL_ERROR, nullptr}; +} + void FrontendDelegateDeclarative::CreateSnapshot( std::function&& customBuilder, NG::ComponentSnapshot::JsCallback&& callback, bool enableInspector, const NG::SnapshotParam& param) diff --git a/frameworks/bridge/declarative_frontend/frontend_delegate_declarative.h b/frameworks/bridge/declarative_frontend/frontend_delegate_declarative.h index c4ff365de00..d2e006271ed 100644 --- a/frameworks/bridge/declarative_frontend/frontend_delegate_declarative.h +++ b/frameworks/bridge/declarative_frontend/frontend_delegate_declarative.h @@ -285,6 +285,9 @@ public: std::function, int32_t, std::function)>&& callback, bool enableInspector, const NG::SnapshotParam& param) override; + std::pair> GetSyncSnapshot(const std::string& componentId, + const NG::SnapshotOptions& options) override; + void AddFrameNodeToOverlay( const RefPtr& node, std::optional index = std::nullopt) override; void RemoveFrameNodeOnOverlay(const RefPtr& node) override; diff --git a/frameworks/bridge/declarative_frontend/ng/frontend_delegate_declarative_ng.cpp b/frameworks/bridge/declarative_frontend/ng/frontend_delegate_declarative_ng.cpp index 4d832e18ce8..1d04e2ae7f0 100644 --- a/frameworks/bridge/declarative_frontend/ng/frontend_delegate_declarative_ng.cpp +++ b/frameworks/bridge/declarative_frontend/ng/frontend_delegate_declarative_ng.cpp @@ -1175,6 +1175,15 @@ void FrontendDelegateDeclarativeNG::GetSnapshot( #endif } +std::pair> FrontendDelegateDeclarativeNG::GetSyncSnapshot( + const std::string& componentId, const NG::SnapshotOptions& options) +{ +#ifdef ENABLE_ROSEN_BACKEND + return NG::ComponentSnapshot::GetSync(componentId, options); +#endif + return {ERROR_CODE_INTERNAL_ERROR, nullptr}; +} + std::string FrontendDelegateDeclarativeNG::GetContentInfo(ContentInfoType type) { auto jsonContentInfo = JsonUtil::Create(true); diff --git a/frameworks/bridge/declarative_frontend/ng/frontend_delegate_declarative_ng.h b/frameworks/bridge/declarative_frontend/ng/frontend_delegate_declarative_ng.h index 812db009294..083d9124aa5 100644 --- a/frameworks/bridge/declarative_frontend/ng/frontend_delegate_declarative_ng.h +++ b/frameworks/bridge/declarative_frontend/ng/frontend_delegate_declarative_ng.h @@ -223,6 +223,9 @@ public: std::function, int32_t, std::function)>&& callback, bool enableInspector, const NG::SnapshotParam& param) override; + std::pair> GetSyncSnapshot(const std::string& componentId, + const NG::SnapshotOptions& options) override; + void AddFrameNodeToOverlay( const RefPtr& node, std::optional index = std::nullopt) override; void RemoveFrameNodeOnOverlay(const RefPtr& node) override; diff --git a/frameworks/bridge/js_frontend/frontend_delegate.h b/frameworks/bridge/js_frontend/frontend_delegate.h index a39032e9da4..46682d4beb9 100644 --- a/frameworks/bridge/js_frontend/frontend_delegate.h +++ b/frameworks/bridge/js_frontend/frontend_delegate.h @@ -238,6 +238,12 @@ public: bool enableInspector, const NG::SnapshotParam& param) {} + virtual std::pair> GetSyncSnapshot(const std::string& componentId, + const NG::SnapshotOptions& options) + { + return {}; + } + virtual bool GetAssetContent(const std::string& url, std::string& content) = 0; virtual bool GetAssetContent(const std::string& url, std::vector& content) = 0; virtual std::string GetAssetPath(const std::string& url) = 0; diff --git a/frameworks/core/components_ng/render/adapter/component_snapshot.cpp b/frameworks/core/components_ng/render/adapter/component_snapshot.cpp index 746389cdb57..71def740b65 100644 --- a/frameworks/core/components_ng/render/adapter/component_snapshot.cpp +++ b/frameworks/core/components_ng/render/adapter/component_snapshot.cpp @@ -20,6 +20,7 @@ #include "transaction/rs_interfaces.h" +#include "base/log/ace_trace.h" #include "base/log/log_wrapper.h" #include "base/utils/utils.h" #include "bridge/common/utils/utils.h" @@ -34,6 +35,9 @@ namespace OHOS::Ace::NG { namespace { + +constexpr std::chrono::duration SNAPSHOT_TIMEOUT_DURATION(3000); + class CustomizedCallback : public Rosen::SurfaceCaptureCallback { public: CustomizedCallback(ComponentSnapshot::JsCallback&& jsCallback, WeakPtr node) @@ -86,6 +90,45 @@ public: private: ComponentSnapshot::NormalCallback callback_; }; + +class SyncCustomizedCallback : public Rosen::SurfaceCaptureCallback { +public: + SyncCustomizedCallback() = default; + ~SyncCustomizedCallback() override = default; + void OnSurfaceCapture(std::shared_ptr pixelMap) override + { + if (!pixelMap) { + TAG_LOGW(AceLogTag::ACE_COMPONENT_SNAPSHOT, "Internal error! The pixelmap returned by the system is null"); + pixelMap_ = nullptr; + } else { + TAG_LOGI(AceLogTag::ACE_COMPONENT_SNAPSHOT, + "ComponentSnapshot successful! pixelMap.width=%{public}d pixelMap.height=%{public}d", + pixelMap->GetWidth(), pixelMap->GetHeight()); + pixelMap_ = pixelMap; + } + std::unique_lock lock(mutex_); + cv_.notify_all(); + } + + std::pair> GetPixelMap() + { + std::pair> result(ERROR_CODE_INTERNAL_ERROR, nullptr); + std::unique_lock lock(mutex_); + auto status = cv_.wait_for(lock, SNAPSHOT_TIMEOUT_DURATION); + if (status == std::cv_status::timeout) { + return { ERROR_CODE_COMPONENT_SNAPSHOT_TIMEOUT, nullptr }; + } + if (pixelMap_) { + result = { ERROR_CODE_NO_ERROR, pixelMap_ }; + } + return result; + } + +private: + mutable std::mutex mutex_; + std::condition_variable cv_; + std::shared_ptr pixelMap_; +}; } // namespace void ProcessImageNode(const RefPtr& node) @@ -93,7 +136,7 @@ void ProcessImageNode(const RefPtr& node) if (node->GetTag() == V2::IMAGE_ETS_TAG) { auto imageNode = AceType::DynamicCast(node); if (imageNode && AceType::DynamicCast(imageNode->GetPattern())) { - auto imagePattern = AceType::DynamicCast(imageNode->GetPattern()); + auto imagePattern = AceType::DynamicCast(imageNode->GetPattern()); imagePattern->SetIsComponentSnapshotNode(); imagePattern->OnVisibleAreaChange(true); } @@ -111,7 +154,7 @@ bool CheckImageSuccessfullyLoad(const RefPtr& node, int32_t& imageCount) imageCount++; auto imageNode = AceType::DynamicCast(node); CHECK_NULL_RETURN(imageNode, false); - auto imagePattern = AceType::DynamicCast(imageNode->GetPattern()); + auto imagePattern = AceType::DynamicCast(imageNode->GetPattern()); CHECK_NULL_RETURN(imagePattern, false); auto imageLoadContext = imagePattern->GetImageLoadingContext().Upgrade(); CHECK_NULL_RETURN(imageLoadContext, false); @@ -179,8 +222,9 @@ void ComponentSnapshot::Get(const std::string& componentId, JsCallback&& callbac return; } TAG_LOGI(AceLogTag::ACE_COMPONENT_SNAPSHOT, - "Get ComponentSnapshot key=%{public}s Id=%{public}d Tag=%{public}s RsNodeId=%{public}" PRIu64 "", - componentId.c_str(), node->GetId(), node->GetTag().c_str(), rsNode->GetId()); + "Get ComponentSnapshot key=%{public}s options=%{public}s Id=%{public}d Tag=%{public}s " + "RsNodeId=%{public}" PRIu64 "", + componentId.c_str(), options.ToString().c_str(), node->GetId(), node->GetTag().c_str(), rsNode->GetId()); auto& rsInterface = Rosen::RSInterfaces::GetInstance(); rsInterface.TakeSurfaceCaptureForUI(rsNode, std::make_shared(std::move(callback), nullptr), options.scale, options.scale, options.waitUntilRenderFinished); @@ -275,4 +319,54 @@ void ComponentSnapshot::BuilerTask(JsCallback&& callback, const RefPtr(std::move(callback), enableInspector ? node : nullptr), param.options.scale, param.options.scale, param.options.waitUntilRenderFinished); } + +std::pair> ComponentSnapshot::GetSync(const std::string& componentId, + const SnapshotOptions& options) +{ + CHECK_RUN_ON(UI); + ACE_SCOPED_TRACE("ComponentSnapshot::GetSyncStart_%s", componentId.c_str()); + std::pair> result(ERROR_CODE_INTERNAL_ERROR, nullptr); + auto node = Inspector::GetFrameNodeByKey(componentId); + if (!node) { + TAG_LOGW(AceLogTag::ACE_COMPONENT_SNAPSHOT, + "Can't find a component that id or key are %{public}s, Please check your parameters are correct", + componentId.c_str()); + return result; + } + + auto rsNode = GetRsNode(node); + + if (node->GetIsLayoutNode()) { + std::list> children; + node->GetOneDepthVisibleFrame(children); + if (children.empty()) { + TAG_LOGW(AceLogTag::ACE_COMPONENT_SNAPSHOT, + "Children is empty from FrameNode(InspectorId=%{public}s Id=%{public}d)", + componentId.c_str(), node->GetId()); + return result; + } + node = children.front(); + rsNode = GetRsNode(children.front()); + } + + if (!rsNode) { + TAG_LOGW(AceLogTag::ACE_COMPONENT_SNAPSHOT, + "RsNode is null from FrameNode(InspectorId=%{public}s Id=%{public}d)", + componentId.c_str(), node->GetId()); + return result; + } + TAG_LOGI(AceLogTag::ACE_COMPONENT_SNAPSHOT, + "GetSync ComponentSnapshot key=%{public}s options=%{public}s Id=%{public}d Tag=%{public}s " + "RsNodeId=%{public}" PRIu64 "", + componentId.c_str(), options.ToString().c_str(), node->GetId(), node->GetTag().c_str(), rsNode->GetId()); + auto& rsInterface = Rosen::RSInterfaces::GetInstance(); + auto syncCallback = std::make_shared(); + { + ACE_SCOPED_TRACE("ComponentSnapshot::GetSync_TakeSurfaceCaptureForUI_%s_%d_%" PRIu64 "", componentId.c_str(), + node->GetId(), rsNode->GetId()); + } + rsInterface.TakeSurfaceCaptureForUI(rsNode, syncCallback, + options.scale, options.scale, options.waitUntilRenderFinished); + return syncCallback->GetPixelMap(); +} } // namespace OHOS::Ace::NG diff --git a/frameworks/core/components_ng/render/adapter/component_snapshot.h b/frameworks/core/components_ng/render/adapter/component_snapshot.h index 5ab2825b1cb..d0c1ee40725 100644 --- a/frameworks/core/components_ng/render/adapter/component_snapshot.h +++ b/frameworks/core/components_ng/render/adapter/component_snapshot.h @@ -35,6 +35,9 @@ public: bool flag = true); static void GetNormalCapture(const RefPtr& frameNode, NormalCallback&& callback); + static std::pair> GetSync(const std::string& componentId, + const SnapshotOptions& options); + private: static std::shared_ptr GetRsNode(const RefPtr& node); static void PostDelayedTaskOfBuiler(const RefPtr& executor, JsCallback&& callback, diff --git a/frameworks/core/components_ng/render/snapshot_param.h b/frameworks/core/components_ng/render/snapshot_param.h index 4f41febed66..5ed669f89a1 100644 --- a/frameworks/core/components_ng/render/snapshot_param.h +++ b/frameworks/core/components_ng/render/snapshot_param.h @@ -29,6 +29,10 @@ struct SnapshotOptions { bool waitUntilRenderFinished; explicit SnapshotOptions(float scale = DEFAULT_SNAPSHOT_SCALE, bool waitUntilRenderFinished = false) : scale(scale), waitUntilRenderFinished(waitUntilRenderFinished) {} + std::string ToString() const + { + return "{" + std::to_string(scale) + ", " + (waitUntilRenderFinished ? "true}" : "false}"); + } }; struct SnapshotParam { int32_t delay; diff --git a/interfaces/napi/kits/component_snapshot/js_component_snapshot.cpp b/interfaces/napi/kits/component_snapshot/js_component_snapshot.cpp index 671486e4ec4..18dec07661b 100644 --- a/interfaces/napi/kits/component_snapshot/js_component_snapshot.cpp +++ b/interfaces/napi/kits/component_snapshot/js_component_snapshot.cpp @@ -302,7 +302,7 @@ static napi_value JSSnapshotGet(napi_env env, napi_callback_info info) auto delegate = EngineHelper::GetCurrentDelegateSafely(); if (!delegate) { TAG_LOGW(AceLogTag::ACE_COMPONENT_SNAPSHOT, - "Can'nt get delegate of ace_engine. param: %{public}s", + "Can't get delegate of ace_engine. param: %{public}s", componentId.c_str()); auto callback = helper.CreateCallback(&result); callback(nullptr, ERROR_CODE_INTERNAL_ERROR, nullptr); @@ -334,7 +334,7 @@ static napi_value JSSnapshotFromBuilder(napi_env env, napi_callback_info info) napi_value result = nullptr; auto delegate = EngineHelper::GetCurrentDelegateSafely(); if (!delegate) { - TAG_LOGW(AceLogTag::ACE_COMPONENT_SNAPSHOT, "Can'nt get delegate of ace_engine. "); + TAG_LOGW(AceLogTag::ACE_COMPONENT_SNAPSHOT, "Can't get delegate of ace_engine. "); auto callback = helper.CreateCallback(&result); callback(nullptr, ERROR_CODE_INTERNAL_ERROR, nullptr); return nullptr; @@ -353,11 +353,67 @@ static napi_value JSSnapshotFromBuilder(napi_env env, napi_callback_info info) return result; } +static napi_value JSSnapshotGetSync(napi_env env, napi_callback_info info) +{ + napi_escapable_handle_scope scope = nullptr; + napi_open_escapable_handle_scope(env, &scope); + + JsComponentSnapshot helper(env, info); + + napi_value result = nullptr; + + if (!helper.CheckArgs(napi_valuetype::napi_string)) { + TAG_LOGW(AceLogTag::ACE_COMPONENT_SNAPSHOT, "Parsing the first argument failed, not of string type."); + napi_close_escapable_handle_scope(env, scope); + return result; + } + + // parse id + std::string componentId; + napi_valuetype valueType = napi_null; + GetNapiString(env, helper.GetArgv(0), componentId, valueType); + + auto delegate = EngineHelper::GetCurrentDelegateSafely(); + if (!delegate) { + TAG_LOGW(AceLogTag::ACE_COMPONENT_SNAPSHOT, + "Can't get delegate of ace_engine. param: %{public}s", + componentId.c_str()); + NapiThrow(env, "Delegate is null", ERROR_CODE_INTERNAL_ERROR); + napi_close_escapable_handle_scope(env, scope); + return result; + } + + NG::SnapshotOptions options; + helper.ParseParamForGet(options); + + auto pair = delegate->GetSyncSnapshot(componentId, options); + + switch (pair.first) { + case ERROR_CODE_NO_ERROR : +#ifdef PIXEL_MAP_SUPPORTED + result = Media::PixelMapNapi::CreatePixelMap(env, pair.second); +#endif + break; + case ERROR_CODE_INTERNAL_ERROR : + napi_get_null(env, &result); + NapiThrow(env, "Internal error!", ERROR_CODE_INTERNAL_ERROR); + break; + case ERROR_CODE_COMPONENT_SNAPSHOT_TIMEOUT : + napi_get_null(env, &result); + NapiThrow(env, "ComponentSnapshot timeout!", ERROR_CODE_COMPONENT_SNAPSHOT_TIMEOUT); + break; + } + napi_escape_handle(env, scope, result, &result); + napi_close_escapable_handle_scope(env, scope); + return result; +} + static napi_value ComponentSnapshotExport(napi_env env, napi_value exports) { napi_property_descriptor snapshotDesc[] = { DECLARE_NAPI_FUNCTION("get", JSSnapshotGet), DECLARE_NAPI_FUNCTION("createFromBuilder", JSSnapshotFromBuilder), + DECLARE_NAPI_FUNCTION("getSync", JSSnapshotGetSync), }; NAPI_CALL(env, napi_define_properties(env, exports, sizeof(snapshotDesc) / sizeof(snapshotDesc[0]), snapshotDesc));