Skip to content

Commit 1bff239

Browse files
committed
Make save-restore foolproof
1 parent 1a21291 commit 1bff239

File tree

2 files changed

+49
-20
lines changed

2 files changed

+49
-20
lines changed

webrender_api/src/display_list.rs

+36-12
Original file line numberDiff line numberDiff line change
@@ -51,14 +51,6 @@ impl<T> ItemRange<T> {
5151
}
5252
}
5353

54-
#[repr(C)]
55-
#[derive(Debug)]
56-
pub struct DisplayListBuilderSaveState {
57-
dl_len: usize,
58-
clip_stack_len: usize,
59-
next_clip_id: u64,
60-
}
61-
6254
/// A display list.
6355
#[derive(Clone, Default)]
6456
pub struct BuiltDisplayList {
@@ -526,6 +518,13 @@ fn serialize_fast<T: Serialize>(vec: &mut Vec<u8>, e: &T) {
526518
bincode::serialize_into(&mut UnsafeVecWriter(vec), e, bincode::Infinite).unwrap();
527519
}
528520

521+
#[derive(Clone, Debug)]
522+
pub struct SaveState {
523+
dl_len: usize,
524+
clip_stack_len: usize,
525+
next_clip_id: u64,
526+
}
527+
529528
#[derive(Clone)]
530529
pub struct DisplayListBuilder {
531530
pub data: Vec<u8>,
@@ -537,6 +536,7 @@ pub struct DisplayListBuilder {
537536
/// The size of the content of this display list. This is used to allow scrolling
538537
/// outside the bounds of the display list items themselves.
539538
content_size: LayoutSize,
539+
save_state: Option<SaveState>,
540540
}
541541

542542
impl DisplayListBuilder {
@@ -563,23 +563,41 @@ impl DisplayListBuilder {
563563
next_clip_id: FIRST_CLIP_ID,
564564
builder_start_time: start_time,
565565
content_size,
566+
save_state: None,
566567
}
567568
}
568569

569-
pub fn save(&self) -> DisplayListBuilderSaveState {
570-
DisplayListBuilderSaveState {
570+
/// Saves the current display list state, so it may be `restore()`'d.
571+
///
572+
/// # Conditions:
573+
///
574+
/// * Doesn't support popping clips that were pushed before the save.
575+
/// * Doesn't support nested saves.
576+
/// * Must call `clear_save()` if the restore becomes unnecessary.
577+
pub fn save(&mut self) {
578+
assert!(self.save_state.is_none(), "DisplayListBuilder doesn't support nested saves");
579+
580+
self.save_state = Some(SaveState {
571581
clip_stack_len: self.clip_stack.len(),
572582
dl_len: self.data.len(),
573583
next_clip_id: self.next_clip_id,
574-
}
584+
});
575585
}
576586

577-
pub fn restore(&mut self, state: DisplayListBuilderSaveState) {
587+
/// Restores the state of the builder to when `save()` was last called.
588+
pub fn restore(&mut self) {
589+
let state = self.save_state.take().expect("No save to restore DisplayListBuilder from");
590+
578591
self.clip_stack.truncate(state.clip_stack_len);
579592
self.data.truncate(state.dl_len);
580593
self.next_clip_id = state.next_clip_id;
581594
}
582595

596+
/// Discards the builder's save (indicating the attempted operation was sucessful).
597+
pub fn clear_save(&mut self) {
598+
self.save_state.take().expect("No save to clear in DisplayListBuilder");
599+
}
600+
583601
pub fn print_display_list(&mut self) {
584602
let mut temp = BuiltDisplayList::default();
585603
::std::mem::swap(&mut temp.data, &mut self.data);
@@ -1136,6 +1154,10 @@ impl DisplayListBuilder {
11361154

11371155
pub fn pop_clip_id(&mut self) {
11381156
self.clip_stack.pop();
1157+
if let Some(save_state) = self.save_state.as_ref() {
1158+
assert!(self.clip_stack.len() >= save_state.clip_stack_len,
1159+
"Cannot pop clips that were pushed before the DisplayListBuilder save.");
1160+
}
11391161
assert!(self.clip_stack.len() > 0);
11401162
}
11411163

@@ -1155,6 +1177,8 @@ impl DisplayListBuilder {
11551177
}
11561178

11571179
pub fn finalize(self) -> (PipelineId, LayoutSize, BuiltDisplayList) {
1180+
assert!(self.save_state.is_none(), "Finalized DisplayListBuilder with a pending save");
1181+
11581182
let end_time = precise_time_ns();
11591183

11601184

wrench/src/rawtest.rs

+13-8
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ impl<'a> RawtestHarness<'a> {
216216
ColorF::new(0.0, 0.0, 1.0, 1.0));
217217

218218
if should_try_and_fail {
219-
let save_state = builder.save();
219+
builder.save();
220220
let clip = builder.define_clip(None, rect(80., 80., 90., 90.),
221221
None::<ComplexClipRegion>, None);
222222
builder.push_clip_id(clip);
@@ -231,16 +231,21 @@ impl<'a> RawtestHarness<'a> {
231231
builder.push_line(&PrimitiveInfo::new(rect(100., 100., 100., 100.)),
232232
110., 110., 160., LineOrientation::Horizontal, 2.0,
233233
ColorF::new(0.0, 0.0, 0.0, 1.0), LineStyle::Solid);
234-
builder.restore(save_state);
234+
builder.restore();
235235
}
236236

237-
let clip = builder.define_clip(None, rect(80., 80., 100., 100.),
238-
None::<ComplexClipRegion>, None);
239-
builder.push_clip_id(clip);
240-
builder.push_rect(&PrimitiveInfo::new(rect(150., 150., 100., 100.)),
241-
ColorF::new(0.0, 0.0, 1.0, 1.0));
237+
{
238+
builder.save();
239+
let clip = builder.define_clip(None, rect(80., 80., 100., 100.),
240+
None::<ComplexClipRegion>, None);
241+
builder.push_clip_id(clip);
242+
builder.push_rect(&PrimitiveInfo::new(rect(150., 150., 100., 100.)),
243+
ColorF::new(0.0, 0.0, 1.0, 1.0));
244+
245+
builder.pop_clip_id();
246+
builder.clear_save();
247+
}
242248

243-
builder.pop_clip_id();
244249
builder.pop_clip_id();
245250

246251
self.wrench.api.set_display_list(

0 commit comments

Comments
 (0)