mirror of
https://github.com/servo/servo.git
synced 2025-08-06 06:00:15 +01:00
Implement progressive rendering
This commit is contained in:
parent
ad7dc32fc8
commit
6bebda4f26
4 changed files with 322 additions and 86 deletions
|
@ -33,7 +33,7 @@ pub struct RenderLayer {
|
|||
|
||||
pub enum Msg {
|
||||
RenderMsg(RenderLayer),
|
||||
ReRenderMsg(f32),
|
||||
ReRenderMsg(~Rect<uint>], f32),
|
||||
PaintPermissionGranted,
|
||||
PaintPermissionRevoked,
|
||||
ExitMsg(Chan<()>),
|
||||
|
@ -119,11 +119,11 @@ impl<C: RenderListener + Send> RenderTask<C> {
|
|||
loop {
|
||||
match self.port.recv() {
|
||||
RenderMsg(render_layer) => {
|
||||
self.compositor.new_layer(render_layer.size, self.opts.tile_size);
|
||||
self.render_layer = Some(render_layer);
|
||||
self.render(1.0);
|
||||
}
|
||||
ReRenderMsg(scale) => {
|
||||
self.render(scale);
|
||||
ReRenderMsg(tiles, scale) => {
|
||||
self.render(tiles, scale);
|
||||
}
|
||||
PaintPermissionGranted => {
|
||||
self.paint_permission = true;
|
||||
|
@ -146,15 +146,15 @@ impl<C: RenderListener + Send> RenderTask<C> {
|
|||
}
|
||||
}
|
||||
|
||||
fn render(&mut self, scale: f32) {
|
||||
fn render(&mut self, tiles: ~[Rect<uint>], scale: f32) {
|
||||
debug!("render_task: rendering");
|
||||
|
||||
let render_layer;
|
||||
match (self.render_layer) {
|
||||
None => return,
|
||||
match self.render_layer {
|
||||
Some(ref r_layer) => {
|
||||
render_layer = r_layer;
|
||||
}
|
||||
_ => return, // nothing to do
|
||||
}
|
||||
|
||||
self.compositor.set_render_state(RenderingRenderState);
|
||||
|
@ -166,30 +166,26 @@ impl<C: RenderListener + Send> RenderTask<C> {
|
|||
|
||||
// Divide up the layer into tiles.
|
||||
do time::profile(time::RenderingPrepBuffCategory, self.profiler_chan.clone()) {
|
||||
let mut y = 0;
|
||||
while y < (render_layer.size.height as f32 * scale).ceil() as uint {
|
||||
let mut x = 0;
|
||||
while x < (render_layer.size.width as f32 * scale).ceil() as uint {
|
||||
// Figure out the dimension of this tile.
|
||||
let right = uint::min(x + tile_size, (render_layer.size.width as f32 * scale).ceil() as uint);
|
||||
let bottom = uint::min(y + tile_size, (render_layer.size.height as f32 * scale).ceil() as uint);
|
||||
let width = right - x;
|
||||
let height = bottom - y;
|
||||
for tiles.each |tile_rect| {
|
||||
let x = tile_rect.origin.x;
|
||||
let y = tile_rect.origin.y;
|
||||
let width = tile_rect.size.width;
|
||||
let height = tile_rect.size.height;
|
||||
|
||||
let tile_rect = Rect(Point2D(x as f32 / scale, y as f32 / scale), Size2D(width as f32, height as f32));
|
||||
let screen_rect = Rect(Point2D(x, y), Size2D(width, height));
|
||||
let rect = Rect(Point2D(x as f32 / scale, y as f32 / scale), Size2D(width as f32, height as f32));
|
||||
|
||||
let buffer = LayerBuffer {
|
||||
draw_target: DrawTarget::new_with_fbo(self.opts.render_backend,
|
||||
self.share_gl_context,
|
||||
Size2D(width as i32,
|
||||
height as i32),
|
||||
Size2D(width as i32, height as i32),
|
||||
B8G8R8A8),
|
||||
rect: tile_rect,
|
||||
screen_pos: screen_rect,
|
||||
rect: rect,
|
||||
screen_pos: *tile_rect,
|
||||
resolution: scale,
|
||||
stride: (width * 4) as uint
|
||||
};
|
||||
|
||||
|
||||
{
|
||||
// Build the render context.
|
||||
let ctx = RenderContext {
|
||||
|
@ -218,11 +214,8 @@ impl<C: RenderListener + Send> RenderTask<C> {
|
|||
|
||||
new_buffers.push(buffer);
|
||||
|
||||
x += tile_size;
|
||||
}
|
||||
|
||||
y += tile_size;
|
||||
}
|
||||
}
|
||||
|
||||
let layer_buffer_set = LayerBufferSet {
|
||||
|
|
|
@ -10,7 +10,7 @@ use windowing::{ApplicationMethods, WindowMethods, WindowMouseEvent, WindowClick
|
|||
use windowing::{WindowMouseDownEvent, WindowMouseUpEvent};
|
||||
|
||||
|
||||
use servo_msg::compositor_msg::{RenderListener, LayerBufferSet, RenderState};
|
||||
use servo_msg::compositor_msg::{RenderListener, LayerBuffer, LayerBufferSet, RenderState};
|
||||
use servo_msg::compositor_msg::{ReadyState, ScriptListener};
|
||||
use servo_msg::constellation_msg::{CompositorAck, ConstellationChan};
|
||||
use servo_msg::constellation_msg;
|
||||
|
@ -28,6 +28,7 @@ use extra::timer;
|
|||
use geom::matrix::identity;
|
||||
use geom::point::Point2D;
|
||||
use geom::size::Size2D;
|
||||
use geom::rect::Rect; //eschweic
|
||||
use layers::layers::{ARGB32Format, ContainerLayer, ContainerLayerKind, Format};
|
||||
use layers::layers::{ImageData, WithDataFn};
|
||||
use layers::layers::{TextureLayerKind, TextureLayer, TextureManager};
|
||||
|
@ -40,6 +41,10 @@ use servo_util::time::ProfilerChan;
|
|||
use extra::arc;
|
||||
pub use windowing;
|
||||
|
||||
//eschweic
|
||||
use compositing::quadtree::Quadtree;
|
||||
mod quadtree;
|
||||
|
||||
/// The implementation of the layers-based compositor.
|
||||
#[deriving(Clone)]
|
||||
pub struct CompositorChan {
|
||||
|
@ -70,6 +75,17 @@ impl RenderListener for CompositorChan {
|
|||
self.chan.send(Paint(id, layer_buffer_set, new_size))
|
||||
}
|
||||
|
||||
//eschweic
|
||||
fn new_layer(&self, page_size: Size2D<uint>, tile_size: uint) {
|
||||
self.chan.send(NewLayer(page_size, tile_size))
|
||||
}
|
||||
fn resize_layer(&self, page_size: Size2D<uint>) {
|
||||
self.chan.send(ResizeLayer(page_size))
|
||||
}
|
||||
fn delete_layer(&self) {
|
||||
self.chan.send(DeleteLayer)
|
||||
}
|
||||
|
||||
fn set_render_state(&self, render_state: RenderState) {
|
||||
self.chan.send(ChangeRenderState(render_state))
|
||||
}
|
||||
|
@ -102,6 +118,16 @@ pub enum Msg {
|
|||
GetSize(Chan<Size2D<int>>),
|
||||
/// Requests the compositors GL context.
|
||||
GetGLContext(Chan<AzGLContext>),
|
||||
|
||||
//eschweic
|
||||
// FIXME: Attach layer ids and epochs to these messages
|
||||
/// Alerts the compositor that there is a new layer to be rendered.
|
||||
NewLayer(Size2D<uint>, uint),
|
||||
/// Alerts the compositor that the current layer has changed size.
|
||||
ResizeLayer(Size2D<uint>),
|
||||
/// Alerts the compositor that the current layer has been deleted.
|
||||
DeleteLayer,
|
||||
|
||||
/// Requests that the compositor paint the given layer buffer set for the given page size.
|
||||
Paint(uint, arc::ARC<LayerBufferSet>, Size2D<uint>),
|
||||
/// Alerts the compositor to the current status of page loading.
|
||||
|
@ -199,9 +225,61 @@ impl CompositorTask {
|
|||
let local_zoom = @mut 1f32;
|
||||
// Channel to the current renderer.
|
||||
// FIXME: This probably shouldn't be stored like this.
|
||||
|
||||
let render_chan: @mut Option<RenderChan> = @mut None;
|
||||
let pipeline_id: @mut Option<uint> = @mut None;
|
||||
|
||||
// Quadtree for this layer
|
||||
// FIXME: This should be one-per-layer
|
||||
let quadtree: @mut Option<Quadtree<LayerBuffer>> = @mut None;
|
||||
|
||||
|
||||
let ask_for_tiles: @fn() = || {
|
||||
match *quadtree {
|
||||
Some(ref quad) => {
|
||||
let mut tile_size = quad.get_tile_size(); // temporary solution
|
||||
let mut tile_request = ~[]; //FIXME: try not to allocate if possible
|
||||
|
||||
let mut y = world_offset.y as uint;
|
||||
while y < world_offset.y as uint + window_size.height + tile_size {
|
||||
let mut x = world_offset.x as uint;
|
||||
while x < world_offset.x as uint + window_size.width + tile_size {
|
||||
match *(quad.get_tile(x, y, *world_zoom)) {
|
||||
Some(ref current_tile) => {
|
||||
if current_tile.resolution == *world_zoom {
|
||||
x += tile_size;
|
||||
loop; // we already have this tile
|
||||
}
|
||||
}
|
||||
None => {} // fall through
|
||||
}
|
||||
let (tile_pos, new_tile_size) = quad.get_tile_rect(x, y, *world_zoom);
|
||||
tile_size = new_tile_size;
|
||||
x = tile_pos.x;
|
||||
y = tile_pos.y;
|
||||
|
||||
// TODO: clamp tiles to page bounds
|
||||
// TODO: add null buffer/checkerboard tile to stop a flood of requests
|
||||
println(fmt!("requesting tile: (%?, %?): %?", x, y, tile_size));
|
||||
tile_request.push(Rect(Point2D(x, y), Size2D(tile_size, tile_size)));
|
||||
|
||||
x += tile_size;
|
||||
}
|
||||
y += tile_size;
|
||||
}
|
||||
if !tile_request.is_empty() {
|
||||
match *render_chan {
|
||||
Some(ref chan) => {
|
||||
chan.send(ReRenderMsg(tile_request, *world_zoom));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
};
|
||||
|
||||
let update_layout_callbacks: @fn(LayoutChan) = |layout_chan: LayoutChan| {
|
||||
let layout_chan_clone = layout_chan.clone();
|
||||
do window.set_navigation_callback |direction| {
|
||||
|
@ -247,17 +325,31 @@ impl CompositorTask {
|
|||
}
|
||||
WindowMouseDownEvent(button, layer_mouse_point) => {
|
||||
event = MouseDownEvent(button, world_mouse_point(layer_mouse_point));
|
||||
|
||||
//eschweic
|
||||
match *quadtree {
|
||||
Some(ref quad) => {
|
||||
|
||||
/* let wmp = world_mouse_point(layer_mouse_point);
|
||||
println(fmt!("mouse: (%?, %?):", wmp.x as uint, wmp.y as uint));
|
||||
let buffer = quad.get_tile(wmp.x as uint, wmp.y as uint, *world_zoom);
|
||||
match *buffer {
|
||||
None => println("None"),
|
||||
Some(ref buffer) => println(fmt!("Some: (%?, %?), %?, %?", buffer.screen_pos.origin.x, buffer.screen_pos.origin.y, buffer.screen_pos.size.width, buffer.resolution)),
|
||||
|
||||
} */
|
||||
|
||||
println(quad.get_html());
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
WindowMouseUpEvent(button, layer_mouse_point) => {
|
||||
|
||||
// rerender layer at new zoom level
|
||||
// FIXME: this should happen when the user stops zooming, definitely not here
|
||||
match *render_chan {
|
||||
Some(ref r_chan) => {
|
||||
r_chan.send(ReRenderMsg(*world_zoom));
|
||||
}
|
||||
None => {} // Nothing to do
|
||||
}
|
||||
//FIXME: this should not be here eschweic
|
||||
ask_for_tiles();
|
||||
|
||||
|
||||
|
||||
event = MouseUpEvent(button, world_mouse_point(layer_mouse_point));
|
||||
}
|
||||
|
@ -266,6 +358,7 @@ impl CompositorTask {
|
|||
}
|
||||
};
|
||||
|
||||
|
||||
let check_for_messages: @fn(&Port<Msg>) = |port: &Port<Msg>| {
|
||||
// Handle messages
|
||||
while port.peek() {
|
||||
|
@ -292,6 +385,21 @@ impl CompositorTask {
|
|||
|
||||
GetGLContext(chan) => chan.send(current_gl_context()),
|
||||
|
||||
//eschweic
|
||||
NewLayer(new_size, tile_size) => {
|
||||
*page_size = Size2D(new_size.width as f32, new_size.height as f32);
|
||||
*quadtree = Some(Quadtree::new(0, 0, new_size.width, new_size.height, tile_size));
|
||||
ask_for_tiles();
|
||||
|
||||
}
|
||||
ResizeLayer(new_size) => {
|
||||
*page_size = Size2D(new_size.width as f32, new_size.height as f32);
|
||||
// TODO: update quadtree, ask for tiles
|
||||
}
|
||||
DeleteLayer => {
|
||||
// TODO: create secondary layer tree, keep displaying until new tiles come in
|
||||
}
|
||||
|
||||
Paint(id, new_layer_buffer_set, new_size) => {
|
||||
match *pipeline_id {
|
||||
Some(pipeline_id) => if id != pipeline_id { loop; },
|
||||
|
@ -300,6 +408,12 @@ impl CompositorTask {
|
|||
|
||||
debug!("osmain: received new frame");
|
||||
|
||||
let quad;
|
||||
match *quadtree {
|
||||
Some(ref mut q) => quad = q,
|
||||
None => fail!("Compositor: given paint command with no quadtree initialized"),
|
||||
}
|
||||
|
||||
*page_size = Size2D(new_size.width as f32, new_size.height as f32);
|
||||
|
||||
let new_layer_buffer_set = new_layer_buffer_set.get();
|
||||
|
@ -307,7 +421,15 @@ impl CompositorTask {
|
|||
// Iterate over the children of the container layer.
|
||||
let mut current_layer_child = root_layer.first_child;
|
||||
|
||||
for new_layer_buffer_set.buffers.iter().advance |buffer| {
|
||||
// Replace the image layer data with the buffer data.
|
||||
let buffers = util::replace(&mut new_layer_buffer_set.buffers, ~[]);
|
||||
|
||||
do vec::consume(buffers) |_, buffer| {
|
||||
quad.add_tile(buffer.screen_pos.origin.x, buffer.screen_pos.origin.y,
|
||||
*world_zoom, buffer);
|
||||
}
|
||||
|
||||
for quad.get_all_tiles().each |buffer| {
|
||||
let width = buffer.rect.size.width as uint;
|
||||
let height = buffer.rect.size.height as uint;
|
||||
|
||||
|
@ -339,9 +461,10 @@ impl CompositorTask {
|
|||
let origin = Point2D(origin.x as f32, origin.y as f32);
|
||||
|
||||
// Set the layer's transform.
|
||||
let transform = identity().translate(origin.x, origin.y, 0.0);
|
||||
let transform = transform.scale(width as f32, height as f32, 1.0);
|
||||
let transform = identity().translate(origin.x * *world_zoom / buffer.resolution, origin.y * *world_zoom / buffer.resolution, 0.0);
|
||||
let transform = transform.scale(width as f32 * *world_zoom / buffer.resolution, height as f32 * *world_zoom / buffer.resolution, 1.0);
|
||||
texture_layer.common.set_transform(transform);
|
||||
|
||||
}
|
||||
|
||||
// Delete leftover layers
|
||||
|
@ -409,6 +532,8 @@ impl CompositorTask {
|
|||
|
||||
root_layer.common.set_transform(scroll_transform);
|
||||
|
||||
// ask_for_tiles();
|
||||
|
||||
*recomposite = true;
|
||||
}
|
||||
|
||||
|
@ -447,6 +572,7 @@ impl CompositorTask {
|
|||
window_size.height as f32 / -2f32,
|
||||
0.0);
|
||||
root_layer.common.set_transform(zoom_transform);
|
||||
// ask_for_tiles();
|
||||
|
||||
*recomposite = true;
|
||||
}
|
||||
|
|
|
@ -53,6 +53,10 @@ impl<T> Quadtree<T> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Return the maximum allowed tile size
|
||||
pub fn get_tile_size(&self) -> uint {
|
||||
self.max_tile_size
|
||||
}
|
||||
/// Get a tile at a given pixel position and scale.
|
||||
pub fn get_tile<'r>(&'r self, x: uint, y: uint, scale: f32) -> &'r Option<T> {
|
||||
self.root.get_tile(x as f32 / scale, y as f32 / scale)
|
||||
|
@ -61,12 +65,24 @@ impl<T> Quadtree<T> {
|
|||
pub fn add_tile(&mut self, x: uint, y: uint, scale: f32, tile: T) {
|
||||
self.root.add_tile(x as f32 / scale, y as f32 / scale, tile, self.max_tile_size as f32 / scale);
|
||||
}
|
||||
|
||||
/// Get the tile size/offset for a given pixel position
|
||||
pub fn get_tile_rect(&self, x: uint, y: uint, scale: f32) -> (Point2D<uint>, uint) {
|
||||
self.root.get_tile_rect(x as f32 / scale, y as f32 / scale, scale, self.max_tile_size as f32 / scale)
|
||||
}
|
||||
/// Get all the tiles in the tree
|
||||
pub fn get_all_tiles<'r>(&'r self) -> ~[&'r T] {
|
||||
self.root.get_all_tiles()
|
||||
}
|
||||
/// Generate html to visualize the tree
|
||||
pub fn get_html(&self) -> ~str {
|
||||
let header = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\"> <html xmlns=\"http://www.w3.org/1999/xhtml\">";
|
||||
fmt!("%s<body>%s</body></html>", header, self.root.get_html())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl<T> QuadtreeNode<T> {
|
||||
// Private method to create new children
|
||||
/// Private method to create new children
|
||||
fn new_child(x: f32, y: f32, size: f32) -> QuadtreeNode<T> {
|
||||
QuadtreeNode {
|
||||
tile: None,
|
||||
|
@ -105,6 +121,26 @@ impl<T> QuadtreeNode<T> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Get all tiles in the tree, parents first.
|
||||
/// FIXME: this could probably be more efficient
|
||||
fn get_all_tiles<'r>(&'r self) -> ~[&'r T] {
|
||||
let mut ret = ~[];
|
||||
|
||||
match self.tile {
|
||||
Some (ref tile) => ret = ~[tile],
|
||||
None => {}
|
||||
}
|
||||
|
||||
for self.quadrants.each |quad| {
|
||||
match *quad {
|
||||
Some(ref child) => ret = ret + child.get_all_tiles(),
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// Add a tile associated with a given position in page coords. If the tile size exceeds the maximum,
|
||||
/// the node will be split and the method will recurse until the tile size is within limits.
|
||||
fn add_tile(&mut self, x: f32, y: f32, tile: T, tile_size: f32) {
|
||||
|
@ -117,14 +153,14 @@ impl<T> QuadtreeNode<T> {
|
|||
|
||||
if self.size <= tile_size { // We are the child
|
||||
self.tile = Some(tile);
|
||||
for vec::each([TL, TR, BL, BR]) |quad| {
|
||||
for [TL, TR, BL, BR].each |quad| {
|
||||
self.quadrants[*quad as int] = None;
|
||||
}
|
||||
} else { //send tile to children
|
||||
} else { // Send tile to children
|
||||
let quad = self.get_quadrant(x, y);
|
||||
match self.quadrants[quad as int] {
|
||||
Some(ref mut child) => child.add_tile(x, y, tile, tile_size),
|
||||
None => { //make new child
|
||||
None => { // Make new child
|
||||
let new_size = self.size / 2.0;
|
||||
let new_x = match quad {
|
||||
TL | BL => self.origin.x,
|
||||
|
@ -138,19 +174,93 @@ impl<T> QuadtreeNode<T> {
|
|||
c.add_tile(x, y, tile, tile_size);
|
||||
self.quadrants[quad as int] = Some(c);
|
||||
|
||||
// If we have 4 children, we probably shouldn't be hanging onto a tile
|
||||
// Though this isn't always true if we have grandchildren
|
||||
// If my tile is completely occluded, get rid of it.
|
||||
// FIXME: figure out a better way to determine if a tile is completely occluded
|
||||
// e.g. this alg doesn't work if a tile is covered by its grandchildren
|
||||
match self.quadrants {
|
||||
[Some(_), Some(_), Some(_), Some(_)] => {
|
||||
self.tile = None;
|
||||
[Some(ref tl_child), Some(ref tr_child), Some(ref bl_child), Some(ref br_child)] => {
|
||||
match (&tl_child.tile, &tr_child.tile, &bl_child.tile, &br_child.tile) {
|
||||
(&Some(_), &Some(_), &Some(_), &Some(_)) => self.tile = None,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Get an origin and a width/height for a future tile for a given position in page coords
|
||||
fn get_tile_rect(&self, x: f32, y: f32, scale: f32, tile_size: f32) -> (Point2D<uint>, uint) {
|
||||
if x >= self.origin.x + self.size || x < self.origin.x
|
||||
|| y >= self.origin.y + self.size || y < self.origin.y {
|
||||
fail!("Quadtree: Tried to query a tile rect outside of range");
|
||||
}
|
||||
|
||||
if self.size <= tile_size {
|
||||
let self_x = (self.origin.x * scale).ceil() as uint;
|
||||
let self_y = (self.origin.y * scale).ceil() as uint;
|
||||
let self_size = (self.size * scale).ceil() as uint;
|
||||
return (Point2D(self_x, self_y), self_size);
|
||||
}
|
||||
|
||||
let index = self.get_quadrant(x,y) as int;
|
||||
match self.quadrants[index] {
|
||||
None => {
|
||||
// calculate where the new tile should go
|
||||
let factor = self.size / tile_size;
|
||||
let divisor = uint::next_power_of_two(factor.ceil() as uint);
|
||||
let new_size_page = self.size / (divisor as f32);
|
||||
let new_size_pixel = (new_size_page * scale).ceil() as uint;
|
||||
|
||||
let new_x_page = self.origin.x + new_size_page * ((x - self.origin.x) / new_size_page).floor();
|
||||
let new_y_page = self.origin.y + new_size_page * ((y - self.origin.y) / new_size_page).floor();
|
||||
let new_x_pixel = (new_x_page * scale).ceil() as uint;
|
||||
let new_y_pixel = (new_y_page * scale).ceil() as uint;
|
||||
|
||||
(Point2D(new_x_pixel, new_y_pixel), new_size_pixel)
|
||||
}
|
||||
Some(ref child) => child.get_tile_rect(x, y, scale, tile_size),
|
||||
}
|
||||
}
|
||||
|
||||
/// Generate html to visualize the tree.
|
||||
/// This is really inefficient, but it's for testing only.
|
||||
fn get_html(&self) -> ~str {
|
||||
let mut ret = ~"";
|
||||
match self.tile {
|
||||
Some(ref tile) => {
|
||||
ret = fmt!("%s%?", ret, tile);
|
||||
}
|
||||
None => {
|
||||
ret = fmt!("%sNO TILE", ret);
|
||||
}
|
||||
}
|
||||
match self.quadrants {
|
||||
[None, None, None, None] => {}
|
||||
_ => {
|
||||
ret = fmt!("%s<table border=1><tr>", ret);
|
||||
for [TL, TR, BL, BR].each |quad| {
|
||||
match self.quadrants[*quad as int] {
|
||||
Some(ref child) => {
|
||||
ret = fmt!("%s<td>%s</td>", ret, child.get_html());
|
||||
}
|
||||
None => {
|
||||
ret = fmt!("%s<td>EMPTY CHILD</td>", ret);
|
||||
}
|
||||
}
|
||||
match *quad {
|
||||
TR => ret = fmt!("%s</tr><tr>", ret),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
ret = fmt!("%s</table>\n", ret);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -19,8 +19,12 @@ pub struct LayerBuffer {
|
|||
// The rect in pixels that will be drawn to the screen.
|
||||
screen_pos: Rect<uint>,
|
||||
|
||||
// The scale at which this tile is rendered
|
||||
resolution: f32, //eschweic
|
||||
|
||||
// NB: stride is in pixels, like OpenGL GL_UNPACK_ROW_LENGTH.
|
||||
stride: uint
|
||||
stride: uint,
|
||||
|
||||
}
|
||||
|
||||
/// A set of layer buffers. This is an atomic unit used to switch between the front and back
|
||||
|
@ -49,6 +53,9 @@ pub enum ReadyState {
|
|||
/// submit them to be drawn to the display.
|
||||
pub trait RenderListener {
|
||||
fn get_gl_context(&self) -> AzGLContext;
|
||||
fn new_layer(&self, Size2D<uint>, uint); //eschweic
|
||||
fn resize_layer(&self, Size2D<uint>);
|
||||
fn delete_layer(&self);
|
||||
fn paint(&self, id: uint, layer_buffer_set: arc::ARC<LayerBufferSet>, new_size: Size2D<uint>);
|
||||
fn set_render_state(&self, render_state: RenderState);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue