mirror of
https://github.com/servo/servo.git
synced 2025-08-09 07:25:35 +01:00
auto merge of #3722 : pcwalton/servo/flow-construction-overhaul, r=glennw
This is a grab bag of performance improvements that significantly improve style recalculation, layout, and painting on a few static pages. Let me know if you'd like me to split this PR up. r? @glennw
This commit is contained in:
commit
156ca98236
15 changed files with 378 additions and 349 deletions
|
@ -288,10 +288,10 @@ impl DisplayList {
|
|||
pub fn draw_into_context(&self,
|
||||
render_context: &mut RenderContext,
|
||||
current_transform: &Matrix2D<AzFloat>,
|
||||
current_clip_rect: &Rect<Au>) {
|
||||
current_clip_stack: &mut Vec<Rect<Au>>) {
|
||||
debug!("Beginning display list.");
|
||||
for item in self.list.iter() {
|
||||
item.draw_into_context(render_context, current_transform, current_clip_rect)
|
||||
item.draw_into_context(render_context, current_transform, current_clip_stack)
|
||||
}
|
||||
debug!("Ending display list.");
|
||||
}
|
||||
|
@ -504,14 +504,19 @@ impl DisplayItem {
|
|||
fn draw_into_context(&self,
|
||||
render_context: &mut RenderContext,
|
||||
current_transform: &Matrix2D<AzFloat>,
|
||||
current_clip_rect: &Rect<Au>) {
|
||||
current_clip_stack: &mut Vec<Rect<Au>>) {
|
||||
// This should have been flattened to the content stacking level first.
|
||||
assert!(self.base().level == ContentStackingLevel);
|
||||
|
||||
// TODO(pcwalton): This will need some tweaking to deal with more complex clipping regions.
|
||||
let clip_rect = &self.base().clip_rect;
|
||||
let need_to_clip = current_clip_rect != clip_rect;
|
||||
if need_to_clip {
|
||||
if current_clip_stack.len() == 0 || current_clip_stack.last().unwrap() != clip_rect {
|
||||
while current_clip_stack.len() != 0 {
|
||||
render_context.draw_pop_clip();
|
||||
drop(current_clip_stack.pop());
|
||||
}
|
||||
render_context.draw_push_clip(clip_rect);
|
||||
current_clip_stack.push(*clip_rect);
|
||||
}
|
||||
|
||||
match *self {
|
||||
|
@ -608,10 +613,6 @@ impl DisplayItem {
|
|||
|
||||
PseudoDisplayItemClass(_) => {}
|
||||
}
|
||||
|
||||
if need_to_clip {
|
||||
render_context.draw_pop_clip();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn base<'a>(&'a self) -> &'a BaseDisplayItem {
|
||||
|
|
|
@ -100,14 +100,19 @@ pub struct Font {
|
|||
}
|
||||
|
||||
impl Font {
|
||||
pub fn shape_text(&mut self, text: String, is_whitespace: bool) -> Arc<GlyphStore> {
|
||||
pub fn shape_text(&mut self, text: &str, is_whitespace: bool) -> Arc<GlyphStore> {
|
||||
self.make_shaper();
|
||||
let shaper = &self.shaper;
|
||||
self.shape_cache.find_or_create(&text, |txt| {
|
||||
let mut glyphs = GlyphStore::new(text.as_slice().char_len() as int, is_whitespace);
|
||||
shaper.as_ref().unwrap().shape_text(txt.as_slice(), &mut glyphs);
|
||||
Arc::new(glyphs)
|
||||
})
|
||||
match self.shape_cache.find_equiv(&text) {
|
||||
None => {}
|
||||
Some(glyphs) => return (*glyphs).clone(),
|
||||
}
|
||||
|
||||
let mut glyphs = GlyphStore::new(text.char_len() as int, is_whitespace);
|
||||
shaper.as_ref().unwrap().shape_text(text, &mut glyphs);
|
||||
let glyphs = Arc::new(glyphs);
|
||||
self.shape_cache.insert(text.to_string(), glyphs.clone());
|
||||
glyphs
|
||||
}
|
||||
|
||||
fn make_shaper<'a>(&'a mut self) -> &'a Shaper {
|
||||
|
|
|
@ -43,7 +43,7 @@ static SMALL_CAPS_SCALE_FACTOR: f64 = 0.8; // Matches FireFox (see gfxFont.
|
|||
|
||||
struct LayoutFontCacheEntry {
|
||||
family: String,
|
||||
font: Rc<RefCell<Font>>,
|
||||
font: Option<Rc<RefCell<Font>>>,
|
||||
}
|
||||
|
||||
struct FallbackFontCacheEntry {
|
||||
|
@ -132,13 +132,21 @@ impl FontContext {
|
|||
let mut cache_hit = false;
|
||||
for cached_font_entry in self.layout_font_cache.iter() {
|
||||
if cached_font_entry.family.as_slice() == family.name() {
|
||||
let cached_font = cached_font_entry.font.borrow();
|
||||
if cached_font.descriptor == desc &&
|
||||
cached_font.requested_pt_size == style.font_size.to_subpx() &&
|
||||
cached_font.variant == style.font_variant {
|
||||
fonts.push(cached_font_entry.font.clone());
|
||||
cache_hit = true;
|
||||
break;
|
||||
match cached_font_entry.font {
|
||||
None => {
|
||||
cache_hit = true;
|
||||
break;
|
||||
}
|
||||
Some(ref cached_font_ref) => {
|
||||
let cached_font = cached_font_ref.borrow();
|
||||
if cached_font.descriptor == desc &&
|
||||
cached_font.requested_pt_size == style.font_size.to_subpx() &&
|
||||
cached_font.variant == style.font_variant {
|
||||
fonts.push((*cached_font_ref).clone());
|
||||
cache_hit = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -156,11 +164,16 @@ impl FontContext {
|
|||
let layout_font = Rc::new(RefCell::new(layout_font));
|
||||
self.layout_font_cache.push(LayoutFontCacheEntry {
|
||||
family: family.name().to_string(),
|
||||
font: layout_font.clone(),
|
||||
font: Some(layout_font.clone()),
|
||||
});
|
||||
fonts.push(layout_font);
|
||||
}
|
||||
None => {}
|
||||
None => {
|
||||
self.layout_font_cache.push(LayoutFontCacheEntry {
|
||||
family: family.name().to_string(),
|
||||
font: None,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,14 +25,13 @@ use servo_msg::compositor_msg::{LayerMetadata, RenderListener, RenderingRenderSt
|
|||
use servo_msg::constellation_msg::{ConstellationChan, Failure, FailureMsg, PipelineId};
|
||||
use servo_msg::constellation_msg::{RendererReadyMsg};
|
||||
use servo_msg::platform::surface::NativeSurfaceAzureMethods;
|
||||
use servo_util::geometry::{Au, mod};
|
||||
use servo_util::geometry;
|
||||
use servo_util::opts;
|
||||
use servo_util::smallvec::{SmallVec, SmallVec1};
|
||||
use servo_util::task::spawn_named_with_send_on_failure;
|
||||
use servo_util::time::{TimeProfilerChan, profile};
|
||||
use servo_util::time;
|
||||
use std::comm::{Receiver, Sender, channel};
|
||||
use std::i32;
|
||||
use sync::Arc;
|
||||
use font_cache_task::FontCacheTask;
|
||||
|
||||
|
@ -359,9 +358,8 @@ impl<C:RenderListener + Send> RenderTask<C> {
|
|||
None,
|
||||
self.time_profiler_chan.clone(),
|
||||
|| {
|
||||
let clip_rect = Rect(Point2D(Au(i32::MIN), Au(i32::MIN)),
|
||||
Size2D(Au(i32::MAX), Au(i32::MAX)));
|
||||
display_list.draw_into_context(&mut ctx, &matrix, &clip_rect);
|
||||
let mut clip_stack = Vec::new();
|
||||
display_list.draw_into_context(&mut ctx, &matrix, &mut clip_stack);
|
||||
ctx.draw_target.flush();
|
||||
});
|
||||
}
|
||||
|
|
|
@ -162,7 +162,7 @@ impl<'a> TextRun {
|
|||
|
||||
// Create a glyph store for this slice if it's nonempty.
|
||||
if can_break_before && byte_i > byte_last_boundary {
|
||||
let slice = text.slice(byte_last_boundary, byte_i).to_string();
|
||||
let slice = text.slice(byte_last_boundary, byte_i);
|
||||
debug!("creating glyph store for slice {} (ws? {}), {} - {} in run {}",
|
||||
slice, !cur_slice_is_whitespace, byte_last_boundary, byte_i, text);
|
||||
glyphs.push(GlyphRun {
|
||||
|
@ -179,7 +179,7 @@ impl<'a> TextRun {
|
|||
|
||||
// Create a glyph store for the final slice if it's nonempty.
|
||||
if byte_i > byte_last_boundary {
|
||||
let slice = text.slice_from(byte_last_boundary).to_string();
|
||||
let slice = text.slice_from(byte_last_boundary);
|
||||
debug!("creating glyph store for final slice {} (ws? {}), {} - {} in run {}",
|
||||
slice, cur_slice_is_whitespace, byte_last_boundary, text.len(), text);
|
||||
glyphs.push(GlyphRun {
|
||||
|
|
|
@ -17,15 +17,17 @@ pub enum CompressionMode {
|
|||
// High level TODOs:
|
||||
//
|
||||
// * Issue #113: consider incoming text state (arabic, etc)
|
||||
// and propogate outgoing text state (dual of above)
|
||||
// and propagate outgoing text state (dual of above)
|
||||
//
|
||||
// * Issue #114: record skipped and kept chars for mapping original to new text
|
||||
//
|
||||
// * Untracked: various edge cases for bidi, CJK, etc.
|
||||
pub fn transform_text(text: &str, mode: CompressionMode,
|
||||
pub fn transform_text(text: &str,
|
||||
mode: CompressionMode,
|
||||
incoming_whitespace: bool,
|
||||
new_line_pos: &mut Vec<CharIndex>) -> (String, bool) {
|
||||
let mut out_str = String::new();
|
||||
output_text: &mut String,
|
||||
new_line_pos: &mut Vec<CharIndex>)
|
||||
-> bool {
|
||||
let out_whitespace = match mode {
|
||||
CompressNone | DiscardNewline => {
|
||||
let mut new_line_index = CharIndex(0);
|
||||
|
@ -46,7 +48,7 @@ pub fn transform_text(text: &str, mode: CompressionMode,
|
|||
if ch != '\n' {
|
||||
new_line_index = new_line_index + CharIndex(1);
|
||||
}
|
||||
out_str.push_char(ch);
|
||||
output_text.push_char(ch);
|
||||
}
|
||||
}
|
||||
text.len() > 0 && is_in_whitespace(text.char_at_reverse(0), mode)
|
||||
|
@ -65,14 +67,14 @@ pub fn transform_text(text: &str, mode: CompressionMode,
|
|||
// TODO: record skipped char
|
||||
} else {
|
||||
// TODO: record kept char
|
||||
out_str.push_char(ch);
|
||||
output_text.push_char(ch);
|
||||
}
|
||||
} else { /* next_in_whitespace; possibly add a space char */
|
||||
if in_whitespace {
|
||||
// TODO: record skipped char
|
||||
} else {
|
||||
// TODO: record kept char
|
||||
out_str.push_char(' ');
|
||||
output_text.push_char(' ');
|
||||
}
|
||||
}
|
||||
// save whitespace context for next char
|
||||
|
@ -82,7 +84,7 @@ pub fn transform_text(text: &str, mode: CompressionMode,
|
|||
}
|
||||
};
|
||||
|
||||
return (out_str, out_whitespace);
|
||||
return out_whitespace;
|
||||
|
||||
fn is_in_whitespace(ch: char, mode: CompressionMode) -> bool {
|
||||
match (ch, mode) {
|
||||
|
@ -155,7 +157,8 @@ fn test_transform_compress_none() {
|
|||
|
||||
for test in test_strs.iter() {
|
||||
let mut new_line_pos = vec!();
|
||||
let (trimmed_str, _out) = transform_text(*test, mode, true, &mut new_line_pos);
|
||||
let mut trimmed_str = String::new();
|
||||
transform_text(*test, mode, true, &mut trimmed_str, &mut new_line_pos);
|
||||
assert_eq!(trimmed_str.as_slice(), *test)
|
||||
}
|
||||
}
|
||||
|
@ -187,7 +190,8 @@ fn test_transform_discard_newline() {
|
|||
|
||||
for (test, oracle) in test_strs.iter().zip(oracle_strs.iter()) {
|
||||
let mut new_line_pos = vec!();
|
||||
let (trimmed_str, _out) = transform_text(*test, mode, true, &mut new_line_pos);
|
||||
let mut trimmed_str = String::new();
|
||||
transform_text(*test, mode, true, &mut trimmed_str, &mut new_line_pos);
|
||||
assert_eq!(trimmed_str.as_slice(), *oracle)
|
||||
}
|
||||
}
|
||||
|
@ -279,7 +283,8 @@ fn test_transform_compress_whitespace_newline_no_incoming() {
|
|||
|
||||
for (test, oracle) in test_strs.iter().zip(oracle_strs.iter()) {
|
||||
let mut new_line_pos = vec!();
|
||||
let (trimmed_str, _out) = transform_text(*test, mode, false, &mut new_line_pos);
|
||||
let mut trimmed_str = String::new();
|
||||
transform_text(*test, mode, false, &mut trimmed_str, &mut new_line_pos);
|
||||
assert_eq!(trimmed_str.as_slice(), *oracle)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue