Bug 1428766 - Update webrender to commit 722e8b104bf99d29d61ecb1fe456eebe89ad81fd. r=jrmuizel

MozReview-Commit-ID: GsDbUIfQFlm

--HG--
extra : rebase_source : 073d14ce480c795fc6a1c0c3cd2d243a1f7d190c
This commit is contained in:
Kartikaya Gupta 2018-01-11 10:53:24 -05:00
parent 1bc58767e9
commit 90321eec03
8 changed files with 496 additions and 190 deletions

View File

@ -175,4 +175,4 @@ Troubleshooting tips:
-------------------------------------------------------------------------------
The version of WebRender currently in the tree is:
a422f907be948b92bf5c7003a01f7744391a795e
722e8b104bf99d29d61ecb1fe456eebe89ad81fd

View File

@ -582,61 +582,21 @@ impl AlphaBatcher {
match prim_metadata.prim_kind {
PrimitiveKind::Brush => {
let brush = &ctx.prim_store.cpu_brushes[prim_metadata.cpu_prim_index.0];
let base_instance = BrushInstance {
picture_address: task_address,
prim_address: prim_cache_address,
self.add_brush_to_batch(
brush,
prim_metadata,
blend_mode,
clip_chain_rect_index,
scroll_id,
clip_task_address,
item_bounding_rect,
prim_cache_address,
scroll_id,
task_address,
transform_kind,
z,
segment_index: 0,
user_data0: 0,
user_data1: 0,
};
match brush.segment_desc {
Some(ref segment_desc) => {
let opaque_batch = self.batch_list.opaque_batch_list.get_suitable_batch(
brush.get_batch_key(
BlendMode::None
),
item_bounding_rect
);
let alpha_batch = self.batch_list.alpha_batch_list.get_suitable_batch(
brush.get_batch_key(
BlendMode::PremultipliedAlpha
),
item_bounding_rect
);
for (i, segment) in segment_desc.segments.iter().enumerate() {
let is_inner = segment.edge_flags.is_empty();
let needs_blending = !prim_metadata.opacity.is_opaque ||
segment.clip_task_id.is_some() ||
(!is_inner && transform_kind == TransformedRectKind::Complex);
let clip_task_address = segment
.clip_task_id
.map_or(OPAQUE_TASK_ADDRESS, |id| render_tasks.get_task_address(id));
let instance = PrimitiveInstance::from(BrushInstance {
segment_index: i as i32,
clip_task_address,
..base_instance
});
if needs_blending {
alpha_batch.push(instance);
} else {
opaque_batch.push(instance);
}
}
}
None => {
let batch = self.batch_list.get_suitable_batch(brush.get_batch_key(blend_mode), item_bounding_rect);
batch.push(PrimitiveInstance::from(base_instance));
}
}
render_tasks,
);
}
PrimitiveKind::Border => {
let border_cpu =
@ -1020,16 +980,20 @@ impl AlphaBatcher {
secondary_textures,
);
let batch = self.batch_list.get_suitable_batch(key, &item_bounding_rect);
let device_offset = (offset * LayerToWorldScale::new(1.0) * ctx.device_pixel_scale).round().to_i32();
let content_rect = prim_metadata.local_rect.translate(&-offset);
let rect =
(content_rect * LayerToWorldScale::new(1.0) * ctx.device_pixel_scale).round()
.to_i32();
let instance = CompositePrimitiveInstance::new(
task_address,
secondary_task_address,
RenderTaskAddress(0),
item_bounding_rect.origin.x - device_offset.x,
item_bounding_rect.origin.y - device_offset.y,
rect.origin.x,
rect.origin.y,
z,
item_bounding_rect.size.width,
item_bounding_rect.size.height,
rect.size.width,
rect.size.height,
);
batch.push(PrimitiveInstance::from(instance));
@ -1256,6 +1220,78 @@ impl AlphaBatcher {
}
}
}
fn add_brush_to_batch(
&mut self,
brush: &BrushPrimitive,
prim_metadata: &PrimitiveMetadata,
blend_mode: BlendMode,
clip_chain_rect_index: ClipChainRectIndex,
clip_task_address: RenderTaskAddress,
item_bounding_rect: &DeviceIntRect,
prim_cache_address: GpuCacheAddress,
scroll_id: ClipScrollNodeIndex,
task_address: RenderTaskAddress,
transform_kind: TransformedRectKind,
z: i32,
render_tasks: &RenderTaskTree,
) {
let base_instance = BrushInstance {
picture_address: task_address,
prim_address: prim_cache_address,
clip_chain_rect_index,
scroll_id,
clip_task_address,
z,
segment_index: 0,
user_data0: 0,
user_data1: 0,
};
match brush.segment_desc {
Some(ref segment_desc) => {
let opaque_batch = self.batch_list.opaque_batch_list.get_suitable_batch(
brush.get_batch_key(
BlendMode::None
),
item_bounding_rect
);
let alpha_batch = self.batch_list.alpha_batch_list.get_suitable_batch(
brush.get_batch_key(
BlendMode::PremultipliedAlpha
),
item_bounding_rect
);
for (i, segment) in segment_desc.segments.iter().enumerate() {
let is_inner = segment.edge_flags.is_empty();
let needs_blending = !prim_metadata.opacity.is_opaque ||
segment.clip_task_id.is_some() ||
(!is_inner && transform_kind == TransformedRectKind::Complex);
let clip_task_address = segment
.clip_task_id
.map_or(OPAQUE_TASK_ADDRESS, |id| render_tasks.get_task_address(id));
let instance = PrimitiveInstance::from(BrushInstance {
segment_index: i as i32,
clip_task_address,
..base_instance
});
if needs_blending {
alpha_batch.push(instance);
} else {
opaque_batch.push(instance);
}
}
}
None => {
let batch = self.batch_list.get_suitable_batch(brush.get_batch_key(blend_mode), item_bounding_rect);
batch.push(PrimitiveInstance::from(base_instance));
}
}
}
}
impl BrushPrimitive {

View File

@ -300,6 +300,7 @@ impl PicturePrimitive {
prim_context: &PrimitiveContext,
render_tasks: &mut RenderTaskTree,
prim_screen_rect: &DeviceIntRect,
prim_local_rect: &LayerRect,
child_tasks: Vec<RenderTaskId>,
parent_tasks: &mut Vec<RenderTaskId>,
) {
@ -344,12 +345,12 @@ impl PicturePrimitive {
self.render_task_id = Some(blur_render_task_id);
}
Some(PictureCompositeMode::Filter(FilterOp::DropShadow(offset, blur_radius, color))) => {
let screen_offset = (offset * content_scale).round().to_i32();
let rect = (prim_local_rect.translate(&-offset) * content_scale).round().to_i32();
let picture_task = RenderTask::new_picture(
Some(prim_screen_rect.size),
Some(rect.size),
prim_index,
RenderTargetKind::Color,
ContentOrigin::Screen(prim_screen_rect.origin - screen_offset),
ContentOrigin::Screen(rect.origin),
PremultipliedColorF::TRANSPARENT,
ClearMode::Transparent,
child_tasks,

View File

@ -1175,6 +1175,7 @@ impl PrimitiveStore {
prim_context,
render_tasks,
metadata.screen_rect.as_ref().expect("bug: trying to draw an off-screen picture!?"),
&metadata.local_rect,
child_tasks,
parent_tasks,
);
@ -1770,7 +1771,7 @@ impl PrimitiveStore {
let metadata = &mut self.cpu_metadata[prim_index.0];
if metadata.local_rect.size.width <= 0.0 ||
metadata.local_rect.size.height <= 0.0 {
warn!("invalid primitive rect {:?}", metadata.local_rect);
//warn!("invalid primitive rect {:?}", metadata.local_rect);
return None;
}

View File

@ -66,12 +66,15 @@ pub fn should_record_msg(msg: &ApiMsg) -> bool {
ApiMsg::UpdateResources(..) |
ApiMsg::AddDocument { .. } |
ApiMsg::DeleteDocument(..) => true,
ApiMsg::UpdateDocument(_, ref msg) => {
match *msg {
DocumentMsg::GetScrollNodeState(..) |
DocumentMsg::HitTest(..) => false,
_ => true,
ApiMsg::UpdateDocument(_, ref msgs) => {
for msg in msgs {
match *msg {
DocumentMsg::GetScrollNodeState(..) |
DocumentMsg::HitTest(..) => {}
_ => { return true; }
}
}
false
}
_ => false,
}

View File

@ -145,12 +145,33 @@ impl Document {
}
}
enum DocumentOp {
Nop,
Built,
ScrolledNop,
Scrolled(RenderedDocument),
Rendered(RenderedDocument),
struct DocumentOps {
scroll: bool,
build: bool,
render: bool,
}
impl DocumentOps {
fn nop() -> Self {
DocumentOps {
scroll: false,
build: false,
render: false,
}
}
fn build() -> Self {
DocumentOps {
build: true,
..DocumentOps::nop()
}
}
fn combine(&mut self, other: Self) {
self.scroll = self.scroll || other.scroll;
self.build = self.build || other.build;
self.render = self.render || other.render;
}
}
/// The unique id for WR resource identification.
@ -232,14 +253,14 @@ impl RenderBackend {
message: DocumentMsg,
frame_counter: u32,
profile_counters: &mut BackendProfileCounters,
) -> DocumentOp {
) -> DocumentOps {
let doc = self.documents.get_mut(&document_id).expect("No document?");
match message {
//TODO: move view-related messages in a separate enum?
DocumentMsg::SetPageZoom(factor) => {
doc.view.page_zoom_factor = factor.get();
DocumentOp::Nop
DocumentOps::nop()
}
DocumentMsg::EnableFrameOutput(pipeline_id, enable) => {
if enable {
@ -247,15 +268,15 @@ impl RenderBackend {
} else {
doc.output_pipelines.remove(&pipeline_id);
}
DocumentOp::Nop
DocumentOps::nop()
}
DocumentMsg::SetPinchZoom(factor) => {
doc.view.pinch_zoom_factor = factor.get();
DocumentOp::Nop
DocumentOps::nop()
}
DocumentMsg::SetPan(pan) => {
doc.view.pan = pan;
DocumentOp::Nop
DocumentOps::nop()
}
DocumentMsg::SetWindowParameters {
window_size,
@ -265,7 +286,7 @@ impl RenderBackend {
doc.view.window_size = window_size;
doc.view.inner_rect = inner_rect;
doc.view.device_pixel_ratio = device_pixel_ratio;
DocumentOp::Nop
DocumentOps::nop()
}
DocumentMsg::SetDisplayList {
epoch,
@ -277,10 +298,13 @@ impl RenderBackend {
preserve_frame_state,
resources,
} => {
profile_scope!("SetDisplayList");
// TODO: this will be removed from the SetDisplayList message soon.
self.resource_cache.update_resources(
resources,
&mut profile_counters.resources
);
self.resource_cache
.update_resources(resources, &mut profile_counters.resources);
profile_scope!("SetDisplayList");
let mut data;
while {
@ -316,7 +340,6 @@ impl RenderBackend {
viewport_size,
content_size,
);
doc.build_scene(&mut self.resource_cache);
}
if let Some(ref mut ros) = doc.render_on_scroll {
@ -337,7 +360,22 @@ impl RenderBackend {
display_list_len,
);
DocumentOp::Built
DocumentOps::build()
}
DocumentMsg::UpdateResources(updates) => {
profile_scope!("UpdateResources");
self.resource_cache.update_resources(
updates,
&mut profile_counters.resources
);
DocumentOps::nop()
}
DocumentMsg::UpdateEpoch(pipeline_id, epoch) => {
doc.scene.update_epoch(pipeline_id, epoch);
doc.frame_ctx.update_epoch(pipeline_id, epoch);
DocumentOps::nop()
}
DocumentMsg::UpdatePipelineResources { resources, pipeline_id, epoch } => {
profile_scope!("UpdateResources");
@ -348,40 +386,35 @@ impl RenderBackend {
doc.scene.update_epoch(pipeline_id, epoch);
doc.frame_ctx.update_epoch(pipeline_id, epoch);
DocumentOp::Nop
DocumentOps::nop()
}
DocumentMsg::SetRootPipeline(pipeline_id) => {
profile_scope!("SetRootPipeline");
doc.scene.set_root_pipeline_id(pipeline_id);
if doc.scene.pipelines.get(&pipeline_id).is_some() {
let _timer = profile_counters.total_time.timer();
doc.build_scene(&mut self.resource_cache);
DocumentOp::Built
DocumentOps::build()
} else {
DocumentOp::Nop
DocumentOps::nop()
}
}
DocumentMsg::RemovePipeline(pipeline_id) => {
profile_scope!("RemovePipeline");
doc.scene.remove_pipeline(pipeline_id);
DocumentOp::Nop
DocumentOps::nop()
}
DocumentMsg::Scroll(delta, cursor, move_phase) => {
profile_scope!("Scroll");
let _timer = profile_counters.total_time.timer();
if doc.frame_ctx.scroll(delta, cursor, move_phase) && doc.render_on_scroll == Some(true)
{
let frame = doc.render(
&mut self.resource_cache,
&mut self.gpu_cache,
&mut profile_counters.resources,
);
DocumentOp::Scrolled(frame)
} else {
DocumentOp::ScrolledNop
let should_render = doc.frame_ctx.scroll(delta, cursor, move_phase)
&& doc.render_on_scroll == Some(true);
DocumentOps {
scroll: true,
build: false,
render: should_render,
}
}
DocumentMsg::HitTest(pipeline_id, point, flags, tx) => {
@ -392,21 +425,19 @@ impl RenderBackend {
.unwrap()
.hit_test(cst, pipeline_id, point, flags);
tx.send(result).unwrap();
DocumentOp::Nop
DocumentOps::nop()
}
DocumentMsg::ScrollNodeWithId(origin, id, clamp) => {
profile_scope!("ScrollNodeWithScrollId");
let _timer = profile_counters.total_time.timer();
if doc.frame_ctx.scroll_node(origin, id, clamp) && doc.render_on_scroll == Some(true) {
let frame = doc.render(
&mut self.resource_cache,
&mut self.gpu_cache,
&mut profile_counters.resources,
);
DocumentOp::Scrolled(frame)
} else {
DocumentOp::ScrolledNop
let should_render = doc.frame_ctx.scroll_node(origin, id, clamp)
&& doc.render_on_scroll == Some(true);
DocumentOps {
scroll: true,
build: false,
render: should_render,
}
}
DocumentMsg::TickScrollingBounce => {
@ -414,44 +445,46 @@ impl RenderBackend {
let _timer = profile_counters.total_time.timer();
doc.frame_ctx.tick_scrolling_bounce_animations();
if doc.render_on_scroll == Some(true) {
let frame = doc.render(
&mut self.resource_cache,
&mut self.gpu_cache,
&mut profile_counters.resources,
);
DocumentOp::Scrolled(frame)
} else {
DocumentOp::ScrolledNop
DocumentOps {
scroll: true,
build: false,
render: doc.render_on_scroll == Some(true),
}
}
DocumentMsg::GetScrollNodeState(tx) => {
profile_scope!("GetScrollNodeState");
tx.send(doc.frame_ctx.get_scroll_node_state()).unwrap();
DocumentOp::Nop
DocumentOps::nop()
}
DocumentMsg::GenerateFrame(property_bindings) => {
profile_scope!("GenerateFrame");
DocumentMsg::UpdateDynamicProperties(property_bindings) => {
// Ideally, when there are property bindings present,
// we won't need to rebuild the entire frame here.
// However, to avoid conflicts with the ongoing work to
// refactor how scroll roots + transforms work, this
// just rebuilds the frame if there are animated property
// bindings present for now.
// TODO(gw): Once the scrolling / reference frame changes
// are completed, optimize the internals of
// animated properties to not require a full
// rebuild of the frame!
doc.scene.properties.set_properties(property_bindings);
DocumentOps::build()
}
DocumentMsg::GenerateFrame => {
let _timer = profile_counters.total_time.timer();
if let Some(property_bindings) = property_bindings {
doc.scene.properties.set_properties(property_bindings);
}
let mut op = DocumentOps::nop();
if let Some(ref mut ros) = doc.render_on_scroll {
*ros = true;
}
if doc.scene.root_pipeline_id.is_some() {
let frame = doc.render(
&mut self.resource_cache,
&mut self.gpu_cache,
&mut profile_counters.resources,
);
DocumentOp::Rendered(frame)
} else {
DocumentOp::ScrolledNop
op.render = true;
}
op
}
}
}
@ -515,30 +548,6 @@ impl RenderBackend {
);
self.documents.insert(document_id, document);
}
ApiMsg::UpdateDocument(document_id, doc_msg) => match self.process_document(
document_id,
doc_msg,
frame_counter,
&mut profile_counters,
) {
DocumentOp::Nop => {}
DocumentOp::Built => {}
DocumentOp::ScrolledNop => {
self.notify_compositor_of_new_scroll_document(document_id, false);
}
DocumentOp::Scrolled(doc) => {
self.publish_document(document_id, doc, &mut profile_counters);
self.notify_compositor_of_new_scroll_document(document_id, true);
}
DocumentOp::Rendered(doc) => {
frame_counter += 1;
self.publish_document_and_notify_compositor(
document_id,
doc,
&mut profile_counters,
);
}
},
ApiMsg::DeleteDocument(document_id) => {
self.documents.remove(&document_id);
}
@ -614,42 +623,71 @@ impl RenderBackend {
self.notifier.shut_down();
break;
}
ApiMsg::UpdateDocument(document_id, doc_msgs) => {
self.update_document(
document_id,
doc_msgs,
&mut frame_counter,
&mut profile_counters
)
}
}
}
}
fn publish_document(
fn update_document(
&mut self,
document_id: DocumentId,
document: RenderedDocument,
doc_msgs: Vec<DocumentMsg>,
frame_counter: &mut u32,
profile_counters: &mut BackendProfileCounters,
) {
let pending_update = self.resource_cache.pending_updates();
let msg = ResultMsg::PublishDocument(document_id, document, pending_update, profile_counters.clone());
self.result_tx.send(msg).unwrap();
profile_counters.reset();
let mut op = DocumentOps::nop();
for doc_msg in doc_msgs {
op.combine(
self.process_document(
document_id,
doc_msg,
*frame_counter,
profile_counters,
)
);
}
let doc = self.documents.get_mut(&document_id).unwrap();
if op.build {
profile_scope!("build scene");
doc.build_scene(&mut self.resource_cache);
}
if op.render {
profile_scope!("generate frame");
*frame_counter += 1;
let rendered_document = doc.render(
&mut self.resource_cache,
&mut self.gpu_cache,
&mut profile_counters.resources,
);
// Publish the frame
let pending_update = self.resource_cache.pending_updates();
let msg = ResultMsg::PublishDocument(
document_id,
rendered_document,
pending_update,
profile_counters.clone()
);
self.result_tx.send(msg).unwrap();
profile_counters.reset();
}
if op.render || op.scroll {
self.notifier.new_document_ready(document_id, op.scroll, op.render);
}
}
fn publish_document_and_notify_compositor(
&mut self,
document_id: DocumentId,
document: RenderedDocument,
profile_counters: &mut BackendProfileCounters,
) {
self.publish_document(document_id, document, profile_counters);
self.notifier.new_document_ready(document_id, false, true);
}
fn notify_compositor_of_new_scroll_document(
&self,
document_id: DocumentId,
composite_needed: bool,
) {
self.notifier.new_document_ready(document_id, true, composite_needed);
}
#[cfg(not(feature = "debugger"))]
fn get_docs_for_debugger(&self) -> String {
String::new()
@ -870,7 +908,18 @@ impl RenderBackend {
&mut self.gpu_cache,
&mut profile_counters.resources,
);
self.publish_document_and_notify_compositor(id, render_doc, profile_counters);
let pending_update = self.resource_cache.pending_updates();
let msg = ResultMsg::PublishDocument(
id,
render_doc,
pending_update,
profile_counters.clone()
);
self.result_tx.send(msg).unwrap();
profile_counters.reset();
self.notifier.new_document_ready(id, false, true);
self.documents.insert(id, doc);
}

View File

@ -2470,6 +2470,16 @@ impl Renderer {
fn debug_alpha_target(target: &AlphaRenderTarget) -> debug_server::Target {
let mut debug_target = debug_server::Target::new("A8");
debug_target.add(
debug_server::BatchKind::Cache,
"Scalings",
target.scalings.len(),
);
debug_target.add(
debug_server::BatchKind::Cache,
"Zero Clears",
target.zero_clears.len(),
);
debug_target.add(
debug_server::BatchKind::Clip,
"Clear",
@ -2516,6 +2526,16 @@ impl Renderer {
fn debug_color_target(target: &ColorRenderTarget) -> debug_server::Target {
let mut debug_target = debug_server::Target::new("RGBA8");
debug_target.add(
debug_server::BatchKind::Cache,
"Scalings",
target.scalings.len(),
);
debug_target.add(
debug_server::BatchKind::Cache,
"Readbacks",
target.readbacks.len(),
);
debug_target.add(
debug_server::BatchKind::Cache,
"Vertical Blur",

View File

@ -123,6 +123,174 @@ impl ResourceUpdates {
}
}
/// A Transaction is a group of commands to apply atomically to a document.
///
/// This mechanism ensures that:
/// - no other message can be interleaved between two commands that need to be applied together.
/// - no redundant work is performed if two commands in the same transaction cause the scene or
/// the frame to be rebuilt.
pub struct Transaction {
ops: Vec<DocumentMsg>,
payloads: Vec<Payload>,
}
impl Transaction {
pub fn new() -> Self {
Transaction {
ops: Vec::new(),
payloads: Vec::new(),
}
}
pub fn is_empty(&self) -> bool {
self.ops.is_empty()
}
pub fn update_epoch(&mut self, pipeline_id: PipelineId, epoch: Epoch) {
self.ops.push(DocumentMsg::UpdateEpoch(pipeline_id, epoch));
}
/// Sets the root pipeline.
///
/// # Examples
///
/// ```
/// # use webrender_api::{DeviceUintSize, PipelineId, RenderApiSender, Transaction};
/// # fn example() {
/// let pipeline_id = PipelineId(0, 0);
/// let mut txn = Transaction::new();
/// txn.set_root_pipeline(pipeline_id);
/// # }
/// ```
pub fn set_root_pipeline(&mut self, pipeline_id: PipelineId) {
self.ops.push(DocumentMsg::SetRootPipeline(pipeline_id));
}
/// Removes data associated with a pipeline from the internal data structures.
/// If the specified `pipeline_id` is for the root pipeline, the root pipeline
/// is reset back to `None`.
pub fn remove_pipeline(&mut self, pipeline_id: PipelineId) {
self.ops.push(DocumentMsg::RemovePipeline(pipeline_id));
}
/// Supplies a new frame to WebRender.
///
/// Non-blocking, it notifies a worker process which processes the display list.
/// When it's done and a RenderNotifier has been set in `webrender::Renderer`,
/// [new_frame_ready()][notifier] gets called.
///
/// Note: Scrolling doesn't require an own Frame.
///
/// Arguments:
///
/// * `document_id`: Target Document ID.
/// * `epoch`: The unique Frame ID, monotonically increasing.
/// * `background`: The background color of this pipeline.
/// * `viewport_size`: The size of the viewport for this frame.
/// * `pipeline_id`: The ID of the pipeline that is supplying this display list.
/// * `content_size`: The total screen space size of this display list's display items.
/// * `display_list`: The root Display list used in this frame.
/// * `preserve_frame_state`: If a previous frame exists which matches this pipeline
/// id, this setting determines if frame state (such as scrolling
/// position) should be preserved for this new display list.
/// * `resources`: A set of resource updates that must be applied at the same time as the
/// display list.
///
/// [notifier]: trait.RenderNotifier.html#tymethod.new_frame_ready
pub fn set_display_list(
&mut self,
epoch: Epoch,
background: Option<ColorF>,
viewport_size: LayoutSize,
(pipeline_id, content_size, display_list): (PipelineId, LayoutSize, BuiltDisplayList),
preserve_frame_state: bool,
) {
let (display_list_data, list_descriptor) = display_list.into_data();
self.ops.push(
DocumentMsg::SetDisplayList {
epoch,
pipeline_id,
background,
viewport_size,
content_size,
list_descriptor,
preserve_frame_state,
resources: ResourceUpdates::new(),
}
);
self.payloads.push(Payload { epoch, pipeline_id, display_list_data });
}
pub fn update_resources(&mut self, resources: ResourceUpdates) {
self.ops.push(DocumentMsg::UpdateResources(resources));
}
pub fn set_window_parameters(
&mut self,
window_size: DeviceUintSize,
inner_rect: DeviceUintRect,
device_pixel_ratio: f32,
) {
self.ops.push(
DocumentMsg::SetWindowParameters {
window_size,
inner_rect,
device_pixel_ratio,
},
);
}
/// Scrolls the scrolling layer under the `cursor`
///
/// WebRender looks for the layer closest to the user
/// which has `ScrollPolicy::Scrollable` set.
pub fn scroll(
&mut self,
scroll_location: ScrollLocation,
cursor: WorldPoint,
phase: ScrollEventPhase,
) {
self.ops.push(DocumentMsg::Scroll(scroll_location, cursor, phase));
}
pub fn scroll_node_with_id(
&mut self,
origin: LayoutPoint,
id: ClipId,
clamp: ScrollClamping,
) {
self.ops.push(DocumentMsg::ScrollNodeWithId(origin, id, clamp));
}
pub fn set_page_zoom(&mut self, page_zoom: ZoomFactor) {
self.ops.push(DocumentMsg::SetPageZoom(page_zoom));
}
pub fn set_pinch_zoom(&mut self, pinch_zoom: ZoomFactor) {
self.ops.push(DocumentMsg::SetPinchZoom(pinch_zoom));
}
pub fn set_pan(&mut self, pan: DeviceIntPoint) {
self.ops.push(DocumentMsg::SetPan(pan));
}
pub fn tick_scrolling_bounce_animations(&mut self) {
self.ops.push(DocumentMsg::TickScrollingBounce);
}
/// Generate a new frame.
pub fn generate_frame(&mut self) {
self.ops.push(DocumentMsg::GenerateFrame);
}
/// Supply a list of animated property bindings that should be used to resolve
/// bindings in the current display list.
pub fn update_dynamic_properties(&mut self, properties: DynamicProperties) {
self.ops.push(DocumentMsg::UpdateDynamicProperties(properties));
}
}
#[derive(Clone, Deserialize, Serialize)]
pub struct AddImage {
pub key: ImageKey,
@ -199,11 +367,14 @@ pub enum DocumentMsg {
preserve_frame_state: bool,
resources: ResourceUpdates,
},
UpdateResources(ResourceUpdates),
// TODO(nical): Remove this once gecko doesn't use it anymore.
UpdatePipelineResources {
resources: ResourceUpdates,
pipeline_id: PipelineId,
epoch: Epoch,
},
UpdateEpoch(PipelineId, Epoch),
SetPageZoom(ZoomFactor),
SetPinchZoom(ZoomFactor),
SetPan(DeviceIntPoint),
@ -219,7 +390,8 @@ pub enum DocumentMsg {
ScrollNodeWithId(LayoutPoint, ClipId, ScrollClamping),
TickScrollingBounce,
GetScrollNodeState(MsgSender<Vec<ScrollLayerState>>),
GenerateFrame(Option<DynamicProperties>),
GenerateFrame,
UpdateDynamicProperties(DynamicProperties),
}
impl fmt::Debug for DocumentMsg {
@ -238,8 +410,11 @@ impl fmt::Debug for DocumentMsg {
DocumentMsg::ScrollNodeWithId(..) => "DocumentMsg::ScrollNodeWithId",
DocumentMsg::TickScrollingBounce => "DocumentMsg::TickScrollingBounce",
DocumentMsg::GetScrollNodeState(..) => "DocumentMsg::GetScrollNodeState",
DocumentMsg::GenerateFrame(..) => "DocumentMsg::GenerateFrame",
DocumentMsg::GenerateFrame => "DocumentMsg::GenerateFrame",
DocumentMsg::EnableFrameOutput(..) => "DocumentMsg::EnableFrameOutput",
DocumentMsg::UpdateResources(..) => "DocumentMsg::UpdateResources",
DocumentMsg::UpdateEpoch(..) => "DocumentMsg::UpdateEpoch",
DocumentMsg::UpdateDynamicProperties(..) => "DocumentMsg::UpdateDynamicProperties",
})
}
}
@ -293,7 +468,7 @@ pub enum ApiMsg {
/// Adds a new document with given initial size.
AddDocument(DocumentId, DeviceUintSize, DocumentLayer),
/// A message targeted at a particular document.
UpdateDocument(DocumentId, DocumentMsg),
UpdateDocument(DocumentId, Vec<DocumentMsg>),
/// Deletes an existing document.
DeleteDocument(DocumentId),
/// An opaque handle that must be passed to the render notifier. It is used by Gecko
@ -570,10 +745,15 @@ impl RenderApi {
// `RenderApi` instances for layout and compositor.
//assert_eq!(document_id.0, self.namespace_id);
self.api_sender
.send(ApiMsg::UpdateDocument(document_id, msg))
.send(ApiMsg::UpdateDocument(document_id, vec![msg]))
.unwrap()
}
// TODO(nical) - decide what to do with the methods that are duplicated in Transaction.
// I think that we should remove them from RenderApi but we could also leave them here if
// it makes things easier for servo.
// They are all equivalent to creating a transaction with a single command.
/// Sets the root pipeline.
///
/// # Examples
@ -630,8 +810,14 @@ impl RenderApi {
viewport_size: LayoutSize,
(pipeline_id, content_size, display_list): (PipelineId, LayoutSize, BuiltDisplayList),
preserve_frame_state: bool,
resources: ResourceUpdates,
resources: ResourceUpdates, // TODO: this will be removed soon.
) {
// TODO(nical) set_display_list uses the epoch to match the displaylist and the payload
// coming from different channels when receiving in the render backend.
// It would be cleaner to use a separate id that is implicitly generated for the displaylist-payload
// matching so that the semantics of epochs is really up to the api user and so that the latter can't
// introduce bugs by accidently using the same epoch twice.
let (display_list_data, list_descriptor) = display_list.into_data();
self.send(
document_id,
@ -656,6 +842,13 @@ impl RenderApi {
.unwrap();
}
pub fn send_transaction(&mut self, document_id: DocumentId, transaction: Transaction) {
for payload in transaction.payloads {
self.payload_sender.send_payload(payload).unwrap();
}
self.api_sender.send(ApiMsg::UpdateDocument(document_id, transaction.ops)).unwrap();
}
/// Scrolls the scrolling layer under the `cursor`
///
/// WebRender looks for the layer closest to the user
@ -764,7 +957,10 @@ impl RenderApi {
document_id: DocumentId,
property_bindings: Option<DynamicProperties>,
) {
self.send(document_id, DocumentMsg::GenerateFrame(property_bindings));
if let Some(properties) = property_bindings {
self.send(document_id, DocumentMsg::UpdateDynamicProperties(properties));
}
self.send(document_id, DocumentMsg::GenerateFrame);
}
/// Save a capture of the current frame state for debugging.