mirror of
https://github.com/servo/servo.git
synced 2025-08-07 06:25:32 +01:00
Add NodeStatus enum, infrastructure for compositor-side invalidation
This commit is contained in:
parent
2359587cbb
commit
f9df74595c
4 changed files with 111 additions and 16 deletions
|
@ -12,7 +12,7 @@ use servo_msg::constellation_msg::PipelineId;
|
||||||
use script::dom::event::{ClickEvent, MouseDownEvent, MouseUpEvent};
|
use script::dom::event::{ClickEvent, MouseDownEvent, MouseUpEvent};
|
||||||
use script::script_task::SendEventMsg;
|
use script::script_task::SendEventMsg;
|
||||||
use windowing::{MouseWindowEvent, MouseWindowClickEvent, MouseWindowMouseDownEvent, MouseWindowMouseUpEvent};
|
use windowing::{MouseWindowEvent, MouseWindowClickEvent, MouseWindowMouseDownEvent, MouseWindowMouseUpEvent};
|
||||||
use compositing::quadtree::Quadtree;
|
use compositing::quadtree::{Quadtree, Invalid};
|
||||||
use layers::layers::{ContainerLayerKind, ContainerLayer, TextureLayerKind, TextureLayer, TextureManager};
|
use layers::layers::{ContainerLayerKind, ContainerLayer, TextureLayerKind, TextureLayer, TextureManager};
|
||||||
use pipeline::Pipeline;
|
use pipeline::Pipeline;
|
||||||
|
|
||||||
|
@ -367,6 +367,19 @@ impl CompositorLayer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn invalidate_rect(&mut self, pipeline_id: PipelineId, rect: Rect<f32>) -> bool {
|
||||||
|
if self.pipeline.id == pipeline_id {
|
||||||
|
let quadtree = match self.quadtree {
|
||||||
|
NoTree(_, _) => return true, // Nothing to do
|
||||||
|
Tree(ref mut quadtree) => quadtree,
|
||||||
|
};
|
||||||
|
quadtree.set_status_page(rect, Invalid, true);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// ID does not match ours, so recurse on descendents (including hidden children).
|
||||||
|
self.children.mut_iter().map(|x| &mut x.child).any(|x| x.invalidate_rect(pipeline_id, rect))
|
||||||
|
}
|
||||||
|
|
||||||
// Adds a child.
|
// Adds a child.
|
||||||
pub fn add_child(&mut self, pipeline: Pipeline, page_size: Option<Size2D<f32>>, tile_size: uint,
|
pub fn add_child(&mut self, pipeline: Pipeline, page_size: Option<Size2D<f32>>, tile_size: uint,
|
||||||
max_mem: Option<uint>, clipping_rect: Rect<f32>) {
|
max_mem: Option<uint>, clipping_rect: Rect<f32>) {
|
||||||
|
|
|
@ -66,6 +66,10 @@ impl ScriptListener for CompositorChan {
|
||||||
self.chan.send(msg);
|
self.chan.send(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn invalidate_rect(&self, id: PipelineId, rect: Rect<uint>) {
|
||||||
|
self.chan.send(InvalidateRect(id, rect));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Implementation of the abstract `RenderListener` interface.
|
/// Implementation of the abstract `RenderListener` interface.
|
||||||
|
@ -131,6 +135,8 @@ pub enum Msg {
|
||||||
ResizeLayer(PipelineId, Size2D<uint>),
|
ResizeLayer(PipelineId, Size2D<uint>),
|
||||||
/// Alerts the compositor that the specified layer has been deleted.
|
/// Alerts the compositor that the specified layer has been deleted.
|
||||||
DeleteLayer(PipelineId),
|
DeleteLayer(PipelineId),
|
||||||
|
/// Invalidate a rect for a given layer
|
||||||
|
InvalidateRect(PipelineId, Rect<uint>),
|
||||||
|
|
||||||
/// Requests that the compositor paint the given layer buffer set for the given page size.
|
/// Requests that the compositor paint the given layer buffer set for the given page size.
|
||||||
Paint(PipelineId, arc::Arc<LayerBufferSet>),
|
Paint(PipelineId, arc::Arc<LayerBufferSet>),
|
||||||
|
@ -312,6 +318,19 @@ impl CompositorTask {
|
||||||
// TODO: Recycle the old buffers; send them back to the renderer to reuse if
|
// TODO: Recycle the old buffers; send them back to the renderer to reuse if
|
||||||
// it wishes.
|
// it wishes.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
InvalidateRect(id, rect) => {
|
||||||
|
match compositor_layer {
|
||||||
|
Some(ref mut layer) => {
|
||||||
|
layer.invalidate_rect(id, Rect(Point2D(rect.origin.x as f32,
|
||||||
|
rect.origin.y as f32),
|
||||||
|
Size2D(rect.size.width as f32,
|
||||||
|
rect.size.height as f32)));
|
||||||
|
ask_for_tiles();
|
||||||
|
}
|
||||||
|
None => {} // Nothing to do
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -41,10 +41,24 @@ struct QuadtreeNode<T> {
|
||||||
size: f32,
|
size: f32,
|
||||||
/// The node's children.
|
/// The node's children.
|
||||||
quadrants: [Option<~QuadtreeNode<T>>, ..4],
|
quadrants: [Option<~QuadtreeNode<T>>, ..4],
|
||||||
/// If this node is marked for rendering
|
|
||||||
render_flag: bool,
|
|
||||||
/// Combined size of self.tile and tiles of all descendants
|
/// Combined size of self.tile and tiles of all descendants
|
||||||
tile_mem: uint,
|
tile_mem: uint,
|
||||||
|
/// The current status of this node. See below for details.
|
||||||
|
status: NodeStatus,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The status of a QuadtreeNode. This determines the behavior of the node
|
||||||
|
/// when querying for tile requests.
|
||||||
|
#[deriving(Eq)]
|
||||||
|
pub enum NodeStatus {
|
||||||
|
/// If we have no valid tile, request one; otherwise, don't send a request.
|
||||||
|
Normal,
|
||||||
|
/// Render request has been sent; ignore this node until tile is inserted.
|
||||||
|
Rendering,
|
||||||
|
/// Do not send tile requests. Overrides Invalid.
|
||||||
|
Hidden,
|
||||||
|
/// Send tile requests, even if the node has (or child nodes have) a valid tile.
|
||||||
|
Invalid,
|
||||||
}
|
}
|
||||||
|
|
||||||
enum Quadrant {
|
enum Quadrant {
|
||||||
|
@ -72,8 +86,8 @@ impl<T: Tile> Quadtree<T> {
|
||||||
origin: Point2D(0f32, 0f32),
|
origin: Point2D(0f32, 0f32),
|
||||||
size: size as f32,
|
size: size as f32,
|
||||||
quadrants: [None, None, None, None],
|
quadrants: [None, None, None, None],
|
||||||
render_flag: false,
|
|
||||||
tile_mem: 0,
|
tile_mem: 0,
|
||||||
|
status: Normal,
|
||||||
},
|
},
|
||||||
clip_size: Size2D(width, height),
|
clip_size: Size2D(width, height),
|
||||||
max_tile_size: tile_size,
|
max_tile_size: tile_size,
|
||||||
|
@ -184,7 +198,7 @@ impl<T: Tile> Quadtree<T> {
|
||||||
Rect(Point2D(window.origin.x as f32 / scale, window.origin.y as f32 / scale),
|
Rect(Point2D(window.origin.x as f32 / scale, window.origin.y as f32 / scale),
|
||||||
Size2D(window.size.width as f32 / scale, window.size.height as f32 / scale)),
|
Size2D(window.size.width as f32 / scale, window.size.height as f32 / scale)),
|
||||||
Size2D(self.clip_size.width as f32, self.clip_size.height as f32),
|
Size2D(self.clip_size.width as f32, self.clip_size.height as f32),
|
||||||
scale, self.max_tile_size as f32 / scale);
|
scale, self.max_tile_size as f32 / scale, false);
|
||||||
(ret, redisplay)
|
(ret, redisplay)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -193,7 +207,7 @@ impl<T: Tile> Quadtree<T> {
|
||||||
let (ret, redisplay, _) = self.root.get_tile_rects(
|
let (ret, redisplay, _) = self.root.get_tile_rects(
|
||||||
window,
|
window,
|
||||||
Size2D(self.clip_size.width as f32, self.clip_size.height as f32),
|
Size2D(self.clip_size.width as f32, self.clip_size.height as f32),
|
||||||
scale, self.max_tile_size as f32 / scale);
|
scale, self.max_tile_size as f32 / scale, false);
|
||||||
(ret, redisplay)
|
(ret, redisplay)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -218,8 +232,8 @@ impl<T: Tile> Quadtree<T> {
|
||||||
origin: Point2D(0f32, 0f32),
|
origin: Point2D(0f32, 0f32),
|
||||||
size: new_size as f32 / ((difference - i - 1) as f32).exp2(),
|
size: new_size as f32 / ((difference - i - 1) as f32).exp2(),
|
||||||
quadrants: [None, None, None, None],
|
quadrants: [None, None, None, None],
|
||||||
render_flag: false,
|
|
||||||
tile_mem: self.root.tile_mem,
|
tile_mem: self.root.tile_mem,
|
||||||
|
status: Normal,
|
||||||
};
|
};
|
||||||
self.root.quadrants[TL as int] = Some(replace(&mut self.root, new_root));
|
self.root.quadrants[TL as int] = Some(replace(&mut self.root, new_root));
|
||||||
}
|
}
|
||||||
|
@ -235,8 +249,8 @@ impl<T: Tile> Quadtree<T> {
|
||||||
origin: Point2D(0f32, 0f32),
|
origin: Point2D(0f32, 0f32),
|
||||||
size: new_size as f32,
|
size: new_size as f32,
|
||||||
quadrants: [None, None, None, None],
|
quadrants: [None, None, None, None],
|
||||||
render_flag: false,
|
|
||||||
tile_mem: 0,
|
tile_mem: 0,
|
||||||
|
status: Normal,
|
||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -245,6 +259,13 @@ impl<T: Tile> Quadtree<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set the status of all quadtree nodes within the given rect in page coordinates. If
|
||||||
|
/// include_border is true, then nodes on the edge of the rect will be included; otherwise,
|
||||||
|
/// only nodes completely occluded by the rect will be changed.
|
||||||
|
pub fn set_status_page(&mut self, rect: Rect<f32>, status: NodeStatus, include_border: bool) {
|
||||||
|
self.root.set_status(rect, status, include_border);
|
||||||
|
}
|
||||||
|
|
||||||
/// Generate html to visualize the tree. For debugging purposes only.
|
/// Generate html to visualize the tree. For debugging purposes only.
|
||||||
pub fn get_html(&self) -> ~str {
|
pub fn get_html(&self) -> ~str {
|
||||||
static HEADER: &'static str = "<!DOCTYPE html><html>";
|
static HEADER: &'static str = "<!DOCTYPE html><html>";
|
||||||
|
@ -261,8 +282,8 @@ impl<T: Tile> QuadtreeNode<T> {
|
||||||
origin: Point2D(x, y),
|
origin: Point2D(x, y),
|
||||||
size: size,
|
size: size,
|
||||||
quadrants: [None, None, None, None],
|
quadrants: [None, None, None, None],
|
||||||
render_flag: false,
|
|
||||||
tile_mem: 0,
|
tile_mem: 0,
|
||||||
|
status: Normal,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -335,7 +356,7 @@ impl<T: Tile> QuadtreeNode<T> {
|
||||||
for quad in quads.iter() {
|
for quad in quads.iter() {
|
||||||
self.quadrants[*quad as int] = None;
|
self.quadrants[*quad as int] = None;
|
||||||
}
|
}
|
||||||
self.render_flag = false;
|
self.status = Normal;
|
||||||
self.tile_mem as int - old_size as int
|
self.tile_mem as int - old_size as int
|
||||||
} else { // Send tile to children
|
} else { // Send tile to children
|
||||||
let quad = self.get_quadrant(x, y);
|
let quad = self.get_quadrant(x, y);
|
||||||
|
@ -380,7 +401,7 @@ impl<T: Tile> QuadtreeNode<T> {
|
||||||
let page_height = (clip_y - self.origin.y).min(&self.size);
|
let page_height = (clip_y - self.origin.y).min(&self.size);
|
||||||
let pix_width = (page_width * scale).ceil() as uint;
|
let pix_width = (page_width * scale).ceil() as uint;
|
||||||
let pix_height = (page_height * scale).ceil() as uint;
|
let pix_height = (page_height * scale).ceil() as uint;
|
||||||
self.render_flag = true;
|
self.status = Rendering;
|
||||||
return BufferRequest(Rect(Point2D(pix_x, pix_y), Size2D(pix_width, pix_height)),
|
return BufferRequest(Rect(Point2D(pix_x, pix_y), Size2D(pix_width, pix_height)),
|
||||||
Rect(Point2D(self.origin.x, self.origin.y), Size2D(page_width, page_height)));
|
Rect(Point2D(self.origin.x, self.origin.y), Size2D(page_width, page_height)));
|
||||||
}
|
}
|
||||||
|
@ -477,9 +498,11 @@ impl<T: Tile> QuadtreeNode<T> {
|
||||||
|
|
||||||
/// Given a window rect in page coordinates, returns a BufferRequest array,
|
/// Given a window rect in page coordinates, returns a BufferRequest array,
|
||||||
/// a redisplay boolean, and the difference in tile memory between the new and old quadtree nodes.
|
/// a redisplay boolean, and the difference in tile memory between the new and old quadtree nodes.
|
||||||
|
/// The override bool will be true if a parent node was marked as invalid; child nodes will be
|
||||||
|
/// treated as invalid as well.
|
||||||
/// NOTE: this method will sometimes modify the tree by deleting tiles.
|
/// NOTE: this method will sometimes modify the tree by deleting tiles.
|
||||||
/// See the QuadTree function description for more details.
|
/// See the QuadTree function description for more details.
|
||||||
fn get_tile_rects(&mut self, window: Rect<f32>, clip: Size2D<f32>, scale: f32, tile_size: f32) ->
|
fn get_tile_rects(&mut self, window: Rect<f32>, clip: Size2D<f32>, scale: f32, tile_size: f32, override: bool) ->
|
||||||
(~[BufferRequest], bool, int) {
|
(~[BufferRequest], bool, int) {
|
||||||
|
|
||||||
let w_x = window.origin.x;
|
let w_x = window.origin.x;
|
||||||
|
@ -503,8 +526,9 @@ impl<T: Tile> QuadtreeNode<T> {
|
||||||
|
|
||||||
if s_size <= tile_size { // We are the child
|
if s_size <= tile_size { // We are the child
|
||||||
return match self.tile {
|
return match self.tile {
|
||||||
_ if self.render_flag => (~[], false, 0),
|
_ if self.status == Rendering || self.status == Hidden => (~[], false, 0),
|
||||||
Some(ref tile) if tile.is_valid(scale) => {
|
Some(ref tile) if tile.is_valid(scale) && !override
|
||||||
|
&& self.status != Invalid => {
|
||||||
let redisplay = match self.quadrants {
|
let redisplay = match self.quadrants {
|
||||||
[None, None, None, None] => false,
|
[None, None, None, None] => false,
|
||||||
_ => true,
|
_ => true,
|
||||||
|
@ -582,8 +606,10 @@ impl<T: Tile> QuadtreeNode<T> {
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let override = override || self.status == Invalid;
|
||||||
|
self.status = Normal;
|
||||||
let (c_ret, c_redisplay, c_delta) = match self.quadrants[*quad as int] {
|
let (c_ret, c_redisplay, c_delta) = match self.quadrants[*quad as int] {
|
||||||
Some(ref mut child) => child.get_tile_rects(new_window, clip, scale, tile_size),
|
Some(ref mut child) => child.get_tile_rects(new_window, clip, scale, tile_size, override),
|
||||||
None => {
|
None => {
|
||||||
// Create new child
|
// Create new child
|
||||||
let new_size = self.size / 2.0;
|
let new_size = self.size / 2.0;
|
||||||
|
@ -596,7 +622,7 @@ impl<T: Tile> QuadtreeNode<T> {
|
||||||
BL | BR => self.origin.y + new_size,
|
BL | BR => self.origin.y + new_size,
|
||||||
};
|
};
|
||||||
let mut child = ~QuadtreeNode::new_child(new_x, new_y, new_size);
|
let mut child = ~QuadtreeNode::new_child(new_x, new_y, new_size);
|
||||||
let ret = child.get_tile_rects(new_window, clip, scale, tile_size);
|
let ret = child.get_tile_rects(new_window, clip, scale, tile_size, override);
|
||||||
self.quadrants[*quad as int] = Some(child);
|
self.quadrants[*quad as int] = Some(child);
|
||||||
ret
|
ret
|
||||||
}
|
}
|
||||||
|
@ -610,6 +636,42 @@ impl<T: Tile> QuadtreeNode<T> {
|
||||||
(ret, redisplay, delta)
|
(ret, redisplay, delta)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set the status of nodes contained within the rect. See the quadtree method for
|
||||||
|
/// more info.
|
||||||
|
fn set_status(&mut self, rect: Rect<f32>, status: NodeStatus, borders: bool) {
|
||||||
|
let self_rect = Rect(self.origin, Size2D(self.size, self.size));
|
||||||
|
let intersect = rect.intersection(&self_rect);
|
||||||
|
let intersect = match intersect {
|
||||||
|
None => return, // We do not intersect the rect, nothing to do
|
||||||
|
Some(rect) => rect,
|
||||||
|
};
|
||||||
|
|
||||||
|
if self_rect == intersect { // We are completely contained in the rect
|
||||||
|
if !(self.status == Hidden && status == Invalid) { // Hidden trumps Invalid
|
||||||
|
self.status = status;
|
||||||
|
}
|
||||||
|
return; // No need to recurse
|
||||||
|
}
|
||||||
|
|
||||||
|
match self.quadrants {
|
||||||
|
[None, None, None, None] => { // We are a leaf
|
||||||
|
if borders && !(self.status == Hidden && status == Invalid) {
|
||||||
|
self.status = status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => { // We are internal
|
||||||
|
for quad in self.quadrants.mut_iter() {
|
||||||
|
match *quad {
|
||||||
|
None => {} // Nothing to do
|
||||||
|
Some(ref mut child) => {
|
||||||
|
child.set_status(intersect, status, borders);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Generate html to visualize the tree.
|
/// Generate html to visualize the tree.
|
||||||
/// This is really inefficient, but it's for testing only.
|
/// This is really inefficient, but it's for testing only.
|
||||||
fn get_html(&self) -> ~str {
|
fn get_html(&self) -> ~str {
|
||||||
|
|
|
@ -69,6 +69,7 @@ pub trait RenderListener {
|
||||||
/// which is used in displaying the appropriate message in the window's title.
|
/// which is used in displaying the appropriate message in the window's title.
|
||||||
pub trait ScriptListener : Clone {
|
pub trait ScriptListener : Clone {
|
||||||
fn set_ready_state(&self, ReadyState);
|
fn set_ready_state(&self, ReadyState);
|
||||||
|
fn invalidate_rect(&self, PipelineId, Rect<uint>);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The interface used by the quadtree to get info about LayerBuffers
|
/// The interface used by the quadtree to get info about LayerBuffers
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue