mirror of
https://github.com/servo/servo.git
synced 2025-08-06 22:15:33 +01:00
auto merge of #468 : jdm/servo/investigate, r=metajack
By the power vested in me through the agency of gdb, massif, and valgrind, here are some changes that fix various crashes that occur when shutting down at arbitrary points, along with some honest-to-goodness shutdown leaks reported by valgrind, and the layout cycles that were causing 1gb/s memory explosions when running test_hammer_layout.html.
This commit is contained in:
commit
943139b397
15 changed files with 155 additions and 27 deletions
|
@ -177,6 +177,10 @@ pub impl FontGroup {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn teardown(&mut self) {
|
||||||
|
self.fonts = ~[];
|
||||||
|
}
|
||||||
|
|
||||||
fn create_textrun(&self, text: ~str) -> TextRun {
|
fn create_textrun(&self, text: ~str) -> TextRun {
|
||||||
assert!(self.fonts.len() > 0);
|
assert!(self.fonts.len() > 0);
|
||||||
|
|
||||||
|
@ -283,6 +287,11 @@ pub impl Font {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn teardown(&mut self) {
|
||||||
|
self.shaper = None;
|
||||||
|
self.azure_font = None;
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: this should return a borrowed pointer, but I can't figure
|
// TODO: this should return a borrowed pointer, but I can't figure
|
||||||
// out why borrowck doesn't like my implementation.
|
// out why borrowck doesn't like my implementation.
|
||||||
|
|
||||||
|
|
|
@ -132,7 +132,6 @@ impl FontFamily {
|
||||||
/// In the common case, each FontFamily will have a singleton FontEntry, or it will have the
|
/// In the common case, each FontFamily will have a singleton FontEntry, or it will have the
|
||||||
/// standard four faces: Normal, Bold, Italic, BoldItalic.
|
/// standard four faces: Normal, Bold, Italic, BoldItalic.
|
||||||
pub struct FontEntry {
|
pub struct FontEntry {
|
||||||
family: @mut FontFamily,
|
|
||||||
face_name: ~str,
|
face_name: ~str,
|
||||||
priv weight: CSSFontWeight,
|
priv weight: CSSFontWeight,
|
||||||
priv italic: bool,
|
priv italic: bool,
|
||||||
|
@ -141,9 +140,8 @@ pub struct FontEntry {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FontEntry {
|
impl FontEntry {
|
||||||
pub fn new(family: @mut FontFamily, handle: FontHandle) -> FontEntry {
|
pub fn new(handle: FontHandle) -> FontEntry {
|
||||||
FontEntry {
|
FontEntry {
|
||||||
family: family,
|
|
||||||
face_name: handle.face_name(),
|
face_name: handle.face_name(),
|
||||||
weight: handle.boldness(),
|
weight: handle.boldness(),
|
||||||
italic: handle.is_italic(),
|
italic: handle.is_italic(),
|
||||||
|
|
|
@ -53,6 +53,7 @@ pub struct FontHandle {
|
||||||
// if the font is created using FT_Memory_Face.
|
// if the font is created using FT_Memory_Face.
|
||||||
source: FontSource,
|
source: FontSource,
|
||||||
face: FT_Face,
|
face: FT_Face,
|
||||||
|
handle: FontContextHandle
|
||||||
}
|
}
|
||||||
|
|
||||||
#[unsafe_destructor]
|
#[unsafe_destructor]
|
||||||
|
@ -81,7 +82,14 @@ impl FontHandleMethods for FontHandle {
|
||||||
// and moving buf into the struct ctor, but cant' move out of
|
// and moving buf into the struct ctor, but cant' move out of
|
||||||
// captured binding.
|
// captured binding.
|
||||||
return match face_result {
|
return match face_result {
|
||||||
Ok(face) => Ok(FontHandle { face: face, source: FontSourceMem(buf) }),
|
Ok(face) => {
|
||||||
|
let handle = FontHandle {
|
||||||
|
face: face,
|
||||||
|
source: FontSourceMem(buf),
|
||||||
|
handle: *fctx
|
||||||
|
};
|
||||||
|
Ok(handle)
|
||||||
|
}
|
||||||
Err(()) => Err(())
|
Err(()) => Err(())
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -247,7 +255,11 @@ pub impl<'self> FontHandle {
|
||||||
return Err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
if FontHandle::set_char_size(face, style.pt_size).is_ok() {
|
if FontHandle::set_char_size(face, style.pt_size).is_ok() {
|
||||||
Ok(FontHandle { source: FontSourceFile(file), face: face })
|
Ok(FontHandle {
|
||||||
|
source: FontSourceFile(file),
|
||||||
|
face: face,
|
||||||
|
handle: *fctx
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
Err(())
|
Err(())
|
||||||
}
|
}
|
||||||
|
@ -268,7 +280,11 @@ pub impl<'self> FontHandle {
|
||||||
return Err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(FontHandle { source: FontSourceFile(file), face: face })
|
Ok(FontHandle {
|
||||||
|
source: FontSourceFile(file),
|
||||||
|
face: face,
|
||||||
|
handle: *fctx
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
priv fn get_face_rec(&'self self) -> &'self FT_FaceRec {
|
priv fn get_face_rec(&'self self) -> &'self FT_FaceRec {
|
||||||
|
|
|
@ -6,7 +6,7 @@ extern mod freetype;
|
||||||
extern mod fontconfig;
|
extern mod fontconfig;
|
||||||
|
|
||||||
use fontconfig::fontconfig::{
|
use fontconfig::fontconfig::{
|
||||||
FcChar8, FcResultMatch, FcSetSystem,
|
FcChar8, FcResultMatch, FcSetSystem, FcPattern,
|
||||||
FcResultNoMatch, FcMatchPattern, FC_SLANT_ITALIC, FC_WEIGHT_BOLD
|
FcResultNoMatch, FcMatchPattern, FC_SLANT_ITALIC, FC_WEIGHT_BOLD
|
||||||
};
|
};
|
||||||
use fontconfig::fontconfig::bindgen::{
|
use fontconfig::fontconfig::bindgen::{
|
||||||
|
@ -116,7 +116,7 @@ pub impl FontListHandle {
|
||||||
let font_handle = font_handle.unwrap();
|
let font_handle = font_handle.unwrap();
|
||||||
|
|
||||||
debug!("Creating new FontEntry for face: %s", font_handle.face_name());
|
debug!("Creating new FontEntry for face: %s", font_handle.face_name());
|
||||||
let entry = @FontEntry::new(family, font_handle);
|
let entry = @FontEntry::new(font_handle);
|
||||||
family.entries.push(entry);
|
family.entries.push(entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,10 +127,21 @@ pub impl FontListHandle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct AutoPattern {
|
||||||
|
pattern: *FcPattern
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for AutoPattern {
|
||||||
|
fn finalize(&self) {
|
||||||
|
FcPatternDestroy(self.pattern);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn path_from_identifier(name: ~str, style: &UsedFontStyle) -> Result<~str, ()> {
|
pub fn path_from_identifier(name: ~str, style: &UsedFontStyle) -> Result<~str, ()> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let config = FcConfigGetCurrent();
|
let config = FcConfigGetCurrent();
|
||||||
let pattern = FcPatternCreate();
|
let wrapper = AutoPattern { pattern: FcPatternCreate() };
|
||||||
|
let pattern = wrapper.pattern;
|
||||||
let res = do str::as_c_str("family") |FC_FAMILY| {
|
let res = do str::as_c_str("family") |FC_FAMILY| {
|
||||||
do str::as_c_str(name) |family| {
|
do str::as_c_str(name) |family| {
|
||||||
FcPatternAddString(pattern, FC_FAMILY, family as *FcChar8)
|
FcPatternAddString(pattern, FC_FAMILY, family as *FcChar8)
|
||||||
|
@ -166,7 +177,8 @@ pub fn path_from_identifier(name: ~str, style: &UsedFontStyle) -> Result<~str, (
|
||||||
}
|
}
|
||||||
FcDefaultSubstitute(pattern);
|
FcDefaultSubstitute(pattern);
|
||||||
let result = FcResultNoMatch;
|
let result = FcResultNoMatch;
|
||||||
let result_pattern = FcFontMatch(config, pattern, &result);
|
let result_wrapper = AutoPattern { pattern: FcFontMatch(config, pattern, &result) };
|
||||||
|
let result_pattern = result_wrapper.pattern;
|
||||||
if result != FcResultMatch && result_pattern.is_null() {
|
if result != FcResultMatch && result_pattern.is_null() {
|
||||||
debug!("obtaining match to pattern failed");
|
debug!("obtaining match to pattern failed");
|
||||||
return Err(());
|
return Err(());
|
||||||
|
|
|
@ -51,7 +51,7 @@ pub impl FontListHandle {
|
||||||
let handle = result::unwrap(FontHandle::new_from_CTFont(&self.fctx, font));
|
let handle = result::unwrap(FontHandle::new_from_CTFont(&self.fctx, font));
|
||||||
|
|
||||||
debug!("Creating new FontEntry for face: %s", handle.face_name());
|
debug!("Creating new FontEntry for face: %s", handle.face_name());
|
||||||
let entry = @FontEntry::new(family, handle);
|
let entry = @FontEntry::new(handle);
|
||||||
family.entries.push(entry)
|
family.entries.push(entry)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,6 +51,10 @@ pub impl<'self> TextRun {
|
||||||
return run;
|
return run;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn teardown(&self) {
|
||||||
|
self.font.teardown();
|
||||||
|
}
|
||||||
|
|
||||||
fn compute_potential_breaks(text: &str, glyphs: &mut GlyphStore) {
|
fn compute_potential_breaks(text: &str, glyphs: &mut GlyphStore) {
|
||||||
// TODO(Issue #230): do a better job. See Gecko's LineBreaker.
|
// TODO(Issue #230): do a better job. See Gecko's LineBreaker.
|
||||||
|
|
||||||
|
|
|
@ -34,18 +34,6 @@ pub fn Document(root: AbstractNode, window: Option<@mut Window>) -> @mut Documen
|
||||||
doc
|
doc
|
||||||
}
|
}
|
||||||
|
|
||||||
#[unsafe_destructor]
|
|
||||||
impl Drop for Document {
|
|
||||||
fn finalize(&self) {
|
|
||||||
let compartment = global_script_context().js_compartment;
|
|
||||||
do self.root.with_base |base| {
|
|
||||||
assert!(base.wrapper.get_wrapper().is_not_null());
|
|
||||||
let rootable = base.wrapper.get_rootable();
|
|
||||||
JS_RemoveObjectRoot(compartment.cx.ptr, rootable);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub impl Document {
|
pub impl Document {
|
||||||
fn getElementsByTagName(&self, tag: DOMString) -> Option<@mut HTMLCollection> {
|
fn getElementsByTagName(&self, tag: DOMString) -> Option<@mut HTMLCollection> {
|
||||||
let mut elements = ~[];
|
let mut elements = ~[];
|
||||||
|
@ -67,5 +55,14 @@ pub impl Document {
|
||||||
window.content_changed()
|
window.content_changed()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn teardown(&self) {
|
||||||
|
let compartment = global_script_context().js_compartment;
|
||||||
|
do self.root.with_base |node| {
|
||||||
|
assert!(node.wrapper.get_wrapper().is_not_null());
|
||||||
|
let rootable = node.wrapper.get_rootable();
|
||||||
|
JS_RemoveObjectRoot(compartment.cx.ptr, rootable);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,14 @@ impl LayoutAuxMethods for AbstractNode {
|
||||||
/// box in the COW model) and populates it with an empty style object.
|
/// box in the COW model) and populates it with an empty style object.
|
||||||
fn initialize_layout_data(self) -> Option<@mut LayoutData> {
|
fn initialize_layout_data(self) -> Option<@mut LayoutData> {
|
||||||
if self.has_layout_data() {
|
if self.has_layout_data() {
|
||||||
|
{
|
||||||
|
let layout_data = &mut self.layout_data().flow;
|
||||||
|
match *layout_data {
|
||||||
|
Some(ref flow) => flow.teardown(),
|
||||||
|
None => ()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.layout_data().flow = None;
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
let data = @mut LayoutData::new();
|
let data = @mut LayoutData::new();
|
||||||
|
|
|
@ -45,6 +45,14 @@ impl BlockFlowData {
|
||||||
is_root: true
|
is_root: true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn teardown(&mut self) {
|
||||||
|
self.common.teardown();
|
||||||
|
for self.box.each |box| {
|
||||||
|
box.teardown();
|
||||||
|
}
|
||||||
|
self.box = None;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait BlockLayout {
|
pub trait BlockLayout {
|
||||||
|
|
|
@ -59,6 +59,15 @@ pub enum RenderBox {
|
||||||
UnscannedTextRenderBoxClass(@mut UnscannedTextRenderBox),
|
UnscannedTextRenderBoxClass(@mut UnscannedTextRenderBox),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl RenderBox {
|
||||||
|
pub fn teardown(&self) {
|
||||||
|
match *self {
|
||||||
|
TextRenderBoxClass(box) => box.teardown(),
|
||||||
|
_ => ()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A box that represents a (replaced content) image and its accompanying borders, shadows, etc.
|
/// A box that represents a (replaced content) image and its accompanying borders, shadows, etc.
|
||||||
pub struct ImageRenderBox {
|
pub struct ImageRenderBox {
|
||||||
base: RenderBoxBase,
|
base: RenderBoxBase,
|
||||||
|
@ -88,6 +97,12 @@ pub struct TextRenderBox {
|
||||||
text_data: TextBoxData,
|
text_data: TextBoxData,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TextRenderBox {
|
||||||
|
fn teardown(&self) {
|
||||||
|
self.text_data.teardown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// The data for an unscanned text box.
|
/// The data for an unscanned text box.
|
||||||
pub struct UnscannedTextRenderBox {
|
pub struct UnscannedTextRenderBox {
|
||||||
base: RenderBoxBase,
|
base: RenderBoxBase,
|
||||||
|
|
|
@ -67,6 +67,43 @@ impl Clone for FlowContext {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl FlowContext {
|
||||||
|
pub fn teardown(&self) {
|
||||||
|
match *self {
|
||||||
|
AbsoluteFlow(data) |
|
||||||
|
FloatFlow(data) |
|
||||||
|
InlineBlockFlow(data) |
|
||||||
|
TableFlow(data) => data.teardown(),
|
||||||
|
BlockFlow(data) => data.teardown(),
|
||||||
|
InlineFlow(data) => data.teardown()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FlowData {
|
||||||
|
pub fn teardown(&mut self) {
|
||||||
|
// Under the assumption that all flows exist in a tree,
|
||||||
|
// we must restrict ourselves to finalizing flows that
|
||||||
|
// are descendents and subsequent siblings to ourselves,
|
||||||
|
// or we risk dynamic borrow failures.
|
||||||
|
self.parent = None;
|
||||||
|
|
||||||
|
for self.first_child.each |flow| {
|
||||||
|
flow.teardown();
|
||||||
|
}
|
||||||
|
self.first_child = None;
|
||||||
|
|
||||||
|
self.last_child = None;
|
||||||
|
|
||||||
|
for self.next_sibling.each |flow| {
|
||||||
|
flow.teardown();
|
||||||
|
}
|
||||||
|
self.next_sibling = None;
|
||||||
|
|
||||||
|
self.prev_sibling = None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl TreeNodeRef<FlowData> for FlowContext {
|
impl TreeNodeRef<FlowData> for FlowContext {
|
||||||
fn with_base<R>(&self, callback: &fn(&FlowData) -> R) -> R {
|
fn with_base<R>(&self, callback: &fn(&FlowData) -> R) -> R {
|
||||||
match *self {
|
match *self {
|
||||||
|
|
|
@ -316,11 +316,18 @@ impl TextRunScanner {
|
||||||
// and then letting `FontGroup` decide which `Font` to stick into the text run.
|
// and then letting `FontGroup` decide which `Font` to stick into the text run.
|
||||||
let font_style = in_boxes[self.clump.begin()].font_style();
|
let font_style = in_boxes[self.clump.begin()].font_style();
|
||||||
let fontgroup = ctx.font_ctx.get_resolved_font_for_style(&font_style);
|
let fontgroup = ctx.font_ctx.get_resolved_font_for_style(&font_style);
|
||||||
let run = @TextRun::new(fontgroup.fonts[0], run_str);
|
|
||||||
|
// TextRuns contain a cycle which is usually resolved by the teardown
|
||||||
|
// sequence. If no clump takes ownership, however, it will leak.
|
||||||
|
let clump = self.clump;
|
||||||
|
let run = if clump.length() != 0 {
|
||||||
|
Some(@TextRun::new(fontgroup.fonts[0], run_str))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
// Make new boxes with the run and adjusted text indices.
|
// Make new boxes with the run and adjusted text indices.
|
||||||
debug!("TextRunScanner: pushing box(es) in range: %?", self.clump);
|
debug!("TextRunScanner: pushing box(es) in range: %?", self.clump);
|
||||||
let clump = self.clump;
|
|
||||||
for clump.eachi |i| {
|
for clump.eachi |i| {
|
||||||
let range = new_ranges[i - self.clump.begin()];
|
let range = new_ranges[i - self.clump.begin()];
|
||||||
if range.length() == 0 {
|
if range.length() == 0 {
|
||||||
|
@ -331,7 +338,7 @@ impl TextRunScanner {
|
||||||
}
|
}
|
||||||
|
|
||||||
do in_boxes[i].with_imm_base |base| {
|
do in_boxes[i].with_imm_base |base| {
|
||||||
let new_box = @mut adapt_textbox_with_range(*base, run, range);
|
let new_box = @mut adapt_textbox_with_range(*base, run.get(), range);
|
||||||
out_boxes.push(TextRenderBoxClass(new_box));
|
out_boxes.push(TextRenderBoxClass(new_box));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -638,6 +645,14 @@ impl InlineFlowData {
|
||||||
elems: ElementMapping::new(),
|
elems: ElementMapping::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn teardown(&mut self) {
|
||||||
|
self.common.teardown();
|
||||||
|
for self.boxes.each |box| {
|
||||||
|
box.teardown();
|
||||||
|
}
|
||||||
|
self.boxes = ~[];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait InlineLayout {
|
pub trait InlineLayout {
|
||||||
|
|
|
@ -21,6 +21,10 @@ impl TextBoxData {
|
||||||
range: range,
|
range: range,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn teardown(&self) {
|
||||||
|
self.run.teardown();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn adapt_textbox_with_range(mut base: RenderBoxBase, run: @TextRun, range: Range)
|
pub fn adapt_textbox_with_range(mut base: RenderBoxBase, run: @TextRun, range: Range)
|
||||||
|
|
|
@ -285,6 +285,10 @@ impl ScriptContext {
|
||||||
|
|
||||||
/// Handles a request to exit the script task and shut down layout.
|
/// Handles a request to exit the script task and shut down layout.
|
||||||
fn handle_exit_msg(&mut self) {
|
fn handle_exit_msg(&mut self) {
|
||||||
|
self.join_layout();
|
||||||
|
for self.root_frame.each |frame| {
|
||||||
|
frame.document.teardown();
|
||||||
|
}
|
||||||
self.layout_task.send(layout_task::ExitMsg)
|
self.layout_task.send(layout_task::ExitMsg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,8 @@ var count = 1000000;
|
||||||
var start = new Date();
|
var start = new Date();
|
||||||
for (var i = 0; i < count; i++) {
|
for (var i = 0; i < count; i++) {
|
||||||
div.setAttribute('id', 'styled');
|
div.setAttribute('id', 'styled');
|
||||||
div.getBoundingClientRect();
|
//div.getBoundingClientRect();
|
||||||
}
|
}
|
||||||
var stop = new Date();
|
var stop = new Date();
|
||||||
window.alert((stop - start) / count * 1e6);
|
window.alert((stop - start) / count * 1e6);
|
||||||
|
window.close();
|
Loading…
Add table
Add a link
Reference in a new issue