diff --git a/adapter/ohos/entrance/ace_container.cpp b/adapter/ohos/entrance/ace_container.cpp index 6572443d356e091474c86fe2e8bc47da6e973f30..a56dd723458020800dba18bf8ff382e55f9f3acf 100644 --- a/adapter/ohos/entrance/ace_container.cpp +++ b/adapter/ohos/entrance/ace_container.cpp @@ -1533,6 +1533,13 @@ UIContentErrorCode AceContainer::SetViewNew( if (container->isFormRender_) { auto window = std::make_shared(taskExecutor, view->GetInstanceId()); + if (!window->GetRSSurfaceNode()) { + TAG_LOGW(AceLogTag::ACE_FORM, + "SurfaceNode is null, try to create form render window again, instanceId_:%{public}d.", + view->GetInstanceId()); + window->Destroy(); + window = std::make_shared(taskExecutor, view->GetInstanceId()); + } container->AttachView(window, view, density, width, height, view->GetInstanceId(), nullptr); } else { auto window = std::make_shared(rsWindow, taskExecutor, view->GetInstanceId()); @@ -3701,11 +3708,20 @@ sptr AceContainer::GetParentToken() std::shared_ptr AceContainer::GetFormSurfaceNode(int32_t instanceId) { auto container = AceType::DynamicCast(AceEngine::Get().GetContainer(instanceId)); - CHECK_NULL_RETURN(container, nullptr); + if (!container) { + TAG_LOGE(AceLogTag::ACE_FORM, "get surfaceNode failed, container is null, instanceId_:%{public}d", instanceId); + return nullptr; + } auto context = AceType::DynamicCast(container->GetPipelineContext()); - CHECK_NULL_RETURN(context, nullptr); - auto window = static_cast(context->GetWindow()); - CHECK_NULL_RETURN(window, nullptr); + if (!context) { + TAG_LOGE(AceLogTag::ACE_FORM, "get surfaceNode failed, context is null, instanceId_:%{public}d", instanceId); + return nullptr; + } + auto window = static_cast(context->GetWindow()); + if (!window) { + TAG_LOGE(AceLogTag::ACE_FORM, "get surfaceNode failed, window is null, instanceId_:%{public}d", instanceId); + return nullptr; + } return window->GetRSSurfaceNode(); } diff --git a/frameworks/core/components_ng/pattern/form/BUILD.gn b/frameworks/core/components_ng/pattern/form/BUILD.gn index b72bffad1fab7e0ac376fa9927eb1eaa5f2e1963..a28fbd37ab84db7e2926cc2c2dee1481b4df2a16 100644 --- a/frameworks/core/components_ng/pattern/form/BUILD.gn +++ b/frameworks/core/components_ng/pattern/form/BUILD.gn @@ -23,6 +23,7 @@ build_component_ng("form_pattern_ng") { "form_node.cpp", "form_pattern.cpp", "form_special_style.cpp", + "form_util.cpp", ] if (is_ohos_standard_system) { @@ -36,6 +37,7 @@ build_component_ng("form_pattern_ng") { "i18n:intl_util", "input:libmmi-client", "ipc:ipc_core", + "image_framework:image_native", ] } } diff --git a/frameworks/core/components_ng/pattern/form/form_pattern.cpp b/frameworks/core/components_ng/pattern/form/form_pattern.cpp index 8ffd08bdc251853d75dbf478ffcc808624793a7c..2a2f0c4f713c7b449481626e0536dbfbf4115c6f 100644 --- a/frameworks/core/components_ng/pattern/form/form_pattern.cpp +++ b/frameworks/core/components_ng/pattern/form/form_pattern.cpp @@ -44,7 +44,7 @@ #endif #include "core/common/udmf/udmf_client.h" -#include "form_pattern.h" +#include "form_util.h" static const int64_t MAX_NUMBER_OF_JS = 0x20000000000000; @@ -434,6 +434,17 @@ void FormPattern::OnSnapshot(std::shared_ptr pixelMap) CHECK_NULL_VOID(host); auto context = host->GetContext(); CHECK_NULL_VOID(context); + if (!pixelMap) { + TAG_LOGW(AceLogTag::ACE_FORM, "FormPattern::OnSnapshot pixelmap is null"); + return; + } + + if (!isDynamic_ && FormUtil::IsTransparent(pixelMap)) { + TAG_LOGW(AceLogTag::ACE_FORM, "FormPattern::OnSnapshot pixelmap is transparent"); + needSnapshotAgain_ = true; + return; + } + auto uiTaskExecutor = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::UI); uiTaskExecutor.PostTask([weak = WeakClaim(this), pixelMap] { @@ -447,6 +458,7 @@ void FormPattern::HandleOnSnapshot(std::shared_ptr pixelMap) { TAG_LOGI(AceLogTag::ACE_FORM, "call."); CHECK_NULL_VOID(pixelMap); + pixelMap_ = PixelMap::CreatePixelMap(reinterpret_cast(&pixelMap)); UpdateStaticCard(); isSnapshot_ = true; diff --git a/frameworks/core/components_ng/pattern/form/form_util.cpp b/frameworks/core/components_ng/pattern/form/form_util.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ced8a796139ac9bdcb5ce9988b639a234d228c3b --- /dev/null +++ b/frameworks/core/components_ng/pattern/form/form_util.cpp @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "form_util.h" +#include "base/log/log_wrapper.h" + +namespace OHOS::Ace::NG { +namespace { +constexpr uint32_t ALPHA_MASK = 0xFF000000; + +uint32_t PixelMapSamplingDump(std::shared_ptr& pixelMap, int32_t x, int32_t y) +{ + if (pixelMap == nullptr) { + TAG_LOGE(AceLogTag::ACE_FORM, "FormUtil::PixelMapSamplingDump fail: pixelmap is nullptr"); + return 0; + } + if (x < 0 || y < 0 || x >= pixelMap->GetWidth() || y >= pixelMap->GetHeight()) { + TAG_LOGE(AceLogTag::ACE_FORM, "FormUtil::PixelMapSamplingDump fail: x or y invalid"); + return 0; + } + uint32_t pixel = 0; + pixelMap->ReadPixel({x, y}, pixel); + return pixel; +} +} // namespace + +/** + * @brief Determine whether the snapshot is transparent. + * @param pixelMap the snapshot of SurfaceNode + * @return true if the snapshot is transparent, false otherwise. + */ +bool FormUtil::IsTransparent(std::shared_ptr& pixelMap) +{ + if (!pixelMap) { + TAG_LOGW(AceLogTag::ACE_FORM, "FormPattern::OnSnapshot pixelmap is nullptr"); + return true; + } + auto pixelDump = PixelMapSamplingDump(pixelMap, pixelMap->GetWidth() / 2, 0) | + PixelMapSamplingDump(pixelMap, 0, pixelMap->GetHeight() / 2) | + PixelMapSamplingDump(pixelMap, pixelMap->GetWidth() / 2, pixelMap->GetHeight() / 2) | + PixelMapSamplingDump(pixelMap, pixelMap->GetWidth() - 1, pixelMap->GetHeight() / 2) | + PixelMapSamplingDump(pixelMap, pixelMap->GetWidth() / 2, pixelMap->GetHeight() - 1); + return (pixelDump & ALPHA_MASK) == 0; +} +} // namespace OHOS::Ace::NG diff --git a/frameworks/core/components_ng/pattern/form/form_util.h b/frameworks/core/components_ng/pattern/form/form_util.h new file mode 100644 index 0000000000000000000000000000000000000000..8a474afa7be430e8c3a2497c89dd65a08fa49ff4 --- /dev/null +++ b/frameworks/core/components_ng/pattern/form/form_util.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License")_; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERN_FORM_FORM_UTIL_H +#define FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERN_FORM_FORM_UTIL_H + +#include +#include "pixel_map.h" + +namespace OHOS::Ace::NG { +using namespace std; +using namespace OHOS::Media; + +/** + * @class FormUtil + * form util. + */ +class FormUtil { +public: + /** + * @brief Determine whether the snapshot is transparent. + * @param pixelMap the snapshot of SurfaceNode + * @return true if the snapshot is transparent, false otherwise. + */ + static bool IsTransparent(std::shared_ptr& pixelMap); +}; +} // namespace OHOS::Ace::NG +#endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERN_FORM_FORM_UTIL_H diff --git a/test/unittest/core/pattern/form/BUILD.gn b/test/unittest/core/pattern/form/BUILD.gn index c705fdf8ec4e5995d9b204ebcb6eb5c3202e11f5..e0ae85ddaf3fd562db9af994f274749644f50fb3 100644 --- a/test/unittest/core/pattern/form/BUILD.gn +++ b/test/unittest/core/pattern/form/BUILD.gn @@ -126,6 +126,7 @@ ace_unittest("form_pattern_test") { "$ace_root/frameworks/core/components_ng/pattern/form/form_node.cpp", "$ace_root/frameworks/core/components_ng/pattern/form/form_pattern.cpp", "$ace_root/frameworks/core/components_ng/pattern/form/form_special_style.cpp", + "$ace_root/frameworks/core/components_ng/pattern/form/form_util.cpp", "$ace_root/frameworks/core/components_ng/pattern/shape/shape_layout_algorithm.cpp", "$ace_root/frameworks/core/components_ng/pattern/shape/shape_overlay_modifier.cpp", "$ace_root/frameworks/core/components_ng/pattern/shape/shape_paint_property.cpp", @@ -158,6 +159,7 @@ ace_unittest("form_pattern_test") { "icu:shared_icuuc", "input:libmmi-client", "resource_management:global_resmgr", + "image_framework:image_native", ] } } diff --git a/test/unittest/core/pattern/form/form_pattern_test.cpp b/test/unittest/core/pattern/form/form_pattern_test.cpp index d4efe9f3a6edd0a04d0c6c56cb27c98baba043f3..77613755ab5d0b2fa7a468c64a517444381e81ad 100644 --- a/test/unittest/core/pattern/form/form_pattern_test.cpp +++ b/test/unittest/core/pattern/form/form_pattern_test.cpp @@ -24,7 +24,7 @@ #include "mock/mock_form_utils.h" #include "mock/mock_sub_container.h" -#include "test/mock/base/mock_pixel_map.h" +#include "mock/mock_pixel_map.h" #include "test/mock/base/mock_task_executor.h" #include "test/mock/core/common/mock_container.h" #include "test/mock/core/pipeline/mock_pipeline_context.h" @@ -497,8 +497,19 @@ HWTEST_F(FormPatternTest, FormPatternTest_012, TestSize.Level1) pattern->OnSnapshot(pixelMap); EXPECT_EQ(pattern->isSnapshot_, false); weak.refCounter_ = refBak; -} + pattern->isDynamic_ = false; + std::shared_ptr mockPixelMap = std::make_shared(); + EXPECT_CALL(*mockPixelMap, GetWidth()).WillRepeatedly(Return(-200)); + pattern->OnSnapshot(mockPixelMap); + EXPECT_EQ(pattern->needSnapshotAgain_, true); + + EXPECT_CALL(*mockPixelMap, GetWidth()).WillRepeatedly(Return(200)); + EXPECT_CALL(*mockPixelMap, GetHeight()).WillRepeatedly(Return(200)); + pattern->needSnapshotAgain_ = false; + pattern->OnSnapshot(mockPixelMap); + EXPECT_EQ(pattern->needSnapshotAgain_, true); +} /** * @tc.name: FormPatternTest_014 diff --git a/test/unittest/core/pattern/form/mock/mock_pixel_map.h b/test/unittest/core/pattern/form/mock/mock_pixel_map.h new file mode 100644 index 0000000000000000000000000000000000000000..5fec6756f3997c2660090449003efc9689d137ec --- /dev/null +++ b/test/unittest/core/pattern/form/mock/mock_pixel_map.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_TEST_MOCK_PATTERN_FORM_MOCK_MEDIA_PIXEL_MAP_H +#define FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_TEST_MOCK_PATTERN_FORM_MOCK_MEDIA_PIXEL_MAP_H +#include "gmock/gmock.h" + +#include "pixel_map.h" + +namespace OHOS::Media { +class MockPixelMap : public PixelMap { +public: + MOCK_METHOD(int32_t, GetWidth, ()); + MOCK_METHOD(int32_t, GetHeight, ()); +}; +} // namespace OHOS::Ace +#endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_TEST_MOCK_PATTERN_FORM_MOCK_MEDIA_PIXEL_MAP_H