Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Several fixes #492

Closed
wants to merge 20 commits into from
Closed
Changes from 1 commit
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter...
Filter file types
Jump to…
Jump to file
Failed to load files.

Always

Just for now

Refactor display lists to use less memory.

  • Loading branch information
pcwalton committed May 29, 2013
commit 6012a3e13e3b912bedd19b479fe2ec8454ebf061
@@ -2,129 +2,151 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use color::{Color, rgb};
//! Servo heavily uses display lists, which are retained-mode lists of rendering commands to
/// perform. Using a list instead of rendering elements in immediate mode allows transforms, hit
/// testing, and invalidation to be performed using the same primitives as painting. It also allows
/// Servo to aggressively cull invisible and out-of-bounds rendering elements, to reduce overdraw.
/// Finally, display lists allow tiles to be farmed out onto multiple CPUs and rendered in
/// parallel (although this benefit does not apply to GPU-based rendering).
///
/// Display items describe relatively high-level drawing operations (for example, entire borders
/// and shadows instead of lines and blur operations), to reduce the amount of allocation required.
/// They are therefore not exactly analogous to constructs like Skia pictures, which consist of
/// low-level drawing primitives.

use color::Color;
use geometry::Au;
use render_context::RenderContext;
use text::SendableTextRun;

use clone_arc = std::arc::clone;
use geom::Rect;
use geom::{Point2D, Size2D};
use std::arc::ARC;
use geom::{Point2D, Rect, Size2D};
use servo_net::image::base::Image;
use servo_util::range::Range;
use std::arc::ARC;
use std::arc;

