* Copyright (c) 2024-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 "platformview_pattern.h"
#include <cmath>
#include <cstdlib>
#include "platform_view_impl.h"
#include "base/geometry/ng/point_t.h"
#include "base/geometry/ng/size_t.h"
#include "base/log/dump_log.h"
#include "base/log/frame_report.h"
#include "base/log/log_wrapper.h"
#include "base/memory/ace_type.h"
#include "base/utils/system_properties.h"
#include "base/utils/utils.h"
#include "core/common/ace_engine.h"
#include "core/common/ace_view.h"
#include "core/components_ng/event/gesture_event_hub.h"
#include "core/event/touch_event.h"
#include "core/pipeline_ng/pipeline_context.h"
#ifdef NG_BUILD
#include "bridge/declarative_frontend/ng/declarative_frontend_ng.h"
#else
#include "bridge/declarative_frontend/declarative_frontend.h"
#endif
#include "platformview_event_hub.h"
namespace OHOS::Ace::NG {
PlatformViewPattern::PlatformViewPattern(
const std::string& id, const std::int32_t type, const std::optional<std::string>& data)
: id_(id), type_(type), data_(data)
{
LOGE("PlatformViewPattern constructor type_: %{public}d", type_);
}
void PlatformViewPattern::RequestFocus()
{
auto host = GetHost();
CHECK_NULL_VOID(host);
auto eventHub = host->GetEventHub<PlatformViewEventHub>();
CHECK_NULL_VOID(eventHub);
auto focusHub = eventHub->GetOrCreateFocusHub();
CHECK_NULL_VOID(focusHub);
focusHub->RequestFocusImmediately();
}
void* PlatformViewPattern::GetNativeWindow(int32_t instanceId, int64_t textureId)
{
auto container = AceEngine::Get().GetContainer(instanceId);
CHECK_NULL_RETURN(container, nullptr);
auto nativeView = container->GetAceView();
CHECK_NULL_RETURN(nativeView, nullptr);
return const_cast<void*>(nativeView->GetNativeWindowById(textureId));
}
void PlatformViewPattern::OnTextureRefresh(void* surface)
{
CHECK_NULL_VOID(surface);
auto renderContextForPlatformView = renderContextForPlatformViewWeakPtr_.Upgrade();
CHECK_NULL_VOID(renderContextForPlatformView);
renderContextForPlatformView->MarkNewFrameAvailable(surface);
UpdatePlatformViewLayoutIfNeeded();
#ifdef IOS_PLATFORM
isTextureReady = true;
#endif
}
void PlatformViewPattern::RegisterPlatformViewEvent()
{
CHECK_NULL_VOID(platformView_);
ContainerScope scope(GetHostInstanceId());
auto context = PipelineContext::GetCurrentContext();
CHECK_NULL_VOID(context);
auto uiTaskExecutor = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::UI);
auto pvPattern = WeakClaim(this);
auto&& textureRefreshEvent = [pvPattern, uiTaskExecutor](int32_t instanceId, int64_t textureId) {
uiTaskExecutor.PostSyncTask(
[&pvPattern, instanceId, textureId] {
auto platformViewPattern = pvPattern.Upgrade();
CHECK_NULL_VOID(platformViewPattern);
void* nativeWindow = platformViewPattern->GetNativeWindow(instanceId, textureId);
if (!nativeWindow) {
LOGE("the native window is nullptr.");
return;
}
platformViewPattern->OnTextureRefresh(nativeWindow);
},
"ArkUIPlatformViewPatternTextureRefreshEvent");
};
platformView_->RegisterTextureEvent(textureRefreshEvent);
auto&& platformViewReadyEvent = [pvPattern, uiTaskExecutor]() {
uiTaskExecutor.PostSyncTask(
[&pvPattern] {
auto platformViewPattern = pvPattern.Upgrade();
CHECK_NULL_VOID(platformViewPattern);
auto host = platformViewPattern->GetHost();
CHECK_NULL_VOID(host);
host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
},
"ArkUIPlatformViewPatternPlatformViewReadyEvent");
};
platformView_->RegisterPlatformViewReadyEvent(platformViewReadyEvent);
}
void PlatformViewPattern::PrepareSurface()
{
if (!platformView_ || renderSurface_->IsSurfaceValid() || !IsTexture()) {
return;
}
if (!SystemProperties::GetExtSurfaceEnabled()) {
renderSurface_->SetRenderContext(renderContextForPlatformView_);
}
renderSurface_->InitSurface();
platformView_->SetRenderSurface(renderSurface_);
}
void PlatformViewPattern::OnAttachToFrameNode()
{
auto host = GetHost();
CHECK_NULL_VOID(host);
auto pipeline = PipelineContext::GetCurrentContext();
CHECK_NULL_VOID(pipeline);
pipeline->AddWindowStateChangedCallback(host->GetId());
if (FrameReport::GetInstance().GetEnable()) {
FrameReport::GetInstance().EnableSelfRender();
}
PlatformViewInitialize();
}
void PlatformViewPattern::PlatformViewInitialize()
{
InitEvent();
platformView_ = AceType::MakeRefPtr<NG::PlatformViewImpl>(id_, data_);
platformView_->InitPlatformView();
platformViewWeakPtr_ = platformView_;
renderContextForPlatformView_ = RenderContext::Create();
auto contextType = RenderContext::ContextType::HARDWARE_SURFACE;
if (IsTexture()) {
renderSurface_ = RenderSurface::Create();
renderSurface_->SetInstanceId(GetHostInstanceId());
renderSurfaceWeakPtr_ = renderSurface_;
contextType = RenderContext::ContextType::HARDWARE_TEXTURE;
}
LOGD("RenderContext contextType: %{public}d", contextType);
RenderContext::ContextParam param = { contextType, "PlatformViewSurface",
RenderContext::PatternType::PLATFORM_VIEW };
renderContextForPlatformView_->InitContext(false, param);
renderContextForPlatformViewWeakPtr_ = renderContextForPlatformView_;
if (IsTexture()) {
PlatformViewAddCallBack();
}
auto host = GetHost();
CHECK_NULL_VOID(host);
auto renderContext = host->GetRenderContext();
CHECK_NULL_VOID(renderContext);
renderContext->UpdateBackgroundColor(Color::WHITE);
renderContextForPlatformView_->UpdateBackgroundColor(Color::WHITE);
renderContext->SetClipToBounds(true);
}
void PlatformViewPattern::PlatformViewAddCallBack()
{
auto OnAttachCallBack = [weak = WeakClaim(this)](int64_t textureId, bool isAttach) mutable {
auto platformViewPattern = weak.Upgrade();
CHECK_NULL_VOID(platformViewPattern);
if (auto renderSurface = platformViewPattern->renderSurfaceWeakPtr_.Upgrade(); renderSurface) {
renderSurface->AttachToGLContext(textureId, isAttach);
}
};
renderContextForPlatformView_->AddAttachCallBack(OnAttachCallBack);
auto OnUpdateCallBack = [weak = WeakClaim(this)](std::vector<float>& matrix) mutable {
auto platformViewPattern = weak.Upgrade();
CHECK_NULL_VOID(platformViewPattern);
#if defined(ANDROID_PLATFORM)
if (auto renderSurface = platformViewPattern->renderSurfaceWeakPtr_.Upgrade(); renderSurface) {
renderSurface->UpdateTextureImage(matrix);
}
#endif
#if defined(IOS_PLATFORM)
if (auto platformView = platformViewPattern->platformViewWeakPtr_.Upgrade(); platformView) {
platformView->ExchangeBind();
}
#endif
};
renderContextForPlatformView_->AddUpdateCallBack(OnUpdateCallBack);
#if defined(IOS_PLATFORM)
auto OnInitTypeCallback = [weak = WeakClaim(this)](int32_t& type) mutable {
auto platformViewPattern = weak.Upgrade();
CHECK_NULL_VOID(platformViewPattern);
if (auto platformView = platformViewPattern->platformViewWeakPtr_.Upgrade(); platformView) {
platformView->GetPlatformViewType(type);
}
};
renderContextForPlatformView_->AddInitTypeCallBack(OnInitTypeCallback);
#endif
#if defined(ANDROID_PLATFORM)
auto OnInitTypeCallback = [weak = WeakClaim(this)](int32_t& type) {
auto platformViewPattern = weak.Upgrade();
CHECK_NULL_VOID(platformViewPattern);
if (auto renderSurface = platformViewPattern->renderSurfaceWeakPtr_.Upgrade(); renderSurface) {
renderSurface->AddInitTypeCallBack(type);
}
};
renderContextForPlatformView_->AddInitTypeCallBack(OnInitTypeCallback);
#endif
}
void PlatformViewPattern::OnAreaChangedInner()
{
auto host = GetHost();
CHECK_NULL_VOID(host);
auto context = host->GetRenderContext();
auto rect = context->GetPaintRectWithoutTransform();
auto offset = rect.GetOffset();
auto parent = host->GetAncestorNodeOfFrame(true);
while (parent) {
auto parentRenderContext = parent->GetRenderContext();
offset += parentRenderContext->GetPaintRectWithoutTransform().GetOffset();
parent = parent->GetAncestorNodeOfFrame(true);
}
platformView_->UpdatePlatformViewLayout(rect.GetSize(), offset);
}
void PlatformViewPattern::OnModifyDone()
{
ContainerScope scope(GetHostInstanceId());
auto context = PipelineContext::GetCurrentContext();
CHECK_NULL_VOID(context);
auto host = GetHost();
CHECK_NULL_VOID(host);
context->AddOnAreaChangeNode(host->GetId());
if (!IsTexture()) {
platformView_->RegisterPlatformView();
return;
}
auto platformTask = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::BACKGROUND);
platformTask.PostTask(
[weak = WeakClaim(this)] {
auto platformViewPattern = weak.Upgrade();
CHECK_NULL_VOID(platformViewPattern);
platformViewPattern->RegisterPlatformViewEvent();
platformViewPattern->PrepareSurface();
},
"ArkUIPlatformViewPatternOnModifyDone");
}
void PlatformViewPattern::OnRebuildFrame()
{
auto host = GetHost();
CHECK_NULL_VOID(host);
auto renderContext = host->GetRenderContext();
CHECK_NULL_VOID(renderContext);
CHECK_NULL_VOID(renderContextForPlatformView_);
renderContext->AddChild(renderContextForPlatformView_, 0);
}
void PlatformViewPattern::OnDetachFromFrameNode(FrameNode* frameNode)
{
CHECK_NULL_VOID(frameNode);
if (!hasPlatformViewInit_) {
return;
}
auto id = frameNode->GetId();
auto pipeline = AceType::DynamicCast<PipelineContext>(PipelineBase::GetCurrentContext());
CHECK_NULL_VOID(pipeline);
pipeline->RemoveWindowStateChangedCallback(id);
if (FrameReport::GetInstance().GetEnable()) {
FrameReport::GetInstance().DisableSelfRender();
}
}
void PlatformViewPattern::OnAttachContext(PipelineContext* context)
{
CHECK_NULL_VOID(context);
auto host = GetHost();
CHECK_NULL_VOID(host);
context->AddWindowStateChangedCallback(host->GetId());
}
void PlatformViewPattern::OnDetachContext(PipelineContext* context)
{
CHECK_NULL_VOID(context);
auto host = GetHost();
CHECK_NULL_VOID(host);
context->RemoveWindowStateChangedCallback(host->GetId());
}
void PlatformViewPattern::BeforeSyncGeometryProperties(const DirtySwapConfig& config)
{
if (config.skipMeasure) {
return;
}
auto host = GetHost();
CHECK_NULL_VOID(host);
auto geometryNode = host->GetGeometryNode();
CHECK_NULL_VOID(geometryNode);
drawSize_ = geometryNode->GetContentSize();
if (!drawSize_.IsPositive()) {
LOGW("PlatformView[%{public}s]'s size is not positive", id_.c_str());
return;
}
localPosition_ = geometryNode->GetContentOffset();
if (!hasPlatformViewInit_) {
hasPlatformViewInit_ = true;
}
#ifdef IOS_PLATFORM
isTextureReady = false;
#endif
UpdatePlatformViewLayoutIfNeeded();
host->MarkNeedSyncRenderTree();
}
void PlatformViewPattern::UpdatePlatformViewLayoutIfNeeded()
{
auto host = GetHost();
CHECK_NULL_VOID(host);
auto transformRelativeOffset = host->GetTransformRelativeOffset();
OffsetF offset = localPosition_ + transformRelativeOffset;
auto rect = GetRenderContext()->GetPaintRectWithoutTransform();
if (lastDrawSize_ != drawSize_ || lastOffset_ != offset) {
platformView_->UpdatePlatformViewLayout(rect.GetSize(), rect.GetOffset());
#ifdef IOS_PLATFORM
if (!isTextureReady) {
return;
}
#endif
if (renderContextForPlatformView_) {
renderContextForPlatformView_->SetBounds(
localPosition_.GetX(), localPosition_.GetY(), drawSize_.Width(), drawSize_.Height());
}
if (SystemProperties::GetExtSurfaceEnabled() && IsTexture()) {
renderSurface_->SetExtSurfaceBounds(transformRelativeOffset.GetX() + localPosition_.GetX(),
transformRelativeOffset.GetY() + localPosition_.GetY(), drawSize_.Width(), drawSize_.Height());
}
lastDrawSize_ = drawSize_;
lastOffset_ = offset;
}
}
void PlatformViewPattern::DumpInfo()
{
DumpLog::GetInstance().AddDesc(std::string("paltformviewId: ").append(id_));
}
void PlatformViewPattern::InitEvent()
{
auto host = GetHost();
CHECK_NULL_VOID(host);
auto eventHub = host->GetEventHub<PlatformViewEventHub>();
CHECK_NULL_VOID(eventHub);
auto gestureHub = eventHub->GetOrCreateGestureEventHub();
CHECK_NULL_VOID(gestureHub);
InitTouchEvent(gestureHub);
#if defined(ANDROID_PLATFORM)
InitPanGesture(gestureHub);
#endif
auto focusHub = host->GetOrCreateFocusHub();
CHECK_NULL_VOID(focusHub);
InitFocusEvent(focusHub);
}
void PlatformViewPattern::InitPanGesture(const RefPtr<GestureEventHub>& gestureHub)
{
if (!gestureHub) {
return;
}
if (panGesture_) {
if (gestureHub->WillRecreateGesture()) {
gestureHub->AddGesture(panGesture_);
}
return;
}
auto option = MakeRefPtr<PanGestureOption>();
PanDirection panDirection;
panDirection.type = PanDirection::ALL;
option->SetDirection(panDirection);
option->SetDistance(0.0);
option->SetFingers(1);
panGesture_ = MakeRefPtr<PanGesture>(option);
CHECK_NULL_VOID(panGesture_);
panGesture_->SetPriority(GesturePriority::High);
gestureHub->AddGesture(panGesture_);
}
void PlatformViewPattern::InitFocusEvent(const RefPtr<FocusHub>& focusHub)
{
CHECK_NULL_VOID(focusHub);
focusHub->SetFocusable(true);
}
void PlatformViewPattern::InitTouchEvent(const RefPtr<GestureEventHub>& gestureHub)
{
CHECK_NULL_VOID(!touchEvent_);
auto touchTask = [weak = WeakClaim(this)](const TouchEventInfo& info) {
auto pattern = weak.Upgrade();
CHECK_NULL_VOID(pattern);
pattern->HandleTouchEvent(info);
};
touchEvent_ = MakeRefPtr<TouchEventImpl>(std::move(touchTask));
gestureHub->AddTouchEvent(touchEvent_);
}
void PlatformViewPattern::HandleTouchEvent(const TouchEventInfo& info)
{
auto touchInfoList = info.GetChangedTouches();
if (touchInfoList.empty()) {
return;
}
auto touchType = touchInfoList.front().GetTouchType();
if (touchType == TouchType::DOWN) {
RequestFocus();
}
const auto& changedPoint = touchInfoList.front();
PlatformViewDispatchTouchEvent(changedPoint);
}
void PlatformViewPattern::PlatformViewDispatchTouchEvent(const TouchLocationInfo& changedPoint)
{
CHECK_NULL_VOID(platformView_);
auto host = GetHost();
CHECK_NULL_VOID(host);
auto transformRelativeOffset = host->GetTransformRelativeOffset();
NG::OffsetF pointOffset = localPosition_ + transformRelativeOffset;
if (changedPoint.GetTouchType() == TouchType::DOWN) {
platformView_->HandleTouchDown(pointOffset);
} else if (changedPoint.GetTouchType() == TouchType::MOVE) {
platformView_->HandleTouchMove(pointOffset);
} else if (changedPoint.GetTouchType() == TouchType::UP) {
platformView_->HandleTouchUp(pointOffset);
} else if (changedPoint.GetTouchType() == TouchType::CANCEL) {
platformView_->HandleTouchCancel(pointOffset);
}
}
void PlatformViewPattern::SetScale(float x, float y, float z, const std::string& centerX, const std::string& centerY)
{
CHECK_NULL_VOID(platformView_);
platformView_->SetScale(x, y, z, centerX, centerY);
}
void PlatformViewPattern::SetRotation(float x, float y, float z, const std::string& angle, const std::string& centerX,
const std::string& centerY, const std::string& centerZ, const std::string& perspective)
{
CHECK_NULL_VOID(platformView_);
platformView_->SetRotation(x, y, z, angle, centerX, centerY, centerZ, perspective);
}
void PlatformViewPattern::SetTranslate(const std::string& x, const std::string& y, const std::string& z)
{
CHECK_NULL_VOID(platformView_);
platformView_->SetTranslate(x, y, z);
}
void PlatformViewPattern::SetTransformMatrix(const std::vector<float>& matrix)
{
CHECK_NULL_VOID(platformView_);
platformView_->SetTransformMatrix(matrix);
}
}