mirror of
https://github.com/servo/servo.git
synced 2025-08-04 21:20:23 +01:00
Merge remote-tracking branch 'origin/master' into pcwalton-master
Conflicts: src/components/main/layout/box_builder.rs
This commit is contained in:
commit
5425154f96
14 changed files with 252 additions and 193 deletions
|
@ -112,14 +112,14 @@ pub impl<'self> FontContext {
|
||||||
|
|
||||||
debug!("(create font group) --- starting ---");
|
debug!("(create font group) --- starting ---");
|
||||||
|
|
||||||
|
let list = self.get_font_list();
|
||||||
|
|
||||||
// TODO(Issue #193): make iteration over 'font-family' more robust.
|
// TODO(Issue #193): make iteration over 'font-family' more robust.
|
||||||
for str::each_split_char(style.families, ',') |family| {
|
for str::each_split_char(style.families, ',') |family| {
|
||||||
let family_name = str::trim(family);
|
let family_name = str::trim(family);
|
||||||
let transformed_family_name = self.transform_family(family_name);
|
let transformed_family_name = self.transform_family(family_name);
|
||||||
debug!("(create font group) transformed family is `%s`", transformed_family_name);
|
debug!("(create font group) transformed family is `%s`", transformed_family_name);
|
||||||
|
|
||||||
let list = self.get_font_list();
|
|
||||||
|
|
||||||
let result = list.find_font_in_family(transformed_family_name, style);
|
let result = list.find_font_in_family(transformed_family_name, style);
|
||||||
let mut found = false;
|
let mut found = false;
|
||||||
for result.each |font_entry| {
|
for result.each |font_entry| {
|
||||||
|
@ -134,6 +134,16 @@ pub impl<'self> FontContext {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let last_resort = FontList::get_last_resort_font_families();
|
||||||
|
|
||||||
|
for last_resort.each |family| {
|
||||||
|
let result = list.find_font_in_family(*family,style);
|
||||||
|
for result.each |font_entry| {
|
||||||
|
let instance = Font::new_from_existing_handle(self, &font_entry.handle, style, self.backend);
|
||||||
|
do result::iter(&instance) |font: &@mut Font| { fonts.push(*font); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
assert!(fonts.len() > 0);
|
assert!(fonts.len() > 0);
|
||||||
// TODO(Issue #179): Split FontStyle into specified and used styles
|
// TODO(Issue #179): Split FontStyle into specified and used styles
|
||||||
let used_style = copy *style;
|
let used_style = copy *style;
|
||||||
|
|
|
@ -19,6 +19,7 @@ pub type FontFamilyMap = HashMap<~str, @mut FontFamily>;
|
||||||
trait FontListHandleMethods {
|
trait FontListHandleMethods {
|
||||||
fn get_available_families(&self, fctx: &FontContextHandle) -> FontFamilyMap;
|
fn get_available_families(&self, fctx: &FontContextHandle) -> FontFamilyMap;
|
||||||
fn load_variations_for_family(&self, family: @mut FontFamily);
|
fn load_variations_for_family(&self, family: @mut FontFamily);
|
||||||
|
fn get_last_resort_font_families() -> ~[~str];
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The platform-independent font list abstraction.
|
/// The platform-independent font list abstraction.
|
||||||
|
@ -86,6 +87,11 @@ pub impl FontList {
|
||||||
// TODO(Issue #188): look up localized font family names if canonical name not found
|
// TODO(Issue #188): look up localized font family names if canonical name not found
|
||||||
family.map(|f| **f)
|
family.map(|f| **f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_last_resort_font_families() -> ~[~str] {
|
||||||
|
let last_resort = FontListHandle::get_last_resort_font_families();
|
||||||
|
last_resort
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Holds a specific font family, and the various
|
// Holds a specific font family, and the various
|
||||||
|
|
|
@ -125,6 +125,10 @@ pub impl FontListHandle {
|
||||||
FcObjectSetDestroy(object_set);
|
FcObjectSetDestroy(object_set);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_last_resort_font_families() -> ~[~str] {
|
||||||
|
~[~"Arial"]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct AutoPattern {
|
struct AutoPattern {
|
||||||
|
|
|
@ -55,4 +55,8 @@ pub impl FontListHandle {
|
||||||
family.entries.push(entry)
|
family.entries.push(entry)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_last_resort_font_families() -> ~[~str] {
|
||||||
|
~[~"Arial Unicode MS",~"Arial"]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -175,7 +175,9 @@ impl BlockFlowData {
|
||||||
/// Dual boxes consume some width first, and the remainder is assigned to all child (block)
|
/// Dual boxes consume some width first, and the remainder is assigned to all child (block)
|
||||||
/// contexts.
|
/// contexts.
|
||||||
pub fn assign_widths_block(@mut self, ctx: &LayoutContext) {
|
pub fn assign_widths_block(@mut self, ctx: &LayoutContext) {
|
||||||
|
debug!("assign_widths_block: assigning width for flow %?", self.common.id);
|
||||||
if self.is_root {
|
if self.is_root {
|
||||||
|
debug!("Setting root position");
|
||||||
self.common.position.origin = Au::zero_point();
|
self.common.position.origin = Au::zero_point();
|
||||||
self.common.position.size.width = ctx.screen_size.size.width;
|
self.common.position.size.width = ctx.screen_size.size.width;
|
||||||
}
|
}
|
||||||
|
|
|
@ -626,7 +626,21 @@ pub impl RenderBox {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
GenericRenderBoxClass(_) => {}
|
GenericRenderBoxClass(_) => {
|
||||||
|
debug!("%?", {
|
||||||
|
// Compute the text box bounds and draw a border surrounding them.
|
||||||
|
do list.with_mut_ref |list| {
|
||||||
|
let border_display_item = ~BorderDisplayItem {
|
||||||
|
base: BaseDisplayItem {
|
||||||
|
bounds: absolute_box_bounds,
|
||||||
|
},
|
||||||
|
width: Au::from_px(1),
|
||||||
|
color: rgb(0, 0, 0).to_gfx_color(),
|
||||||
|
};
|
||||||
|
list.append_item(BorderDisplayItemClass(border_display_item))
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
ImageRenderBoxClass(image_box) => {
|
ImageRenderBoxClass(image_box) => {
|
||||||
match image_box.image.get_image() {
|
match image_box.image.get_image() {
|
||||||
|
|
|
@ -14,8 +14,13 @@ use layout::flow::{AbsoluteFlow, BlockFlow, FloatFlow, Flow_Absolute, Flow_Block
|
||||||
use layout::flow::{Flow_Inline, Flow_InlineBlock, Flow_Root, Flow_Table, FlowContext};
|
use layout::flow::{Flow_Inline, Flow_InlineBlock, Flow_Root, Flow_Table, FlowContext};
|
||||||
use layout::flow::{FlowContextType, FlowData, InlineBlockFlow, InlineFlow, TableFlow};
|
use layout::flow::{FlowContextType, FlowData, InlineBlockFlow, InlineFlow, TableFlow};
|
||||||
use layout::inline::{InlineFlowData, InlineLayout};
|
use layout::inline::{InlineFlowData, InlineLayout};
|
||||||
|
use css::node_style::StyledNode;
|
||||||
|
|
||||||
use newcss::values::{CSSDisplay, CSSDisplayBlock, CSSDisplayInline, CSSDisplayInlineBlock};
|
use newcss::values::{CSSDisplay, CSSDisplayBlock, CSSDisplayInline, CSSDisplayInlineBlock};
|
||||||
|
use newcss::values::{CSSDisplayTable, CSSDisplayInlineTable, CSSDisplayListItem};
|
||||||
|
use newcss::values::{CSSDisplayTableRowGroup, CSSDisplayTableHeaderGroup, CSSDisplayTableFooterGroup};
|
||||||
|
use newcss::values::{CSSDisplayTableRow, CSSDisplayTableColumnGroup, CSSDisplayTableColumn};
|
||||||
|
use newcss::values::{CSSDisplayTableCell, CSSDisplayTableCaption};
|
||||||
use newcss::values::{CSSDisplayNone};
|
use newcss::values::{CSSDisplayNone};
|
||||||
use script::dom::element::*;
|
use script::dom::element::*;
|
||||||
use script::dom::node::{AbstractNode, CommentNodeTypeId, DoctypeNodeTypeId};
|
use script::dom::node::{AbstractNode, CommentNodeTypeId, DoctypeNodeTypeId};
|
||||||
|
@ -25,16 +30,16 @@ use servo_util::tree::{TreeNodeRef, TreeUtils};
|
||||||
|
|
||||||
pub struct LayoutTreeBuilder {
|
pub struct LayoutTreeBuilder {
|
||||||
root_flow: Option<FlowContext>,
|
root_flow: Option<FlowContext>,
|
||||||
|
next_cid: int,
|
||||||
next_bid: int,
|
next_bid: int,
|
||||||
next_cid: int
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub impl LayoutTreeBuilder {
|
pub impl LayoutTreeBuilder {
|
||||||
fn new() -> LayoutTreeBuilder {
|
fn new() -> LayoutTreeBuilder {
|
||||||
LayoutTreeBuilder {
|
LayoutTreeBuilder {
|
||||||
root_flow: None,
|
root_flow: None,
|
||||||
|
next_cid: -1,
|
||||||
next_bid: -1,
|
next_bid: -1,
|
||||||
next_cid: -1
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -86,6 +91,8 @@ priv fn simulate_UA_display_rules(node: AbstractNode<LayoutView>) -> CSSDisplay
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BoxGenerator {
|
impl BoxGenerator {
|
||||||
|
/* Debug ids only */
|
||||||
|
|
||||||
fn new(flow: FlowContext) -> BoxGenerator {
|
fn new(flow: FlowContext) -> BoxGenerator {
|
||||||
debug!("Creating box generator for flow: %s", flow.debug_str());
|
debug!("Creating box generator for flow: %s", flow.debug_str());
|
||||||
BoxGenerator {
|
BoxGenerator {
|
||||||
|
@ -110,14 +117,14 @@ impl BoxGenerator {
|
||||||
|
|
||||||
pub fn push_node(&mut self,
|
pub fn push_node(&mut self,
|
||||||
ctx: &LayoutContext,
|
ctx: &LayoutContext,
|
||||||
builder: &mut LayoutTreeBuilder,
|
node: AbstractNode<LayoutView>,
|
||||||
node: AbstractNode<LayoutView>) {
|
builder: &mut LayoutTreeBuilder) {
|
||||||
debug!("BoxGenerator[f%d]: pushing node: %s", self.flow.id(), node.debug_str());
|
debug!("BoxGenerator[f%d]: pushing node: %s", self.flow.id(), node.debug_str());
|
||||||
|
|
||||||
// first, determine the box type, based on node characteristics
|
// first, determine the box type, based on node characteristics
|
||||||
let simulated_display = simulate_UA_display_rules(node);
|
let simulated_display = simulate_UA_display_rules(node);
|
||||||
// TODO: remove this once UA styles work
|
// TODO: remove this once UA styles work
|
||||||
let box_type = builder.decide_box_type(node, simulated_display);
|
let box_type = self.decide_box_type(node, simulated_display);
|
||||||
|
|
||||||
debug!("BoxGenerator[f%d]: point a", self.flow.id());
|
debug!("BoxGenerator[f%d]: point a", self.flow.id());
|
||||||
|
|
||||||
|
@ -129,7 +136,7 @@ impl BoxGenerator {
|
||||||
|
|
||||||
// if a leaf, make a box.
|
// if a leaf, make a box.
|
||||||
if node.is_leaf() {
|
if node.is_leaf() {
|
||||||
let new_box = builder.make_box(ctx, box_type, node, self.flow);
|
let new_box = self.make_box(ctx, box_type, node, self.flow, builder);
|
||||||
inline.boxes.push(new_box);
|
inline.boxes.push(new_box);
|
||||||
} else if self.inline_spacers_needed_for_node(node) {
|
} else if self.inline_spacers_needed_for_node(node) {
|
||||||
// else, maybe make a spacer for "left" margin, border, padding
|
// else, maybe make a spacer for "left" margin, border, padding
|
||||||
|
@ -142,7 +149,7 @@ impl BoxGenerator {
|
||||||
},
|
},
|
||||||
BlockFlow(block) => {
|
BlockFlow(block) => {
|
||||||
debug!("BoxGenerator[f%d]: point b", block.common.id);
|
debug!("BoxGenerator[f%d]: point b", block.common.id);
|
||||||
let new_box = builder.make_box(ctx, box_type, node, self.flow);
|
let new_box = self.make_box(ctx, box_type, node, self.flow, builder);
|
||||||
|
|
||||||
debug!("BoxGenerator[f%d]: attaching box[b%d] to block flow (node: %s)",
|
debug!("BoxGenerator[f%d]: attaching box[b%d] to block flow (node: %s)",
|
||||||
block.common.id,
|
block.common.id,
|
||||||
|
@ -158,7 +165,6 @@ impl BoxGenerator {
|
||||||
|
|
||||||
pub fn pop_node(&mut self,
|
pub fn pop_node(&mut self,
|
||||||
ctx: &LayoutContext,
|
ctx: &LayoutContext,
|
||||||
_builder: &LayoutTreeBuilder,
|
|
||||||
node: AbstractNode<LayoutView>) {
|
node: AbstractNode<LayoutView>) {
|
||||||
debug!("BoxGenerator[f%d]: popping node: %s", self.flow.id(), node.debug_str());
|
debug!("BoxGenerator[f%d]: popping node: %s", self.flow.id(), node.debug_str());
|
||||||
|
|
||||||
|
@ -189,148 +195,106 @@ impl BoxGenerator {
|
||||||
_ => warn!("pop_node() not implemented for flow %?", self.flow.id()),
|
_ => warn!("pop_node() not implemented for flow %?", self.flow.id()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
struct BuilderContext {
|
/// Disambiguate between different methods here instead of inlining, since each case has very
|
||||||
default_collector: @mut BoxGenerator,
|
/// different complexity.
|
||||||
priv inline_collector: Option<@mut BoxGenerator>
|
fn make_box(&mut self,
|
||||||
}
|
layout_ctx: &LayoutContext,
|
||||||
|
ty: RenderBoxType,
|
||||||
impl BuilderContext {
|
|
||||||
fn new(collector: @mut BoxGenerator) -> BuilderContext {
|
|
||||||
{
|
|
||||||
let collector = &mut *collector;
|
|
||||||
debug!("Creating new BuilderContext for flow: %s", collector.flow.debug_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
BuilderContext {
|
|
||||||
default_collector: collector,
|
|
||||||
inline_collector: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn clone(self) -> BuilderContext {
|
|
||||||
debug!("BuilderContext: cloning context");
|
|
||||||
copy self
|
|
||||||
}
|
|
||||||
|
|
||||||
priv fn attach_child_flow(&self, child: FlowContext) {
|
|
||||||
let default_collector = &mut *self.default_collector;
|
|
||||||
debug!("BuilderContext: Adding child flow f%? of f%?",
|
|
||||||
default_collector.flow.id(),
|
|
||||||
child.id());
|
|
||||||
default_collector.flow.add_child(child);
|
|
||||||
}
|
|
||||||
|
|
||||||
priv fn create_child_flow_of_type(&self,
|
|
||||||
flow_type: FlowContextType,
|
|
||||||
builder: &mut LayoutTreeBuilder,
|
|
||||||
node: AbstractNode<LayoutView>) -> BuilderContext {
|
|
||||||
let new_flow = builder.make_flow(flow_type, node);
|
|
||||||
self.attach_child_flow(new_flow);
|
|
||||||
|
|
||||||
BuilderContext::new(@mut BoxGenerator::new(new_flow))
|
|
||||||
}
|
|
||||||
|
|
||||||
priv fn make_inline_collector(&mut self,
|
|
||||||
builder: &mut LayoutTreeBuilder,
|
|
||||||
node: AbstractNode<LayoutView>)
|
|
||||||
-> BuilderContext {
|
|
||||||
debug!("BuilderContext: making new inline collector flow");
|
|
||||||
let new_flow = builder.make_flow(Flow_Inline, node);
|
|
||||||
let new_generator = @mut BoxGenerator::new(new_flow);
|
|
||||||
|
|
||||||
self.inline_collector = Some(new_generator);
|
|
||||||
self.attach_child_flow(new_flow);
|
|
||||||
|
|
||||||
BuilderContext::new(new_generator)
|
|
||||||
}
|
|
||||||
|
|
||||||
priv fn get_inline_collector(&mut self,
|
|
||||||
builder: &mut LayoutTreeBuilder,
|
|
||||||
node: AbstractNode<LayoutView>)
|
|
||||||
-> BuilderContext {
|
|
||||||
match copy self.inline_collector {
|
|
||||||
Some(collector) => BuilderContext::new(collector),
|
|
||||||
None => self.make_inline_collector(builder, node)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
priv fn clear_inline_collector(&mut self) {
|
|
||||||
self.inline_collector = None;
|
|
||||||
}
|
|
||||||
|
|
||||||
// returns a context for the current node, or None if the document subtree rooted
|
|
||||||
// by the node should not generate a layout tree. For example, nodes with style 'display:none'
|
|
||||||
// should just not generate any flows or boxes.
|
|
||||||
fn containing_context_for_node(&mut self,
|
|
||||||
node: AbstractNode<LayoutView>,
|
node: AbstractNode<LayoutView>,
|
||||||
|
flow_context: FlowContext,
|
||||||
builder: &mut LayoutTreeBuilder)
|
builder: &mut LayoutTreeBuilder)
|
||||||
-> Option<BuilderContext> {
|
-> RenderBox {
|
||||||
// TODO: remove this once UA styles work
|
let base = RenderBoxBase::new(node, flow_context, builder.next_box_id());
|
||||||
// TODO: handle interactions with 'float', 'position' (CSS 2.1, Section 9.7)
|
let result = match ty {
|
||||||
let simulated_display = match simulate_UA_display_rules(node) {
|
RenderBox_Generic => GenericRenderBoxClass(@mut base),
|
||||||
CSSDisplayNone => return None, // tree ends here if 'display: none'
|
RenderBox_Text => UnscannedTextRenderBoxClass(@mut UnscannedTextRenderBox::new(base)),
|
||||||
v => v
|
RenderBox_Image => self.make_image_box(layout_ctx, node, base),
|
||||||
};
|
};
|
||||||
|
debug!("BoxGenerator: created box: %s", result.debug_str());
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
let containing_context = match (simulated_display, self.default_collector.flow) {
|
fn make_image_box(&mut self,
|
||||||
(CSSDisplayBlock, BlockFlow(info)) => match (info.is_root, node.parent_node()) {
|
layout_ctx: &LayoutContext,
|
||||||
// If this is the root node, then use the root flow's
|
node: AbstractNode<LayoutView>,
|
||||||
// context. Otherwise, make a child block context.
|
base: RenderBoxBase)
|
||||||
(true, Some(_)) => { self.create_child_flow_of_type(Flow_Block, builder, node) }
|
-> RenderBox {
|
||||||
(true, None) => { self.clone() }
|
assert!(node.is_image_element());
|
||||||
(false, _) => {
|
|
||||||
self.clear_inline_collector();
|
|
||||||
self.create_child_flow_of_type(Flow_Block, builder, node)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
(CSSDisplayInline, InlineFlow(*)) => self.clone(),
|
|
||||||
(CSSDisplayInlineBlock, InlineFlow(*)) => self.clone(),
|
|
||||||
(CSSDisplayInline, BlockFlow(*)) => self.get_inline_collector(builder, node),
|
|
||||||
(CSSDisplayInlineBlock, BlockFlow(*)) => self.get_inline_collector(builder, node),
|
|
||||||
_ => self.clone()
|
|
||||||
};
|
|
||||||
|
|
||||||
Some(containing_context)
|
do node.with_imm_image_element |image_element| {
|
||||||
|
if image_element.image.is_some() {
|
||||||
|
// FIXME(pcwalton): Don't copy URLs.
|
||||||
|
let url = copy *image_element.image.get_ref();
|
||||||
|
ImageRenderBoxClass(@mut ImageRenderBox::new(base, url, layout_ctx.image_cache))
|
||||||
|
} else {
|
||||||
|
info!("Tried to make image box, but couldn't find image. Made generic box \
|
||||||
|
instead.");
|
||||||
|
GenericRenderBoxClass(@mut base)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn decide_box_type(&self, node: AbstractNode<LayoutView>, _: CSSDisplay) -> RenderBoxType {
|
||||||
|
if node.is_text() {
|
||||||
|
RenderBox_Text
|
||||||
|
} else if node.is_image_element() {
|
||||||
|
do node.with_imm_image_element |image_element| {
|
||||||
|
match image_element.image {
|
||||||
|
Some(_) => RenderBox_Image,
|
||||||
|
None => RenderBox_Generic,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if node.is_element() {
|
||||||
|
RenderBox_Generic
|
||||||
|
} else {
|
||||||
|
fail!(~"Hey, doctypes and comments shouldn't get here! They are display:none!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
pub impl LayoutTreeBuilder {
|
pub impl LayoutTreeBuilder {
|
||||||
/* Debug-only ids */
|
/* Debug-only ids */
|
||||||
fn next_box_id(&mut self) -> int { self.next_bid += 1; self.next_bid }
|
|
||||||
fn next_flow_id(&mut self) -> int { self.next_cid += 1; self.next_cid }
|
fn next_flow_id(&mut self) -> int { self.next_cid += 1; self.next_cid }
|
||||||
|
fn next_box_id(&mut self) -> int { self.next_bid += 1; self.next_bid }
|
||||||
|
|
||||||
/// Creates necessary box(es) and flow context(s) for the current DOM node,
|
/// Creates necessary box(es) and flow context(s) for the current DOM node,
|
||||||
/// and recurses on its children.
|
/// and recurses on its children.
|
||||||
fn construct_recursively(&mut self,
|
fn construct_recursively(&mut self,
|
||||||
layout_ctx: &LayoutContext,
|
layout_ctx: &LayoutContext,
|
||||||
cur_node: AbstractNode<LayoutView>,
|
cur_node: AbstractNode<LayoutView>,
|
||||||
parent_ctx: &mut BuilderContext) {
|
parent_generator: @mut BoxGenerator,
|
||||||
|
prev_sibling_generator: Option<@mut BoxGenerator>)
|
||||||
|
-> Option<@mut BoxGenerator> {
|
||||||
debug!("Considering node: %s", cur_node.debug_str());
|
debug!("Considering node: %s", cur_node.debug_str());
|
||||||
|
|
||||||
let mut this_ctx = match parent_ctx.containing_context_for_node(cur_node, self) {
|
let this_generator = match self.box_generator_for_node(cur_node,
|
||||||
Some(ctx) => ctx,
|
parent_generator,
|
||||||
None => { return; } // no context because of display: none. Stop building subtree.
|
prev_sibling_generator) {
|
||||||
|
Some(gen) => gen,
|
||||||
|
None => { return prev_sibling_generator; }
|
||||||
};
|
};
|
||||||
|
|
||||||
debug!("point a: %s", cur_node.debug_str());
|
debug!("point a: %s", cur_node.debug_str());
|
||||||
this_ctx.default_collector.push_node(layout_ctx, self, cur_node);
|
this_generator.push_node(layout_ctx, cur_node, self);
|
||||||
debug!("point b: %s", cur_node.debug_str());
|
debug!("point b: %s", cur_node.debug_str());
|
||||||
|
|
||||||
// recurse on child nodes.
|
// recurse on child nodes.
|
||||||
|
let mut prev_generator: Option<@mut BoxGenerator> = None;
|
||||||
for cur_node.each_child |child_node| {
|
for cur_node.each_child |child_node| {
|
||||||
self.construct_recursively(layout_ctx, child_node, &mut this_ctx);
|
prev_generator = self.construct_recursively(layout_ctx, child_node, this_generator, prev_generator);
|
||||||
}
|
}
|
||||||
|
|
||||||
this_ctx.default_collector.pop_node(layout_ctx, self, cur_node);
|
this_generator.pop_node(layout_ctx, cur_node);
|
||||||
self.simplify_children_of_flow(layout_ctx, &this_ctx);
|
self.simplify_children_of_flow(layout_ctx, &mut this_generator.flow);
|
||||||
|
|
||||||
// store reference to the flow context which contains any
|
// store reference to the flow context which contains any
|
||||||
// boxes that correspond to child_flow.node. These boxes may
|
// boxes that correspond to child_flow.node. These boxes may
|
||||||
// eventually be elided or split, but the mapping between
|
// eventually be elided or split, but the mapping between
|
||||||
// nodes and FlowContexts should not change during layout.
|
// nodes and FlowContexts should not change during layout.
|
||||||
let flow = &mut this_ctx.default_collector.flow;
|
let flow: &FlowContext = &this_generator.flow;
|
||||||
let flow: &FlowContext = flow;
|
|
||||||
for flow.each_child |child_flow| {
|
for flow.each_child |child_flow| {
|
||||||
do child_flow.with_base |child_node| {
|
do child_flow.with_base |child_node| {
|
||||||
let dom_node = child_node.node;
|
let dom_node = child_node.node;
|
||||||
|
@ -338,6 +302,118 @@ pub impl LayoutTreeBuilder {
|
||||||
dom_node.layout_data().flow = Some(child_flow);
|
dom_node.layout_data().flow = Some(child_flow);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Some(this_generator)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn box_generator_for_node(&mut self,
|
||||||
|
node: AbstractNode<LayoutView>,
|
||||||
|
parent_generator: @mut BoxGenerator,
|
||||||
|
sibling_generator: Option<@mut BoxGenerator>)
|
||||||
|
-> Option<@mut BoxGenerator> {
|
||||||
|
|
||||||
|
fn is_root(node: AbstractNode<LayoutView>) -> bool {
|
||||||
|
match node.parent_node() {
|
||||||
|
None => true,
|
||||||
|
Some(_) => false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let display = if (node.is_element()) {
|
||||||
|
match node.style().display(is_root(node)) {
|
||||||
|
CSSDisplayNone => return None, // tree ends here if 'display: none'
|
||||||
|
// TODO(eatkinson) these are hacks so that the code doesn't crash
|
||||||
|
// when unsupported display values are used. They should be deleted
|
||||||
|
// as they are implemented.
|
||||||
|
CSSDisplayListItem => CSSDisplayBlock,
|
||||||
|
CSSDisplayTable => CSSDisplayBlock,
|
||||||
|
CSSDisplayInlineTable => CSSDisplayInlineBlock,
|
||||||
|
CSSDisplayTableRowGroup => CSSDisplayBlock,
|
||||||
|
CSSDisplayTableHeaderGroup => CSSDisplayBlock,
|
||||||
|
CSSDisplayTableFooterGroup => CSSDisplayBlock,
|
||||||
|
CSSDisplayTableRow => CSSDisplayBlock,
|
||||||
|
CSSDisplayTableColumnGroup => return None,
|
||||||
|
CSSDisplayTableColumn => return None,
|
||||||
|
CSSDisplayTableCell => CSSDisplayBlock,
|
||||||
|
CSSDisplayTableCaption => CSSDisplayBlock,
|
||||||
|
v => v
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
match node.type_id() {
|
||||||
|
|
||||||
|
ElementNodeTypeId(_) => CSSDisplayInline,
|
||||||
|
TextNodeTypeId => CSSDisplayInline,
|
||||||
|
DoctypeNodeTypeId | CommentNodeTypeId => return None,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let sibling_flow: Option<FlowContext> = match sibling_generator {
|
||||||
|
None => None,
|
||||||
|
Some(gen) => Some(gen.flow)
|
||||||
|
};
|
||||||
|
|
||||||
|
let new_generator = match (display, parent_generator.flow, sibling_flow) {
|
||||||
|
(CSSDisplayBlock, BlockFlow(info), _) => match (info.is_root, node.parent_node()) {
|
||||||
|
// If this is the root node, then use the root flow's
|
||||||
|
// context. Otherwise, make a child block context.
|
||||||
|
(true, Some(_)) => { self.create_child_generator(node, parent_generator, Flow_Block) }
|
||||||
|
(true, None) => { parent_generator }
|
||||||
|
(false, _) => {
|
||||||
|
self.create_child_generator(node, parent_generator, Flow_Block)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// Inlines that are children of inlines are part of the same flow
|
||||||
|
(CSSDisplayInline, InlineFlow(*), _) => parent_generator,
|
||||||
|
(CSSDisplayInlineBlock, InlineFlow(*), _) => parent_generator,
|
||||||
|
|
||||||
|
// Inlines that are children of blocks create new flows if their
|
||||||
|
// previous sibling was a block.
|
||||||
|
(CSSDisplayInline, BlockFlow(*), Some(BlockFlow(*))) |
|
||||||
|
(CSSDisplayInlineBlock, BlockFlow(*), Some(BlockFlow(*))) => {
|
||||||
|
self.create_child_generator(node, parent_generator, Flow_Inline)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inlines whose previous sibling was not a block try to use their
|
||||||
|
// sibling's flow context.
|
||||||
|
(CSSDisplayInline, BlockFlow(*), _) |
|
||||||
|
(CSSDisplayInlineBlock, BlockFlow(*), _) => {
|
||||||
|
self.create_child_generator_if_needed(node,
|
||||||
|
parent_generator,
|
||||||
|
sibling_generator,
|
||||||
|
Flow_Inline)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(eatkinson): blocks that are children of inlines need
|
||||||
|
// to split their parent flows.
|
||||||
|
//
|
||||||
|
// TODO(eatkinson): floats and positioned elements.
|
||||||
|
_ => parent_generator
|
||||||
|
};
|
||||||
|
|
||||||
|
Some(new_generator)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_child_generator(&mut self,
|
||||||
|
node: AbstractNode<LayoutView>,
|
||||||
|
parent_generator: @mut BoxGenerator,
|
||||||
|
ty: FlowContextType)
|
||||||
|
-> @mut BoxGenerator {
|
||||||
|
|
||||||
|
let new_flow = self.make_flow(ty, node);
|
||||||
|
parent_generator.flow.add_child(new_flow);
|
||||||
|
|
||||||
|
@mut BoxGenerator::new(new_flow)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_child_generator_if_needed(&mut self,
|
||||||
|
node: AbstractNode<LayoutView>,
|
||||||
|
parent_generator: @mut BoxGenerator,
|
||||||
|
maybe_generator: Option<@mut BoxGenerator>,
|
||||||
|
ty: FlowContextType)
|
||||||
|
-> @mut BoxGenerator {
|
||||||
|
|
||||||
|
match maybe_generator {
|
||||||
|
None => self.create_child_generator(node, parent_generator, ty),
|
||||||
|
Some(gen) => gen
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Fix up any irregularities such as:
|
/// Fix up any irregularities such as:
|
||||||
|
@ -348,15 +424,14 @@ pub impl LayoutTreeBuilder {
|
||||||
///
|
///
|
||||||
/// The latter can only be done immediately adjacent to, or at the beginning or end of a block
|
/// The latter can only be done immediately adjacent to, or at the beginning or end of a block
|
||||||
/// flow. Otherwise, the whitespace might affect whitespace collapsing with adjacent text.
|
/// flow. Otherwise, the whitespace might affect whitespace collapsing with adjacent text.
|
||||||
fn simplify_children_of_flow(&self, _: &LayoutContext, parent_ctx: &BuilderContext) {
|
fn simplify_children_of_flow(&self, _: &LayoutContext, parent_flow: &mut FlowContext) {
|
||||||
match parent_ctx.default_collector.flow {
|
match *parent_flow {
|
||||||
InlineFlow(*) => {
|
InlineFlow(*) => {
|
||||||
let mut found_child_inline = false;
|
let mut found_child_inline = false;
|
||||||
let mut found_child_block = false;
|
let mut found_child_block = false;
|
||||||
|
|
||||||
let flow = &mut parent_ctx.default_collector.flow;
|
let flow = *parent_flow;
|
||||||
let flow: &FlowContext = flow;
|
for flow.each_child |child_ctx: FlowContext| {
|
||||||
for flow.each_child |child_ctx| {
|
|
||||||
match child_ctx {
|
match child_ctx {
|
||||||
InlineFlow(*) | InlineBlockFlow(*) => found_child_inline = true,
|
InlineFlow(*) | InlineBlockFlow(*) => found_child_inline = true,
|
||||||
BlockFlow(*) => found_child_block = true,
|
BlockFlow(*) => found_child_block = true,
|
||||||
|
@ -365,13 +440,12 @@ pub impl LayoutTreeBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
if found_child_block && found_child_inline {
|
if found_child_block && found_child_inline {
|
||||||
self.fixup_split_inline(parent_ctx.default_collector.flow)
|
self.fixup_split_inline(*parent_flow)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
BlockFlow(*) => {
|
BlockFlow(*) => {
|
||||||
// FIXME: this will create refcounted cycles between the removed flow and any
|
// FIXME: this will create refcounted cycles between the removed flow and any
|
||||||
// of its RenderBox or FlowContext children, and possibly keep alive other junk
|
// of its RenderBox or FlowContext children, and possibly keep alive other junk
|
||||||
let parent_flow = parent_ctx.default_collector.flow;
|
|
||||||
|
|
||||||
// check first/last child for whitespace-ness
|
// check first/last child for whitespace-ness
|
||||||
let first_child = do parent_flow.with_base |parent_node| {
|
let first_child = do parent_flow.with_base |parent_node| {
|
||||||
|
@ -434,10 +508,9 @@ pub impl LayoutTreeBuilder {
|
||||||
-> Result<FlowContext, ()> {
|
-> Result<FlowContext, ()> {
|
||||||
let new_flow = self.make_flow(Flow_Root, root);
|
let new_flow = self.make_flow(Flow_Root, root);
|
||||||
let new_generator = @mut BoxGenerator::new(new_flow);
|
let new_generator = @mut BoxGenerator::new(new_flow);
|
||||||
let mut root_ctx = BuilderContext::new(new_generator);
|
|
||||||
|
|
||||||
self.root_flow = Some(new_flow);
|
self.root_flow = Some(new_flow);
|
||||||
self.construct_recursively(layout_ctx, root, &mut root_ctx);
|
self.construct_recursively(layout_ctx, root, new_generator, None);
|
||||||
return Ok(new_flow)
|
return Ok(new_flow)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -456,59 +529,4 @@ pub impl LayoutTreeBuilder {
|
||||||
debug!("LayoutTreeBuilder: created flow: %s", result.debug_str());
|
debug!("LayoutTreeBuilder: created flow: %s", result.debug_str());
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Disambiguate between different methods here instead of inlining, since each case has very
|
|
||||||
/// different complexity.
|
|
||||||
fn make_box(&mut self,
|
|
||||||
layout_ctx: &LayoutContext,
|
|
||||||
ty: RenderBoxType,
|
|
||||||
node: AbstractNode<LayoutView>,
|
|
||||||
flow_context: FlowContext)
|
|
||||||
-> RenderBox {
|
|
||||||
let base = RenderBoxBase::new(node, flow_context, self.next_box_id());
|
|
||||||
let result = match ty {
|
|
||||||
RenderBox_Generic => GenericRenderBoxClass(@mut base),
|
|
||||||
RenderBox_Text => UnscannedTextRenderBoxClass(@mut UnscannedTextRenderBox::new(base)),
|
|
||||||
RenderBox_Image => self.make_image_box(layout_ctx, node, base),
|
|
||||||
};
|
|
||||||
debug!("LayoutTreeBuilder: created box: %s", result.debug_str());
|
|
||||||
result
|
|
||||||
}
|
|
||||||
|
|
||||||
fn make_image_box(&mut self,
|
|
||||||
layout_ctx: &LayoutContext,
|
|
||||||
node: AbstractNode<LayoutView>,
|
|
||||||
base: RenderBoxBase)
|
|
||||||
-> RenderBox {
|
|
||||||
assert!(node.is_image_element());
|
|
||||||
|
|
||||||
do node.with_imm_image_element |image_element| {
|
|
||||||
if image_element.image.is_some() {
|
|
||||||
// FIXME(pcwalton): Don't copy URLs.
|
|
||||||
let url = copy *image_element.image.get_ref();
|
|
||||||
ImageRenderBoxClass(@mut ImageRenderBox::new(base, url, layout_ctx.image_cache))
|
|
||||||
} else {
|
|
||||||
info!("Tried to make image box, but couldn't find image. Made generic box \
|
|
||||||
instead.");
|
|
||||||
GenericRenderBoxClass(@mut base)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn decide_box_type(&self, node: AbstractNode<LayoutView>, _: CSSDisplay) -> RenderBoxType {
|
|
||||||
if node.is_text() {
|
|
||||||
RenderBox_Text
|
|
||||||
} else if node.is_image_element() {
|
|
||||||
do node.with_imm_image_element |image_element| {
|
|
||||||
match image_element.image {
|
|
||||||
Some(_) => RenderBox_Image,
|
|
||||||
None => RenderBox_Generic,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if node.is_element() {
|
|
||||||
RenderBox_Generic
|
|
||||||
} else {
|
|
||||||
fail!(~"Hey, doctypes and comments shouldn't get here! They are display:none!")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -412,7 +412,7 @@ impl<'self> FlowContext {
|
||||||
};
|
};
|
||||||
|
|
||||||
do self.with_base |base| {
|
do self.with_base |base| {
|
||||||
fmt!("f%? %?", base.id, repr)
|
fmt!("f%? %? size %?", base.id, repr, base.position)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -252,6 +252,8 @@ impl Layout {
|
||||||
} // time(layout: display list building)
|
} // time(layout: display list building)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
debug!("%?", layout_root.dump());
|
||||||
|
|
||||||
// Tell script that we're done.
|
// Tell script that we're done.
|
||||||
data.script_join_chan.send(());
|
data.script_join_chan.send(());
|
||||||
}
|
}
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit ff8e2a63938ded5d2688619680a981c73d25080d
|
Subproject commit d916b9796668d4bb46a3b1b4976c95ab7da79837
|
|
@ -1 +1 @@
|
||||||
Subproject commit 2f3f03cbafb88608d4f89216da7172d3b754fbef
|
Subproject commit 09d2db847c11bcab7f1832d5daf5947a7c1384ee
|
|
@ -1 +1 @@
|
||||||
Subproject commit 969af0260ef38d2c80ef2f51037da7ed1fc5cc85
|
Subproject commit dd25d69abde67e2275fbbbd93196043b69afd67b
|
|
@ -1 +1 @@
|
||||||
Subproject commit 3565b32ba3d15d31b02cc76bdf76d6b13fc88451
|
Subproject commit 8ecca4b5d779e749a298b1c2ca1152aa2ecd4e79
|
|
@ -9,8 +9,7 @@
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<div>Hello</div>
|
<div>Hello!</div>
|
||||||
|
|
||||||
<div>World</div>
|
<div>World</div>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue