• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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