1 /*
2 * Copyright (c) 2021-2022 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/pipeline/base/rosen_render_context.h"
17
18 #include "core/pipeline/base/render_sub_container.h"
19 #include "render_service_client/core/ui/rs_canvas_node.h"
20
21 namespace OHOS::Ace {
22 namespace {
23
24 constexpr int32_t OVERFLOW_PLATFORM_VERSION = 7;
25
ShouldPaint(const RefPtr<RenderNode> & node)26 inline bool ShouldPaint(const RefPtr<RenderNode>& node)
27 {
28 return node != nullptr && node->GetVisible() && !node->GetHidden();
29 }
30
31 } // namespace
32
~RosenRenderContext()33 RosenRenderContext::~RosenRenderContext()
34 {
35 StopRecordingIfNeeded();
36 }
37
Repaint(const RefPtr<RenderNode> & node)38 void RosenRenderContext::Repaint(const RefPtr<RenderNode>& node)
39 {
40 if (!ShouldPaint(node) || !node->NeedRender() || node->GetRSNode() == nullptr) {
41 return;
42 }
43
44 auto rsNode = node->GetRSNode();
45 auto offset =
46 node->GetTransitionPaintRect().GetOffset() -
47 Offset(rsNode->GetStagingProperties().GetFrame().x_, rsNode->GetStagingProperties().GetFrame().y_);
48
49 std::string name = AceType::TypeName(node);
50 if (name != "RosenRenderForm" && name != "RosenRenderPlugin") {
51 InitContext(rsNode, node->GetRectWithShadow(), offset);
52 node->RenderWithContext(*this, offset);
53 UpdateChildren(rsNode);
54 } else {
55 node->RenderWithContext(*this, offset);
56 }
57 StopRecordingIfNeeded();
58 }
59
PaintChild(const RefPtr<RenderNode> & child,const Offset & offset)60 void RosenRenderContext::PaintChild(const RefPtr<RenderNode>& child, const Offset& offset)
61 {
62 if (!ShouldPaint(child)) {
63 return;
64 }
65 auto pipelineContext = child->GetContext().Upgrade();
66 if (!pipelineContext) {
67 LOGE("pipelineContext is null.");
68 return;
69 }
70 bool canChildOverflow = pipelineContext->GetMinPlatformVersion() >= OVERFLOW_PLATFORM_VERSION;
71 Rect rect = child->GetTransitionPaintRect() + offset;
72 if (!(child->IsPaintOutOfParent() || canChildOverflow) && !estimatedRect_.IsIntersectWith(rect)) {
73 #if defined(PREVIEW)
74 child->ClearAccessibilityRect();
75 #endif
76 return;
77 }
78
79 auto childRSNode = child->GetRSNode();
80 if (childRSNode && childRSNode != rsNode_) {
81 childNodes_.emplace_back(childRSNode);
82 std::string name = AceType::TypeName(child);
83 if (name != "RosenRenderForm" && name != "RosenRenderPlugin") {
84 if (child->NeedRender()) {
85 RosenRenderContext context;
86 auto transparentHole = pipelineContext->GetTransparentHole();
87 if (transparentHole.IsValid() && child->GetNeedClip()) {
88 Offset childOffset = rect.GetOffset();
89 Rect hole = transparentHole - childOffset;
90 context.SetClipHole(hole);
91 }
92 context.Repaint(child);
93 } else {
94 // No need to repaint, notify to update AccessibilityNode info.
95 child->NotifyPaintFinish();
96 }
97 }
98 Offset pos = rect.GetOffset();
99 if (name == "RosenRenderPlugin") {
100 auto renderPlugin = AceType::DynamicCast<RenderSubContainer>(child);
101 if (!renderPlugin) {
102 return;
103 }
104 auto pluginContext = renderPlugin->GetSubPipelineContext();
105 if (!pluginContext) {
106 return;
107 }
108 auto density = pipelineContext->GetDensity();
109 Offset pluginOffset = {pos.GetX() / density, pos.GetY() / density};
110 pluginContext->SetPluginEventOffset(child->GetGlobalOffset());
111 }
112 } else {
113 child->RenderWithContext(*this, rect.GetOffset());
114 }
115 }
116
StartRecording()117 void RosenRenderContext::StartRecording()
118 {
119 recordingCanvas_ = new Rosen::Drawing::RecordingCanvas(estimatedRect_.Width(), estimatedRect_.Height());
120 if (clipHole_.IsValid()) {
121 recordingCanvas_->Save();
122 needRestoreHole_ = true;
123 recordingCanvas_->ClipRect(
124 RSRect(clipHole_.Left(), clipHole_.Top(), clipHole_.Right(), clipHole_.Bottom()),
125 RSClipOp::DIFFERENCE, true);
126 }
127 }
128
StopRecordingIfNeeded()129 void RosenRenderContext::StopRecordingIfNeeded()
130 {
131 auto rsCanvasNode = RSNode::ReinterpretCast<Rosen::RSCanvasNode>(rsNode_);
132 if (rosenCanvas_ && rsCanvasNode) {
133 rsCanvasNode->FinishRecording();
134 rosenCanvas_ = nullptr;
135 }
136
137 if (needRestoreHole_) {
138 recordingCanvas_->Restore();
139 needRestoreHole_ = false;
140 }
141
142 if (IsRecording()) {
143 delete recordingCanvas_;
144 recordingCanvas_ = nullptr;
145 }
146 }
147
IsIntersectWith(const RefPtr<RenderNode> & child,Offset & offset)148 bool RosenRenderContext::IsIntersectWith(const RefPtr<RenderNode>& child, Offset& offset)
149 {
150 if (!ShouldPaint(child)) {
151 return false;
152 }
153
154 Rect rect = child->GetTransitionPaintRect() + offset;
155 if (!estimatedRect_.IsIntersectWith(rect)) {
156 #if defined(PREVIEW)
157 child->ClearAccessibilityRect();
158 #endif
159 return false;
160 }
161
162 offset = rect.GetOffset();
163 return true;
164 }
165
InitContext(const std::shared_ptr<RSNode> & rsNode,const Rect & rect,const Offset & initialOffset)166 void RosenRenderContext::InitContext(
167 const std::shared_ptr<RSNode>& rsNode, const Rect& rect, const Offset& initialOffset)
168 {
169 rsNode_ = rsNode;
170 estimatedRect_ = rect + initialOffset;
171 if (rsNode_ == nullptr) {
172 return;
173 }
174 childNodes_.clear();
175 if (auto rsCanvasNode = rsNode_->ReinterpretCastTo<Rosen::RSCanvasNode>()) {
176 rosenCanvas_ = rsCanvasNode->BeginRecording(rsCanvasNode->GetPaintWidth(), rsCanvasNode->GetPaintHeight());
177 }
178 }
179
GetCanvas()180 RSCanvas* RosenRenderContext::GetCanvas()
181 {
182 // if recording, return recording canvas
183 return recordingCanvas_ ? recordingCanvas_ : rosenCanvas_;
184 }
185
GetRSNode()186 const std::shared_ptr<RSNode>& RosenRenderContext::GetRSNode()
187 {
188 return rsNode_;
189 }
190
FinishRecordingAsPicture()191 std::shared_ptr<RSPicture> RosenRenderContext::FinishRecordingAsPicture()
192 {
193 LOGE("Drawing is not supported");
194 return nullptr;
195 }
196
FinishRecordingAsImage()197 std::shared_ptr<RSImage> RosenRenderContext::FinishRecordingAsImage()
198 {
199 LOGE("Drawing is not supported");
200 return nullptr;
201 }
202
Restore()203 void RosenRenderContext::Restore()
204 {
205 auto canvas = GetCanvas();
206 if (canvas != nullptr) {
207 canvas->Restore();
208 }
209 }
210
UpdateChildren(const std::shared_ptr<RSNode> & rsNode)211 void RosenRenderContext::UpdateChildren(const std::shared_ptr<RSNode>& rsNode)
212 {
213 std::vector<OHOS::Rosen::NodeId> childNodeIds;
214 for (auto& child : childNodes_) {
215 if (auto childNode = child.lock()) {
216 childNodeIds.emplace_back(childNode->GetId());
217 }
218 }
219 if (childNodeIds != rsNode->GetChildren()) {
220 rsNode->ClearChildren();
221 for (auto& child : childNodes_) {
222 rsNode->AddChild(child.lock());
223 }
224 }
225 }
226 } // namespace OHOS::Ace
227