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