• 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/flutter_render_context.h"
17 
18 #include "core/components/plugin/render_plugin.h"
19 #include "core/pipeline/base/render_node.h"
20 #include "core/pipeline/base/render_sub_container.h"
21 
22 namespace OHOS::Ace {
23 namespace {
24 
25 constexpr int32_t OVERFLOW_PLATFORM_VERSION = 7;
26 
ShouldPaint(const RefPtr<RenderNode> & node)27 inline bool ShouldPaint(const RefPtr<RenderNode>& node)
28 {
29     return node != nullptr && node->GetVisible() && !node->GetHidden();
30 }
31 
32 } // namespace
33 
34 using namespace Flutter;
35 
~FlutterRenderContext()36 FlutterRenderContext::~FlutterRenderContext()
37 {
38     StopRecordingIfNeeded();
39 }
40 
Repaint(const RefPtr<RenderNode> & node)41 void FlutterRenderContext::Repaint(const RefPtr<RenderNode>& node)
42 {
43     if (!ShouldPaint(node) || !node->NeedRender() || !node->GetRenderLayer()) {
44         return;
45     }
46     InitContext(node->GetRenderLayer(), node->GetRectWithShadow());
47     node->RenderWithContext(*this, Offset::Zero());
48     StopRecordingIfNeeded();
49 }
50 
PaintChild(const RefPtr<RenderNode> & child,const Offset & offset)51 void FlutterRenderContext::PaintChild(const RefPtr<RenderNode>& child, const Offset& offset)
52 {
53     if (!ShouldPaint(child)) {
54         return;
55     }
56 
57     bool canChildOverflow = false;
58     auto pipeline = child->GetContext().Upgrade();
59     if (pipeline) {
60         canChildOverflow = pipeline->GetMinPlatformVersion() >= OVERFLOW_PLATFORM_VERSION;
61     }
62 
63     Rect rect = child->GetTransitionPaintRect() + offset;
64     if (!(child->IsPaintOutOfParent() || canChildOverflow) && !estimatedRect_.IsIntersectWith(rect)) {
65 #if defined(PREVIEW)
66         child->ClearAccessibilityRect();
67 #endif
68         return;
69     }
70 
71     if (child->GetRenderLayer()) {
72         StopRecordingIfNeeded();
73         std::string name = AceType::TypeName(child);
74         if (name != "FlutterRenderForm" && name != "FlutterRenderPlugin") {
75             if (child->NeedRender()) {
76                 FlutterRenderContext context;
77                 auto pipelineContext = child->GetContext().Upgrade();
78                 auto transparentHole = pipelineContext->GetTransparentHole();
79                 if (transparentHole.IsValid() && child->GetNeedClip()) {
80                     Offset childOffset = rect.GetOffset();
81                     Rect hole = transparentHole - childOffset;
82                     context.SetClipHole(hole);
83                 }
84                 context.Repaint(child);
85             } else {
86                 // No need to repaint, notify to update AccessibilityNode info.
87                 child->NotifyPaintFinish();
88             }
89         }
90         // add child layer to parent layer
91         OffsetLayer* layer = CastLayerAs<OffsetLayer>(child->GetRenderLayer());
92         if (!layer) {
93             LOGE("layer is null");
94             return;
95         }
96         Offset pos = rect.GetOffset();
97         if (name != "FlutterRenderForm" && name != "FlutterRenderPlugin") {
98             layer->SetOffset(pos.GetX(), pos.GetY());
99         } else {
100             SetOffSet(child, layer, pos, name);
101         }
102         containerLayer_->AddChildren(AceType::Claim(layer));
103     } else {
104         child->RenderWithContext(*this, rect.GetOffset());
105     }
106 }
107 
SetOffSet(const RefPtr<RenderNode> & child,OffsetLayer * layer,const Offset & pos,const std::string & name)108 void FlutterRenderContext::SetOffSet(
109     const RefPtr<RenderNode>& child, OffsetLayer* layer, const Offset& pos, const std::string& name)
110 {
111     if (!child || !layer) {
112         LOGE("child is nullptr, or layer is nullptr");
113         return;
114     }
115 
116     auto renderPost = child->GetGlobalOffset();
117     auto context = child->GetContext().Upgrade();
118     if (context) {
119         auto density = context->GetDensity();
120         auto parent = child->GetParent();
121         Offset pluginOffset = { 0, 0 };
122         if (!NearZero(density)) {
123             if (parent.Upgrade() && parent.Upgrade()->GetRenderLayer()) {
124                 layer->SetOffset(
125                     renderPost.GetX() / density - renderPost.GetX(), renderPost.GetY() / density - renderPost.GetY());
126                 pluginOffset = { renderPost.GetX() / density - renderPost.GetX(),
127                     renderPost.GetY() / density - renderPost.GetY() };
128             } else {
129                 layer->SetOffset(pos.GetX() / density, pos.GetY() / density);
130                 pluginOffset = { pos.GetX() / density, pos.GetY() / density };
131             }
132         }
133         // plugin offset
134         if (name == "FlutterRenderPlugin" || name == "FlutterRenderForm") {
135             auto renderPlugin = AceType::DynamicCast<RenderSubContainer>(child);
136             if (!renderPlugin) {
137                 return;
138             }
139             auto pluginContext = renderPlugin->GetSubPipelineContext();
140             if (!pluginContext) {
141                 return;
142             }
143             pluginContext->SetPluginEventOffset(renderPost);
144             pluginContext->SetPluginOffset(pluginOffset);
145         }
146     }
147 }
148 
StartRecording()149 void FlutterRenderContext::StartRecording()
150 {
151     currentLayer_ = AceType::MakeRefPtr<PictureLayer>();
152     recorder_ = flutter::PictureRecorder::Create();
153     canvas_ = flutter::Canvas::Create(
154         recorder_.get(), estimatedRect_.Left(), estimatedRect_.Top(), estimatedRect_.Right(), estimatedRect_.Bottom());
155     if (clipHole_.IsValid()) {
156         canvas_->save();
157         needRestoreHole_ = true;
158         canvas_->clipRect(
159             clipHole_.Left(), clipHole_.Top(), clipHole_.Right(), clipHole_.Bottom(), SkClipOp::kDifference);
160     }
161     containerLayer_->AddChildren(currentLayer_);
162 }
163 
StopRecordingIfNeeded()164 void FlutterRenderContext::StopRecordingIfNeeded()
165 {
166     if (!IsRecording()) {
167         return;
168     }
169 
170     if (needRestoreHole_) {
171         canvas_->restore();
172         needRestoreHole_ = false;
173     }
174     currentLayer_->SetPicture(recorder_->endRecording());
175     currentLayer_ = nullptr;
176     recorder_ = nullptr;
177     canvas_ = nullptr;
178 }
179 
IsIntersectWith(const RefPtr<RenderNode> & child,Offset & offset)180 bool FlutterRenderContext::IsIntersectWith(const RefPtr<RenderNode>& child, Offset& offset)
181 {
182     if (!ShouldPaint(child)) {
183         return false;
184     }
185 
186     Rect rect = child->GetTransitionPaintRect() + offset;
187     if (!estimatedRect_.IsIntersectWith(rect)) {
188 #if defined(PREVIEW)
189         child->ClearAccessibilityRect();
190 #endif
191         return false;
192     }
193 
194     offset = rect.GetOffset();
195     return true;
196 }
197 
InitContext(RenderLayer layer,const Rect & rect)198 void FlutterRenderContext::InitContext(RenderLayer layer, const Rect& rect)
199 {
200     estimatedRect_ = rect;
201     containerLayer_ = CastLayerAs<ContainerLayer>(layer);
202     containerLayer_->RemoveChildren();
203 }
204 
GetCanvas()205 flutter::Canvas* FlutterRenderContext::GetCanvas()
206 {
207     if (!IsRecording()) {
208         StartRecording();
209     }
210     return canvas_.get();
211 }
212 
Restore()213 void FlutterRenderContext::Restore()
214 {
215     auto canvas = GetCanvas();
216     if (canvas != nullptr) {
217         canvas->restore();
218     }
219 }
220 
221 } // namespace OHOS::Ace
222