• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "flutter/flow/scene_update_context.h"
6 
7 #include "flutter/flow/layers/layer.h"
8 #include "flutter/flow/matrix_decomposition.h"
9 #include "flutter/fml/trace_event.h"
10 
11 namespace flutter {
12 
13 // Helper function to generate clip planes for a scenic::EntityNode.
SetEntityNodeClipPlanes(scenic::EntityNode & entity_node,const SkRect & bounds)14 static void SetEntityNodeClipPlanes(scenic::EntityNode& entity_node,
15                                     const SkRect& bounds) {
16   const float top = bounds.top();
17   const float bottom = bounds.bottom();
18   const float left = bounds.left();
19   const float right = bounds.right();
20 
21   // We will generate 4 oriented planes, one for each edge of the bounding rect.
22   std::vector<fuchsia::ui::gfx::Plane3> clip_planes;
23   clip_planes.resize(4);
24 
25   // Top plane.
26   clip_planes[0].dist = top;
27   clip_planes[0].dir.x = 0.f;
28   clip_planes[0].dir.y = 1.f;
29   clip_planes[0].dir.z = 0.f;
30 
31   // Bottom plane.
32   clip_planes[1].dist = -bottom;
33   clip_planes[1].dir.x = 0.f;
34   clip_planes[1].dir.y = -1.f;
35   clip_planes[1].dir.z = 0.f;
36 
37   // Left plane.
38   clip_planes[2].dist = left;
39   clip_planes[2].dir.x = 1.f;
40   clip_planes[2].dir.y = 0.f;
41   clip_planes[2].dir.z = 0.f;
42 
43   // Right plane.
44   clip_planes[3].dist = -right;
45   clip_planes[3].dir.x = -1.f;
46   clip_planes[3].dir.y = 0.f;
47   clip_planes[3].dir.z = 0.f;
48 
49   entity_node.SetClipPlanes(std::move(clip_planes));
50 }
51 
SceneUpdateContext(scenic::Session * session,SurfaceProducer * surface_producer)52 SceneUpdateContext::SceneUpdateContext(scenic::Session* session,
53                                        SurfaceProducer* surface_producer)
54     : session_(session), surface_producer_(surface_producer) {
55   FML_DCHECK(surface_producer_ != nullptr);
56 }
57 
CreateFrame(scenic::EntityNode entity_node,scenic::ShapeNode shape_node,const SkRRect & rrect,SkColor color,const SkRect & paint_bounds,std::vector<Layer * > paint_layers,Layer * layer)58 void SceneUpdateContext::CreateFrame(scenic::EntityNode entity_node,
59                                      scenic::ShapeNode shape_node,
60                                      const SkRRect& rrect,
61                                      SkColor color,
62                                      const SkRect& paint_bounds,
63                                      std::vector<Layer*> paint_layers,
64                                      Layer* layer) {
65   // Frames always clip their children.
66   SetEntityNodeClipPlanes(entity_node, rrect.getBounds());
67   // TODO(SCN-1274): SetClip() will be deleted.
68   entity_node.SetClip(0u, true /* clip to self */);
69 
70   // We don't need a shape if the frame is zero size.
71   if (rrect.isEmpty())
72     return;
73 
74   // Add a part which represents the frame's geometry for clipping purposes
75   // and possibly for its texture.
76   // TODO(SCN-137): Need to be able to express the radii as vectors.
77   SkRect shape_bounds = rrect.getBounds();
78   scenic::RoundedRectangle shape(
79       session_,                                      // session
80       rrect.width(),                                 // width
81       rrect.height(),                                // height
82       rrect.radii(SkRRect::kUpperLeft_Corner).x(),   // top_left_radius
83       rrect.radii(SkRRect::kUpperRight_Corner).x(),  // top_right_radius
84       rrect.radii(SkRRect::kLowerRight_Corner).x(),  // bottom_right_radius
85       rrect.radii(SkRRect::kLowerLeft_Corner).x()    // bottom_left_radius
86   );
87   shape_node.SetShape(shape);
88   shape_node.SetTranslation(shape_bounds.width() * 0.5f + shape_bounds.left(),
89                             shape_bounds.height() * 0.5f + shape_bounds.top(),
90                             0.f);
91 
92   // Check whether the painted layers will be visible.
93   if (paint_bounds.isEmpty() || !paint_bounds.intersects(shape_bounds))
94     paint_layers.clear();
95 
96   // Check whether a solid color will suffice.
97   if (paint_layers.empty()) {
98     SetShapeColor(shape_node, color);
99     return;
100   }
101 
102   // Apply current metrics and transformation scale factors.
103   const float scale_x = ScaleX();
104   const float scale_y = ScaleY();
105 
106   // Apply a texture to the whole shape.
107   SetShapeTextureAndColor(shape_node, color, scale_x, scale_y, shape_bounds,
108                           std::move(paint_layers), layer,
109                           std::move(entity_node));
110 }
111 
SetShapeTextureAndColor(scenic::ShapeNode & shape_node,SkColor color,SkScalar scale_x,SkScalar scale_y,const SkRect & paint_bounds,std::vector<Layer * > paint_layers,Layer * layer,scenic::EntityNode entity_node)112 void SceneUpdateContext::SetShapeTextureAndColor(
113     scenic::ShapeNode& shape_node,
114     SkColor color,
115     SkScalar scale_x,
116     SkScalar scale_y,
117     const SkRect& paint_bounds,
118     std::vector<Layer*> paint_layers,
119     Layer* layer,
120     scenic::EntityNode entity_node) {
121   scenic::Image* image = GenerateImageIfNeeded(
122       color, scale_x, scale_y, paint_bounds, std::move(paint_layers), layer,
123       std::move(entity_node));
124   if (image != nullptr) {
125     scenic::Material material(session_);
126     material.SetTexture(*image);
127     shape_node.SetMaterial(material);
128     return;
129   }
130 
131   SetShapeColor(shape_node, color);
132 }
133 
SetShapeColor(scenic::ShapeNode & shape_node,SkColor color)134 void SceneUpdateContext::SetShapeColor(scenic::ShapeNode& shape_node,
135                                        SkColor color) {
136   if (SkColorGetA(color) == 0)
137     return;
138 
139   scenic::Material material(session_);
140   material.SetColor(SkColorGetR(color), SkColorGetG(color), SkColorGetB(color),
141                     SkColorGetA(color));
142   shape_node.SetMaterial(material);
143 }
144 
GenerateImageIfNeeded(SkColor color,SkScalar scale_x,SkScalar scale_y,const SkRect & paint_bounds,std::vector<Layer * > paint_layers,Layer * layer,scenic::EntityNode entity_node)145 scenic::Image* SceneUpdateContext::GenerateImageIfNeeded(
146     SkColor color,
147     SkScalar scale_x,
148     SkScalar scale_y,
149     const SkRect& paint_bounds,
150     std::vector<Layer*> paint_layers,
151     Layer* layer,
152     scenic::EntityNode entity_node) {
153   // Bail if there's nothing to paint.
154   if (paint_layers.empty())
155     return nullptr;
156 
157   // Bail if the physical bounds are empty after rounding.
158   SkISize physical_size = SkISize::Make(paint_bounds.width() * scale_x,
159                                         paint_bounds.height() * scale_y);
160   if (physical_size.isEmpty())
161     return nullptr;
162 
163   // Acquire a surface from the surface producer and register the paint tasks.
164   std::unique_ptr<SurfaceProducerSurface> surface =
165       surface_producer_->ProduceSurface(
166           physical_size,
167           LayerRasterCacheKey(
168               // Root frame has a nullptr layer
169               layer ? layer->unique_id() : 0, Matrix()),
170           std::make_unique<scenic::EntityNode>(std::move(entity_node)));
171 
172   if (!surface) {
173     FML_LOG(ERROR) << "Could not acquire a surface from the surface producer "
174                       "of size: "
175                    << physical_size.width() << "x" << physical_size.height();
176     return nullptr;
177   }
178 
179   auto image = surface->GetImage();
180 
181   // Enqueue the paint task.
182   paint_tasks_.push_back({.surface = std::move(surface),
183                           .left = paint_bounds.left(),
184                           .top = paint_bounds.top(),
185                           .scale_x = scale_x,
186                           .scale_y = scale_y,
187                           .background_color = color,
188                           .layers = std::move(paint_layers)});
189   return image;
190 }
191 
192 std::vector<
193     std::unique_ptr<flutter::SceneUpdateContext::SurfaceProducerSurface>>
ExecutePaintTasks(CompositorContext::ScopedFrame & frame)194 SceneUpdateContext::ExecutePaintTasks(CompositorContext::ScopedFrame& frame) {
195   TRACE_EVENT0("flutter", "SceneUpdateContext::ExecutePaintTasks");
196   std::vector<std::unique_ptr<SurfaceProducerSurface>> surfaces_to_submit;
197   for (auto& task : paint_tasks_) {
198     FML_DCHECK(task.surface);
199     SkCanvas* canvas = task.surface->GetSkiaSurface()->getCanvas();
200     Layer::PaintContext context = {canvas,
201                                    canvas,
202                                    frame.gr_context(),
203                                    nullptr,
204                                    frame.context().raster_time(),
205                                    frame.context().ui_time(),
206                                    frame.context().texture_registry(),
207                                    &frame.context().raster_cache(),
208                                    false};
209     canvas->restoreToCount(1);
210     canvas->save();
211     canvas->clear(task.background_color);
212     canvas->scale(task.scale_x, task.scale_y);
213     canvas->translate(-task.left, -task.top);
214     for (Layer* layer : task.layers) {
215       layer->Paint(context);
216     }
217     surfaces_to_submit.emplace_back(std::move(task.surface));
218   }
219   paint_tasks_.clear();
220   return surfaces_to_submit;
221 }
222 
Entity(SceneUpdateContext & context)223 SceneUpdateContext::Entity::Entity(SceneUpdateContext& context)
224     : context_(context),
225       previous_entity_(context.top_entity_),
226       entity_node_(context.session()) {
227   if (previous_entity_)
228     previous_entity_->embedder_node().AddChild(entity_node_);
229   context.top_entity_ = this;
230 }
231 
~Entity()232 SceneUpdateContext::Entity::~Entity() {
233   FML_DCHECK(context_.top_entity_ == this);
234   context_.top_entity_ = previous_entity_;
235 }
236 
Transform(SceneUpdateContext & context,const SkMatrix & transform)237 SceneUpdateContext::Transform::Transform(SceneUpdateContext& context,
238                                          const SkMatrix& transform)
239     : Entity(context),
240       previous_scale_x_(context.top_scale_x_),
241       previous_scale_y_(context.top_scale_y_) {
242   if (!transform.isIdentity()) {
243     // TODO(SCN-192): The perspective and shear components in the matrix
244     // are not handled correctly.
245     MatrixDecomposition decomposition(transform);
246     if (decomposition.IsValid()) {
247       entity_node().SetTranslation(decomposition.translation().x(),  //
248                                    decomposition.translation().y(),  //
249                                    -decomposition.translation().z()  //
250       );
251 
252       entity_node().SetScale(decomposition.scale().x(),  //
253                              decomposition.scale().y(),  //
254                              decomposition.scale().z()   //
255       );
256       context.top_scale_x_ *= decomposition.scale().x();
257       context.top_scale_y_ *= decomposition.scale().y();
258 
259       entity_node().SetRotation(decomposition.rotation().fData[0],  //
260                                 decomposition.rotation().fData[1],  //
261                                 decomposition.rotation().fData[2],  //
262                                 decomposition.rotation().fData[3]   //
263       );
264     }
265   }
266 }
267 
Transform(SceneUpdateContext & context,float scale_x,float scale_y,float scale_z)268 SceneUpdateContext::Transform::Transform(SceneUpdateContext& context,
269                                          float scale_x,
270                                          float scale_y,
271                                          float scale_z)
272     : Entity(context),
273       previous_scale_x_(context.top_scale_x_),
274       previous_scale_y_(context.top_scale_y_) {
275   if (scale_x != 1.f || scale_y != 1.f || scale_z != 1.f) {
276     entity_node().SetScale(scale_x, scale_y, scale_z);
277     context.top_scale_x_ *= scale_x;
278     context.top_scale_y_ *= scale_y;
279   }
280 }
281 
~Transform()282 SceneUpdateContext::Transform::~Transform() {
283   context().top_scale_x_ = previous_scale_x_;
284   context().top_scale_y_ = previous_scale_y_;
285 }
286 
Shape(SceneUpdateContext & context)287 SceneUpdateContext::Shape::Shape(SceneUpdateContext& context)
288     : Entity(context), shape_node_(context.session()) {
289   entity_node().AddChild(shape_node_);
290 }
291 
Frame(SceneUpdateContext & context,const SkRRect & rrect,SkColor color,float local_elevation,float world_elevation,float depth,Layer * layer)292 SceneUpdateContext::Frame::Frame(SceneUpdateContext& context,
293                                  const SkRRect& rrect,
294                                  SkColor color,
295                                  float local_elevation,
296                                  float world_elevation,
297                                  float depth,
298                                  Layer* layer)
299     : Shape(context),
300       rrect_(rrect),
301       color_(color),
302       paint_bounds_(SkRect::MakeEmpty()),
303       layer_(layer) {
304   if (depth > -1 && world_elevation > depth) {
305     // TODO(mklim): Deal with bounds overflow more elegantly. We'd like to be
306     // able to have developers specify the behavior here to alternatives besides
307     // clamping, like normalization on some arbitrary curve.
308 
309     // Clamp the local z coordinate at our max bound. Take into account the
310     // parent z position here to fix clamping in cases where the child is
311     // overflowing because of its parents.
312     const float parent_elevation = world_elevation - local_elevation;
313     local_elevation = depth - parent_elevation;
314   }
315   if (local_elevation != 0.0) {
316     entity_node().SetTranslation(0.f, 0.f, -local_elevation);
317   }
318 }
319 
~Frame()320 SceneUpdateContext::Frame::~Frame() {
321   context().CreateFrame(std::move(entity_node()), std::move(shape_node()),
322                         rrect_, color_, paint_bounds_, std::move(paint_layers_),
323                         layer_);
324 }
325 
AddPaintLayer(Layer * layer)326 void SceneUpdateContext::Frame::AddPaintLayer(Layer* layer) {
327   FML_DCHECK(layer->needs_painting());
328   paint_layers_.push_back(layer);
329   paint_bounds_.join(layer->paint_bounds());
330 }
331 
Clip(SceneUpdateContext & context,const SkRect & shape_bounds)332 SceneUpdateContext::Clip::Clip(SceneUpdateContext& context,
333                                const SkRect& shape_bounds)
334     : Entity(context) {
335   SetEntityNodeClipPlanes(entity_node(), shape_bounds);
336 }
337 
338 }  // namespace flutter
339