!39562 组件截图:新增getSync接口

Merge pull request !39562 from 胡清云/0802_getSync
This commit is contained in:
openharmony_ci 2024-08-06 14:15:25 +00:00 committed by Gitee
commit 6782e5f6ea
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
11 changed files with 200 additions and 6 deletions

View File

@ -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;

View File

@ -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 {

View File

@ -3366,6 +3366,15 @@ void FrontendDelegateDeclarative::GetSnapshot(
#endif
}
std::pair<int32_t, std::shared_ptr<Media::PixelMap>> 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<void()>&& customBuilder, NG::ComponentSnapshot::JsCallback&& callback, bool enableInspector,
const NG::SnapshotParam& param)

View File

@ -285,6 +285,9 @@ public:
std::function<void(std::shared_ptr<Media::PixelMap>, int32_t, std::function<void()>)>&& callback,
bool enableInspector, const NG::SnapshotParam& param) override;
std::pair<int32_t, std::shared_ptr<Media::PixelMap>> GetSyncSnapshot(const std::string& componentId,
const NG::SnapshotOptions& options) override;
void AddFrameNodeToOverlay(
const RefPtr<NG::FrameNode>& node, std::optional<int32_t> index = std::nullopt) override;
void RemoveFrameNodeOnOverlay(const RefPtr<NG::FrameNode>& node) override;

View File

@ -1175,6 +1175,15 @@ void FrontendDelegateDeclarativeNG::GetSnapshot(
#endif
}
std::pair<int32_t, std::shared_ptr<Media::PixelMap>> 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);

View File

@ -223,6 +223,9 @@ public:
std::function<void(std::shared_ptr<Media::PixelMap>, int32_t, std::function<void()>)>&& callback,
bool enableInspector, const NG::SnapshotParam& param) override;
std::pair<int32_t, std::shared_ptr<Media::PixelMap>> GetSyncSnapshot(const std::string& componentId,
const NG::SnapshotOptions& options) override;
void AddFrameNodeToOverlay(
const RefPtr<NG::FrameNode>& node, std::optional<int32_t> index = std::nullopt) override;
void RemoveFrameNodeOnOverlay(const RefPtr<NG::FrameNode>& node) override;

View File

@ -238,6 +238,12 @@ public:
bool enableInspector, const NG::SnapshotParam& param)
{}
virtual std::pair<int32_t, std::shared_ptr<Media::PixelMap>> 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<uint8_t>& content) = 0;
virtual std::string GetAssetPath(const std::string& url) = 0;

View File

@ -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<int, std::milli> SNAPSHOT_TIMEOUT_DURATION(3000);
class CustomizedCallback : public Rosen::SurfaceCaptureCallback {
public:
CustomizedCallback(ComponentSnapshot::JsCallback&& jsCallback, WeakPtr<FrameNode> 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<Media::PixelMap> 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<std::mutex> lock(mutex_);
cv_.notify_all();
}
std::pair<int32_t, std::shared_ptr<Media::PixelMap>> GetPixelMap()
{
std::pair<int32_t, std::shared_ptr<Media::PixelMap>> result(ERROR_CODE_INTERNAL_ERROR, nullptr);
std::unique_lock<std::mutex> 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<Media::PixelMap> pixelMap_;
};
} // namespace
void ProcessImageNode(const RefPtr<UINode>& node)
@ -93,7 +136,7 @@ void ProcessImageNode(const RefPtr<UINode>& node)
if (node->GetTag() == V2::IMAGE_ETS_TAG) {
auto imageNode = AceType::DynamicCast<FrameNode>(node);
if (imageNode && AceType::DynamicCast<ImagePattern>(imageNode->GetPattern())) {
auto imagePattern = AceType::DynamicCast<ImagePattern>(imageNode->GetPattern());
auto imagePattern = AceType::DynamicCast<ImagePattern>(imageNode->GetPattern());
imagePattern->SetIsComponentSnapshotNode();
imagePattern->OnVisibleAreaChange(true);
}
@ -111,7 +154,7 @@ bool CheckImageSuccessfullyLoad(const RefPtr<UINode>& node, int32_t& imageCount)
imageCount++;
auto imageNode = AceType::DynamicCast<FrameNode>(node);
CHECK_NULL_RETURN(imageNode, false);
auto imagePattern = AceType::DynamicCast<ImagePattern>(imageNode->GetPattern());
auto imagePattern = AceType::DynamicCast<ImagePattern>(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<CustomizedCallback>(std::move(callback), nullptr),
options.scale, options.scale, options.waitUntilRenderFinished);
@ -275,4 +319,54 @@ void ComponentSnapshot::BuilerTask(JsCallback&& callback, const RefPtr<FrameNode
std::make_shared<CustomizedCallback>(std::move(callback), enableInspector ? node : nullptr),
param.options.scale, param.options.scale, param.options.waitUntilRenderFinished);
}
std::pair<int32_t, std::shared_ptr<Media::PixelMap>> ComponentSnapshot::GetSync(const std::string& componentId,
const SnapshotOptions& options)
{
CHECK_RUN_ON(UI);
ACE_SCOPED_TRACE("ComponentSnapshot::GetSyncStart_%s", componentId.c_str());
std::pair<int32_t, std::shared_ptr<Media::PixelMap>> 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<RefPtr<FrameNode>> 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<SyncCustomizedCallback>();
{
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

View File

@ -35,6 +35,9 @@ public:
bool flag = true);
static void GetNormalCapture(const RefPtr<FrameNode>& frameNode, NormalCallback&& callback);
static std::pair<int32_t, std::shared_ptr<Media::PixelMap>> GetSync(const std::string& componentId,
const SnapshotOptions& options);
private:
static std::shared_ptr<Rosen::RSNode> GetRsNode(const RefPtr<FrameNode>& node);
static void PostDelayedTaskOfBuiler(const RefPtr<TaskExecutor>& executor, JsCallback&& callback,

View File

@ -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;

View File

@ -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));