Source code

Revision control

Other Tools

1
/* This Source Code Form is subject to the terms of the Mozilla Public
2
* License, v. 2.0. If a copy of the MPL was not distributed with this
3
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5
use api::{BuiltDisplayList, DisplayListWithCache, ColorF, DynamicProperties, Epoch, FontRenderMode};
6
use api::{PipelineId, PropertyBinding, PropertyBindingId, PropertyValue, MixBlendMode, StackingContext};
7
use api::MemoryReport;
8
use api::units::*;
9
use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
10
use crate::composite::CompositorKind;
11
use crate::clip::{ClipStore, ClipDataStore};
12
use crate::spatial_tree::{SpatialTree, SpatialNodeIndex};
13
use crate::frame_builder::{ChasePrimitive, FrameBuilderConfig};
14
use crate::hit_test::{HitTester, HitTestingScene, HitTestingSceneStats};
15
use crate::internal_types::{FastHashMap, FastHashSet};
16
use crate::prim_store::{PrimitiveStore, PrimitiveStoreStats, PictureIndex};
17
use std::sync::Arc;
18
19
/// Stores a map of the animated property bindings for the current display list. These
20
/// can be used to animate the transform and/or opacity of a display list without
21
/// re-submitting the display list itself.
22
#[cfg_attr(feature = "capture", derive(Serialize))]
23
#[cfg_attr(feature = "replay", derive(Deserialize))]
24
pub struct SceneProperties {
25
transform_properties: FastHashMap<PropertyBindingId, LayoutTransform>,
26
float_properties: FastHashMap<PropertyBindingId, f32>,
27
color_properties: FastHashMap<PropertyBindingId, ColorF>,
28
current_properties: DynamicProperties,
29
pending_properties: Option<DynamicProperties>,
30
}
31
32
impl SceneProperties {
33
pub fn new() -> Self {
34
SceneProperties {
35
transform_properties: FastHashMap::default(),
36
float_properties: FastHashMap::default(),
37
color_properties: FastHashMap::default(),
38
current_properties: DynamicProperties::default(),
39
pending_properties: None,
40
}
41
}
42
43
/// Set the current property list for this display list.
44
pub fn set_properties(&mut self, properties: DynamicProperties) {
45
self.pending_properties = Some(properties);
46
}
47
48
/// Add to the current property list for this display list.
49
pub fn add_transforms(&mut self, transforms: Vec<PropertyValue<LayoutTransform>>) {
50
let mut pending_properties = self.pending_properties
51
.take()
52
.unwrap_or_default();
53
54
pending_properties.transforms.extend(transforms);
55
56
self.pending_properties = Some(pending_properties);
57
}
58
59
/// Flush any pending updates to the scene properties. Returns
60
/// true if the properties have changed since the last flush
61
/// was called. This code allows properties to be changed by
62
/// multiple set_properties and add_properties calls during a
63
/// single transaction, and still correctly determine if any
64
/// properties have changed. This can have significant power
65
/// saving implications, allowing a frame build to be skipped
66
/// if the properties haven't changed in many cases.
67
pub fn flush_pending_updates(&mut self) -> bool {
68
let mut properties_changed = false;
69
70
if let Some(ref pending_properties) = self.pending_properties {
71
if *pending_properties != self.current_properties {
72
self.transform_properties.clear();
73
self.float_properties.clear();
74
75
for property in &pending_properties.transforms {
76
self.transform_properties
77
.insert(property.key.id, property.value);
78
}
79
80
for property in &pending_properties.floats {
81
self.float_properties
82
.insert(property.key.id, property.value);
83
}
84
85
for property in &pending_properties.colors {
86
self.color_properties
87
.insert(property.key.id, property.value);
88
}
89
90
self.current_properties = pending_properties.clone();
91
properties_changed = true;
92
}
93
}
94
95
properties_changed
96
}
97
98
/// Get the current value for a transform property.
99
pub fn resolve_layout_transform(
100
&self,
101
property: &PropertyBinding<LayoutTransform>,
102
) -> LayoutTransform {
103
match *property {
104
PropertyBinding::Value(value) => value,
105
PropertyBinding::Binding(ref key, v) => {
106
self.transform_properties
107
.get(&key.id)
108
.cloned()
109
.unwrap_or(v)
110
}
111
}
112
}
113
114
/// Get the current value for a float property.
115
pub fn resolve_float(
116
&self,
117
property: &PropertyBinding<f32>
118
) -> f32 {
119
match *property {
120
PropertyBinding::Value(value) => value,
121
PropertyBinding::Binding(ref key, v) => {
122
self.float_properties
123
.get(&key.id)
124
.cloned()
125
.unwrap_or(v)
126
}
127
}
128
}
129
130
pub fn float_properties(&self) -> &FastHashMap<PropertyBindingId, f32> {
131
&self.float_properties
132
}
133
134
/// Get the current value for a color property.
135
pub fn resolve_color(
136
&self,
137
property: &PropertyBinding<ColorF>
138
) -> ColorF {
139
match *property {
140
PropertyBinding::Value(value) => value,
141
PropertyBinding::Binding(ref key, v) => {
142
self.color_properties
143
.get(&key.id)
144
.cloned()
145
.unwrap_or(v)
146
}
147
}
148
}
149
150
pub fn color_properties(&self) -> &FastHashMap<PropertyBindingId, ColorF> {
151
&self.color_properties
152
}
153
154
}
155
156
/// A representation of the layout within the display port for a given document or iframe.
157
#[cfg_attr(feature = "capture", derive(Serialize))]
158
#[cfg_attr(feature = "replay", derive(Deserialize))]
159
#[derive(Clone)]
160
pub struct ScenePipeline {
161
pub pipeline_id: PipelineId,
162
pub viewport_size: LayoutSize,
163
pub content_size: LayoutSize,
164
pub background_color: Option<ColorF>,
165
pub display_list: DisplayListWithCache,
166
}
167
168
/// A complete representation of the layout bundling visible pipelines together.
169
#[cfg_attr(feature = "capture", derive(Serialize))]
170
#[cfg_attr(feature = "replay", derive(Deserialize))]
171
#[derive(Clone)]
172
pub struct Scene {
173
pub root_pipeline_id: Option<PipelineId>,
174
pub pipelines: FastHashMap<PipelineId, ScenePipeline>,
175
pub pipeline_epochs: FastHashMap<PipelineId, Epoch>,
176
}
177
178
impl Scene {
179
pub fn new() -> Self {
180
Scene {
181
root_pipeline_id: None,
182
pipelines: FastHashMap::default(),
183
pipeline_epochs: FastHashMap::default(),
184
}
185
}
186
187
pub fn set_root_pipeline_id(&mut self, pipeline_id: PipelineId) {
188
self.root_pipeline_id = Some(pipeline_id);
189
}
190
191
pub fn set_display_list(
192
&mut self,
193
pipeline_id: PipelineId,
194
epoch: Epoch,
195
display_list: BuiltDisplayList,
196
background_color: Option<ColorF>,
197
viewport_size: LayoutSize,
198
content_size: LayoutSize,
199
) {
200
// Adds a cache to the given display list. If this pipeline already had
201
// a display list before, that display list is updated and used instead.
202
let display_list = match self.pipelines.remove(&pipeline_id) {
203
Some(mut pipeline) => {
204
pipeline.display_list.update(display_list);
205
pipeline.display_list
206
}
207
None => DisplayListWithCache::new_from_list(display_list)
208
};
209
210
let new_pipeline = ScenePipeline {
211
pipeline_id,
212
viewport_size,
213
content_size,
214
background_color,
215
display_list,
216
};
217
218
self.pipelines.insert(pipeline_id, new_pipeline);
219
self.pipeline_epochs.insert(pipeline_id, epoch);
220
}
221
222
pub fn remove_pipeline(&mut self, pipeline_id: PipelineId) {
223
if self.root_pipeline_id == Some(pipeline_id) {
224
self.root_pipeline_id = None;
225
}
226
self.pipelines.remove(&pipeline_id);
227
self.pipeline_epochs.remove(&pipeline_id);
228
}
229
230
pub fn update_epoch(&mut self, pipeline_id: PipelineId, epoch: Epoch) {
231
self.pipeline_epochs.insert(pipeline_id, epoch);
232
}
233
234
pub fn has_root_pipeline(&self) -> bool {
235
if let Some(ref root_id) = self.root_pipeline_id {
236
return self.pipelines.contains_key(root_id);
237
}
238
239
false
240
}
241
242
pub fn report_memory(
243
&self,
244
ops: &mut MallocSizeOfOps,
245
report: &mut MemoryReport
246
) {
247
for (_, pipeline) in &self.pipelines {
248
report.display_list += pipeline.display_list.size_of(ops)
249
}
250
}
251
}
252
253
pub trait StackingContextHelpers {
254
fn mix_blend_mode_for_compositing(&self) -> Option<MixBlendMode>;
255
}
256
257
impl StackingContextHelpers for StackingContext {
258
fn mix_blend_mode_for_compositing(&self) -> Option<MixBlendMode> {
259
match self.mix_blend_mode {
260
MixBlendMode::Normal => None,
261
_ => Some(self.mix_blend_mode),
262
}
263
}
264
}
265
266
267
/// WebRender's internal representation of the scene.
268
pub struct BuiltScene {
269
pub has_root_pipeline: bool,
270
pub pipeline_epochs: FastHashMap<PipelineId, Epoch>,
271
pub output_rect: DeviceIntRect,
272
pub background_color: Option<ColorF>,
273
pub root_pic_index: PictureIndex,
274
pub prim_store: PrimitiveStore,
275
pub clip_store: ClipStore,
276
pub config: FrameBuilderConfig,
277
pub spatial_tree: SpatialTree,
278
pub hit_testing_scene: Arc<HitTestingScene>,
279
pub content_slice_count: usize,
280
pub picture_cache_spatial_nodes: FastHashSet<SpatialNodeIndex>,
281
}
282
283
impl BuiltScene {
284
pub fn empty() -> Self {
285
BuiltScene {
286
has_root_pipeline: false,
287
pipeline_epochs: FastHashMap::default(),
288
output_rect: DeviceIntRect::zero(),
289
background_color: None,
290
root_pic_index: PictureIndex(0),
291
prim_store: PrimitiveStore::new(&PrimitiveStoreStats::empty()),
292
clip_store: ClipStore::new(),
293
spatial_tree: SpatialTree::new(),
294
hit_testing_scene: Arc::new(HitTestingScene::new(&HitTestingSceneStats::empty())),
295
content_slice_count: 0,
296
picture_cache_spatial_nodes: FastHashSet::default(),
297
config: FrameBuilderConfig {
298
default_font_render_mode: FontRenderMode::Mono,
299
dual_source_blending_is_enabled: true,
300
dual_source_blending_is_supported: false,
301
chase_primitive: ChasePrimitive::Nothing,
302
global_enable_picture_caching: false,
303
testing: false,
304
gpu_supports_fast_clears: false,
305
gpu_supports_advanced_blend: false,
306
advanced_blend_is_coherent: false,
307
batch_lookback_count: 0,
308
background_color: None,
309
compositor_kind: CompositorKind::default(),
310
tile_size_override: None,
311
max_depth_ids: 0,
312
},
313
}
314
}
315
316
/// Get the memory usage statistics to pre-allocate for the next scene.
317
pub fn get_stats(&self) -> SceneStats {
318
SceneStats {
319
prim_store_stats: self.prim_store.get_stats(),
320
hit_test_stats: self.hit_testing_scene.get_stats(),
321
}
322
}
323
324
pub fn create_hit_tester(
325
&mut self,
326
clip_data_store: &ClipDataStore,
327
) -> HitTester {
328
HitTester::new(
329
Arc::clone(&self.hit_testing_scene),
330
&self.spatial_tree,
331
&self.clip_store,
332
clip_data_store,
333
)
334
}
335
}
336
337
/// Stores the allocation sizes of various arrays in the built
338
/// scene. This is retrieved from the current frame builder
339
/// and used to reserve an approximately correct capacity of
340
/// the arrays for the next scene that is getting built.
341
pub struct SceneStats {
342
pub prim_store_stats: PrimitiveStoreStats,
343
pub hit_test_stats: HitTestingSceneStats,
344
}
345
346
impl SceneStats {
347
pub fn empty() -> Self {
348
SceneStats {
349
prim_store_stats: PrimitiveStoreStats::empty(),
350
hit_test_stats: HitTestingSceneStats::empty(),
351
}
352
}
353
}