Skip to content

Commit bf9ad79

Browse files
committed
Add API for scrolling individual layers
This will allow Servo to reimplement scroll_to_fragment.
1 parent 82a0ca4 commit bf9ad79

File tree

5 files changed

+105
-2
lines changed

5 files changed

+105
-2
lines changed

webrender/src/frame.rs

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use webrender_traits::{AuxiliaryLists, PipelineId, Epoch, ScrollPolicy, ScrollLa
2121
use webrender_traits::{ClipRegion, ColorF, DisplayItem, StackingContext, FilterOp, MixBlendMode};
2222
use webrender_traits::{ScrollEventPhase, ScrollLayerInfo, SpecificDisplayItem, ScrollLayerState};
2323
use webrender_traits::{LayerRect, LayerPoint, LayerSize};
24-
use webrender_traits::{ScrollLayerRect, as_scroll_parent_rect, ScrollLayerPixel};
24+
use webrender_traits::{ServoScrollRootId, ScrollLayerRect, as_scroll_parent_rect, ScrollLayerPixel};
2525
use webrender_traits::WorldPoint4D;
2626
use webrender_traits::{LayerTransform, LayerToScrollTransform, ScrollToWorldTransform};
2727

@@ -52,6 +52,7 @@ pub struct Frame {
5252
AuxiliaryLists,
5353
BuildHasherDefault<FnvHasher>>,
5454
pub root_scroll_layer_id: Option<ScrollLayerId>,
55+
pending_scroll_offsets: HashMap<PipelineId, HashMap<ServoScrollRootId, LayerPoint>>,
5556
id: FrameId,
5657
debug: bool,
5758
frame_builder_config: FrameBuilderConfig,
@@ -210,6 +211,7 @@ impl Frame {
210211
pipeline_auxiliary_lists: HashMap::with_hasher(Default::default()),
211212
layers: HashMap::with_hasher(Default::default()),
212213
root_scroll_layer_id: None,
214+
pending_scroll_offsets: HashMap::new(),
213215
id: FrameId(0),
214216
debug: debug,
215217
frame_builder: None,
@@ -295,6 +297,40 @@ impl Frame {
295297
result
296298
}
297299

300+
/// Returns true if any layers actually changed position or false otherwise.
301+
pub fn scroll_layers(&mut self,
302+
origin: Point2D<f32>,
303+
pipeline_id: PipelineId,
304+
scroll_root_id: ServoScrollRootId)
305+
-> bool {
306+
let origin = LayerPoint::new(origin.x.max(0.0), origin.y.max(0.0));
307+
308+
let mut scrolled_a_layer = false;
309+
let mut found_layer = false;
310+
for (layer_id, layer) in self.layers.iter_mut() {
311+
if layer_id.pipeline_id != pipeline_id {
312+
continue;
313+
}
314+
315+
match layer_id.info {
316+
ScrollLayerInfo::Scrollable(_, id) if id != scroll_root_id => continue,
317+
ScrollLayerInfo::Fixed => continue,
318+
_ => {}
319+
}
320+
321+
found_layer = true;
322+
scrolled_a_layer |= layer.set_scroll_origin(&origin);
323+
}
324+
325+
if !found_layer {
326+
let scroll_offsets =
327+
self.pending_scroll_offsets.entry(pipeline_id).or_insert_with(HashMap::new);
328+
scroll_offsets.insert(scroll_root_id, origin);
329+
}
330+
331+
scrolled_a_layer
332+
}
333+
298334
/// Returns true if any layers actually changed position or false otherwise.
299335
pub fn scroll(&mut self,
300336
mut delta: Point2D<f32>,
@@ -480,6 +516,19 @@ impl Frame {
480516
};
481517

482518
layer.finalize(&scrolling_state);
519+
520+
let scroll_root_id = match scroll_layer_id.info {
521+
ScrollLayerInfo::Scrollable(_, scroll_root_id) => scroll_root_id,
522+
_ => continue,
523+
};
524+
525+
526+
let pipeline_id = scroll_layer_id.pipeline_id;
527+
if let Some(pending_offsets) = self.pending_scroll_offsets.get_mut(&pipeline_id) {
528+
if let Some(ref offset) = pending_offsets.remove(&scroll_root_id) {
529+
layer.set_scroll_origin(offset);
530+
}
531+
}
483532
}
484533
}
485534

webrender/src/layer.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,26 @@ impl Layer {
8686
LayerSize::new(overscroll_x, overscroll_y)
8787
}
8888

89+
pub fn set_scroll_origin(&mut self, origin: &LayerPoint) -> bool{
90+
if self.content_size.width <= self.local_viewport_rect.size.width &&
91+
self.content_size.height <= self.local_viewport_rect.size.height {
92+
return false;
93+
}
94+
95+
let new_offset = LayerPoint::new(
96+
(-origin.x).max(-self.content_size.width + self.local_viewport_rect.size.width),
97+
(-origin.y).max(-self.content_size.height + self.local_viewport_rect.size.height));
98+
let new_offset = LayerPoint::new(new_offset.x.min(0.0).round(), new_offset.y.min(0.0).round());
99+
if new_offset == self.scrolling.offset {
100+
return false;
101+
}
102+
103+
self.scrolling.offset = new_offset;
104+
self.scrolling.bouncing_back = false;
105+
self.scrolling.started_bouncing_back = false;
106+
return true;
107+
}
108+
89109
pub fn stretch_overscroll_spring(&mut self) {
90110
let overscroll_amount = self.overscroll_amount();
91111
self.scrolling.spring.coords(self.scrolling.offset,

webrender/src/render_backend.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,24 @@ impl RenderBackend {
246246
None => self.notify_compositor_of_new_scroll_frame(false),
247247
}
248248
}
249+
ApiMsg::ScrollLayersWithScrollId(origin, pipeline_id, scroll_root_id) => {
250+
let frame = profile_counters.total_time.profile(|| {
251+
if self.frame.scroll_layers(origin, pipeline_id, scroll_root_id) {
252+
Some(self.render())
253+
} else {
254+
None
255+
}
256+
});
257+
258+
match frame {
259+
Some(frame) => {
260+
self.publish_frame(frame, &mut profile_counters);
261+
self.notify_compositor_of_new_scroll_frame(true)
262+
}
263+
None => self.notify_compositor_of_new_scroll_frame(false),
264+
}
265+
266+
}
249267
ApiMsg::TickScrollingBounce => {
250268
let frame = profile_counters.total_time.profile(|| {
251269
self.frame.tick_scrolling_bounce_animations();

webrender_traits/src/api.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use offscreen_gl_context::{GLContextAttributes, GLLimits};
99
use std::cell::Cell;
1010
use {ApiMsg, AuxiliaryLists, BuiltDisplayList, ColorF, Epoch};
1111
use {FontKey, IdNamespace, ImageFormat, ImageKey, NativeFontHandle, PipelineId};
12-
use {RenderApiSender, ResourceId, ScrollEventPhase, ScrollLayerState};
12+
use {RenderApiSender, ResourceId, ScrollEventPhase, ScrollLayerState, ServoScrollRootId};
1313
use {GlyphKey, GlyphDimensions, ImageData, WebGLContextId, WebGLCommand};
1414

1515
impl RenderApiSender {
@@ -193,6 +193,14 @@ impl RenderApi {
193193
self.api_sender.send(msg).unwrap();
194194
}
195195

196+
pub fn scroll_layers_with_scroll_root_id(&self,
197+
new_scroll_origin: Point2D<f32>,
198+
pipeline_id: PipelineId,
199+
scroll_root_id: ServoScrollRootId) {
200+
let msg = ApiMsg::ScrollLayersWithScrollId(new_scroll_origin, pipeline_id, scroll_root_id);
201+
self.api_sender.send(msg).unwrap();
202+
}
203+
196204
pub fn tick_scrolling_bounce_animations(&self) {
197205
let msg = ApiMsg::TickScrollingBounce;
198206
self.api_sender.send(msg).unwrap();

webrender_traits/src/types.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ pub enum ApiMsg {
4949
AuxiliaryListsDescriptor),
5050
SetRootPipeline(PipelineId),
5151
Scroll(Point2D<f32>, Point2D<f32>, ScrollEventPhase),
52+
ScrollLayersWithScrollId(Point2D<f32>, PipelineId, ServoScrollRootId),
5253
TickScrollingBounce,
5354
TranslatePointToLayerSpace(Point2D<f32>, MsgSender<(Point2D<f32>, PipelineId)>),
5455
GetScrollLayerState(MsgSender<Vec<ScrollLayerState>>),
@@ -449,6 +450,13 @@ impl ScrollLayerId {
449450
info: ScrollLayerInfo::Scrollable(0, ServoScrollRootId(0)),
450451
}
451452
}
453+
454+
pub fn scroll_root_id(&self) -> Option<ServoScrollRootId> {
455+
match self.info {
456+
ScrollLayerInfo::Scrollable(_, scroll_root_id) => Some(scroll_root_id),
457+
ScrollLayerInfo::Fixed => None,
458+
}
459+
}
452460
}
453461

454462
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]

0 commit comments

Comments
 (0)