OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2015 The Chromium 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 "services/gfx/compositor/graph/node_def.h" | |
6 | |
7 #include <sstream> | |
8 | |
9 #include "base/logging.h" | |
10 #include "mojo/services/gfx/composition/cpp/logging.h" | |
11 #include "services/gfx/compositor/graph/scene_def.h" | |
12 #include "services/gfx/compositor/graph/snapshot.h" | |
13 #include "services/gfx/compositor/render/render_image.h" | |
14 #include "services/gfx/compositor/render/render_layer.h" | |
15 | |
16 namespace compositor { | |
17 | |
18 // TODO(jeffbrown): Move these conversion functions somewhere more useful. | |
abarth
2016/01/10 22:55:36
There's a converters directory in mojo/common. Ma
jeffbrown
2016/01/16 03:28:32
Yeah... but maybe later. :)
| |
19 | |
20 static SkRect ToSkRect(const mojo::Rect& rect) { | |
abarth
2016/01/10 22:55:36
The mojo types have template magic to make these s
| |
21 return SkRect::MakeXYWH(rect.x, rect.y, rect.width, rect.height); | |
22 } | |
23 | |
24 static SkRRect ToSkRRect(const mojo::RRect& rrect) { | |
25 SkVector radii[4] = { | |
26 {rrect.top_left_radius_x, rrect.top_left_radius_y}, | |
27 {rrect.top_right_radius_x, rrect.top_right_radius_y}, | |
28 {rrect.bottom_left_radius_x, rrect.bottom_left_radius_y}, | |
29 {rrect.bottom_right_radius_x, rrect.bottom_right_radius_y}}; | |
30 SkRRect result; | |
31 result.setRectRadii( | |
32 SkRect::MakeXYWH(rrect.x, rrect.y, rrect.width, rrect.height), radii); | |
abarth
2016/01/10 22:55:35
Note that this routine is more expensive that setR
jeffbrown
2016/01/16 03:28:32
Yes, but we don't know whether we're in the fast c
| |
33 return result; | |
34 } | |
35 | |
36 static SkMatrix ToSkMatrix(const mojo::Transform& transform) { | |
37 // TODO(jeffbrown): What to do with the Z components? | |
38 // Perhaps we need a simpler 2D transform matrix mojom. | |
abarth
2016/01/10 22:55:36
This is the same thing we do in Flutter. We can t
jeffbrown
2016/01/16 03:28:32
Acknowledged.
| |
39 SkMatrix result; | |
40 result.setAll(transform.matrix[0], transform.matrix[1], transform.matrix[3], | |
41 transform.matrix[4], transform.matrix[5], transform.matrix[7], | |
42 transform.matrix[12], transform.matrix[13], | |
43 transform.matrix[15]); | |
44 return result; | |
45 } | |
46 | |
47 static SkColor ToSkColor(const mojo::gfx::composition::Color& color) { | |
48 return SkColorSetARGBInline(color.alpha, color.red, color.green, color.blue); | |
49 } | |
50 | |
51 static SkPath ToSkPath(const mojo::gfx::composition::Clip& clip) { | |
52 SkPath result; | |
53 if (clip.is_rect()) { | |
54 result.addRect(ToSkRect(*clip.get_rect())); | |
abarth
2016/01/10 22:55:36
Woah there. I haven't seen where you're using thi
jeffbrown
2016/01/16 03:28:32
Dropping RRect clips for now.
| |
55 } else if (clip.is_rect()) { | |
56 result.addRRect(ToSkRRect(*clip.get_rrect())); | |
57 } else { | |
58 DCHECK(false); // was checked during validation | |
59 } | |
60 return result; | |
61 } | |
62 | |
63 static SkPaint ToSkPaint(const mojo::gfx::composition::Blend& blend) { | |
64 SkPaint result; | |
65 result.setAlpha(blend.alpha); | |
66 return result; | |
67 } | |
68 | |
69 NodeDef::NodeDef(uint32_t node_id, | |
70 mojo::TransformPtr content_transform, | |
71 mojo::gfx::composition::ClipPtr content_clip, | |
72 uint32_t hit_id, | |
73 Combinator combinator, | |
74 const std::vector<uint32_t>& child_node_ids, | |
75 NodeOp* op) | |
76 : node_id_(node_id), | |
77 content_transform_(content_transform.Pass()), | |
78 content_clip_(content_clip.Pass()), | |
79 hit_id_(hit_id), | |
80 combinator_(combinator), | |
81 child_node_ids_(child_node_ids), | |
82 op_(op) {} | |
83 | |
84 NodeDef::~NodeDef() {} | |
85 | |
86 bool NodeDef::Validate(SceneDef* scene, std::ostream& err) { | |
87 if (content_clip_) { | |
88 if (!content_clip_->is_rect() && !content_clip_->is_rrect()) { | |
89 err << "Node contains unsupported content clip type: " | |
90 << FormattedLabel(scene); | |
91 return false; | |
92 } | |
93 } | |
94 | |
95 child_nodes_.clear(); | |
96 for (uint32_t child_node_id : child_node_ids_) { | |
97 NodeDef* child_node = scene->FindNode(child_node_id); | |
98 if (!child_node) { | |
99 err << "Node refers to unknown child: " << FormattedLabel(scene) | |
100 << ", child_node_id=" << child_node_id; | |
101 return false; | |
102 } | |
103 child_nodes_.push_back(child_node); | |
104 } | |
105 | |
106 return !op_ || op_->Validate(scene, this, err); | |
107 } | |
108 | |
109 bool NodeDef::Snapshot(SnapshotBuilder* snapshot_builder, | |
110 RenderLayerBuilder* layer_builder, | |
111 SceneDef* scene) { | |
112 DCHECK(snapshot_builder); | |
113 DCHECK(layer_builder); | |
114 DCHECK(scene); | |
115 | |
116 // Detect cycles. | |
117 if (visited_) { | |
118 if (snapshot_builder->block_log()) { | |
119 *snapshot_builder->block_log() | |
120 << "Node blocked due to recursive cycle: " << FormattedLabel(scene) | |
121 << std::endl; | |
122 } | |
123 return false; | |
124 } | |
125 | |
126 // Snapshot the contents of the node. | |
127 visited_ = true; | |
128 bool success = SnapshotInner(snapshot_builder, layer_builder, scene); | |
129 visited_ = false; | |
130 return success; | |
131 } | |
132 | |
133 bool NodeDef::SnapshotInner(SnapshotBuilder* snapshot_builder, | |
134 RenderLayerBuilder* layer_builder, | |
135 SceneDef* scene) { | |
136 // TODO(jeffbrown): Frequently referenced and reused nodes, especially | |
137 // layer nodes, may benefit from caching. | |
138 layer_builder->PushNode( | |
139 node_id_, hit_id_, | |
140 content_transform_ ? ToSkMatrix(*content_transform_) : SkMatrix::I(), | |
141 content_clip_ ? ToSkPath(*content_clip_) : SkPath()); | |
142 | |
143 bool success = | |
144 op_ ? op_->Snapshot(snapshot_builder, layer_builder, scene, this) | |
145 : SnapshotChildren(snapshot_builder, layer_builder, scene); | |
146 if (!success) | |
147 return false; | |
148 | |
149 layer_builder->PopNode(); | |
150 return true; | |
151 } | |
152 | |
153 bool NodeDef::SnapshotChildren(SnapshotBuilder* snapshot_builder, | |
154 RenderLayerBuilder* layer_builder, | |
155 SceneDef* scene) { | |
156 DCHECK(snapshot_builder); | |
157 DCHECK(layer_builder); | |
158 DCHECK(scene); | |
159 | |
160 switch (combinator_) { | |
161 // MERGE: All or nothing. | |
162 case Combinator::MERGE: { | |
163 for (NodeDef* child_node : child_nodes_) { | |
164 if (!child_node->Snapshot(snapshot_builder, layer_builder, scene)) { | |
165 if (snapshot_builder->block_log()) { | |
166 *snapshot_builder->block_log() | |
167 << "Node with MERGE combinator blocked since " | |
168 "one of its children is blocked: " | |
169 << FormattedLabel(scene) << ", blocked child " | |
170 << child_node->FormattedLabel(scene) << std::endl; | |
171 } | |
172 return false; // blocked | |
173 } | |
174 } | |
175 return true; | |
176 } | |
177 | |
178 // PRUNE: Silently discard blocked children. | |
179 case Combinator::PRUNE: { | |
180 for (NodeDef* child_node : child_nodes_) { | |
181 RenderLayerBuilder child_layer_builder; | |
182 if (child_node->Snapshot(snapshot_builder, &child_layer_builder, | |
183 scene)) { | |
184 layer_builder->DrawLayer(child_layer_builder.Build()); | |
185 } | |
186 } | |
187 return true; | |
188 } | |
189 | |
190 // FALLBACK: Keep only the first unblocked child. | |
191 case Combinator::FALLBACK: { | |
192 if (child_nodes_.empty()) | |
193 return true; | |
194 for (NodeDef* child_node : child_nodes_) { | |
195 RenderLayerBuilder child_layer_builder; | |
196 if (child_node->Snapshot(snapshot_builder, &child_layer_builder, | |
197 scene)) { | |
198 layer_builder->DrawLayer(child_layer_builder.Build()); | |
199 return true; | |
200 } | |
201 } | |
202 if (snapshot_builder->block_log()) { | |
203 *snapshot_builder->block_log() | |
204 << "Node with FALLBACK combinator blocked since " | |
205 "all of its children are blocked: " | |
206 << FormattedLabel(scene) << std::endl; | |
207 } | |
208 return false; // blocked | |
209 } | |
210 } | |
211 } | |
212 | |
213 std::string NodeDef::FormattedLabel(SceneDef* scene) { | |
214 std::ostringstream s; | |
215 s << scene->FormattedLabel() << "[" << node_id_ << "]"; | |
216 return s.str(); | |
abarth
2016/01/10 22:55:35
base::StringPrintf
jeffbrown
2016/01/16 03:28:32
Done.
| |
217 } | |
218 | |
219 bool NodeOp::Validate(SceneDef* scene, NodeDef* node, std::ostream& err) { | |
220 return true; | |
221 } | |
222 | |
223 RectNodeOp::RectNodeOp(const mojo::Rect& content_rect, | |
224 const mojo::gfx::composition::Color& color) | |
225 : content_rect_(content_rect), color_(color) {} | |
226 | |
227 RectNodeOp::~RectNodeOp() {} | |
228 | |
229 bool RectNodeOp::Snapshot(SnapshotBuilder* snapshot_builder, | |
230 RenderLayerBuilder* layer_builder, | |
231 SceneDef* scene, | |
232 NodeDef* node) { | |
233 if (!node->SnapshotChildren(snapshot_builder, layer_builder, scene)) | |
234 return false; | |
235 | |
236 SkPaint paint; | |
237 paint.setColor(ToSkColor(color_)); | |
238 layer_builder->DrawRect(ToSkRect(content_rect_), paint); | |
239 return true; | |
240 } | |
241 | |
242 ImageNodeOp::ImageNodeOp(const mojo::Rect& content_rect, | |
243 mojo::RectPtr image_rect, | |
244 uint32 image_resource_id, | |
245 mojo::gfx::composition::BlendPtr blend) | |
246 : content_rect_(content_rect), | |
247 image_rect_(image_rect.Pass()), | |
248 image_resource_id_(image_resource_id), | |
249 blend_(blend.Pass()) {} | |
250 | |
251 ImageNodeOp::~ImageNodeOp() {} | |
252 | |
253 bool ImageNodeOp::Validate(SceneDef* scene, NodeDef* node, std::ostream& err) { | |
254 image_resource_ = scene->FindImageResource(image_resource_id_); | |
255 if (!image_resource_) { | |
256 err << "Node refers to unknown or invalid image resource: " | |
257 << node->FormattedLabel(scene) | |
258 << ", image_resource_id=" << image_resource_id_; | |
259 return false; | |
260 } | |
261 return true; | |
262 } | |
263 | |
264 bool ImageNodeOp::Snapshot(SnapshotBuilder* snapshot_builder, | |
265 RenderLayerBuilder* layer_builder, | |
266 SceneDef* scene, | |
267 NodeDef* node) { | |
268 DCHECK(image_resource_); | |
269 | |
270 if (!image_resource_->image()) { | |
271 if (snapshot_builder->block_log()) { | |
272 *snapshot_builder->block_log() | |
273 << "Node blocked due to its referenced image " | |
274 "resource being unavailable: " | |
275 << node->FormattedLabel(scene) << std::endl; | |
276 } | |
277 return false; | |
278 } | |
279 | |
280 if (!node->SnapshotChildren(snapshot_builder, layer_builder, scene)) | |
281 return false; | |
282 | |
283 layer_builder->DrawImage( | |
284 image_resource_->image(), ToSkRect(content_rect_), | |
285 image_rect_ ? ToSkRect(*image_rect_) | |
286 : SkRect::MakeWH(image_resource_->image()->width(), | |
287 image_resource_->image()->height()), | |
288 blend_ ? ToSkPaint(*blend_) : SkPaint()); | |
289 return true; | |
290 } | |
291 | |
292 SceneNodeOp::SceneNodeOp(uint32_t scene_resource_id, uint32_t scene_version) | |
293 : scene_resource_id_(scene_resource_id), scene_version_(scene_version) {} | |
294 | |
295 SceneNodeOp::~SceneNodeOp() {} | |
296 | |
297 bool SceneNodeOp::Validate(SceneDef* scene, NodeDef* node, std::ostream& err) { | |
298 scene_resource_ = scene->FindSceneResource(scene_resource_id_); | |
299 if (!scene_resource_) { | |
300 err << "Node refers to unknown or invalid scene resource: " | |
301 << node->FormattedLabel(scene) | |
302 << ", scene_resource_id=" << scene_resource_id_; | |
303 return false; | |
304 } | |
305 return true; | |
306 } | |
307 | |
308 bool SceneNodeOp::Snapshot(SnapshotBuilder* snapshot_builder, | |
309 RenderLayerBuilder* layer_builder, | |
310 SceneDef* scene, | |
311 NodeDef* node) { | |
312 DCHECK(scene_resource_); | |
313 | |
314 SceneDef* referenced_scene = scene_resource_->referenced_scene(); | |
315 if (!referenced_scene) { | |
316 if (snapshot_builder->block_log()) { | |
317 *snapshot_builder->block_log() | |
318 << "Node blocked due to its referenced scene " | |
319 "resource being unavailable: " | |
320 << node->FormattedLabel(scene) << std::endl; | |
321 } | |
322 return false; | |
323 } | |
324 | |
325 uint32_t actual_version = referenced_scene->version(); | |
326 if (scene_version_ != mojo::gfx::composition::kSceneVersionNone && | |
327 actual_version != mojo::gfx::composition::kSceneVersionNone && | |
328 scene_version_ != actual_version) { | |
329 if (snapshot_builder->block_log()) { | |
330 *snapshot_builder->block_log() | |
331 << "Node blocked due to its referenced scene " | |
332 "resource not having the desired version: " | |
333 << node->FormattedLabel(scene) | |
334 << ", requested_version=" << scene_version_ | |
335 << ", actual_version=" << actual_version << std::endl; | |
336 } | |
337 return false; | |
338 } | |
339 | |
340 if (!node->SnapshotChildren(snapshot_builder, layer_builder, scene)) | |
341 return false; | |
342 | |
343 return referenced_scene->Snapshot(snapshot_builder, layer_builder); | |
344 } | |
345 | |
346 LayerNodeOp::LayerNodeOp(const mojo::Size& size, | |
347 mojo::gfx::composition::BlendPtr blend) | |
348 : size_(size), blend_(blend.Pass()) {} | |
349 | |
350 LayerNodeOp::~LayerNodeOp() {} | |
351 | |
352 bool LayerNodeOp::Snapshot(SnapshotBuilder* snapshot_builder, | |
353 RenderLayerBuilder* layer_builder, | |
354 SceneDef* scene, | |
355 NodeDef* node) { | |
356 SkRect content_rect = SkRect::MakeWH(size_.width, size_.height); | |
357 RenderLayerBuilder children_layer_builder(&content_rect); | |
358 if (!node->SnapshotChildren(snapshot_builder, &children_layer_builder, scene)) | |
359 return false; | |
360 | |
361 layer_builder->DrawSavedLayer(children_layer_builder.Build(), content_rect, | |
362 blend_ ? ToSkPaint(*blend_) : SkPaint()); | |
363 return true; | |
364 } | |
365 | |
366 } // namespace compositor | |
OLD | NEW |