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