struct DisplayItemData {
bounds : Rect<Au>, // TODO: whose coordinate system should this use?
/// A list of rendering operations to be performed.
pub struct DisplayList {
priv list: ~[DisplayItem]
}

pub impl DisplayItemData {
fn new(bounds: &Rect<Au>) -> DisplayItemData {
DisplayItemData { bounds: copy *bounds }
impl DisplayList {
/// Creates a new display list.
pub fn new() -> DisplayList {
DisplayList {
list: ~[]
}
}
}

pub enum DisplayItem {
SolidColor(DisplayItemData, Color),
// TODO: need to provide spacing data for text run.
// (i.e, to support rendering of CSS 'word-spacing' and 'letter-spacing')
// TODO: don't copy text runs, ever.
Text(DisplayItemData, ~SendableTextRun, Range, Color),
Image(DisplayItemData, ARC<~Image>),
Border(DisplayItemData, Au, Color)
}
/// Appends the given item to the display list.
pub fn append_item(&mut self, item: DisplayItem) {
// FIXME(Issue #150): crashes
//debug!("Adding display item %u: %?", self.len(), item);
self.list.push(item)
}

pub impl<'self> DisplayItem {
fn d(&'self self) -> &'self DisplayItemData {
match *self {
SolidColor(ref d, _) => d,
Text(ref d, _, _, _) => d,
Image(ref d, _) => d,
Border(ref d, _, _) => d
/// Draws the display list into the given render context.
pub fn draw_into_context(&self, render_context: &RenderContext) {
debug!("Beginning display list.");
for self.list.each |item| {
// FIXME(Issue #150): crashes
//debug!("drawing %?", *item);
item.draw_into_context(render_context)
}
debug!("Ending display list.")
}

fn draw_into_context(&self, ctx: &RenderContext) {
match self {
&SolidColor(_, color) => {
ctx.draw_solid_color(&self.d().bounds, color)
}
&Text(_, ref run, ref range, color) => {
debug!("drawing text at %?", self.d().bounds);
let new_run = @run.deserialize(ctx.font_ctx);
let font = new_run.font;
let origin = self.d().bounds.origin;
let baseline_origin = Point2D(origin.x, origin.y + font.metrics.ascent);
font.draw_text_into_context(ctx, new_run, range, baseline_origin, color);
if(new_run.underline){
//TODO: Use the font metrics to properly position the underline bar
let width = self.d().bounds.size.width;
let u_size = font.metrics.underline_size;
let u_bounds = Rect(
Point2D(baseline_origin.x, baseline_origin.y),
Size2D(width, u_size)
);
ctx.draw_solid_color(&u_bounds, color);
}
},
&Image(_, ref img) => {
debug!("drawing image at %?", self.d().bounds);
ctx.draw_image(self.d().bounds, clone_arc(img));
}
&Border(_, width, color) => {
ctx.draw_border(&self.d().bounds, width, color)
}
}
}

debug!("%?", {
ctx.draw_border(&self.d().bounds, Au::from_px(1), rgb(150, 150, 150));
() });
}
/// One drawing command in the list.
pub enum DisplayItem {
SolidColorDisplayItemClass(~SolidColorDisplayItem),
TextDisplayItemClass(~TextDisplayItem),
ImageDisplayItemClass(~ImageDisplayItem),
BorderDisplayItemClass(~BorderDisplayItem),
}

fn new_SolidColor(bounds: &Rect<Au>, color: Color) -> DisplayItem {
SolidColor(DisplayItemData::new(bounds), color)
}
/// Information common to all display items.
pub struct BaseDisplayItem {
/// The boundaries of the display item.
///
/// TODO: Which coordinate system should this use?
bounds: Rect<Au>,
}

fn new_Border(bounds: &Rect<Au>, width: Au, color: Color) -> DisplayItem {
Border(DisplayItemData::new(bounds), width, color)
}
/// Renders a solid color.
pub struct SolidColorDisplayItem {
base: BaseDisplayItem,
color: Color,
}

fn new_Text(bounds: &Rect<Au>,
run: ~SendableTextRun,
range: Range,
color: Color) -> DisplayItem {
Text(DisplayItemData::new(bounds), run, range, color)
}
/// Renders text.
pub struct TextDisplayItem {
base: BaseDisplayItem,
text_run: ~SendableTextRun,
range: Range,
color: Color,
}

// ARC should be cloned into ImageData, but Images are not sendable
fn new_Image(bounds: &Rect<Au>, image: ARC<~Image>) -> DisplayItem {
Image(DisplayItemData::new(bounds), image)
}
/// Renders an image.
pub struct ImageDisplayItem {
base: BaseDisplayItem,
image: ARC<~Image>,
}

// Dual-mode/freezable.
pub struct DisplayList {
list: ~[~DisplayItem]
/// Renders a border.
pub struct BorderDisplayItem {
base: BaseDisplayItem,
/// The width of the border.
width: Au,
/// The color of the border.
color: Color,
}

pub impl DisplayList {
fn new() -> DisplayList {
DisplayList { list: ~[] }
}
impl DisplayItem {
/// Renders this display item into the given render context.
fn draw_into_context(&self, render_context: &RenderContext) {
match *self {
SolidColorDisplayItemClass(ref solid_color) => {
render_context.draw_solid_color(&solid_color.base.bounds, solid_color.color)
}

fn append_item(&mut self, item: ~DisplayItem) {
// FIXME(Issue #150): crashes
//debug!("Adding display item %u: %?", self.len(), item);
self.list.push(item);
}
TextDisplayItemClass(ref text) => {
debug!("Drawing text at %?.", text.base.bounds);

fn draw_into_context(&self, ctx: &RenderContext) {
debug!("beginning display list");
for self.list.each |item| {
// FIXME(Issue #150): crashes
//debug!("drawing %?", *item);
item.draw_into_context(ctx);
// FIXME(pcwalton): Allocating? Why?
let new_run = @text.text_run.deserialize(render_context.font_ctx);

let font = new_run.font;
let origin = text.base.bounds.origin;
let baseline_origin = Point2D(origin.x, origin.y + font.metrics.ascent);

font.draw_text_into_context(render_context,
new_run,
&text.range,
baseline_origin,
text.color);

if new_run.underline {
// TODO(eatkinson): Use the font metrics to properly position the underline
// bar.
let width = text.base.bounds.size.width;
let underline_size = font.metrics.underline_size;
let underline_bounds = Rect(Point2D(baseline_origin.x, baseline_origin.y),
Size2D(width, underline_size));
render_context.draw_solid_color(&underline_bounds, text.color);
}
}

ImageDisplayItemClass(ref image_item) => {
debug!("Drawing image at %?.", image_item.base.bounds);

render_context.draw_image(image_item.base.bounds, image_item.image.clone())
}

BorderDisplayItemClass(ref border) => {
render_context.draw_border(&border.base.bounds, border.width, border.color)
}
}
debug!("ending display list");
}
}

ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.