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