Invert control flow, fix resizing, and improve checkerboarding

significantly by giving tiles some time to paint before we render
unrendered content.
This commit is contained in:
Patrick Walton 2014-10-19 09:23:18 -07:00
parent e483a189a3
commit 10f7b49cf7
27 changed files with 1195 additions and 678 deletions

View file

@ -19,6 +19,7 @@ use render_context::RenderContext;
use text::glyph::CharIndex;
use text::TextRun;
use azure::azure::AzFloat;
use collections::Deque;
use collections::dlist::{mod, DList};
use geom::{Point2D, Rect, SideOffsets2D, Size2D, Matrix2D};
@ -26,18 +27,11 @@ use libc::uintptr_t;
use servo_net::image::base::Image;
use servo_util::dlist as servo_dlist;
use servo_util::geometry::Au;
use servo_util::opts;
use servo_util::range::Range;
use std::fmt;
use std::slice::Items;
use style::computed_values::border_style;
use sync::Arc;
use std::num::Zero;
use std::ptr;
use azure::AzFloat;
use azure::scaled_font::ScaledFont;
use azure::azure_hl::ColorPattern;
pub mod optimizer;
@ -58,88 +52,6 @@ impl OpaqueNode {
}
}
trait ScaledFontExtensionMethods {
fn draw_text_into_context(&self,
rctx: &RenderContext,
run: &Box<TextRun>,
range: &Range<CharIndex>,
baseline_origin: Point2D<Au>,
color: Color,
antialias: bool);
}
impl ScaledFontExtensionMethods for ScaledFont {
fn draw_text_into_context(&self,
rctx: &RenderContext,
run: &Box<TextRun>,
range: &Range<CharIndex>,
baseline_origin: Point2D<Au>,
color: Color,
antialias: bool) {
use libc::types::common::c99::uint32_t;
use azure::{struct__AzDrawOptions,
struct__AzGlyph,
struct__AzGlyphBuffer,
struct__AzPoint};
use azure::azure::{AzDrawTargetFillGlyphs};
let target = rctx.get_draw_target();
let pattern = ColorPattern::new(color);
let azure_pattern = pattern.azure_color_pattern;
assert!(azure_pattern.is_not_null());
let fields = if antialias {
0x0200
} else {
0
};
let mut options = struct__AzDrawOptions {
mAlpha: 1f64 as AzFloat,
fields: fields,
};
let mut origin = baseline_origin.clone();
let mut azglyphs = vec!();
azglyphs.reserve(range.length().to_uint());
for (glyphs, _offset, slice_range) in run.iter_slices_for_range(range) {
for (_i, glyph) in glyphs.iter_glyphs_for_char_range(&slice_range) {
let glyph_advance = glyph.advance();
let glyph_offset = glyph.offset().unwrap_or(Zero::zero());
let azglyph = struct__AzGlyph {
mIndex: glyph.id() as uint32_t,
mPosition: struct__AzPoint {
x: (origin.x + glyph_offset.x).to_subpx() as AzFloat,
y: (origin.y + glyph_offset.y).to_subpx() as AzFloat
}
};
origin = Point2D(origin.x + glyph_advance, origin.y);
azglyphs.push(azglyph)
};
}
let azglyph_buf_len = azglyphs.len();
if azglyph_buf_len == 0 { return; } // Otherwise the Quartz backend will assert.
let mut glyphbuf = struct__AzGlyphBuffer {
mGlyphs: azglyphs.as_mut_ptr(),
mNumGlyphs: azglyph_buf_len as uint32_t
};
unsafe {
// TODO(Issue #64): this call needs to move into azure_hl.rs
AzDrawTargetFillGlyphs(target.azure_draw_target,
self.get_ref(),
&mut glyphbuf,
azure_pattern,
&mut options,
ptr::null_mut());
}
}
}
/// "Steps" as defined by CSS 2.1 § E.2.
#[deriving(Clone, PartialEq, Show)]
pub enum StackingLevel {
@ -543,55 +455,7 @@ impl DisplayItem {
TextDisplayItemClass(ref text) => {
debug!("Drawing text at {}.", text.base.bounds);
// Optimization: Dont set a transform matrix for upright text,
// and pass a strart point to `draw_text_into_context`.
// For sideways text, its easier to do the rotation such that its center
// (the baselines start point) is at (0, 0) coordinates.
let baseline_origin = match text.orientation {
Upright => text.baseline_origin,
SidewaysLeft => {
let x = text.baseline_origin.x.to_nearest_px() as AzFloat;
let y = text.baseline_origin.y.to_nearest_px() as AzFloat;
render_context.draw_target.set_transform(&current_transform.mul(
&Matrix2D::new(
0., -1.,
1., 0.,
x, y
)
));
Zero::zero()
},
SidewaysRight => {
let x = text.baseline_origin.x.to_nearest_px() as AzFloat;
let y = text.baseline_origin.y.to_nearest_px() as AzFloat;
render_context.draw_target.set_transform(&current_transform.mul(
&Matrix2D::new(
0., 1.,
-1., 0.,
x, y
)
));
Zero::zero()
}
};
render_context.font_ctx.get_render_font_from_template(
&text.text_run.font_template,
text.text_run.actual_pt_size
).borrow().draw_text_into_context(
render_context,
&*text.text_run,
&text.range,
baseline_origin,
text.text_color,
opts::get().enable_text_antialiasing
);
// Undo the transform, only when we did one.
if text.orientation != Upright {
render_context.draw_target.set_transform(current_transform)
}
render_context.draw_text(&**text, current_transform);
}
ImageDisplayItemClass(ref image_item) => {

View file

@ -30,6 +30,7 @@ extern crate "util" as servo_util;
extern crate "msg" as servo_msg;
extern crate style;
extern crate sync;
extern crate time;
extern crate url;
// Eventually we would like the shaper to be pluggable, as many operating systems have their own

View file

@ -2,23 +2,32 @@
* 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 display_list::{SidewaysLeft, SidewaysRight, TextDisplayItem, Upright};
use font_context::FontContext;
use style::computed_values::border_style;
use azure::azure_hl::{B8G8R8A8, A8, Color, ColorPattern, ColorPatternRef, DrawOptions};
use azure::azure_hl::{DrawSurfaceOptions, DrawTarget, Linear, SourceOp, StrokeOptions};
use azure::AZ_CAP_BUTT;
use azure::AzFloat;
use azure::azure_hl::{DrawSurfaceOptions,DrawTarget, Linear, SourceOp, StrokeOptions};
use azure::scaled_font::ScaledFont;
use azure::{AZ_CAP_BUTT, AzDrawTargetFillGlyphs, AzFloat, struct__AzDrawOptions, struct__AzGlyph};
use azure::{struct__AzGlyphBuffer, struct__AzPoint};
use geom::matrix2d::Matrix2D;
use geom::point::Point2D;
use geom::rect::Rect;
use geom::size::Size2D;
use geom::side_offsets::SideOffsets2D;
use libc::types::common::c99::uint16_t;
use libc::types::common::c99::{uint16_t, uint32_t};
use libc::size_t;
use png::{RGB8, RGBA8, K8, KA8};
use servo_net::image::base::Image;
use servo_util::geometry::Au;
use servo_util::opts;
use servo_util::range::Range;
use std::num::Zero;
use std::ptr;
use sync::Arc;
use text::glyph::CharIndex;
use text::TextRun;
pub struct RenderContext<'a> {
pub draw_target: &'a DrawTarget,
@ -390,6 +399,50 @@ impl<'a> RenderContext<'a> {
self.draw_border_path(original_bounds, direction, border, scaled_color);
}
pub fn draw_text(&mut self,
text: &TextDisplayItem,
current_transform: &Matrix2D<AzFloat>) {
// Optimization: Dont set a transform matrix for upright text, and pass a start point to
// `draw_text_into_context`.
//
// For sideways text, its easier to do the rotation such that its center (the baselines
// start point) is at (0, 0) coordinates.
let baseline_origin = match text.orientation {
Upright => text.baseline_origin,
SidewaysLeft => {
let x = text.baseline_origin.x.to_subpx() as AzFloat;
let y = text.baseline_origin.y.to_subpx() as AzFloat;
self.draw_target.set_transform(&current_transform.mul(&Matrix2D::new(0., -1.,
1., 0.,
x, y)));
Zero::zero()
}
SidewaysRight => {
let x = text.baseline_origin.x.to_subpx() as AzFloat;
let y = text.baseline_origin.y.to_subpx() as AzFloat;
self.draw_target.set_transform(&current_transform.mul(&Matrix2D::new(0., 1.,
-1., 0.,
x, y)));
Zero::zero()
}
};
self.font_ctx
.get_render_font_from_template(&text.text_run.font_template,
text.text_run.actual_pt_size)
.borrow()
.draw_text_into_context(self,
&*text.text_run,
&text.range,
baseline_origin,
text.text_color,
opts::get().enable_text_antialiasing);
// Undo the transform, only when we did one.
if text.orientation != Upright {
self.draw_target.set_transform(current_transform)
}
}
}
trait ToAzureRect {
@ -417,3 +470,78 @@ impl ToSideOffsetsPx for SideOffsets2D<Au> {
self.left.to_nearest_px() as AzFloat)
}
}
trait ScaledFontExtensionMethods {
fn draw_text_into_context(&self,
rctx: &RenderContext,
run: &Box<TextRun>,
range: &Range<CharIndex>,
baseline_origin: Point2D<Au>,
color: Color,
antialias: bool);
}
impl ScaledFontExtensionMethods for ScaledFont {
fn draw_text_into_context(&self,
rctx: &RenderContext,
run: &Box<TextRun>,
range: &Range<CharIndex>,
baseline_origin: Point2D<Au>,
color: Color,
antialias: bool) {
let target = rctx.get_draw_target();
let pattern = ColorPattern::new(color);
let azure_pattern = pattern.azure_color_pattern;
assert!(azure_pattern.is_not_null());
let fields = if antialias {
0x0200
} else {
0
};
let mut options = struct__AzDrawOptions {
mAlpha: 1f64 as AzFloat,
fields: fields,
};
let mut origin = baseline_origin.clone();
let mut azglyphs = vec!();
azglyphs.reserve(range.length().to_uint());
for (glyphs, _offset, slice_range) in run.iter_slices_for_range(range) {
for (_i, glyph) in glyphs.iter_glyphs_for_char_range(&slice_range) {
let glyph_advance = glyph.advance();
let glyph_offset = glyph.offset().unwrap_or(Zero::zero());
let azglyph = struct__AzGlyph {
mIndex: glyph.id() as uint32_t,
mPosition: struct__AzPoint {
x: (origin.x + glyph_offset.x).to_subpx() as AzFloat,
y: (origin.y + glyph_offset.y).to_subpx() as AzFloat
}
};
origin = Point2D(origin.x + glyph_advance, origin.y);
azglyphs.push(azglyph)
};
}
let azglyph_buf_len = azglyphs.len();
if azglyph_buf_len == 0 { return; } // Otherwise the Quartz backend will assert.
let mut glyphbuf = struct__AzGlyphBuffer {
mGlyphs: azglyphs.as_mut_ptr(),
mNumGlyphs: azglyph_buf_len as uint32_t
};
unsafe {
// TODO(Issue #64): this call needs to move into azure_hl.rs
AzDrawTargetFillGlyphs(target.azure_draw_target,
self.get_ref(),
&mut glyphbuf,
azure_pattern,
&mut options,
ptr::null_mut());
}
}
}

View file

@ -7,6 +7,7 @@
use buffer_map::BufferMap;
use display_list::optimizer::DisplayListOptimizer;
use display_list::DisplayList;
use font_cache_task::FontCacheTask;
use font_context::FontContext;
use render_context::RenderContext;
@ -37,7 +38,6 @@ use std::comm::{Receiver, Sender, channel};
use std::mem;
use std::task::TaskBuilder;
use sync::Arc;
use font_cache_task::FontCacheTask;
/// Information about a layer that layout sends to the painting task.
#[deriving(Clone)]
@ -153,7 +153,10 @@ impl<C> RenderTask<C> where C: RenderListener + Send {
shutdown_chan: Sender<()>) {
let ConstellationChan(c) = constellation_chan.clone();
spawn_named_with_send_on_failure("RenderTask", task_state::Render, proc() {
{ // Ensures RenderTask and graphics context are destroyed before shutdown msg
{
// Ensures that the render task and graphics context are destroyed before the
// shutdown message.
let mut compositor = compositor;
let native_graphics_context = compositor.get_graphics_metadata().map(
|md| NativePaintingGraphicsContext::from_metadata(&md));
let worker_threads = WorkerThreadProxy::spawn(compositor.get_graphics_metadata(),