• 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 #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