mirror of
https://github.com/servo/servo.git
synced 2025-07-24 15:50:21 +01:00
layout: Implement ordered lists, CSS counters, and quotes
per CSS 2.1
§ 12.3-12.5. Only simple alphabetic and numeric counter styles are supported. (This is most of them though.) Although this PR adds a sequential pass to layout, I verified that on pages that contain a reasonable number of ordered lists (Reddit `/r/rust`), the time spent in generated content resolution is dwarfed by the time spent in the parallelizable parts of layout. So I don't expect this to negatively affect our parallelism expect perhaps in pathological cases.
This commit is contained in:
parent
2df4dd9e09
commit
f9cdd05d58
39 changed files with 1704 additions and 537 deletions
|
@ -27,7 +27,6 @@
|
||||||
|
|
||||||
#![deny(unsafe_blocks)]
|
#![deny(unsafe_blocks)]
|
||||||
|
|
||||||
use construct::FlowConstructor;
|
|
||||||
use context::LayoutContext;
|
use context::LayoutContext;
|
||||||
use css::node_style::StyledNode;
|
use css::node_style::StyledNode;
|
||||||
use display_list_builder::{BlockFlowDisplayListBuilding, FragmentDisplayListBuilding};
|
use display_list_builder::{BlockFlowDisplayListBuilding, FragmentDisplayListBuilding};
|
||||||
|
@ -50,12 +49,8 @@ use wrapper::ThreadSafeLayoutNode;
|
||||||
|
|
||||||
use geom::{Point2D, Rect, Size2D};
|
use geom::{Point2D, Rect, Size2D};
|
||||||
use gfx::display_list::{ClippingRegion, DisplayList};
|
use gfx::display_list::{ClippingRegion, DisplayList};
|
||||||
use rustc_serialize::{Encoder, Encodable};
|
|
||||||
use msg::compositor_msg::LayerId;
|
use msg::compositor_msg::LayerId;
|
||||||
use msg::constellation_msg::ConstellationChan;
|
use rustc_serialize::{Encoder, Encodable};
|
||||||
use util::geometry::{Au, MAX_AU};
|
|
||||||
use util::logical_geometry::{LogicalPoint, LogicalRect, LogicalSize, WritingMode};
|
|
||||||
use util::opts;
|
|
||||||
use std::cmp::{max, min};
|
use std::cmp::{max, min};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use style::computed_values::{overflow_x, overflow_y, position, box_sizing, display, float};
|
use style::computed_values::{overflow_x, overflow_y, position, box_sizing, display, float};
|
||||||
|
@ -63,6 +58,9 @@ use style::properties::ComputedValues;
|
||||||
use style::values::computed::{LengthOrPercentage, LengthOrPercentageOrAuto};
|
use style::values::computed::{LengthOrPercentage, LengthOrPercentageOrAuto};
|
||||||
use style::values::computed::{LengthOrPercentageOrNone};
|
use style::values::computed::{LengthOrPercentageOrNone};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use util::geometry::{Au, MAX_AU};
|
||||||
|
use util::logical_geometry::{LogicalPoint, LogicalRect, LogicalSize, WritingMode};
|
||||||
|
use util::opts;
|
||||||
|
|
||||||
/// Information specific to floated blocks.
|
/// Information specific to floated blocks.
|
||||||
#[derive(Clone, RustcEncodable)]
|
#[derive(Clone, RustcEncodable)]
|
||||||
|
@ -570,20 +568,6 @@ impl Encodable for BlockFlowFlags {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BlockFlow {
|
impl BlockFlow {
|
||||||
pub fn from_node(constructor: &mut FlowConstructor, node: &ThreadSafeLayoutNode) -> BlockFlow {
|
|
||||||
let writing_mode = node.style().writing_mode;
|
|
||||||
BlockFlow {
|
|
||||||
base: BaseFlow::new(Some((*node).clone()), writing_mode, ForceNonfloatedFlag::ForceNonfloated),
|
|
||||||
fragment: Fragment::new(constructor, node),
|
|
||||||
static_b_offset: Au::new(0),
|
|
||||||
inline_size_of_preceding_left_floats: Au(0),
|
|
||||||
inline_size_of_preceding_right_floats: Au(0),
|
|
||||||
hypothetical_position: LogicalPoint::new(writing_mode, Au(0), Au(0)),
|
|
||||||
float: None,
|
|
||||||
flags: BlockFlowFlags::empty(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn from_node_and_fragment(node: &ThreadSafeLayoutNode, fragment: Fragment) -> BlockFlow {
|
pub fn from_node_and_fragment(node: &ThreadSafeLayoutNode, fragment: Fragment) -> BlockFlow {
|
||||||
let writing_mode = node.style().writing_mode;
|
let writing_mode = node.style().writing_mode;
|
||||||
BlockFlow {
|
BlockFlow {
|
||||||
|
@ -598,23 +582,6 @@ impl BlockFlow {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn float_from_node(constructor: &mut FlowConstructor,
|
|
||||||
node: &ThreadSafeLayoutNode,
|
|
||||||
float_kind: FloatKind)
|
|
||||||
-> BlockFlow {
|
|
||||||
let writing_mode = node.style().writing_mode;
|
|
||||||
BlockFlow {
|
|
||||||
base: BaseFlow::new(Some((*node).clone()), writing_mode, ForceNonfloatedFlag::FloatIfNecessary),
|
|
||||||
fragment: Fragment::new(constructor, node),
|
|
||||||
static_b_offset: Au::new(0),
|
|
||||||
inline_size_of_preceding_left_floats: Au(0),
|
|
||||||
inline_size_of_preceding_right_floats: Au(0),
|
|
||||||
hypothetical_position: LogicalPoint::new(writing_mode, Au(0), Au(0)),
|
|
||||||
float: Some(box FloatedBlockInfo::new(float_kind)),
|
|
||||||
flags: BlockFlowFlags::empty(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn float_from_node_and_fragment(node: &ThreadSafeLayoutNode,
|
pub fn float_from_node_and_fragment(node: &ThreadSafeLayoutNode,
|
||||||
fragment: Fragment,
|
fragment: Fragment,
|
||||||
float_kind: FloatKind)
|
float_kind: FloatKind)
|
||||||
|
@ -1950,8 +1917,8 @@ impl Flow for BlockFlow {
|
||||||
.translate(stacking_context_position));
|
.translate(stacking_context_position));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove_compositor_layers(&self, constellation_chan: ConstellationChan) {
|
fn mutate_fragments(&mut self, mutator: &mut FnMut(&mut Fragment)) {
|
||||||
self.fragment.remove_compositor_layers(constellation_chan);
|
(*mutator)(&mut self.fragment)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,23 +16,23 @@
|
||||||
use block::BlockFlow;
|
use block::BlockFlow;
|
||||||
use context::LayoutContext;
|
use context::LayoutContext;
|
||||||
use css::node_style::StyledNode;
|
use css::node_style::StyledNode;
|
||||||
|
use data::{HAS_NEWLY_CONSTRUCTED_FLOW, LayoutDataAccess, LayoutDataWrapper};
|
||||||
use floats::FloatKind;
|
use floats::FloatKind;
|
||||||
use flow::{Descendants, AbsDescendants};
|
use flow::{Descendants, AbsDescendants};
|
||||||
use flow::{Flow, ImmutableFlowUtils, MutableOwnedFlowUtils};
|
use flow::{Flow, ImmutableFlowUtils, MutableOwnedFlowUtils};
|
||||||
use flow::{IS_ABSOLUTELY_POSITIONED};
|
use flow::{IS_ABSOLUTELY_POSITIONED};
|
||||||
use flow;
|
use flow;
|
||||||
use flow_ref::FlowRef;
|
use flow_ref::FlowRef;
|
||||||
|
use fragment::{Fragment, GeneratedContentInfo, IframeFragmentInfo};
|
||||||
use fragment::CanvasFragmentInfo;
|
use fragment::CanvasFragmentInfo;
|
||||||
use fragment::ImageFragmentInfo;
|
use fragment::ImageFragmentInfo;
|
||||||
use fragment::InlineAbsoluteHypotheticalFragmentInfo;
|
use fragment::InlineAbsoluteHypotheticalFragmentInfo;
|
||||||
use fragment::TableColumnFragmentInfo;
|
use fragment::TableColumnFragmentInfo;
|
||||||
use fragment::UnscannedTextFragmentInfo;
|
use fragment::UnscannedTextFragmentInfo;
|
||||||
use fragment::{Fragment, IframeFragmentInfo};
|
|
||||||
use fragment::{InlineBlockFragmentInfo, SpecificFragmentInfo};
|
use fragment::{InlineBlockFragmentInfo, SpecificFragmentInfo};
|
||||||
use incremental::{RECONSTRUCT_FLOW, RestyleDamage};
|
use incremental::{RECONSTRUCT_FLOW, RestyleDamage};
|
||||||
use inline::InlineFlow;
|
use inline::InlineFlow;
|
||||||
use data::{HAS_NEWLY_CONSTRUCTED_FLOW, LayoutDataAccess, LayoutDataWrapper};
|
use list_item::{ListItemFlow, ListStyleTypeContent};
|
||||||
use list_item::{self, ListItemFlow};
|
|
||||||
use opaque_node::OpaqueNodeMethods;
|
use opaque_node::OpaqueNodeMethods;
|
||||||
use parallel;
|
use parallel;
|
||||||
use table::TableFlow;
|
use table::TableFlow;
|
||||||
|
@ -55,9 +55,10 @@ use std::borrow::ToOwned;
|
||||||
use std::collections::DList;
|
use std::collections::DList;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::sync::atomic::Ordering;
|
use std::sync::atomic::Ordering;
|
||||||
|
use style::computed_values::content::ContentItem;
|
||||||
use style::computed_values::{caption_side, display, empty_cells, float, list_style_position};
|
use style::computed_values::{caption_side, display, empty_cells, float, list_style_position};
|
||||||
use style::computed_values::{position};
|
use style::computed_values::{position};
|
||||||
use style::properties::{ComputedValues, make_inline};
|
use style::properties::{self, ComputedValues};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
|
@ -265,41 +266,51 @@ impl<'a> FlowConstructor<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Builds specific `Fragment` info for the given node.
|
/// Builds the fragment for the given block or subclass thereof.
|
||||||
///
|
fn build_fragment_for_block(&mut self, node: &ThreadSafeLayoutNode) -> Fragment {
|
||||||
/// This does *not* construct the text for generated content (but, for generated content with
|
let specific_fragment_info = match node.type_id() {
|
||||||
/// `display: block`, it does construct the generic fragment corresponding to the block).
|
Some(NodeTypeId::Element(ElementTypeId::HTMLElement(
|
||||||
/// Construction of the text fragment is done specially by `build_flow_using_children()` and
|
HTMLElementTypeId::HTMLIFrameElement))) => {
|
||||||
/// `build_fragments_for_replaced_inline_content()`.
|
|
||||||
pub fn build_specific_fragment_info_for_node(&mut self, node: &ThreadSafeLayoutNode)
|
|
||||||
-> SpecificFragmentInfo {
|
|
||||||
match node.type_id() {
|
|
||||||
Some(NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLIFrameElement))) => {
|
|
||||||
SpecificFragmentInfo::Iframe(box IframeFragmentInfo::new(node))
|
SpecificFragmentInfo::Iframe(box IframeFragmentInfo::new(node))
|
||||||
}
|
}
|
||||||
Some(NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLImageElement))) => {
|
Some(NodeTypeId::Element(ElementTypeId::HTMLElement(
|
||||||
|
HTMLElementTypeId::HTMLImageElement))) => {
|
||||||
self.build_fragment_info_for_image(node, node.image_url())
|
self.build_fragment_info_for_image(node, node.image_url())
|
||||||
}
|
}
|
||||||
Some(NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLObjectElement))) => {
|
Some(NodeTypeId::Element(ElementTypeId::HTMLElement(
|
||||||
|
HTMLElementTypeId::HTMLObjectElement))) => {
|
||||||
let data = node.get_object_data();
|
let data = node.get_object_data();
|
||||||
self.build_fragment_info_for_image(node, data)
|
self.build_fragment_info_for_image(node, data)
|
||||||
}
|
}
|
||||||
Some(NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTableElement))) => SpecificFragmentInfo::TableWrapper,
|
Some(NodeTypeId::Element(ElementTypeId::HTMLElement(
|
||||||
Some(NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTableColElement))) => {
|
HTMLElementTypeId::HTMLTableElement))) => {
|
||||||
|
SpecificFragmentInfo::TableWrapper
|
||||||
|
}
|
||||||
|
Some(NodeTypeId::Element(ElementTypeId::HTMLElement(
|
||||||
|
HTMLElementTypeId::HTMLTableColElement))) => {
|
||||||
SpecificFragmentInfo::TableColumn(TableColumnFragmentInfo::new(node))
|
SpecificFragmentInfo::TableColumn(TableColumnFragmentInfo::new(node))
|
||||||
}
|
}
|
||||||
Some(NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTableCellElement(_)))) => SpecificFragmentInfo::TableCell,
|
Some(NodeTypeId::Element(ElementTypeId::HTMLElement(
|
||||||
Some(NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTableRowElement))) |
|
HTMLElementTypeId::HTMLTableCellElement(_)))) => {
|
||||||
Some(NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTableSectionElement))) => SpecificFragmentInfo::TableRow,
|
SpecificFragmentInfo::TableCell
|
||||||
Some(NodeTypeId::Text) => SpecificFragmentInfo::UnscannedText(UnscannedTextFragmentInfo::new(node)),
|
}
|
||||||
Some(NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLCanvasElement))) => {
|
Some(NodeTypeId::Element(ElementTypeId::HTMLElement(
|
||||||
|
HTMLElementTypeId::HTMLTableRowElement))) |
|
||||||
|
Some(NodeTypeId::Element(ElementTypeId::HTMLElement(
|
||||||
|
HTMLElementTypeId::HTMLTableSectionElement))) => {
|
||||||
|
SpecificFragmentInfo::TableRow
|
||||||
|
}
|
||||||
|
Some(NodeTypeId::Element(ElementTypeId::HTMLElement(
|
||||||
|
HTMLElementTypeId::HTMLCanvasElement))) => {
|
||||||
SpecificFragmentInfo::Canvas(box CanvasFragmentInfo::new(node))
|
SpecificFragmentInfo::Canvas(box CanvasFragmentInfo::new(node))
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
// This includes pseudo-elements.
|
// This includes pseudo-elements.
|
||||||
SpecificFragmentInfo::Generic
|
SpecificFragmentInfo::Generic
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
|
Fragment::new(node, specific_fragment_info)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates an inline flow from a set of inline fragments, then adds it as a child of the given
|
/// Creates an inline flow from a set of inline fragments, then adds it as a child of the given
|
||||||
|
@ -339,7 +350,9 @@ impl<'a> FlowConstructor<'a> {
|
||||||
let mut inline_block_flows = vec!();
|
let mut inline_block_flows = vec!();
|
||||||
for f in fragments.iter() {
|
for f in fragments.iter() {
|
||||||
match f.specific {
|
match f.specific {
|
||||||
SpecificFragmentInfo::InlineBlock(ref info) => inline_block_flows.push(info.flow_ref.clone()),
|
SpecificFragmentInfo::InlineBlock(ref info) => {
|
||||||
|
inline_block_flows.push(info.flow_ref.clone())
|
||||||
|
}
|
||||||
SpecificFragmentInfo::InlineAbsoluteHypothetical(ref info) => {
|
SpecificFragmentInfo::InlineAbsoluteHypothetical(ref info) => {
|
||||||
inline_block_flows.push(info.flow_ref.clone())
|
inline_block_flows.push(info.flow_ref.clone())
|
||||||
}
|
}
|
||||||
|
@ -473,8 +486,8 @@ impl<'a> FlowConstructor<'a> {
|
||||||
whitespace_damage)) => {
|
whitespace_damage)) => {
|
||||||
// Add whitespace results. They will be stripped out later on when
|
// Add whitespace results. They will be stripped out later on when
|
||||||
// between block elements, and retained when between inline elements.
|
// between block elements, and retained when between inline elements.
|
||||||
let fragment_info =
|
let fragment_info = SpecificFragmentInfo::UnscannedText(
|
||||||
SpecificFragmentInfo::UnscannedText(UnscannedTextFragmentInfo::from_text(" ".to_owned()));
|
UnscannedTextFragmentInfo::from_text(" ".to_owned()));
|
||||||
let fragment = Fragment::from_opaque_node_and_style(whitespace_node,
|
let fragment = Fragment::from_opaque_node_and_style(whitespace_node,
|
||||||
whitespace_style,
|
whitespace_style,
|
||||||
whitespace_damage,
|
whitespace_damage,
|
||||||
|
@ -488,25 +501,20 @@ impl<'a> FlowConstructor<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Constructs a block flow, beginning with the given `initial_fragment` if present and then
|
/// Constructs a block flow, beginning with the given `initial_fragments` if present and then
|
||||||
/// appending the construction results of children to the child list of the block flow. {ib}
|
/// appending the construction results of children to the child list of the block flow. {ib}
|
||||||
/// splits and absolutely-positioned descendants are handled correctly.
|
/// splits and absolutely-positioned descendants are handled correctly.
|
||||||
fn build_flow_for_block_starting_with_fragment(&mut self,
|
fn build_flow_for_block_starting_with_fragments(&mut self,
|
||||||
mut flow: FlowRef,
|
mut flow: FlowRef,
|
||||||
node: &ThreadSafeLayoutNode,
|
node: &ThreadSafeLayoutNode,
|
||||||
initial_fragment: Option<Fragment>)
|
mut initial_fragments: DList<Fragment>)
|
||||||
-> ConstructionResult {
|
-> ConstructionResult {
|
||||||
// Gather up fragments for the inline flows we might need to create.
|
// Gather up fragments for the inline flows we might need to create.
|
||||||
let mut inline_fragment_accumulator = InlineFragmentsAccumulator::new();
|
let mut inline_fragment_accumulator = InlineFragmentsAccumulator::new();
|
||||||
let mut consecutive_siblings = vec!();
|
let mut consecutive_siblings = vec!();
|
||||||
|
|
||||||
let mut first_fragment = match initial_fragment {
|
inline_fragment_accumulator.fragments.append(&mut initial_fragments);
|
||||||
None => true,
|
let mut first_fragment = inline_fragment_accumulator.fragments.is_empty();
|
||||||
Some(initial_fragment) => {
|
|
||||||
inline_fragment_accumulator.fragments.push_back(initial_fragment);
|
|
||||||
false
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// List of absolute descendants, in tree order.
|
// List of absolute descendants, in tree order.
|
||||||
let mut abs_descendants = Descendants::new();
|
let mut abs_descendants = Descendants::new();
|
||||||
|
@ -558,7 +566,7 @@ impl<'a> FlowConstructor<'a> {
|
||||||
|
|
||||||
/// Constructs a flow for the given block node and its children. This method creates an
|
/// Constructs a flow for the given block node and its children. This method creates an
|
||||||
/// initial fragment as appropriate and then dispatches to
|
/// initial fragment as appropriate and then dispatches to
|
||||||
/// `build_flow_for_block_starting_with_fragment`. Currently the following kinds of flows get
|
/// `build_flow_for_block_starting_with_fragments`. Currently the following kinds of flows get
|
||||||
/// initial content:
|
/// initial content:
|
||||||
///
|
///
|
||||||
/// * Generated content gets the initial content specified by the `content` attribute of the
|
/// * Generated content gets the initial content specified by the `content` attribute of the
|
||||||
|
@ -569,32 +577,60 @@ impl<'a> FlowConstructor<'a> {
|
||||||
/// `<textarea>`.
|
/// `<textarea>`.
|
||||||
fn build_flow_for_block(&mut self, flow: FlowRef, node: &ThreadSafeLayoutNode)
|
fn build_flow_for_block(&mut self, flow: FlowRef, node: &ThreadSafeLayoutNode)
|
||||||
-> ConstructionResult {
|
-> ConstructionResult {
|
||||||
let initial_fragment = if node.get_pseudo_element_type() != PseudoElementType::Normal ||
|
let mut initial_fragments = DList::new();
|
||||||
node.type_id() == Some(NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLInputElement))) ||
|
if node.get_pseudo_element_type() != PseudoElementType::Normal ||
|
||||||
node.type_id() == Some(NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTextAreaElement))) {
|
node.type_id() == Some(NodeTypeId::Element(ElementTypeId::HTMLElement(
|
||||||
|
HTMLElementTypeId::HTMLInputElement))) ||
|
||||||
|
node.type_id() == Some(NodeTypeId::Element(ElementTypeId::HTMLElement(
|
||||||
|
HTMLElementTypeId::HTMLTextAreaElement))) {
|
||||||
// A TextArea's text contents are displayed through the input text
|
// A TextArea's text contents are displayed through the input text
|
||||||
// box, so don't construct them.
|
// box, so don't construct them.
|
||||||
if node.type_id() == Some(NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTextAreaElement))) {
|
if node.type_id() == Some(NodeTypeId::Element(ElementTypeId::HTMLElement(
|
||||||
|
HTMLElementTypeId::HTMLTextAreaElement))) {
|
||||||
for kid in node.children() {
|
for kid in node.children() {
|
||||||
self.set_flow_construction_result(&kid, ConstructionResult::None)
|
kid.set_flow_construction_result(ConstructionResult::None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(Fragment::new_from_specific_info(
|
|
||||||
node,
|
|
||||||
SpecificFragmentInfo::UnscannedText(UnscannedTextFragmentInfo::new(node))))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
self.build_flow_for_block_starting_with_fragment(flow, node, initial_fragment)
|
self.create_fragments_for_node_text_content(&mut initial_fragments, node, node.style());
|
||||||
|
}
|
||||||
|
|
||||||
|
self.build_flow_for_block_starting_with_fragments(flow, node, initial_fragments)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Pushes fragments appropriate for the content of the given node onto the given list.
|
||||||
|
fn create_fragments_for_node_text_content(&self,
|
||||||
|
fragments: &mut DList<Fragment>,
|
||||||
|
node: &ThreadSafeLayoutNode,
|
||||||
|
style: &Arc<ComputedValues>) {
|
||||||
|
for content_item in node.text_content().into_iter() {
|
||||||
|
let specific = match content_item {
|
||||||
|
ContentItem::String(string) => {
|
||||||
|
let info = UnscannedTextFragmentInfo::from_text(string);
|
||||||
|
SpecificFragmentInfo::UnscannedText(info)
|
||||||
|
}
|
||||||
|
content_item => {
|
||||||
|
let content_item = box GeneratedContentInfo::ContentItem(content_item);
|
||||||
|
SpecificFragmentInfo::GeneratedContent(content_item)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let opaque_node = OpaqueNodeMethods::from_thread_safe_layout_node(node);
|
||||||
|
fragments.push_back(Fragment::from_opaque_node_and_style(opaque_node,
|
||||||
|
style.clone(),
|
||||||
|
node.restyle_damage(),
|
||||||
|
specific))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Builds a flow for a node with `display: block`. This yields a `BlockFlow` with possibly
|
/// Builds a flow for a node with `display: block`. This yields a `BlockFlow` with possibly
|
||||||
/// other `BlockFlow`s or `InlineFlow`s underneath it, depending on whether {ib} splits needed
|
/// other `BlockFlow`s or `InlineFlow`s underneath it, depending on whether {ib} splits needed
|
||||||
/// to happen.
|
/// to happen.
|
||||||
fn build_flow_for_nonfloated_block(&mut self, node: &ThreadSafeLayoutNode)
|
fn build_flow_for_nonfloated_block(&mut self, node: &ThreadSafeLayoutNode)
|
||||||
-> ConstructionResult {
|
-> ConstructionResult {
|
||||||
let flow = box BlockFlow::from_node(self, node) as Box<Flow>;
|
let flow = box BlockFlow::from_node_and_fragment(node, self.build_fragment_for_block(node))
|
||||||
|
as Box<Flow>;
|
||||||
self.build_flow_for_block(FlowRef::new(flow), node)
|
self.build_flow_for_block(FlowRef::new(flow), node)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -602,7 +638,9 @@ impl<'a> FlowConstructor<'a> {
|
||||||
/// a `BlockFlow` underneath it.
|
/// a `BlockFlow` underneath it.
|
||||||
fn build_flow_for_floated_block(&mut self, node: &ThreadSafeLayoutNode, float_kind: FloatKind)
|
fn build_flow_for_floated_block(&mut self, node: &ThreadSafeLayoutNode, float_kind: FloatKind)
|
||||||
-> ConstructionResult {
|
-> ConstructionResult {
|
||||||
let flow = box BlockFlow::float_from_node(self, node, float_kind) as Box<Flow>;
|
let fragment = self.build_fragment_for_block(node);
|
||||||
|
let flow = box BlockFlow::float_from_node_and_fragment(node, fragment, float_kind) as
|
||||||
|
Box<Flow>;
|
||||||
self.build_flow_for_block(FlowRef::new(flow), node)
|
self.build_flow_for_block(FlowRef::new(flow), node)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -670,8 +708,8 @@ impl<'a> FlowConstructor<'a> {
|
||||||
whitespace_style,
|
whitespace_style,
|
||||||
whitespace_damage)) => {
|
whitespace_damage)) => {
|
||||||
// Instantiate the whitespace fragment.
|
// Instantiate the whitespace fragment.
|
||||||
let fragment_info = SpecificFragmentInfo::UnscannedText(UnscannedTextFragmentInfo::from_text(
|
let fragment_info = SpecificFragmentInfo::UnscannedText(
|
||||||
" ".to_owned()));
|
UnscannedTextFragmentInfo::from_text(" ".to_owned()));
|
||||||
let fragment = Fragment::from_opaque_node_and_style(whitespace_node,
|
let fragment = Fragment::from_opaque_node_and_style(whitespace_node,
|
||||||
whitespace_style,
|
whitespace_style,
|
||||||
whitespace_damage,
|
whitespace_damage,
|
||||||
|
@ -706,7 +744,7 @@ impl<'a> FlowConstructor<'a> {
|
||||||
fn build_fragments_for_replaced_inline_content(&mut self, node: &ThreadSafeLayoutNode)
|
fn build_fragments_for_replaced_inline_content(&mut self, node: &ThreadSafeLayoutNode)
|
||||||
-> ConstructionResult {
|
-> ConstructionResult {
|
||||||
for kid in node.children() {
|
for kid in node.children() {
|
||||||
self.set_flow_construction_result(&kid, ConstructionResult::None)
|
kid.set_flow_construction_result(ConstructionResult::None)
|
||||||
}
|
}
|
||||||
|
|
||||||
// If this node is ignorable whitespace, bail out now.
|
// If this node is ignorable whitespace, bail out now.
|
||||||
|
@ -725,30 +763,22 @@ impl<'a> FlowConstructor<'a> {
|
||||||
// `baz` had better not be absolutely positioned!
|
// `baz` had better not be absolutely positioned!
|
||||||
let mut style = (*node.style()).clone();
|
let mut style = (*node.style()).clone();
|
||||||
if style.get_box().display != display::T::inline {
|
if style.get_box().display != display::T::inline {
|
||||||
style = Arc::new(make_inline(&*style))
|
style = Arc::new(properties::make_inline(&*style))
|
||||||
}
|
}
|
||||||
|
|
||||||
// If this is generated content, then we need to initialize the accumulator with the
|
// If this is generated content, then we need to initialize the accumulator with the
|
||||||
// fragment corresponding to that content. Otherwise, just initialize with the ordinary
|
// fragment corresponding to that content. Otherwise, just initialize with the ordinary
|
||||||
// fragment that needs to be generated for this inline node.
|
// fragment that needs to be generated for this inline node.
|
||||||
let fragment = if node.get_pseudo_element_type() != PseudoElementType::Normal {
|
|
||||||
let fragment_info =
|
|
||||||
SpecificFragmentInfo::UnscannedText(UnscannedTextFragmentInfo::new(node));
|
|
||||||
Fragment::from_opaque_node_and_style(
|
|
||||||
OpaqueNodeMethods::from_thread_safe_layout_node(node),
|
|
||||||
style,
|
|
||||||
node.restyle_damage(),
|
|
||||||
fragment_info)
|
|
||||||
} else {
|
|
||||||
Fragment::from_opaque_node_and_style(
|
|
||||||
OpaqueNodeMethods::from_thread_safe_layout_node(node),
|
|
||||||
style,
|
|
||||||
node.restyle_damage(),
|
|
||||||
self.build_specific_fragment_info_for_node(node))
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut fragments = DList::new();
|
let mut fragments = DList::new();
|
||||||
fragments.push_back(fragment);
|
match (node.get_pseudo_element_type(), node.type_id()) {
|
||||||
|
(_, Some(NodeTypeId::Text)) => {
|
||||||
|
self.create_fragments_for_node_text_content(&mut fragments, node, &style)
|
||||||
|
}
|
||||||
|
(PseudoElementType::Normal, _) => {
|
||||||
|
fragments.push_back(self.build_fragment_for_block(node));
|
||||||
|
}
|
||||||
|
(_, _) => self.create_fragments_for_node_text_content(&mut fragments, node, &style),
|
||||||
|
}
|
||||||
|
|
||||||
let construction_item =
|
let construction_item =
|
||||||
ConstructionItem::InlineFragments(InlineFragmentsConstructionResult {
|
ConstructionItem::InlineFragments(InlineFragmentsConstructionResult {
|
||||||
|
@ -769,7 +799,7 @@ impl<'a> FlowConstructor<'a> {
|
||||||
|
|
||||||
let fragment_info = SpecificFragmentInfo::InlineBlock(InlineBlockFragmentInfo::new(
|
let fragment_info = SpecificFragmentInfo::InlineBlock(InlineBlockFragmentInfo::new(
|
||||||
block_flow));
|
block_flow));
|
||||||
let fragment = Fragment::new_from_specific_info(node, fragment_info);
|
let fragment = Fragment::new(node, fragment_info);
|
||||||
|
|
||||||
let mut fragment_accumulator = InlineFragmentsAccumulator::from_inline_node(node);
|
let mut fragment_accumulator = InlineFragmentsAccumulator::from_inline_node(node);
|
||||||
fragment_accumulator.fragments.push_back(fragment);
|
fragment_accumulator.fragments.push_back(fragment);
|
||||||
|
@ -795,7 +825,7 @@ impl<'a> FlowConstructor<'a> {
|
||||||
|
|
||||||
let fragment_info = SpecificFragmentInfo::InlineAbsoluteHypothetical(
|
let fragment_info = SpecificFragmentInfo::InlineAbsoluteHypothetical(
|
||||||
InlineAbsoluteHypotheticalFragmentInfo::new(block_flow));
|
InlineAbsoluteHypotheticalFragmentInfo::new(block_flow));
|
||||||
let fragment = Fragment::new_from_specific_info(node, fragment_info);
|
let fragment = Fragment::new(node, fragment_info);
|
||||||
|
|
||||||
let mut fragment_accumulator = InlineFragmentsAccumulator::from_inline_node(node);
|
let mut fragment_accumulator = InlineFragmentsAccumulator::from_inline_node(node);
|
||||||
fragment_accumulator.fragments.push_back(fragment);
|
fragment_accumulator.fragments.push_back(fragment);
|
||||||
|
@ -880,7 +910,7 @@ impl<'a> FlowConstructor<'a> {
|
||||||
/// possibly other `TableCaptionFlow`s or `TableFlow`s underneath it.
|
/// possibly other `TableCaptionFlow`s or `TableFlow`s underneath it.
|
||||||
fn build_flow_for_table_wrapper(&mut self, node: &ThreadSafeLayoutNode, float_value: float::T)
|
fn build_flow_for_table_wrapper(&mut self, node: &ThreadSafeLayoutNode, float_value: float::T)
|
||||||
-> ConstructionResult {
|
-> ConstructionResult {
|
||||||
let fragment = Fragment::new_from_specific_info(node, SpecificFragmentInfo::TableWrapper);
|
let fragment = Fragment::new(node, SpecificFragmentInfo::TableWrapper);
|
||||||
let wrapper_flow = match float_value {
|
let wrapper_flow = match float_value {
|
||||||
float::T::none => box TableWrapperFlow::from_node_and_fragment(node, fragment),
|
float::T::none => box TableWrapperFlow::from_node_and_fragment(node, fragment),
|
||||||
_ => {
|
_ => {
|
||||||
|
@ -890,7 +920,7 @@ impl<'a> FlowConstructor<'a> {
|
||||||
};
|
};
|
||||||
let mut wrapper_flow = FlowRef::new(wrapper_flow as Box<Flow>);
|
let mut wrapper_flow = FlowRef::new(wrapper_flow as Box<Flow>);
|
||||||
|
|
||||||
let table_fragment = Fragment::new_from_specific_info(node, SpecificFragmentInfo::Table);
|
let table_fragment = Fragment::new(node, SpecificFragmentInfo::Table);
|
||||||
let table_flow = box TableFlow::from_node_and_fragment(node, table_fragment);
|
let table_flow = box TableFlow::from_node_and_fragment(node, table_fragment);
|
||||||
let table_flow = FlowRef::new(table_flow as Box<Flow>);
|
let table_flow = FlowRef::new(table_flow as Box<Flow>);
|
||||||
|
|
||||||
|
@ -924,7 +954,8 @@ impl<'a> FlowConstructor<'a> {
|
||||||
wrapper_flow.finish();
|
wrapper_flow.finish();
|
||||||
let is_positioned = wrapper_flow.as_block().is_positioned();
|
let is_positioned = wrapper_flow.as_block().is_positioned();
|
||||||
let is_fixed_positioned = wrapper_flow.as_block().is_fixed();
|
let is_fixed_positioned = wrapper_flow.as_block().is_fixed();
|
||||||
let is_absolutely_positioned = flow::base(&*wrapper_flow).flags.contains(IS_ABSOLUTELY_POSITIONED);
|
let is_absolutely_positioned =
|
||||||
|
flow::base(&*wrapper_flow).flags.contains(IS_ABSOLUTELY_POSITIONED);
|
||||||
if is_positioned {
|
if is_positioned {
|
||||||
// This is the containing block for all the absolute descendants.
|
// This is the containing block for all the absolute descendants.
|
||||||
wrapper_flow.set_absolute_descendants(abs_descendants);
|
wrapper_flow.set_absolute_descendants(abs_descendants);
|
||||||
|
@ -947,7 +978,8 @@ impl<'a> FlowConstructor<'a> {
|
||||||
/// Builds a flow for a node with `display: table-caption`. This yields a `TableCaptionFlow`
|
/// Builds a flow for a node with `display: table-caption`. This yields a `TableCaptionFlow`
|
||||||
/// with possibly other `BlockFlow`s or `InlineFlow`s underneath it.
|
/// with possibly other `BlockFlow`s or `InlineFlow`s underneath it.
|
||||||
fn build_flow_for_table_caption(&mut self, node: &ThreadSafeLayoutNode) -> ConstructionResult {
|
fn build_flow_for_table_caption(&mut self, node: &ThreadSafeLayoutNode) -> ConstructionResult {
|
||||||
let flow = box TableCaptionFlow::from_node(self, node) as Box<Flow>;
|
let fragment = self.build_fragment_for_block(node);
|
||||||
|
let flow = box TableCaptionFlow::from_node_and_fragment(node, fragment) as Box<Flow>;
|
||||||
self.build_flow_for_block(FlowRef::new(flow), node)
|
self.build_flow_for_block(FlowRef::new(flow), node)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -955,7 +987,7 @@ impl<'a> FlowConstructor<'a> {
|
||||||
/// with possibly other `TableRowFlow`s underneath it.
|
/// with possibly other `TableRowFlow`s underneath it.
|
||||||
fn build_flow_for_table_rowgroup(&mut self, node: &ThreadSafeLayoutNode)
|
fn build_flow_for_table_rowgroup(&mut self, node: &ThreadSafeLayoutNode)
|
||||||
-> ConstructionResult {
|
-> ConstructionResult {
|
||||||
let fragment = Fragment::new_from_specific_info(node, SpecificFragmentInfo::TableRow);
|
let fragment = Fragment::new(node, SpecificFragmentInfo::TableRow);
|
||||||
let flow = box TableRowGroupFlow::from_node_and_fragment(node, fragment);
|
let flow = box TableRowGroupFlow::from_node_and_fragment(node, fragment);
|
||||||
let flow = flow as Box<Flow>;
|
let flow = flow as Box<Flow>;
|
||||||
self.build_flow_for_block(FlowRef::new(flow), node)
|
self.build_flow_for_block(FlowRef::new(flow), node)
|
||||||
|
@ -964,7 +996,7 @@ impl<'a> FlowConstructor<'a> {
|
||||||
/// Builds a flow for a node with `display: table-row`. This yields a `TableRowFlow` with
|
/// Builds a flow for a node with `display: table-row`. This yields a `TableRowFlow` with
|
||||||
/// possibly other `TableCellFlow`s underneath it.
|
/// possibly other `TableCellFlow`s underneath it.
|
||||||
fn build_flow_for_table_row(&mut self, node: &ThreadSafeLayoutNode) -> ConstructionResult {
|
fn build_flow_for_table_row(&mut self, node: &ThreadSafeLayoutNode) -> ConstructionResult {
|
||||||
let fragment = Fragment::new_from_specific_info(node, SpecificFragmentInfo::TableRow);
|
let fragment = Fragment::new(node, SpecificFragmentInfo::TableRow);
|
||||||
let flow = box TableRowFlow::from_node_and_fragment(node, fragment) as Box<Flow>;
|
let flow = box TableRowFlow::from_node_and_fragment(node, fragment) as Box<Flow>;
|
||||||
self.build_flow_for_block(FlowRef::new(flow), node)
|
self.build_flow_for_block(FlowRef::new(flow), node)
|
||||||
}
|
}
|
||||||
|
@ -972,7 +1004,7 @@ impl<'a> FlowConstructor<'a> {
|
||||||
/// Builds a flow for a node with `display: table-cell`. This yields a `TableCellFlow` with
|
/// Builds a flow for a node with `display: table-cell`. This yields a `TableCellFlow` with
|
||||||
/// possibly other `BlockFlow`s or `InlineFlow`s underneath it.
|
/// possibly other `BlockFlow`s or `InlineFlow`s underneath it.
|
||||||
fn build_flow_for_table_cell(&mut self, node: &ThreadSafeLayoutNode) -> ConstructionResult {
|
fn build_flow_for_table_cell(&mut self, node: &ThreadSafeLayoutNode) -> ConstructionResult {
|
||||||
let fragment = Fragment::new_from_specific_info(node, SpecificFragmentInfo::TableCell);
|
let fragment = Fragment::new(node, SpecificFragmentInfo::TableCell);
|
||||||
|
|
||||||
// Determine if the table cell should be hidden. Per CSS 2.1 § 17.6.1.1, this will be true
|
// Determine if the table cell should be hidden. Per CSS 2.1 § 17.6.1.1, this will be true
|
||||||
// if the cell has any in-flow elements (even empty ones!) and has `empty-cells` set to
|
// if the cell has any in-flow elements (even empty ones!) and has `empty-cells` set to
|
||||||
|
@ -1000,19 +1032,18 @@ impl<'a> FlowConstructor<'a> {
|
||||||
};
|
};
|
||||||
let marker_fragment = match node.style().get_list().list_style_image {
|
let marker_fragment = match node.style().get_list().list_style_image {
|
||||||
Some(ref url) => {
|
Some(ref url) => {
|
||||||
Some(Fragment::new_from_specific_info(
|
Some(Fragment::new(node,
|
||||||
node,
|
self.build_fragment_info_for_image(node, Some((*url).clone()))))
|
||||||
self.build_fragment_info_for_image(node, Some((*url).clone()))))
|
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
match list_item::static_text_for_list_style_type(node.style()
|
match ListStyleTypeContent::from_list_style_type(node.style()
|
||||||
.get_list()
|
.get_list()
|
||||||
.list_style_type) {
|
.list_style_type) {
|
||||||
None => None,
|
ListStyleTypeContent::None => None,
|
||||||
Some(text) => {
|
ListStyleTypeContent::StaticText(ch) => {
|
||||||
let text = text.to_owned();
|
let text = format!("{}\u{a0}", ch);
|
||||||
let mut unscanned_marker_fragments = DList::new();
|
let mut unscanned_marker_fragments = DList::new();
|
||||||
unscanned_marker_fragments.push_back(Fragment::new_from_specific_info(
|
unscanned_marker_fragments.push_back(Fragment::new(
|
||||||
node,
|
node,
|
||||||
SpecificFragmentInfo::UnscannedText(
|
SpecificFragmentInfo::UnscannedText(
|
||||||
UnscannedTextFragmentInfo::from_text(text))));
|
UnscannedTextFragmentInfo::from_text(text))));
|
||||||
|
@ -1022,6 +1053,9 @@ impl<'a> FlowConstructor<'a> {
|
||||||
debug_assert!(marker_fragments.len() == 1);
|
debug_assert!(marker_fragments.len() == 1);
|
||||||
marker_fragments.fragments.into_iter().next()
|
marker_fragments.fragments.into_iter().next()
|
||||||
}
|
}
|
||||||
|
ListStyleTypeContent::GeneratedContent(info) => {
|
||||||
|
Some(Fragment::new(node, SpecificFragmentInfo::GeneratedContent(info)))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1031,28 +1065,29 @@ impl<'a> FlowConstructor<'a> {
|
||||||
// we adopt Gecko's behavior rather than WebKit's when the marker causes an {ib} split,
|
// we adopt Gecko's behavior rather than WebKit's when the marker causes an {ib} split,
|
||||||
// which has caused some malaise (Bugzilla #36854) but CSS 2.1 § 12.5.1 lets me do it, so
|
// which has caused some malaise (Bugzilla #36854) but CSS 2.1 § 12.5.1 lets me do it, so
|
||||||
// there.
|
// there.
|
||||||
let flow;
|
let mut initial_fragments = DList::new();
|
||||||
let initial_fragment;
|
let main_fragment = self.build_fragment_for_block(node);
|
||||||
match node.style().get_list().list_style_position {
|
let flow = match node.style().get_list().list_style_position {
|
||||||
list_style_position::T::outside => {
|
list_style_position::T::outside => {
|
||||||
flow = box ListItemFlow::from_node_marker_and_flotation(self,
|
box ListItemFlow::from_node_fragments_and_flotation(node,
|
||||||
node,
|
main_fragment,
|
||||||
marker_fragment,
|
marker_fragment,
|
||||||
flotation);
|
flotation)
|
||||||
initial_fragment = None;
|
|
||||||
}
|
}
|
||||||
list_style_position::T::inside => {
|
list_style_position::T::inside => {
|
||||||
flow = box ListItemFlow::from_node_marker_and_flotation(self,
|
if let Some(marker_fragment) = marker_fragment {
|
||||||
node,
|
initial_fragments.push_back(marker_fragment)
|
||||||
None,
|
}
|
||||||
flotation);
|
box ListItemFlow::from_node_fragments_and_flotation(node,
|
||||||
initial_fragment = marker_fragment;
|
main_fragment,
|
||||||
|
None,
|
||||||
|
flotation)
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
self.build_flow_for_block_starting_with_fragment(FlowRef::new(flow as Box<Flow>),
|
self.build_flow_for_block_starting_with_fragments(FlowRef::new(flow as Box<Flow>),
|
||||||
node,
|
node,
|
||||||
initial_fragment)
|
initial_fragments)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a fragment for a node with `display: table-column`.
|
/// Creates a fragment for a node with `display: table-column`.
|
||||||
|
@ -1060,13 +1095,12 @@ impl<'a> FlowConstructor<'a> {
|
||||||
-> ConstructionResult {
|
-> ConstructionResult {
|
||||||
// CSS 2.1 § 17.2.1. Treat all child fragments of a `table-column` as `display: none`.
|
// CSS 2.1 § 17.2.1. Treat all child fragments of a `table-column` as `display: none`.
|
||||||
for kid in node.children() {
|
for kid in node.children() {
|
||||||
self.set_flow_construction_result(&kid, ConstructionResult::None)
|
kid.set_flow_construction_result(ConstructionResult::None)
|
||||||
}
|
}
|
||||||
|
|
||||||
let specific = SpecificFragmentInfo::TableColumn(TableColumnFragmentInfo::new(node));
|
let specific = SpecificFragmentInfo::TableColumn(TableColumnFragmentInfo::new(node));
|
||||||
let construction_item = ConstructionItem::TableColumnFragment(
|
let construction_item = ConstructionItem::TableColumnFragment(Fragment::new(node,
|
||||||
Fragment::new_from_specific_info(node, specific)
|
specific));
|
||||||
);
|
|
||||||
ConstructionResult::ConstructionItem(construction_item)
|
ConstructionResult::ConstructionItem(construction_item)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1074,9 +1108,9 @@ impl<'a> FlowConstructor<'a> {
|
||||||
/// This yields a `TableColGroupFlow`.
|
/// This yields a `TableColGroupFlow`.
|
||||||
fn build_flow_for_table_colgroup(&mut self, node: &ThreadSafeLayoutNode)
|
fn build_flow_for_table_colgroup(&mut self, node: &ThreadSafeLayoutNode)
|
||||||
-> ConstructionResult {
|
-> ConstructionResult {
|
||||||
let fragment = Fragment::new_from_specific_info(
|
let fragment =
|
||||||
node,
|
Fragment::new(node,
|
||||||
SpecificFragmentInfo::TableColumn(TableColumnFragmentInfo::new(node)));
|
SpecificFragmentInfo::TableColumn(TableColumnFragmentInfo::new(node)));
|
||||||
let mut col_fragments = vec!();
|
let mut col_fragments = vec!();
|
||||||
for kid in node.children() {
|
for kid in node.children() {
|
||||||
// CSS 2.1 § 17.2.1. Treat all non-column child fragments of `table-column-group`
|
// CSS 2.1 § 17.2.1. Treat all non-column child fragments of `table-column-group`
|
||||||
|
@ -1092,7 +1126,7 @@ impl<'a> FlowConstructor<'a> {
|
||||||
if col_fragments.is_empty() {
|
if col_fragments.is_empty() {
|
||||||
debug!("add SpecificFragmentInfo::TableColumn for empty colgroup");
|
debug!("add SpecificFragmentInfo::TableColumn for empty colgroup");
|
||||||
let specific = SpecificFragmentInfo::TableColumn(TableColumnFragmentInfo::new(node));
|
let specific = SpecificFragmentInfo::TableColumn(TableColumnFragmentInfo::new(node));
|
||||||
col_fragments.push(Fragment::new_from_specific_info(node, specific));
|
col_fragments.push(Fragment::new(node, specific));
|
||||||
}
|
}
|
||||||
let flow = box TableColGroupFlow::from_node_and_fragments(node, fragment, col_fragments);
|
let flow = box TableColGroupFlow::from_node_and_fragments(node, fragment, col_fragments);
|
||||||
let mut flow = FlowRef::new(flow as Box<Flow>);
|
let mut flow = FlowRef::new(flow as Box<Flow>);
|
||||||
|
@ -1188,15 +1222,15 @@ impl<'a> PostorderNodeMutTraversal for FlowConstructor<'a> {
|
||||||
// results of children.
|
// results of children.
|
||||||
(display::T::none, _, _) => {
|
(display::T::none, _, _) => {
|
||||||
for child in node.children() {
|
for child in node.children() {
|
||||||
self.set_flow_construction_result(&child, ConstructionResult::None);
|
child.set_flow_construction_result(ConstructionResult::None);
|
||||||
}
|
}
|
||||||
self.set_flow_construction_result(node, ConstructionResult::None);
|
node.set_flow_construction_result(ConstructionResult::None);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Table items contribute table flow construction results.
|
// Table items contribute table flow construction results.
|
||||||
(display::T::table, float_value, _) => {
|
(display::T::table, float_value, _) => {
|
||||||
let construction_result = self.build_flow_for_table_wrapper(node, float_value);
|
let construction_result = self.build_flow_for_table_wrapper(node, float_value);
|
||||||
self.set_flow_construction_result(node, construction_result)
|
node.set_flow_construction_result(construction_result)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Absolutely positioned elements will have computed value of
|
// Absolutely positioned elements will have computed value of
|
||||||
|
@ -1207,14 +1241,13 @@ impl<'a> PostorderNodeMutTraversal for FlowConstructor<'a> {
|
||||||
// below.
|
// below.
|
||||||
(display::T::block, _, position::T::absolute) |
|
(display::T::block, _, position::T::absolute) |
|
||||||
(_, _, position::T::fixed) => {
|
(_, _, position::T::fixed) => {
|
||||||
let construction_result = self.build_flow_for_nonfloated_block(node);
|
node.set_flow_construction_result(self.build_flow_for_nonfloated_block(node))
|
||||||
self.set_flow_construction_result(node, construction_result)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// List items contribute their own special flows.
|
// List items contribute their own special flows.
|
||||||
(display::T::list_item, float_value, _) => {
|
(display::T::list_item, float_value, _) => {
|
||||||
let construction_result = self.build_flow_for_list_item(node, float_value);
|
node.set_flow_construction_result(self.build_flow_for_list_item(node,
|
||||||
self.set_flow_construction_result(node, construction_result)
|
float_value))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inline items that are absolutely-positioned contribute inline fragment construction
|
// Inline items that are absolutely-positioned contribute inline fragment construction
|
||||||
|
@ -1222,7 +1255,7 @@ impl<'a> PostorderNodeMutTraversal for FlowConstructor<'a> {
|
||||||
(display::T::inline, _, position::T::absolute) => {
|
(display::T::inline, _, position::T::absolute) => {
|
||||||
let construction_result =
|
let construction_result =
|
||||||
self.build_fragment_for_absolutely_positioned_inline(node);
|
self.build_fragment_for_absolutely_positioned_inline(node);
|
||||||
self.set_flow_construction_result(node, construction_result)
|
node.set_flow_construction_result(construction_result)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inline items contribute inline fragment construction results.
|
// Inline items contribute inline fragment construction results.
|
||||||
|
@ -1230,31 +1263,31 @@ impl<'a> PostorderNodeMutTraversal for FlowConstructor<'a> {
|
||||||
// FIXME(pcwalton, #3307): This is not sufficient to handle floated generated content.
|
// FIXME(pcwalton, #3307): This is not sufficient to handle floated generated content.
|
||||||
(display::T::inline, float::T::none, _) => {
|
(display::T::inline, float::T::none, _) => {
|
||||||
let construction_result = self.build_fragments_for_inline(node);
|
let construction_result = self.build_fragments_for_inline(node);
|
||||||
self.set_flow_construction_result(node, construction_result)
|
node.set_flow_construction_result(construction_result)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inline-block items contribute inline fragment construction results.
|
// Inline-block items contribute inline fragment construction results.
|
||||||
(display::T::inline_block, float::T::none, _) => {
|
(display::T::inline_block, float::T::none, _) => {
|
||||||
let construction_result = self.build_fragment_for_inline_block(node);
|
let construction_result = self.build_fragment_for_inline_block(node);
|
||||||
self.set_flow_construction_result(node, construction_result)
|
node.set_flow_construction_result(construction_result)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Table items contribute table flow construction results.
|
// Table items contribute table flow construction results.
|
||||||
(display::T::table_caption, _, _) => {
|
(display::T::table_caption, _, _) => {
|
||||||
let construction_result = self.build_flow_for_table_caption(node);
|
let construction_result = self.build_flow_for_table_caption(node);
|
||||||
self.set_flow_construction_result(node, construction_result)
|
node.set_flow_construction_result(construction_result)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Table items contribute table flow construction results.
|
// Table items contribute table flow construction results.
|
||||||
(display::T::table_column_group, _, _) => {
|
(display::T::table_column_group, _, _) => {
|
||||||
let construction_result = self.build_flow_for_table_colgroup(node);
|
let construction_result = self.build_flow_for_table_colgroup(node);
|
||||||
self.set_flow_construction_result(node, construction_result)
|
node.set_flow_construction_result(construction_result)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Table items contribute table flow construction results.
|
// Table items contribute table flow construction results.
|
||||||
(display::T::table_column, _, _) => {
|
(display::T::table_column, _, _) => {
|
||||||
let construction_result = self.build_fragments_for_table_column(node);
|
let construction_result = self.build_fragments_for_table_column(node);
|
||||||
self.set_flow_construction_result(node, construction_result)
|
node.set_flow_construction_result(construction_result)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Table items contribute table flow construction results.
|
// Table items contribute table flow construction results.
|
||||||
|
@ -1262,19 +1295,19 @@ impl<'a> PostorderNodeMutTraversal for FlowConstructor<'a> {
|
||||||
(display::T::table_header_group, _, _) |
|
(display::T::table_header_group, _, _) |
|
||||||
(display::T::table_footer_group, _, _) => {
|
(display::T::table_footer_group, _, _) => {
|
||||||
let construction_result = self.build_flow_for_table_rowgroup(node);
|
let construction_result = self.build_flow_for_table_rowgroup(node);
|
||||||
self.set_flow_construction_result(node, construction_result)
|
node.set_flow_construction_result(construction_result)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Table items contribute table flow construction results.
|
// Table items contribute table flow construction results.
|
||||||
(display::T::table_row, _, _) => {
|
(display::T::table_row, _, _) => {
|
||||||
let construction_result = self.build_flow_for_table_row(node);
|
let construction_result = self.build_flow_for_table_row(node);
|
||||||
self.set_flow_construction_result(node, construction_result)
|
node.set_flow_construction_result(construction_result)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Table items contribute table flow construction results.
|
// Table items contribute table flow construction results.
|
||||||
(display::T::table_cell, _, _) => {
|
(display::T::table_cell, _, _) => {
|
||||||
let construction_result = self.build_flow_for_table_cell(node);
|
let construction_result = self.build_flow_for_table_cell(node);
|
||||||
self.set_flow_construction_result(node, construction_result)
|
node.set_flow_construction_result(construction_result)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Block flows that are not floated contribute block flow construction results.
|
// Block flows that are not floated contribute block flow construction results.
|
||||||
|
@ -1283,15 +1316,14 @@ impl<'a> PostorderNodeMutTraversal for FlowConstructor<'a> {
|
||||||
// properties separately.
|
// properties separately.
|
||||||
|
|
||||||
(_, float::T::none, _) => {
|
(_, float::T::none, _) => {
|
||||||
let construction_result = self.build_flow_for_nonfloated_block(node);
|
node.set_flow_construction_result(self.build_flow_for_nonfloated_block(node))
|
||||||
self.set_flow_construction_result(node, construction_result)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Floated flows contribute float flow construction results.
|
// Floated flows contribute float flow construction results.
|
||||||
(_, float_value, _) => {
|
(_, float_value, _) => {
|
||||||
let float_kind = FloatKind::from_property(float_value);
|
let float_kind = FloatKind::from_property(float_value);
|
||||||
let construction_result = self.build_flow_for_floated_block(node, float_kind);
|
node.set_flow_construction_result(
|
||||||
self.set_flow_construction_result(node, construction_result)
|
self.build_flow_for_floated_block(node, float_kind))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1310,25 +1342,29 @@ trait NodeUtils {
|
||||||
/// Sets the construction result of a flow.
|
/// Sets the construction result of a flow.
|
||||||
fn set_flow_construction_result(self, result: ConstructionResult);
|
fn set_flow_construction_result(self, result: ConstructionResult);
|
||||||
|
|
||||||
/// Replaces the flow construction result in a node with `ConstructionResult::None` and returns the
|
/// Replaces the flow construction result in a node with `ConstructionResult::None` and returns
|
||||||
/// old value.
|
/// the old value.
|
||||||
fn swap_out_construction_result(self) -> ConstructionResult;
|
fn swap_out_construction_result(self) -> ConstructionResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ln> NodeUtils for ThreadSafeLayoutNode<'ln> {
|
impl<'ln> NodeUtils for ThreadSafeLayoutNode<'ln> {
|
||||||
fn is_replaced_content(&self) -> bool {
|
fn is_replaced_content(&self) -> bool {
|
||||||
match self.type_id() {
|
match self.type_id() {
|
||||||
|
None |
|
||||||
Some(NodeTypeId::Text) |
|
Some(NodeTypeId::Text) |
|
||||||
Some(NodeTypeId::ProcessingInstruction) |
|
Some(NodeTypeId::ProcessingInstruction) |
|
||||||
Some(NodeTypeId::Comment) |
|
Some(NodeTypeId::Comment) |
|
||||||
Some(NodeTypeId::DocumentType) |
|
Some(NodeTypeId::DocumentType) |
|
||||||
Some(NodeTypeId::DocumentFragment) |
|
Some(NodeTypeId::DocumentFragment) |
|
||||||
Some(NodeTypeId::Document) |
|
Some(NodeTypeId::Document) |
|
||||||
None |
|
Some(NodeTypeId::Element(ElementTypeId::HTMLElement(
|
||||||
Some(NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLImageElement))) => true,
|
HTMLElementTypeId::HTMLImageElement))) |
|
||||||
Some(NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLObjectElement))) => self.has_object_data(),
|
Some(NodeTypeId::Element(ElementTypeId::HTMLElement(
|
||||||
Some(NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLIFrameElement))) => true,
|
HTMLElementTypeId::HTMLIFrameElement))) |
|
||||||
Some(NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLCanvasElement))) => true,
|
Some(NodeTypeId::Element(ElementTypeId::HTMLElement(
|
||||||
|
HTMLElementTypeId::HTMLCanvasElement))) => true,
|
||||||
|
Some(NodeTypeId::Element(ElementTypeId::HTMLElement(
|
||||||
|
HTMLElementTypeId::HTMLObjectElement))) => self.has_object_data(),
|
||||||
Some(NodeTypeId::Element(_)) => false,
|
Some(NodeTypeId::Element(_)) => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -957,6 +957,7 @@ impl FragmentDisplayListBuilding for Fragment {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SpecificFragmentInfo::Generic |
|
SpecificFragmentInfo::Generic |
|
||||||
|
SpecificFragmentInfo::GeneratedContent(..) |
|
||||||
SpecificFragmentInfo::Iframe(..) |
|
SpecificFragmentInfo::Iframe(..) |
|
||||||
SpecificFragmentInfo::Table |
|
SpecificFragmentInfo::Table |
|
||||||
SpecificFragmentInfo::TableCell |
|
SpecificFragmentInfo::TableCell |
|
||||||
|
|
|
@ -33,9 +33,9 @@ use floats::Floats;
|
||||||
use flow_list::{FlowList, FlowListIterator, MutFlowListIterator};
|
use flow_list::{FlowList, FlowListIterator, MutFlowListIterator};
|
||||||
use flow_ref::FlowRef;
|
use flow_ref::FlowRef;
|
||||||
use fragment::{Fragment, FragmentBorderBoxIterator, SpecificFragmentInfo};
|
use fragment::{Fragment, FragmentBorderBoxIterator, SpecificFragmentInfo};
|
||||||
use incremental::{RECONSTRUCT_FLOW, REFLOW, REFLOW_OUT_OF_FLOW, RestyleDamage};
|
use incremental::{self, RECONSTRUCT_FLOW, REFLOW, REFLOW_OUT_OF_FLOW, RestyleDamage};
|
||||||
use inline::InlineFlow;
|
use inline::InlineFlow;
|
||||||
use model::{CollapsibleMargins, IntrinsicISizes};
|
use model::{CollapsibleMargins, IntrinsicISizes, MarginCollapseInfo};
|
||||||
use parallel::FlowParallelInfo;
|
use parallel::FlowParallelInfo;
|
||||||
use table::{ColumnComputedInlineSize, ColumnIntrinsicInlineSize, TableFlow};
|
use table::{ColumnComputedInlineSize, ColumnIntrinsicInlineSize, TableFlow};
|
||||||
use table_caption::TableCaptionFlow;
|
use table_caption::TableCaptionFlow;
|
||||||
|
@ -236,6 +236,15 @@ pub trait Flow: fmt::Debug + Sync {
|
||||||
iterator: &mut FragmentBorderBoxIterator,
|
iterator: &mut FragmentBorderBoxIterator,
|
||||||
stacking_context_position: &Point2D<Au>);
|
stacking_context_position: &Point2D<Au>);
|
||||||
|
|
||||||
|
/// Mutably iterates through fragments in this flow.
|
||||||
|
fn mutate_fragments(&mut self, mutator: &mut FnMut(&mut Fragment));
|
||||||
|
|
||||||
|
fn compute_collapsible_block_start_margin(&mut self,
|
||||||
|
_layout_context: &mut LayoutContext,
|
||||||
|
_margin_collapse_info: &mut MarginCollapseInfo) {
|
||||||
|
// The default implementation is a no-op.
|
||||||
|
}
|
||||||
|
|
||||||
/// Marks this flow as the root flow. The default implementation is a no-op.
|
/// Marks this flow as the root flow. The default implementation is a no-op.
|
||||||
fn mark_as_root(&mut self) {}
|
fn mark_as_root(&mut self) {}
|
||||||
|
|
||||||
|
@ -478,51 +487,67 @@ pub trait PostorderFlowTraversal {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An in-order (sequential only) traversal.
|
||||||
|
pub trait InorderFlowTraversal {
|
||||||
|
/// The operation to perform. Returns the level of the tree we're at.
|
||||||
|
fn process(&mut self, flow: &mut Flow, level: u32);
|
||||||
|
|
||||||
|
/// Returns true if this node should be processed and false if neither this node nor its
|
||||||
|
/// descendants should be processed.
|
||||||
|
fn should_process(&mut self, flow: &mut Flow) -> bool;
|
||||||
|
}
|
||||||
|
|
||||||
bitflags! {
|
bitflags! {
|
||||||
#[doc = "Flags used in flows."]
|
#[doc = "Flags used in flows."]
|
||||||
flags FlowFlags: u16 {
|
flags FlowFlags: u32 {
|
||||||
// floated descendants flags
|
// floated descendants flags
|
||||||
#[doc = "Whether this flow has descendants that float left in the same block formatting"]
|
#[doc = "Whether this flow has descendants that float left in the same block formatting"]
|
||||||
#[doc = "context."]
|
#[doc = "context."]
|
||||||
const HAS_LEFT_FLOATED_DESCENDANTS = 0b0000_0000_0000_0001,
|
const HAS_LEFT_FLOATED_DESCENDANTS = 0b0000_0000_0000_0000_0001,
|
||||||
#[doc = "Whether this flow has descendants that float right in the same block formatting"]
|
#[doc = "Whether this flow has descendants that float right in the same block formatting"]
|
||||||
#[doc = "context."]
|
#[doc = "context."]
|
||||||
const HAS_RIGHT_FLOATED_DESCENDANTS = 0b0000_0000_0000_0010,
|
const HAS_RIGHT_FLOATED_DESCENDANTS = 0b0000_0000_0000_0000_0010,
|
||||||
#[doc = "Whether this flow is impacted by floats to the left in the same block formatting"]
|
#[doc = "Whether this flow is impacted by floats to the left in the same block formatting"]
|
||||||
#[doc = "context (i.e. its height depends on some prior flows with `float: left`)."]
|
#[doc = "context (i.e. its height depends on some prior flows with `float: left`)."]
|
||||||
const IMPACTED_BY_LEFT_FLOATS = 0b0000_0000_0000_0100,
|
const IMPACTED_BY_LEFT_FLOATS = 0b0000_0000_0000_0000_0100,
|
||||||
#[doc = "Whether this flow is impacted by floats to the right in the same block"]
|
#[doc = "Whether this flow is impacted by floats to the right in the same block"]
|
||||||
#[doc = "formatting context (i.e. its height depends on some prior flows with `float:"]
|
#[doc = "formatting context (i.e. its height depends on some prior flows with `float:"]
|
||||||
#[doc = "right`)."]
|
#[doc = "right`)."]
|
||||||
const IMPACTED_BY_RIGHT_FLOATS = 0b0000_0000_0000_1000,
|
const IMPACTED_BY_RIGHT_FLOATS = 0b0000_0000_0000_0000_1000,
|
||||||
|
|
||||||
// text align flags
|
// text align flags
|
||||||
#[doc = "Whether this flow contains a flow that has its own layer within the same absolute"]
|
#[doc = "Whether this flow contains a flow that has its own layer within the same absolute"]
|
||||||
#[doc = "containing block."]
|
#[doc = "containing block."]
|
||||||
const LAYERS_NEEDED_FOR_DESCENDANTS = 0b0000_0000_0001_0000,
|
const LAYERS_NEEDED_FOR_DESCENDANTS = 0b0000_0000_0000_0001_0000,
|
||||||
#[doc = "Whether this flow must have its own layer. Even if this flag is not set, it might"]
|
#[doc = "Whether this flow must have its own layer. Even if this flag is not set, it might"]
|
||||||
#[doc = "get its own layer if it's deemed to be likely to overlap flows with their own"]
|
#[doc = "get its own layer if it's deemed to be likely to overlap flows with their own"]
|
||||||
#[doc = "layer."]
|
#[doc = "layer."]
|
||||||
const NEEDS_LAYER = 0b0000_0000_0010_0000,
|
const NEEDS_LAYER = 0b0000_0000_0000_0010_0000,
|
||||||
#[doc = "Whether this flow is absolutely positioned. This is checked all over layout, so a"]
|
#[doc = "Whether this flow is absolutely positioned. This is checked all over layout, so a"]
|
||||||
#[doc = "virtual call is too expensive."]
|
#[doc = "virtual call is too expensive."]
|
||||||
const IS_ABSOLUTELY_POSITIONED = 0b0000_0000_0100_0000,
|
const IS_ABSOLUTELY_POSITIONED = 0b0000_0000_0000_0100_0000,
|
||||||
#[doc = "Whether this flow clears to the left. This is checked all over layout, so a"]
|
#[doc = "Whether this flow clears to the left. This is checked all over layout, so a"]
|
||||||
#[doc = "virtual call is too expensive."]
|
#[doc = "virtual call is too expensive."]
|
||||||
const CLEARS_LEFT = 0b0000_0000_1000_0000,
|
const CLEARS_LEFT = 0b0000_0000_0000_1000_0000,
|
||||||
#[doc = "Whether this flow clears to the right. This is checked all over layout, so a"]
|
#[doc = "Whether this flow clears to the right. This is checked all over layout, so a"]
|
||||||
#[doc = "virtual call is too expensive."]
|
#[doc = "virtual call is too expensive."]
|
||||||
const CLEARS_RIGHT = 0b0000_0001_0000_0000,
|
const CLEARS_RIGHT = 0b0000_0000_0001_0000_0000,
|
||||||
#[doc = "Whether this flow is left-floated. This is checked all over layout, so a"]
|
#[doc = "Whether this flow is left-floated. This is checked all over layout, so a"]
|
||||||
#[doc = "virtual call is too expensive."]
|
#[doc = "virtual call is too expensive."]
|
||||||
const FLOATS_LEFT = 0b0000_0010_0000_0000,
|
const FLOATS_LEFT = 0b0000_0000_0010_0000_0000,
|
||||||
#[doc = "Whether this flow is right-floated. This is checked all over layout, so a"]
|
#[doc = "Whether this flow is right-floated. This is checked all over layout, so a"]
|
||||||
#[doc = "virtual call is too expensive."]
|
#[doc = "virtual call is too expensive."]
|
||||||
const FLOATS_RIGHT = 0b0000_0100_0000_0000,
|
const FLOATS_RIGHT = 0b0000_0000_0100_0000_0000,
|
||||||
#[doc = "Text alignment. \
|
#[doc = "Text alignment. \
|
||||||
|
|
||||||
NB: If you update this, update `TEXT_ALIGN_SHIFT` below."]
|
NB: If you update this, update `TEXT_ALIGN_SHIFT` below."]
|
||||||
const TEXT_ALIGN = 0b0111_1000_0000_0000,
|
const TEXT_ALIGN = 0b0000_0111_1000_0000_0000,
|
||||||
|
#[doc = "Whether this flow has a fragment with `counter-reset` or `counter-increment` \
|
||||||
|
styles."]
|
||||||
|
const AFFECTS_COUNTERS = 0b0000_1000_0000_0000_0000,
|
||||||
|
#[doc = "Whether this flow's descendants have fragments that affect `counter-reset` or \
|
||||||
|
`counter-increment` styles."]
|
||||||
|
const HAS_COUNTER_AFFECTING_CHILDREN = 0b0001_0000_0000_0000_0000
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -548,13 +573,13 @@ impl FlowFlags {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn text_align(self) -> text_align::T {
|
pub fn text_align(self) -> text_align::T {
|
||||||
FromPrimitive::from_u16((self & TEXT_ALIGN).bits() >> TEXT_ALIGN_SHIFT).unwrap()
|
FromPrimitive::from_u32((self & TEXT_ALIGN).bits() >> TEXT_ALIGN_SHIFT).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_text_align(&mut self, value: text_align::T) {
|
pub fn set_text_align(&mut self, value: text_align::T) {
|
||||||
*self = (*self & !TEXT_ALIGN) |
|
*self = (*self & !TEXT_ALIGN) |
|
||||||
FlowFlags::from_bits((value as u16) << TEXT_ALIGN_SHIFT).unwrap();
|
FlowFlags::from_bits((value as u32) << TEXT_ALIGN_SHIFT).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -885,39 +910,41 @@ impl BaseFlow {
|
||||||
force_nonfloated: ForceNonfloatedFlag)
|
force_nonfloated: ForceNonfloatedFlag)
|
||||||
-> BaseFlow {
|
-> BaseFlow {
|
||||||
let mut flags = FlowFlags::empty();
|
let mut flags = FlowFlags::empty();
|
||||||
match node {
|
if let Some(node) = node {
|
||||||
None => {}
|
let node_style = node.style();
|
||||||
Some(node) => {
|
match node_style.get_box().position {
|
||||||
let node_style = node.style();
|
position::T::absolute | position::T::fixed => {
|
||||||
match node_style.get_box().position {
|
flags.insert(IS_ABSOLUTELY_POSITIONED)
|
||||||
position::T::absolute | position::T::fixed => {
|
|
||||||
flags.insert(IS_ABSOLUTELY_POSITIONED)
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
if force_nonfloated == ForceNonfloatedFlag::FloatIfNecessary {
|
if force_nonfloated == ForceNonfloatedFlag::FloatIfNecessary {
|
||||||
match node_style.get_box().float {
|
match node_style.get_box().float {
|
||||||
float::T::none => {}
|
float::T::none => {}
|
||||||
float::T::left => flags.insert(FLOATS_LEFT),
|
float::T::left => flags.insert(FLOATS_LEFT),
|
||||||
float::T::right => flags.insert(FLOATS_RIGHT),
|
float::T::right => flags.insert(FLOATS_RIGHT),
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
match node_style.get_box().clear {
|
match node_style.get_box().clear {
|
||||||
clear::T::none => {}
|
clear::T::none => {}
|
||||||
clear::T::left => flags.insert(CLEARS_LEFT),
|
clear::T::left => flags.insert(CLEARS_LEFT),
|
||||||
clear::T::right => flags.insert(CLEARS_RIGHT),
|
clear::T::right => flags.insert(CLEARS_RIGHT),
|
||||||
clear::T::both => {
|
clear::T::both => {
|
||||||
flags.insert(CLEARS_LEFT);
|
flags.insert(CLEARS_LEFT);
|
||||||
flags.insert(CLEARS_RIGHT);
|
flags.insert(CLEARS_RIGHT);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !node_style.get_counters().counter_reset.0.is_empty() ||
|
||||||
|
!node_style.get_counters().counter_increment.0.is_empty() {
|
||||||
|
flags.insert(AFFECTS_COUNTERS)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// New flows start out as fully damaged.
|
// New flows start out as fully damaged.
|
||||||
let mut damage = RestyleDamage::all();
|
let mut damage = incremental::rebuild_and_reflow();
|
||||||
damage.remove(RECONSTRUCT_FLOW);
|
damage.remove(RECONSTRUCT_FLOW);
|
||||||
|
|
||||||
BaseFlow {
|
BaseFlow {
|
||||||
|
@ -992,10 +1019,12 @@ impl BaseFlow {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ImmutableFlowUtils for &'a (Flow + 'a) {
|
impl<'a> ImmutableFlowUtils for &'a (Flow + 'a) {
|
||||||
/// Returns true if this flow is a block flow.
|
/// Returns true if this flow is a block flow or subclass thereof.
|
||||||
fn is_block_like(self) -> bool {
|
fn is_block_like(self) -> bool {
|
||||||
match self.class() {
|
match self.class() {
|
||||||
FlowClass::Block => true,
|
FlowClass::Block | FlowClass::ListItem | FlowClass::Table | FlowClass::TableRowGroup |
|
||||||
|
FlowClass::TableRow | FlowClass::TableCaption | FlowClass::TableCell |
|
||||||
|
FlowClass::TableWrapper => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,13 +8,12 @@
|
||||||
|
|
||||||
use canvas::canvas_paint_task::CanvasMsg;
|
use canvas::canvas_paint_task::CanvasMsg;
|
||||||
use css::node_style::StyledNode;
|
use css::node_style::StyledNode;
|
||||||
use construct::FlowConstructor;
|
|
||||||
use context::LayoutContext;
|
use context::LayoutContext;
|
||||||
use floats::ClearType;
|
use floats::ClearType;
|
||||||
use flow;
|
use flow;
|
||||||
use flow::Flow;
|
use flow::Flow;
|
||||||
use flow_ref::FlowRef;
|
use flow_ref::FlowRef;
|
||||||
use incremental::RestyleDamage;
|
use incremental::{self, RestyleDamage};
|
||||||
use inline::{InlineFragmentContext, InlineMetrics};
|
use inline::{InlineFragmentContext, InlineMetrics};
|
||||||
use layout_debug;
|
use layout_debug;
|
||||||
use model::{IntrinsicISizes, IntrinsicISizesContribution, MaybeAuto, specified};
|
use model::{IntrinsicISizes, IntrinsicISizesContribution, MaybeAuto, specified};
|
||||||
|
@ -44,15 +43,17 @@ use std::collections::DList;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::num::ToPrimitive;
|
use std::num::ToPrimitive;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::sync::{Arc, Mutex};
|
|
||||||
use std::sync::mpsc::Sender;
|
use std::sync::mpsc::Sender;
|
||||||
|
use std::sync::{Arc, Mutex};
|
||||||
use string_cache::Atom;
|
use string_cache::Atom;
|
||||||
use style::properties::{ComputedValues, cascade_anonymous, make_border};
|
use style::computed_values::content::ContentItem;
|
||||||
use style::node::{TElement, TNode};
|
|
||||||
use style::values::computed::{LengthOrPercentage, LengthOrPercentageOrAuto, LengthOrPercentageOrNone};
|
|
||||||
use style::computed_values::{clear, mix_blend_mode, overflow_wrap};
|
use style::computed_values::{clear, mix_blend_mode, overflow_wrap};
|
||||||
use style::computed_values::{position, text_align, text_decoration, vertical_align, white_space};
|
use style::computed_values::{position, text_align, text_decoration, vertical_align, white_space};
|
||||||
use style::computed_values::{word_break};
|
use style::computed_values::{word_break};
|
||||||
|
use style::node::{TElement, TNode};
|
||||||
|
use style::properties::{ComputedValues, cascade_anonymous, make_border};
|
||||||
|
use style::values::computed::{LengthOrPercentage, LengthOrPercentageOrAuto};
|
||||||
|
use style::values::computed::{LengthOrPercentageOrNone};
|
||||||
use text::TextRunScanner;
|
use text::TextRunScanner;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
|
@ -136,6 +137,11 @@ impl Encodable for Fragment {
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub enum SpecificFragmentInfo {
|
pub enum SpecificFragmentInfo {
|
||||||
Generic,
|
Generic,
|
||||||
|
|
||||||
|
/// A piece of generated content that cannot be resolved into `ScannedText` until the generated
|
||||||
|
/// content resolution phase (e.g. an ordered list item marker).
|
||||||
|
GeneratedContent(Box<GeneratedContentInfo>),
|
||||||
|
|
||||||
Iframe(Box<IframeFragmentInfo>),
|
Iframe(Box<IframeFragmentInfo>),
|
||||||
Image(Box<ImageFragmentInfo>),
|
Image(Box<ImageFragmentInfo>),
|
||||||
Canvas(Box<CanvasFragmentInfo>),
|
Canvas(Box<CanvasFragmentInfo>),
|
||||||
|
@ -158,17 +164,18 @@ impl SpecificFragmentInfo {
|
||||||
fn restyle_damage(&self) -> RestyleDamage {
|
fn restyle_damage(&self) -> RestyleDamage {
|
||||||
let flow =
|
let flow =
|
||||||
match *self {
|
match *self {
|
||||||
SpecificFragmentInfo::Iframe(_)
|
SpecificFragmentInfo::Canvas(_) |
|
||||||
| SpecificFragmentInfo::Image(_)
|
SpecificFragmentInfo::GeneratedContent(_) |
|
||||||
| SpecificFragmentInfo::ScannedText(_)
|
SpecificFragmentInfo::Iframe(_) |
|
||||||
| SpecificFragmentInfo::Table
|
SpecificFragmentInfo::Image(_) |
|
||||||
| SpecificFragmentInfo::TableCell
|
SpecificFragmentInfo::ScannedText(_) |
|
||||||
| SpecificFragmentInfo::TableColumn(_)
|
SpecificFragmentInfo::Table |
|
||||||
| SpecificFragmentInfo::TableRow
|
SpecificFragmentInfo::TableCell |
|
||||||
| SpecificFragmentInfo::TableWrapper
|
SpecificFragmentInfo::TableColumn(_) |
|
||||||
| SpecificFragmentInfo::UnscannedText(_)
|
SpecificFragmentInfo::TableRow |
|
||||||
| SpecificFragmentInfo::Canvas(_)
|
SpecificFragmentInfo::TableWrapper |
|
||||||
| SpecificFragmentInfo::Generic => return RestyleDamage::empty(),
|
SpecificFragmentInfo::UnscannedText(_) |
|
||||||
|
SpecificFragmentInfo::Generic => return RestyleDamage::empty(),
|
||||||
SpecificFragmentInfo::InlineAbsoluteHypothetical(ref info) => &info.flow_ref,
|
SpecificFragmentInfo::InlineAbsoluteHypothetical(ref info) => &info.flow_ref,
|
||||||
SpecificFragmentInfo::InlineBlock(ref info) => &info.flow_ref,
|
SpecificFragmentInfo::InlineBlock(ref info) => &info.flow_ref,
|
||||||
};
|
};
|
||||||
|
@ -180,9 +187,12 @@ impl SpecificFragmentInfo {
|
||||||
match *self {
|
match *self {
|
||||||
SpecificFragmentInfo::Canvas(_) => "SpecificFragmentInfo::Canvas",
|
SpecificFragmentInfo::Canvas(_) => "SpecificFragmentInfo::Canvas",
|
||||||
SpecificFragmentInfo::Generic => "SpecificFragmentInfo::Generic",
|
SpecificFragmentInfo::Generic => "SpecificFragmentInfo::Generic",
|
||||||
|
SpecificFragmentInfo::GeneratedContent(_) => "SpecificFragmentInfo::GeneratedContent",
|
||||||
SpecificFragmentInfo::Iframe(_) => "SpecificFragmentInfo::Iframe",
|
SpecificFragmentInfo::Iframe(_) => "SpecificFragmentInfo::Iframe",
|
||||||
SpecificFragmentInfo::Image(_) => "SpecificFragmentInfo::Image",
|
SpecificFragmentInfo::Image(_) => "SpecificFragmentInfo::Image",
|
||||||
SpecificFragmentInfo::InlineAbsoluteHypothetical(_) => "SpecificFragmentInfo::InlineAbsoluteHypothetical",
|
SpecificFragmentInfo::InlineAbsoluteHypothetical(_) => {
|
||||||
|
"SpecificFragmentInfo::InlineAbsoluteHypothetical"
|
||||||
|
}
|
||||||
SpecificFragmentInfo::InlineBlock(_) => "SpecificFragmentInfo::InlineBlock",
|
SpecificFragmentInfo::InlineBlock(_) => "SpecificFragmentInfo::InlineBlock",
|
||||||
SpecificFragmentInfo::ScannedText(_) => "SpecificFragmentInfo::ScannedText",
|
SpecificFragmentInfo::ScannedText(_) => "SpecificFragmentInfo::ScannedText",
|
||||||
SpecificFragmentInfo::Table => "SpecificFragmentInfo::Table",
|
SpecificFragmentInfo::Table => "SpecificFragmentInfo::Table",
|
||||||
|
@ -196,8 +206,11 @@ impl SpecificFragmentInfo {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Clamp a value obtained from style_length, based on min / max lengths.
|
/// Clamp a value obtained from style_length, based on min / max lengths.
|
||||||
fn clamp_size(size: Au, min_size: LengthOrPercentage, max_size: LengthOrPercentageOrNone,
|
fn clamp_size(size: Au,
|
||||||
container_inline_size: Au) -> Au {
|
min_size: LengthOrPercentage,
|
||||||
|
max_size: LengthOrPercentageOrNone,
|
||||||
|
container_inline_size: Au)
|
||||||
|
-> Au {
|
||||||
let min_size = model::specified(min_size, container_inline_size);
|
let min_size = model::specified(min_size, container_inline_size);
|
||||||
let max_size = model::specified_or_none(max_size, container_inline_size);
|
let max_size = model::specified_or_none(max_size, container_inline_size);
|
||||||
|
|
||||||
|
@ -207,6 +220,13 @@ fn clamp_size(size: Au, min_size: LengthOrPercentage, max_size: LengthOrPercenta
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Information for generated content.
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub enum GeneratedContentInfo {
|
||||||
|
ListItem,
|
||||||
|
ContentItem(ContentItem),
|
||||||
|
}
|
||||||
|
|
||||||
/// A hypothetical box (see CSS 2.1 § 10.3.7) for an absolutely-positioned block that was declared
|
/// A hypothetical box (see CSS 2.1 § 10.3.7) for an absolutely-positioned block that was declared
|
||||||
/// with `display: inline;`.
|
/// with `display: inline;`.
|
||||||
///
|
///
|
||||||
|
@ -637,14 +657,6 @@ pub struct UnscannedTextFragmentInfo {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UnscannedTextFragmentInfo {
|
impl UnscannedTextFragmentInfo {
|
||||||
/// Creates a new instance of `UnscannedTextFragmentInfo` from the given DOM node.
|
|
||||||
pub fn new(node: &ThreadSafeLayoutNode) -> UnscannedTextFragmentInfo {
|
|
||||||
// FIXME(pcwalton): Don't copy text; atomically reference count it instead.
|
|
||||||
UnscannedTextFragmentInfo {
|
|
||||||
text: box node.text(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates a new instance of `UnscannedTextFragmentInfo` from the given text.
|
/// Creates a new instance of `UnscannedTextFragmentInfo` from the given text.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_text(text: String) -> UnscannedTextFragmentInfo {
|
pub fn from_text(text: String) -> UnscannedTextFragmentInfo {
|
||||||
|
@ -678,34 +690,8 @@ impl TableColumnFragmentInfo {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Fragment {
|
impl Fragment {
|
||||||
/// Constructs a new `Fragment` instance for the given node.
|
/// Constructs a new `Fragment` instance.
|
||||||
///
|
pub fn new(node: &ThreadSafeLayoutNode, specific: SpecificFragmentInfo) -> Fragment {
|
||||||
/// This does *not* construct the text for generated content. See comments in
|
|
||||||
/// `FlowConstructor::build_specific_fragment_info_for_node()` for more details.
|
|
||||||
///
|
|
||||||
/// Arguments:
|
|
||||||
///
|
|
||||||
/// * `constructor`: The flow constructor.
|
|
||||||
/// * `node`: The node to create a fragment for.
|
|
||||||
pub fn new(constructor: &mut FlowConstructor, node: &ThreadSafeLayoutNode) -> Fragment {
|
|
||||||
let style = node.style().clone();
|
|
||||||
let writing_mode = style.writing_mode;
|
|
||||||
Fragment {
|
|
||||||
node: OpaqueNodeMethods::from_thread_safe_layout_node(node),
|
|
||||||
style: style,
|
|
||||||
restyle_damage: node.restyle_damage(),
|
|
||||||
border_box: LogicalRect::zero(writing_mode),
|
|
||||||
border_padding: LogicalMargin::zero(writing_mode),
|
|
||||||
margin: LogicalMargin::zero(writing_mode),
|
|
||||||
specific: constructor.build_specific_fragment_info_for_node(node),
|
|
||||||
inline_context: None,
|
|
||||||
debug_id: layout_debug::generate_unique_debug_id(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Constructs a new `Fragment` instance from a specific info.
|
|
||||||
pub fn new_from_specific_info(node: &ThreadSafeLayoutNode, specific: SpecificFragmentInfo)
|
|
||||||
-> Fragment {
|
|
||||||
let style = node.style().clone();
|
let style = node.style().clone();
|
||||||
let writing_mode = style.writing_mode;
|
let writing_mode = style.writing_mode;
|
||||||
Fragment {
|
Fragment {
|
||||||
|
@ -721,24 +707,6 @@ impl Fragment {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Constructs a new `Fragment` instance for an anonymous object.
|
|
||||||
pub fn new_anonymous(constructor: &mut FlowConstructor, node: &ThreadSafeLayoutNode)
|
|
||||||
-> Fragment {
|
|
||||||
let node_style = cascade_anonymous(&**node.style());
|
|
||||||
let writing_mode = node_style.writing_mode;
|
|
||||||
Fragment {
|
|
||||||
node: OpaqueNodeMethods::from_thread_safe_layout_node(node),
|
|
||||||
style: Arc::new(node_style),
|
|
||||||
restyle_damage: node.restyle_damage(),
|
|
||||||
border_box: LogicalRect::zero(writing_mode),
|
|
||||||
border_padding: LogicalMargin::zero(writing_mode),
|
|
||||||
margin: LogicalMargin::zero(writing_mode),
|
|
||||||
specific: constructor.build_specific_fragment_info_for_node(node),
|
|
||||||
inline_context: None,
|
|
||||||
debug_id: layout_debug::generate_unique_debug_id(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Constructs a new `Fragment` instance for an anonymous table object.
|
/// Constructs a new `Fragment` instance for an anonymous table object.
|
||||||
pub fn new_anonymous_from_specific_info(node: &ThreadSafeLayoutNode,
|
pub fn new_anonymous_from_specific_info(node: &ThreadSafeLayoutNode,
|
||||||
specific: SpecificFragmentInfo)
|
specific: SpecificFragmentInfo)
|
||||||
|
@ -837,7 +805,7 @@ impl Fragment {
|
||||||
Fragment {
|
Fragment {
|
||||||
node: self.node,
|
node: self.node,
|
||||||
style: self.style.clone(),
|
style: self.style.clone(),
|
||||||
restyle_damage: RestyleDamage::all(),
|
restyle_damage: incremental::rebuild_and_reflow(),
|
||||||
border_box: new_border_box,
|
border_box: new_border_box,
|
||||||
border_padding: self.border_padding,
|
border_padding: self.border_padding,
|
||||||
margin: self.margin,
|
margin: self.margin,
|
||||||
|
@ -912,6 +880,7 @@ impl Fragment {
|
||||||
match self.specific {
|
match self.specific {
|
||||||
SpecificFragmentInfo::Canvas(_) |
|
SpecificFragmentInfo::Canvas(_) |
|
||||||
SpecificFragmentInfo::Generic |
|
SpecificFragmentInfo::Generic |
|
||||||
|
SpecificFragmentInfo::GeneratedContent(_) |
|
||||||
SpecificFragmentInfo::Iframe(_) |
|
SpecificFragmentInfo::Iframe(_) |
|
||||||
SpecificFragmentInfo::Image(_) |
|
SpecificFragmentInfo::Image(_) |
|
||||||
SpecificFragmentInfo::InlineBlock(_) => {
|
SpecificFragmentInfo::InlineBlock(_) => {
|
||||||
|
@ -931,7 +900,9 @@ impl Fragment {
|
||||||
INTRINSIC_INLINE_SIZE_INCLUDES_BORDER |
|
INTRINSIC_INLINE_SIZE_INCLUDES_BORDER |
|
||||||
INTRINSIC_INLINE_SIZE_INCLUDES_SPECIFIED
|
INTRINSIC_INLINE_SIZE_INCLUDES_SPECIFIED
|
||||||
}
|
}
|
||||||
SpecificFragmentInfo::ScannedText(_) | SpecificFragmentInfo::TableColumn(_) | SpecificFragmentInfo::UnscannedText(_) |
|
SpecificFragmentInfo::ScannedText(_) |
|
||||||
|
SpecificFragmentInfo::TableColumn(_) |
|
||||||
|
SpecificFragmentInfo::UnscannedText(_) |
|
||||||
SpecificFragmentInfo::InlineAbsoluteHypothetical(_) => {
|
SpecificFragmentInfo::InlineAbsoluteHypothetical(_) => {
|
||||||
QuantitiesIncludedInIntrinsicInlineSizes::empty()
|
QuantitiesIncludedInIntrinsicInlineSizes::empty()
|
||||||
}
|
}
|
||||||
|
@ -1221,6 +1192,14 @@ impl Fragment {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns true if and only if this fragment is a generated content fragment.
|
||||||
|
pub fn is_generated_content(&self) -> bool {
|
||||||
|
match self.specific {
|
||||||
|
SpecificFragmentInfo::GeneratedContent(..) => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns true if and only if this is a scanned text fragment.
|
/// Returns true if and only if this is a scanned text fragment.
|
||||||
pub fn is_scanned_text_fragment(&self) -> bool {
|
pub fn is_scanned_text_fragment(&self) -> bool {
|
||||||
match self.specific {
|
match self.specific {
|
||||||
|
@ -1234,6 +1213,7 @@ impl Fragment {
|
||||||
let mut result = self.style_specified_intrinsic_inline_size();
|
let mut result = self.style_specified_intrinsic_inline_size();
|
||||||
match self.specific {
|
match self.specific {
|
||||||
SpecificFragmentInfo::Generic |
|
SpecificFragmentInfo::Generic |
|
||||||
|
SpecificFragmentInfo::GeneratedContent(_) |
|
||||||
SpecificFragmentInfo::Iframe(_) |
|
SpecificFragmentInfo::Iframe(_) |
|
||||||
SpecificFragmentInfo::Table |
|
SpecificFragmentInfo::Table |
|
||||||
SpecificFragmentInfo::TableCell |
|
SpecificFragmentInfo::TableCell |
|
||||||
|
@ -1303,6 +1283,7 @@ impl Fragment {
|
||||||
pub fn content_inline_size(&self) -> Au {
|
pub fn content_inline_size(&self) -> Au {
|
||||||
match self.specific {
|
match self.specific {
|
||||||
SpecificFragmentInfo::Generic |
|
SpecificFragmentInfo::Generic |
|
||||||
|
SpecificFragmentInfo::GeneratedContent(_) |
|
||||||
SpecificFragmentInfo::Iframe(_) |
|
SpecificFragmentInfo::Iframe(_) |
|
||||||
SpecificFragmentInfo::Table |
|
SpecificFragmentInfo::Table |
|
||||||
SpecificFragmentInfo::TableCell |
|
SpecificFragmentInfo::TableCell |
|
||||||
|
@ -1334,6 +1315,7 @@ impl Fragment {
|
||||||
pub fn content_block_size(&self, layout_context: &LayoutContext) -> Au {
|
pub fn content_block_size(&self, layout_context: &LayoutContext) -> Au {
|
||||||
match self.specific {
|
match self.specific {
|
||||||
SpecificFragmentInfo::Generic |
|
SpecificFragmentInfo::Generic |
|
||||||
|
SpecificFragmentInfo::GeneratedContent(_) |
|
||||||
SpecificFragmentInfo::Iframe(_) |
|
SpecificFragmentInfo::Iframe(_) |
|
||||||
SpecificFragmentInfo::Table |
|
SpecificFragmentInfo::Table |
|
||||||
SpecificFragmentInfo::TableCell |
|
SpecificFragmentInfo::TableCell |
|
||||||
|
@ -1352,7 +1334,7 @@ impl Fragment {
|
||||||
self.calculate_line_height(layout_context)
|
self.calculate_line_height(layout_context)
|
||||||
}
|
}
|
||||||
SpecificFragmentInfo::TableColumn(_) => {
|
SpecificFragmentInfo::TableColumn(_) => {
|
||||||
panic!("Table column fragments do not have block_size")
|
panic!("Table column fragments do not have block size")
|
||||||
}
|
}
|
||||||
SpecificFragmentInfo::UnscannedText(_) => {
|
SpecificFragmentInfo::UnscannedText(_) => {
|
||||||
panic!("Unscanned text fragments should have been scanned by now!")
|
panic!("Unscanned text fragments should have been scanned by now!")
|
||||||
|
@ -1382,6 +1364,7 @@ impl Fragment {
|
||||||
match self.specific {
|
match self.specific {
|
||||||
SpecificFragmentInfo::Canvas(_) |
|
SpecificFragmentInfo::Canvas(_) |
|
||||||
SpecificFragmentInfo::Generic |
|
SpecificFragmentInfo::Generic |
|
||||||
|
SpecificFragmentInfo::GeneratedContent(_) |
|
||||||
SpecificFragmentInfo::Iframe(_) |
|
SpecificFragmentInfo::Iframe(_) |
|
||||||
SpecificFragmentInfo::Image(_) |
|
SpecificFragmentInfo::Image(_) |
|
||||||
SpecificFragmentInfo::Table |
|
SpecificFragmentInfo::Table |
|
||||||
|
@ -1689,22 +1672,23 @@ impl Fragment {
|
||||||
pub fn assign_replaced_inline_size_if_necessary<'a>(&'a mut self, container_inline_size: Au) {
|
pub fn assign_replaced_inline_size_if_necessary<'a>(&'a mut self, container_inline_size: Au) {
|
||||||
match self.specific {
|
match self.specific {
|
||||||
SpecificFragmentInfo::Generic |
|
SpecificFragmentInfo::Generic |
|
||||||
|
SpecificFragmentInfo::GeneratedContent(_) |
|
||||||
SpecificFragmentInfo::Table |
|
SpecificFragmentInfo::Table |
|
||||||
SpecificFragmentInfo::TableCell |
|
SpecificFragmentInfo::TableCell |
|
||||||
SpecificFragmentInfo::TableRow |
|
SpecificFragmentInfo::TableRow |
|
||||||
SpecificFragmentInfo::TableWrapper => return,
|
SpecificFragmentInfo::TableWrapper => return,
|
||||||
SpecificFragmentInfo::TableColumn(_) => {
|
SpecificFragmentInfo::TableColumn(_) => {
|
||||||
panic!("Table column fragments do not have inline_size")
|
panic!("Table column fragments do not have inline size")
|
||||||
}
|
}
|
||||||
SpecificFragmentInfo::UnscannedText(_) => {
|
SpecificFragmentInfo::UnscannedText(_) => {
|
||||||
panic!("Unscanned text fragments should have been scanned by now!")
|
panic!("Unscanned text fragments should have been scanned by now!")
|
||||||
}
|
}
|
||||||
SpecificFragmentInfo::Canvas(_) |
|
SpecificFragmentInfo::Canvas(_) |
|
||||||
SpecificFragmentInfo::Image(_) |
|
SpecificFragmentInfo::Image(_) |
|
||||||
SpecificFragmentInfo::ScannedText(_) |
|
SpecificFragmentInfo::Iframe(_) |
|
||||||
SpecificFragmentInfo::InlineBlock(_) |
|
SpecificFragmentInfo::InlineBlock(_) |
|
||||||
SpecificFragmentInfo::InlineAbsoluteHypothetical(_) |
|
SpecificFragmentInfo::InlineAbsoluteHypothetical(_) |
|
||||||
SpecificFragmentInfo::Iframe(_) => {}
|
SpecificFragmentInfo::ScannedText(_) => {}
|
||||||
};
|
};
|
||||||
|
|
||||||
let style = self.style().clone();
|
let style = self.style().clone();
|
||||||
|
@ -1770,22 +1754,23 @@ impl Fragment {
|
||||||
pub fn assign_replaced_block_size_if_necessary(&mut self, containing_block_block_size: Au) {
|
pub fn assign_replaced_block_size_if_necessary(&mut self, containing_block_block_size: Au) {
|
||||||
match self.specific {
|
match self.specific {
|
||||||
SpecificFragmentInfo::Generic |
|
SpecificFragmentInfo::Generic |
|
||||||
|
SpecificFragmentInfo::GeneratedContent(_) |
|
||||||
SpecificFragmentInfo::Table |
|
SpecificFragmentInfo::Table |
|
||||||
SpecificFragmentInfo::TableCell |
|
SpecificFragmentInfo::TableCell |
|
||||||
SpecificFragmentInfo::TableRow |
|
SpecificFragmentInfo::TableRow |
|
||||||
SpecificFragmentInfo::TableWrapper => return,
|
SpecificFragmentInfo::TableWrapper => return,
|
||||||
SpecificFragmentInfo::TableColumn(_) => {
|
SpecificFragmentInfo::TableColumn(_) => {
|
||||||
panic!("Table column fragments do not have block_size")
|
panic!("Table column fragments do not have block size")
|
||||||
}
|
}
|
||||||
SpecificFragmentInfo::UnscannedText(_) => {
|
SpecificFragmentInfo::UnscannedText(_) => {
|
||||||
panic!("Unscanned text fragments should have been scanned by now!")
|
panic!("Unscanned text fragments should have been scanned by now!")
|
||||||
}
|
}
|
||||||
SpecificFragmentInfo::Canvas(_) |
|
SpecificFragmentInfo::Canvas(_) |
|
||||||
|
SpecificFragmentInfo::Iframe(_) |
|
||||||
SpecificFragmentInfo::Image(_) |
|
SpecificFragmentInfo::Image(_) |
|
||||||
SpecificFragmentInfo::ScannedText(_) |
|
|
||||||
SpecificFragmentInfo::InlineBlock(_) |
|
SpecificFragmentInfo::InlineBlock(_) |
|
||||||
SpecificFragmentInfo::InlineAbsoluteHypothetical(_) |
|
SpecificFragmentInfo::InlineAbsoluteHypothetical(_) |
|
||||||
SpecificFragmentInfo::Iframe(_) => {}
|
SpecificFragmentInfo::ScannedText(_) => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
let style = self.style().clone();
|
let style = self.style().clone();
|
||||||
|
@ -1923,6 +1908,7 @@ impl Fragment {
|
||||||
SpecificFragmentInfo::TableWrapper => false,
|
SpecificFragmentInfo::TableWrapper => false,
|
||||||
SpecificFragmentInfo::Canvas(_) |
|
SpecificFragmentInfo::Canvas(_) |
|
||||||
SpecificFragmentInfo::Generic |
|
SpecificFragmentInfo::Generic |
|
||||||
|
SpecificFragmentInfo::GeneratedContent(_) |
|
||||||
SpecificFragmentInfo::Iframe(_) |
|
SpecificFragmentInfo::Iframe(_) |
|
||||||
SpecificFragmentInfo::Image(_) |
|
SpecificFragmentInfo::Image(_) |
|
||||||
SpecificFragmentInfo::ScannedText(_) |
|
SpecificFragmentInfo::ScannedText(_) |
|
||||||
|
|
561
components/layout/generated_content.rs
Normal file
561
components/layout/generated_content.rs
Normal file
|
@ -0,0 +1,561 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* 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/. */
|
||||||
|
|
||||||
|
//! The generated content assignment phase.
|
||||||
|
//!
|
||||||
|
//! This phase handles CSS counters, quotes, and ordered lists per CSS § 12.3-12.5. It cannot be
|
||||||
|
//! done in parallel and is therefore a sequential pass that runs on as little of the flow tree
|
||||||
|
//! as possible.
|
||||||
|
|
||||||
|
use context::LayoutContext;
|
||||||
|
use flow::{self, AFFECTS_COUNTERS, Flow, HAS_COUNTER_AFFECTING_CHILDREN, ImmutableFlowUtils};
|
||||||
|
use flow::{InorderFlowTraversal};
|
||||||
|
use fragment::{Fragment, GeneratedContentInfo, SpecificFragmentInfo, UnscannedTextFragmentInfo};
|
||||||
|
use incremental::{self, RESOLVE_GENERATED_CONTENT};
|
||||||
|
use text::TextRunScanner;
|
||||||
|
|
||||||
|
use gfx::display_list::OpaqueNode;
|
||||||
|
use std::collections::{DList, HashMap};
|
||||||
|
use std::sync::Arc;
|
||||||
|
use style::computed_values::content::ContentItem;
|
||||||
|
use style::computed_values::{display, list_style_type};
|
||||||
|
use style::properties::ComputedValues;
|
||||||
|
use util::smallvec::{SmallVec, SmallVec8};
|
||||||
|
|
||||||
|
// Decimal styles per CSS-COUNTER-STYLES § 6.1:
|
||||||
|
static DECIMAL: [char; 10] = [ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' ];
|
||||||
|
// TODO(pcwalton): `decimal-leading-zero`
|
||||||
|
static ARABIC_INDIC: [char; 10] = [ '٠', '١', '٢', '٣', '٤', '٥', '٦', '٧', '٨', '٩' ];
|
||||||
|
// TODO(pcwalton): `armenian`, `upper-armenian`, `lower-armenian`
|
||||||
|
static BENGALI: [char; 10] = [ '০', '১', '২', '৩', '৪', '৫', '৬', '৭', '৮', '৯' ];
|
||||||
|
static CAMBODIAN: [char; 10] = [ '០', '១', '២', '៣', '៤', '៥', '៦', '៧', '៨', '៩' ];
|
||||||
|
// TODO(pcwalton): Suffix for CJK decimal.
|
||||||
|
static CJK_DECIMAL: [char; 10] = [ '〇', '一', '二', '三', '四', '五', '六', '七', '八', '九' ];
|
||||||
|
static DEVANAGARI: [char; 10] = [ '०', '१', '२', '३', '४', '५', '६', '७', '८', '९' ];
|
||||||
|
// TODO(pcwalton): `georgian`
|
||||||
|
static GUJARATI: [char; 10] = ['૦', '૧', '૨', '૩', '૪', '૫', '૬', '૭', '૮', '૯'];
|
||||||
|
static GURMUKHI: [char; 10] = ['੦', '੧', '੨', '੩', '੪', '੫', '੬', '੭', '੮', '੯'];
|
||||||
|
// TODO(pcwalton): `hebrew`
|
||||||
|
static KANNADA: [char; 10] = ['೦', '೧', '೨', '೩', '೪', '೫', '೬', '೭', '೮', '೯'];
|
||||||
|
static LAO: [char; 10] = ['໐', '໑', '໒', '໓', '໔', '໕', '໖', '໗', '໘', '໙'];
|
||||||
|
static MALAYALAM: [char; 10] = ['൦', '൧', '൨', '൩', '൪', '൫', '൬', '൭', '൮', '൯'];
|
||||||
|
static MONGOLIAN: [char; 10] = ['᠐', '᠑', '᠒', '᠓', '᠔', '᠕', '᠖', '᠗', '᠘', '᠙'];
|
||||||
|
static MYANMAR: [char; 10] = ['၀', '၁', '၂', '၃', '၄', '၅', '၆', '၇', '၈', '၉'];
|
||||||
|
static ORIYA: [char; 10] = ['୦', '୧', '୨', '୩', '୪', '୫', '୬', '୭', '୮', '୯'];
|
||||||
|
static PERSIAN: [char; 10] = ['۰', '۱', '۲', '۳', '۴', '۵', '۶', '۷', '۸', '۹'];
|
||||||
|
// TODO(pcwalton): `lower-roman`, `upper-roman`
|
||||||
|
static TELUGU: [char; 10] = ['౦', '౧', '౨', '౩', '౪', '౫', '౬', '౭', '౮', '౯'];
|
||||||
|
static THAI: [char; 10] = ['๐', '๑', '๒', '๓', '๔', '๕', '๖', '๗', '๘', '๙'];
|
||||||
|
static TIBETAN: [char; 10] = ['༠', '༡', '༢', '༣', '༤', '༥', '༦', '༧', '༨', '༩'];
|
||||||
|
|
||||||
|
// Alphabetic styles per CSS-COUNTER-STYLES § 6.2:
|
||||||
|
static LOWER_ALPHA: [char; 26] = [
|
||||||
|
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's',
|
||||||
|
't', 'u', 'v', 'w', 'x', 'y', 'z'
|
||||||
|
];
|
||||||
|
static UPPER_ALPHA: [char; 26] = [
|
||||||
|
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
|
||||||
|
'T', 'U', 'V', 'W', 'X', 'Y', 'Z'
|
||||||
|
];
|
||||||
|
static CJK_EARTHLY_BRANCH: [char; 12] = [
|
||||||
|
'子', '丑', '寅', '卯', '辰', '巳', '午', '未', '申', '酉', '戌', '亥'
|
||||||
|
];
|
||||||
|
static CJK_HEAVENLY_STEM: [char; 10] = [
|
||||||
|
'甲', '乙', '丙', '丁', '戊', '己', '庚', '辛', '壬', '癸'
|
||||||
|
];
|
||||||
|
static LOWER_GREEK: [char; 24] = [
|
||||||
|
'α', 'β', 'γ', 'δ', 'ε', 'ζ', 'η', 'θ', 'ι', 'κ', 'λ', 'μ', 'ν', 'ξ', 'ο', 'π', 'ρ', 'σ', 'τ',
|
||||||
|
'υ', 'φ', 'χ', 'ψ', 'ω'
|
||||||
|
];
|
||||||
|
static HIRAGANA: [char; 48] = [
|
||||||
|
'あ', 'い', 'う', 'え', 'お', 'か', 'き', 'く', 'け', 'こ', 'さ', 'し', 'す', 'せ', 'そ',
|
||||||
|
'た', 'ち', 'つ', 'て', 'と', 'な', 'に', 'ぬ', 'ね', 'の', 'は', 'ひ', 'ふ', 'へ', 'ほ',
|
||||||
|
'ま', 'み', 'む', 'め', 'も', 'や', 'ゆ', 'よ', 'ら', 'り', 'る', 'れ', 'ろ',
|
||||||
|
'わ', 'ゐ', 'ゑ', 'を', 'ん'
|
||||||
|
];
|
||||||
|
static HIRAGANA_IROHA: [char; 47] = [
|
||||||
|
'い', 'ろ', 'は', 'に', 'ほ', 'へ', 'と', 'ち', 'り', 'ぬ', 'る', 'を', 'わ', 'か', 'よ',
|
||||||
|
'た', 'れ', 'そ', 'つ', 'ね', 'な', 'ら', 'む', 'う', 'ゐ', 'の', 'お', 'く', 'や', 'ま',
|
||||||
|
'け', 'ふ', 'こ', 'え', 'て', 'あ', 'さ', 'き', 'ゆ', 'め', 'み', 'し', 'ゑ',
|
||||||
|
'ひ', 'も', 'せ', 'す'
|
||||||
|
];
|
||||||
|
static KATAKANA: [char; 48] = [
|
||||||
|
'ア', 'イ', 'ウ', 'エ', 'オ', 'カ', 'キ', 'ク', 'ケ', 'コ', 'サ', 'シ', 'ス', 'セ', 'ソ',
|
||||||
|
'タ', 'チ', 'ツ', 'テ', 'ト', 'ナ', 'ニ', 'ヌ', 'ネ', 'ノ', 'ハ', 'ヒ', 'フ', 'ヘ', 'ホ',
|
||||||
|
'マ', 'ミ', 'ム', 'メ', 'モ', 'ヤ', 'ユ', 'ヨ', 'ラ', 'リ', 'ル', 'レ', 'ロ',
|
||||||
|
'ワ', 'ヰ', 'ヱ', 'ヲ', 'ン'
|
||||||
|
];
|
||||||
|
static KATAKANA_IROHA: [char; 47] = [
|
||||||
|
'イ', 'ロ', 'ハ', 'ニ', 'ホ', 'ヘ', 'ト', 'チ', 'リ', 'ヌ', 'ル', 'ヲ', 'ワ', 'カ', 'ヨ',
|
||||||
|
'タ', 'レ', 'ソ', 'ツ', 'ネ', 'ナ', 'ラ', 'ム', 'ウ', 'ヰ', 'ノ', 'オ', 'ク', 'ヤ', 'マ',
|
||||||
|
'ケ', 'フ', 'コ', 'エ', 'テ', 'ア', 'サ', 'キ', 'ユ', 'メ', 'ミ', 'シ', 'ヱ',
|
||||||
|
'ヒ', 'モ', 'セ', 'ス'
|
||||||
|
];
|
||||||
|
|
||||||
|
/// The generated content resolution traversal.
|
||||||
|
pub struct ResolveGeneratedContent<'a> {
|
||||||
|
/// The layout context.
|
||||||
|
layout_context: &'a LayoutContext<'a>,
|
||||||
|
/// The counter representing an ordered list item.
|
||||||
|
list_item: Counter,
|
||||||
|
/// Named CSS counters.
|
||||||
|
counters: HashMap<String,Counter>,
|
||||||
|
/// The level of quote nesting.
|
||||||
|
quote: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> ResolveGeneratedContent<'a> {
|
||||||
|
/// Creates a new generated content resolution traversal.
|
||||||
|
pub fn new(layout_context: &'a LayoutContext<'a>) -> ResolveGeneratedContent<'a> {
|
||||||
|
ResolveGeneratedContent {
|
||||||
|
layout_context: layout_context,
|
||||||
|
list_item: Counter::new(),
|
||||||
|
counters: HashMap::new(),
|
||||||
|
quote: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> InorderFlowTraversal for ResolveGeneratedContent<'a> {
|
||||||
|
#[inline]
|
||||||
|
fn process(&mut self, flow: &mut Flow, level: u32) {
|
||||||
|
let mut mutator = ResolveGeneratedContentFragmentMutator {
|
||||||
|
traversal: self,
|
||||||
|
level: level,
|
||||||
|
is_block: flow.is_block_like(),
|
||||||
|
incremented: false,
|
||||||
|
};
|
||||||
|
flow.mutate_fragments(&mut |fragment| mutator.mutate_fragment(fragment))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn should_process(&mut self, flow: &mut Flow) -> bool {
|
||||||
|
flow::base(flow).restyle_damage.intersects(RESOLVE_GENERATED_CONTENT) ||
|
||||||
|
flow::base(flow).flags.intersects(AFFECTS_COUNTERS | HAS_COUNTER_AFFECTING_CHILDREN)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The object that mutates the generated content fragments.
|
||||||
|
struct ResolveGeneratedContentFragmentMutator<'a,'b:'a> {
|
||||||
|
/// The traversal.
|
||||||
|
traversal: &'a mut ResolveGeneratedContent<'b>,
|
||||||
|
/// The level we're at in the flow tree.
|
||||||
|
level: u32,
|
||||||
|
/// Whether this flow is a block flow.
|
||||||
|
is_block: bool,
|
||||||
|
/// Whether we've incremented the counter yet.
|
||||||
|
incremented: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a,'b> ResolveGeneratedContentFragmentMutator<'a,'b> {
|
||||||
|
fn mutate_fragment(&mut self, fragment: &mut Fragment) {
|
||||||
|
// We only reset and/or increment counters once per flow. This avoids double-incrementing
|
||||||
|
// counters on list items (once for the main fragment and once for the marker).
|
||||||
|
if !self.incremented {
|
||||||
|
self.reset_and_increment_counters_as_necessary(fragment);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut list_style_type = fragment.style().get_list().list_style_type;
|
||||||
|
if fragment.style().get_box().display != display::T::list_item {
|
||||||
|
list_style_type = list_style_type::T::none
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut new_info = None;
|
||||||
|
{
|
||||||
|
let info =
|
||||||
|
if let SpecificFragmentInfo::GeneratedContent(ref mut info) = fragment.specific {
|
||||||
|
info
|
||||||
|
} else {
|
||||||
|
return
|
||||||
|
};
|
||||||
|
|
||||||
|
match **info {
|
||||||
|
GeneratedContentInfo::ListItem => {
|
||||||
|
new_info = self.traversal.list_item.render(self.traversal.layout_context,
|
||||||
|
fragment.node,
|
||||||
|
fragment.style.clone(),
|
||||||
|
list_style_type,
|
||||||
|
RenderingMode::Suffix(".\u{00a0}"))
|
||||||
|
}
|
||||||
|
GeneratedContentInfo::ContentItem(ContentItem::String(_)) => {
|
||||||
|
// Nothing to do here.
|
||||||
|
}
|
||||||
|
GeneratedContentInfo::ContentItem(ContentItem::Counter(ref counter_name,
|
||||||
|
counter_style)) => {
|
||||||
|
let mut temporary_counter = Counter::new();
|
||||||
|
let counter = self.traversal
|
||||||
|
.counters
|
||||||
|
.get(counter_name.as_slice())
|
||||||
|
.unwrap_or(&mut temporary_counter);
|
||||||
|
new_info = counter.render(self.traversal.layout_context,
|
||||||
|
fragment.node,
|
||||||
|
fragment.style.clone(),
|
||||||
|
counter_style,
|
||||||
|
RenderingMode::Plain)
|
||||||
|
}
|
||||||
|
GeneratedContentInfo::ContentItem(ContentItem::Counters(ref counter_name,
|
||||||
|
ref separator,
|
||||||
|
counter_style)) => {
|
||||||
|
let mut temporary_counter = Counter::new();
|
||||||
|
let counter = self.traversal
|
||||||
|
.counters
|
||||||
|
.get(counter_name.as_slice())
|
||||||
|
.unwrap_or(&mut temporary_counter);
|
||||||
|
new_info = counter.render(self.traversal.layout_context,
|
||||||
|
fragment.node,
|
||||||
|
fragment.style.clone(),
|
||||||
|
counter_style,
|
||||||
|
RenderingMode::All(separator.as_slice()));
|
||||||
|
}
|
||||||
|
GeneratedContentInfo::ContentItem(ContentItem::OpenQuote) => {
|
||||||
|
new_info = Some(render_text(self.traversal.layout_context,
|
||||||
|
fragment.node,
|
||||||
|
fragment.style.clone(),
|
||||||
|
self.quote(&*fragment.style, false)));
|
||||||
|
self.traversal.quote += 1
|
||||||
|
}
|
||||||
|
GeneratedContentInfo::ContentItem(ContentItem::CloseQuote) => {
|
||||||
|
if self.traversal.quote >= 1 {
|
||||||
|
self.traversal.quote -= 1
|
||||||
|
}
|
||||||
|
|
||||||
|
new_info = Some(render_text(self.traversal.layout_context,
|
||||||
|
fragment.node,
|
||||||
|
fragment.style.clone(),
|
||||||
|
self.quote(&*fragment.style, true)));
|
||||||
|
}
|
||||||
|
GeneratedContentInfo::ContentItem(ContentItem::NoOpenQuote) => {
|
||||||
|
self.traversal.quote += 1
|
||||||
|
}
|
||||||
|
GeneratedContentInfo::ContentItem(ContentItem::NoCloseQuote) => {
|
||||||
|
if self.traversal.quote >= 1 {
|
||||||
|
self.traversal.quote -= 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(new_info) = new_info {
|
||||||
|
fragment.specific = new_info
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reset_and_increment_counters_as_necessary(&mut self, fragment: &mut Fragment) {
|
||||||
|
let mut list_style_type = fragment.style().get_list().list_style_type;
|
||||||
|
if !self.is_block || fragment.style().get_box().display != display::T::list_item {
|
||||||
|
list_style_type = list_style_type::T::none
|
||||||
|
}
|
||||||
|
|
||||||
|
match list_style_type {
|
||||||
|
list_style_type::T::disc | list_style_type::T::none | list_style_type::T::circle |
|
||||||
|
list_style_type::T::square | list_style_type::T::disclosure_open |
|
||||||
|
list_style_type::T::disclosure_closed => {}
|
||||||
|
_ => self.traversal.list_item.increment(self.level, 1),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Truncate down counters.
|
||||||
|
for (_, counter) in self.traversal.counters.iter_mut() {
|
||||||
|
counter.truncate_to_level(self.level);
|
||||||
|
}
|
||||||
|
self.traversal.list_item.truncate_to_level(self.level);
|
||||||
|
|
||||||
|
for &(ref counter_name, value) in fragment.style().get_counters().counter_reset.0.iter() {
|
||||||
|
if let Some(ref mut counter) = self.traversal.counters.get_mut(counter_name) {
|
||||||
|
counter.reset(self.level, value);
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut counter = Counter::new();
|
||||||
|
counter.reset(self.level, value);
|
||||||
|
self.traversal.counters.insert((*counter_name).clone(), counter);
|
||||||
|
}
|
||||||
|
|
||||||
|
for &(ref counter_name, value) in fragment.style()
|
||||||
|
.get_counters()
|
||||||
|
.counter_increment
|
||||||
|
.0
|
||||||
|
.iter() {
|
||||||
|
if let Some(ref mut counter) = self.traversal.counters.get_mut(counter_name) {
|
||||||
|
counter.increment(self.level, value);
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut counter = Counter::new();
|
||||||
|
counter.increment(self.level, value);
|
||||||
|
self.traversal.counters.insert((*counter_name).clone(), counter);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.incremented = true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn quote(&self, style: &ComputedValues, close: bool) -> String {
|
||||||
|
let quotes = &style.get_list().quotes;
|
||||||
|
debug_assert!(!quotes.0.is_empty());
|
||||||
|
let &(ref open_quote, ref close_quote) =
|
||||||
|
if self.traversal.quote as uint >= quotes.0.len() {
|
||||||
|
quotes.0.last().unwrap()
|
||||||
|
} else {
|
||||||
|
"es.0[self.traversal.quote as uint]
|
||||||
|
};
|
||||||
|
if close {
|
||||||
|
close_quote.to_string()
|
||||||
|
} else {
|
||||||
|
open_quote.to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A counter per CSS 2.1 § 12.4.
|
||||||
|
struct Counter {
|
||||||
|
/// The values at each level.
|
||||||
|
values: Vec<CounterValue>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Counter {
|
||||||
|
fn new() -> Counter {
|
||||||
|
Counter {
|
||||||
|
values: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reset(&mut self, level: u32, value: i32) {
|
||||||
|
// Do we have an instance of the counter at this level? If so, just mutate it.
|
||||||
|
if let Some(ref mut existing_value) = self.values.last_mut() {
|
||||||
|
if level == existing_value.level {
|
||||||
|
existing_value.value = value;
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, push a new instance of the counter.
|
||||||
|
self.values.push(CounterValue {
|
||||||
|
level: level,
|
||||||
|
value: value,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn truncate_to_level(&mut self, level: u32) {
|
||||||
|
if let Some(position) = self.values.iter().position(|value| value.level > level) {
|
||||||
|
self.values.truncate(position)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn increment(&mut self, level: u32, amount: i32) {
|
||||||
|
if let Some(ref mut value) = self.values.last_mut() {
|
||||||
|
value.value += amount;
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
self.values.push(CounterValue {
|
||||||
|
level: level,
|
||||||
|
value: amount,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render(&self,
|
||||||
|
layout_context: &LayoutContext,
|
||||||
|
node: OpaqueNode,
|
||||||
|
style: Arc<ComputedValues>,
|
||||||
|
list_style_type: list_style_type::T,
|
||||||
|
mode: RenderingMode)
|
||||||
|
-> Option<SpecificFragmentInfo> {
|
||||||
|
let mut string = String::new();
|
||||||
|
match mode {
|
||||||
|
RenderingMode::Plain => {
|
||||||
|
let value = match self.values.last() {
|
||||||
|
Some(ref value) => value.value,
|
||||||
|
None => 0,
|
||||||
|
};
|
||||||
|
push_representation(value, list_style_type, &mut string)
|
||||||
|
}
|
||||||
|
RenderingMode::Suffix(suffix) => {
|
||||||
|
let value = match self.values.last() {
|
||||||
|
Some(ref value) => value.value,
|
||||||
|
None => 0,
|
||||||
|
};
|
||||||
|
push_representation(value, list_style_type, &mut string);
|
||||||
|
string.push_str(suffix)
|
||||||
|
}
|
||||||
|
RenderingMode::All(separator) => {
|
||||||
|
let mut first = true;
|
||||||
|
for value in self.values.iter() {
|
||||||
|
if !first {
|
||||||
|
string.push_str(separator)
|
||||||
|
}
|
||||||
|
first = false;
|
||||||
|
push_representation(value.value, list_style_type, &mut string)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if string.is_empty() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(render_text(layout_context, node, style, string))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// How a counter value is to be rendered.
|
||||||
|
enum RenderingMode<'a> {
|
||||||
|
/// The innermost counter value is rendered with no extra decoration.
|
||||||
|
Plain,
|
||||||
|
/// The innermost counter value is rendered with the given string suffix.
|
||||||
|
Suffix(&'a str),
|
||||||
|
/// All values of the counter are rendered with the given separator string between them.
|
||||||
|
All(&'a str),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The value of a counter at a given level.
|
||||||
|
struct CounterValue {
|
||||||
|
/// The level of the flow tree that this corresponds to.
|
||||||
|
level: u32,
|
||||||
|
/// The value of the counter at this level.
|
||||||
|
value: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates fragment info for a literal string.
|
||||||
|
fn render_text(layout_context: &LayoutContext,
|
||||||
|
node: OpaqueNode,
|
||||||
|
style: Arc<ComputedValues>,
|
||||||
|
string: String)
|
||||||
|
-> SpecificFragmentInfo {
|
||||||
|
let mut fragments = DList::new();
|
||||||
|
let info = SpecificFragmentInfo::UnscannedText(UnscannedTextFragmentInfo::from_text(string));
|
||||||
|
fragments.push_back(Fragment::from_opaque_node_and_style(node,
|
||||||
|
style,
|
||||||
|
incremental::rebuild_and_reflow(),
|
||||||
|
info));
|
||||||
|
let fragments = TextRunScanner::new().scan_for_runs(layout_context.font_context(), fragments);
|
||||||
|
debug_assert!(fragments.len() == 1);
|
||||||
|
fragments.fragments.into_iter().next().unwrap().specific
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Appends string that represents the value rendered using the system appropriate for the given
|
||||||
|
/// `list-style-type` onto the given string.
|
||||||
|
fn push_representation(value: i32, list_style_type: list_style_type::T, accumulator: &mut String) {
|
||||||
|
match list_style_type {
|
||||||
|
list_style_type::T::none => {}
|
||||||
|
list_style_type::T::disc |
|
||||||
|
list_style_type::T::circle |
|
||||||
|
list_style_type::T::square |
|
||||||
|
list_style_type::T::disclosure_open |
|
||||||
|
list_style_type::T::disclosure_closed => {
|
||||||
|
accumulator.push(static_representation(list_style_type))
|
||||||
|
}
|
||||||
|
list_style_type::T::decimal => push_numeric_representation(value, &DECIMAL, accumulator),
|
||||||
|
list_style_type::T::arabic_indic => {
|
||||||
|
push_numeric_representation(value, &ARABIC_INDIC, accumulator)
|
||||||
|
}
|
||||||
|
list_style_type::T::bengali => push_numeric_representation(value, &BENGALI, accumulator),
|
||||||
|
list_style_type::T::cambodian | list_style_type::T::khmer => {
|
||||||
|
push_numeric_representation(value, &CAMBODIAN, accumulator)
|
||||||
|
}
|
||||||
|
list_style_type::T::cjk_decimal => {
|
||||||
|
push_numeric_representation(value, &CJK_DECIMAL, accumulator)
|
||||||
|
}
|
||||||
|
list_style_type::T::devanagari => {
|
||||||
|
push_numeric_representation(value, &DEVANAGARI, accumulator)
|
||||||
|
}
|
||||||
|
list_style_type::T::gujarati => push_numeric_representation(value, &GUJARATI, accumulator),
|
||||||
|
list_style_type::T::gurmukhi => push_numeric_representation(value, &GURMUKHI, accumulator),
|
||||||
|
list_style_type::T::kannada => push_numeric_representation(value, &KANNADA, accumulator),
|
||||||
|
list_style_type::T::lao => push_numeric_representation(value, &LAO, accumulator),
|
||||||
|
list_style_type::T::malayalam => {
|
||||||
|
push_numeric_representation(value, &MALAYALAM, accumulator)
|
||||||
|
}
|
||||||
|
list_style_type::T::mongolian => {
|
||||||
|
push_numeric_representation(value, &MONGOLIAN, accumulator)
|
||||||
|
}
|
||||||
|
list_style_type::T::myanmar => push_numeric_representation(value, &MYANMAR, accumulator),
|
||||||
|
list_style_type::T::oriya => push_numeric_representation(value, &ORIYA, accumulator),
|
||||||
|
list_style_type::T::persian => push_numeric_representation(value, &PERSIAN, accumulator),
|
||||||
|
list_style_type::T::telugu => push_numeric_representation(value, &TELUGU, accumulator),
|
||||||
|
list_style_type::T::thai => push_numeric_representation(value, &THAI, accumulator),
|
||||||
|
list_style_type::T::tibetan => push_numeric_representation(value, &TIBETAN, accumulator),
|
||||||
|
list_style_type::T::lower_alpha => {
|
||||||
|
push_alphabetic_representation(value, &LOWER_ALPHA, accumulator)
|
||||||
|
}
|
||||||
|
list_style_type::T::upper_alpha => {
|
||||||
|
push_alphabetic_representation(value, &UPPER_ALPHA, accumulator)
|
||||||
|
}
|
||||||
|
list_style_type::T::cjk_earthly_branch => {
|
||||||
|
push_alphabetic_representation(value, &CJK_EARTHLY_BRANCH, accumulator)
|
||||||
|
}
|
||||||
|
list_style_type::T::cjk_heavenly_stem => {
|
||||||
|
push_alphabetic_representation(value, &CJK_HEAVENLY_STEM, accumulator)
|
||||||
|
}
|
||||||
|
list_style_type::T::lower_greek => {
|
||||||
|
push_alphabetic_representation(value, &LOWER_GREEK, accumulator)
|
||||||
|
}
|
||||||
|
list_style_type::T::hiragana => {
|
||||||
|
push_alphabetic_representation(value, &HIRAGANA, accumulator)
|
||||||
|
}
|
||||||
|
list_style_type::T::hiragana_iroha => {
|
||||||
|
push_alphabetic_representation(value, &HIRAGANA_IROHA, accumulator)
|
||||||
|
}
|
||||||
|
list_style_type::T::katakana => {
|
||||||
|
push_alphabetic_representation(value, &KATAKANA, accumulator)
|
||||||
|
}
|
||||||
|
list_style_type::T::katakana_iroha => {
|
||||||
|
push_alphabetic_representation(value, &KATAKANA_IROHA, accumulator)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the static character that represents the value rendered using the given list-style, if
|
||||||
|
/// possible.
|
||||||
|
pub fn static_representation(list_style_type: list_style_type::T) -> char {
|
||||||
|
match list_style_type {
|
||||||
|
list_style_type::T::disc => '•',
|
||||||
|
list_style_type::T::circle => '◦',
|
||||||
|
list_style_type::T::square => '▪',
|
||||||
|
list_style_type::T::disclosure_open => '▾',
|
||||||
|
list_style_type::T::disclosure_closed => '‣',
|
||||||
|
_ => panic!("No static representation for this list-style-type!"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Pushes the string that represents the value rendered using the given *alphabetic system* onto
|
||||||
|
/// the accumulator per CSS-COUNTER-STYLES § 3.1.4.
|
||||||
|
fn push_alphabetic_representation(mut value: i32, system: &[char], accumulator: &mut String) {
|
||||||
|
let mut string = SmallVec8::new();
|
||||||
|
while value != 0 {
|
||||||
|
// Step 1.
|
||||||
|
value = value - 1;
|
||||||
|
// Step 2.
|
||||||
|
string.push(system[(value as uint) % system.len()]);
|
||||||
|
// Step 3.
|
||||||
|
value = ((value as uint) / system.len()) as i32;
|
||||||
|
}
|
||||||
|
|
||||||
|
for i in range(0, string.len()).rev() {
|
||||||
|
accumulator.push(*string.get(i))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Pushes the string that represents the value rendered using the given *numeric system* onto the
|
||||||
|
/// accumulator per CSS-COUNTER-STYLES § 3.1.4.
|
||||||
|
fn push_numeric_representation(mut value: i32, system: &[char], accumulator: &mut String) {
|
||||||
|
// Step 1.
|
||||||
|
if value == 0 {
|
||||||
|
accumulator.push(system[0]);
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 2.
|
||||||
|
let mut string = SmallVec8::new();
|
||||||
|
while value != 0 {
|
||||||
|
// Step 2.1.
|
||||||
|
string.push(system[(value as uint) % system.len()]);
|
||||||
|
// Step 2.2.
|
||||||
|
value = ((value as uint) / system.len()) as i32;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 3.
|
||||||
|
for &ch in string.iter().rev() {
|
||||||
|
accumulator.push(ch)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -2,8 +2,7 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use flow::{self, Flow};
|
use flow::{self, AFFECTS_COUNTERS, Flow, HAS_COUNTER_AFFECTING_CHILDREN, IS_ABSOLUTELY_POSITIONED};
|
||||||
use flow::{IS_ABSOLUTELY_POSITIONED};
|
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
@ -32,8 +31,12 @@ bitflags! {
|
||||||
#[doc = "top-down."]
|
#[doc = "top-down."]
|
||||||
const REFLOW = 0x08,
|
const REFLOW = 0x08,
|
||||||
|
|
||||||
|
#[doc = "Re-resolve generated content. \
|
||||||
|
Propagates up the flow tree because the computation is inorder."]
|
||||||
|
const RESOLVE_GENERATED_CONTENT = 0x10,
|
||||||
|
|
||||||
#[doc = "The entire flow needs to be reconstructed."]
|
#[doc = "The entire flow needs to be reconstructed."]
|
||||||
const RECONSTRUCT_FLOW = 0x10
|
const RECONSTRUCT_FLOW = 0x20
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,9 +53,9 @@ impl RestyleDamage {
|
||||||
/// we should add to the *parent* of this flow.
|
/// we should add to the *parent* of this flow.
|
||||||
pub fn damage_for_parent(self, child_is_absolutely_positioned: bool) -> RestyleDamage {
|
pub fn damage_for_parent(self, child_is_absolutely_positioned: bool) -> RestyleDamage {
|
||||||
if child_is_absolutely_positioned {
|
if child_is_absolutely_positioned {
|
||||||
self & (REPAINT | REFLOW_OUT_OF_FLOW)
|
self & (REPAINT | REFLOW_OUT_OF_FLOW | RESOLVE_GENERATED_CONTENT)
|
||||||
} else {
|
} else {
|
||||||
self & (REPAINT | REFLOW | REFLOW_OUT_OF_FLOW)
|
self & (REPAINT | REFLOW | REFLOW_OUT_OF_FLOW | RESOLVE_GENERATED_CONTENT)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,10 +94,11 @@ impl fmt::Debug for RestyleDamage {
|
||||||
let mut first_elem = true;
|
let mut first_elem = true;
|
||||||
|
|
||||||
let to_iter =
|
let to_iter =
|
||||||
[ (REPAINT, "Repaint")
|
[ (REPAINT, "Repaint")
|
||||||
, (BUBBLE_ISIZES, "BubbleISizes")
|
, (BUBBLE_ISIZES, "BubbleISizes")
|
||||||
, (REFLOW_OUT_OF_FLOW, "ReflowOutOfFlow")
|
, (REFLOW_OUT_OF_FLOW, "ReflowOutOfFlow")
|
||||||
, (REFLOW, "Reflow")
|
, (REFLOW, "Reflow")
|
||||||
|
, (RESOLVE_GENERATED_CONTENT, "ResolveGeneratedContent")
|
||||||
, (RECONSTRUCT_FLOW, "ReconstructFlow")
|
, (RECONSTRUCT_FLOW, "ReconstructFlow")
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -126,10 +130,18 @@ macro_rules! add_if_not_equal(
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/// Returns a bitmask that represents a flow that needs to be rebuilt and reflowed.
|
||||||
|
///
|
||||||
|
/// Use this instead of `RestyleDamage::all()` because `RestyleDamage::all()` will result in
|
||||||
|
/// unnecessary sequential resolution of generated content.
|
||||||
|
pub fn rebuild_and_reflow() -> RestyleDamage {
|
||||||
|
REPAINT | BUBBLE_ISIZES | REFLOW_OUT_OF_FLOW | REFLOW | RECONSTRUCT_FLOW
|
||||||
|
}
|
||||||
|
|
||||||
pub fn compute_damage(old: &Option<Arc<ComputedValues>>, new: &ComputedValues) -> RestyleDamage {
|
pub fn compute_damage(old: &Option<Arc<ComputedValues>>, new: &ComputedValues) -> RestyleDamage {
|
||||||
let old: &ComputedValues =
|
let old: &ComputedValues =
|
||||||
match old.as_ref() {
|
match old.as_ref() {
|
||||||
None => return RestyleDamage::all(),
|
None => return rebuild_and_reflow(),
|
||||||
Some(cv) => &**cv,
|
Some(cv) => &**cv,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -186,6 +198,9 @@ impl<'a> LayoutDamageComputation for &'a mut (Flow + 'a) {
|
||||||
let mut special_damage = SpecialRestyleDamage::empty();
|
let mut special_damage = SpecialRestyleDamage::empty();
|
||||||
let is_absolutely_positioned = flow::base(self).flags.contains(IS_ABSOLUTELY_POSITIONED);
|
let is_absolutely_positioned = flow::base(self).flags.contains(IS_ABSOLUTELY_POSITIONED);
|
||||||
|
|
||||||
|
// In addition to damage, we use this phase to compute whether nodes affect CSS counters.
|
||||||
|
let mut has_counter_affecting_children = false;
|
||||||
|
|
||||||
{
|
{
|
||||||
let self_base = flow::mut_base(self);
|
let self_base = flow::mut_base(self);
|
||||||
for kid in self_base.children.iter_mut() {
|
for kid in self_base.children.iter_mut() {
|
||||||
|
@ -199,21 +214,32 @@ impl<'a> LayoutDamageComputation for &'a mut (Flow + 'a) {
|
||||||
self_base.restyle_damage
|
self_base.restyle_damage
|
||||||
.insert(flow::base(kid).restyle_damage.damage_for_parent(
|
.insert(flow::base(kid).restyle_damage.damage_for_parent(
|
||||||
child_is_absolutely_positioned));
|
child_is_absolutely_positioned));
|
||||||
|
|
||||||
|
has_counter_affecting_children = has_counter_affecting_children ||
|
||||||
|
flow::base(kid).flags.intersects(AFFECTS_COUNTERS |
|
||||||
|
HAS_COUNTER_AFFECTING_CHILDREN);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let self_base = flow::base(self);
|
let self_base = flow::mut_base(self);
|
||||||
if self_base.flags.float_kind() != float::T::none &&
|
if self_base.flags.float_kind() != float::T::none &&
|
||||||
self_base.restyle_damage.intersects(REFLOW) {
|
self_base.restyle_damage.intersects(REFLOW) {
|
||||||
special_damage.insert(REFLOW_ENTIRE_DOCUMENT);
|
special_damage.insert(REFLOW_ENTIRE_DOCUMENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if has_counter_affecting_children {
|
||||||
|
self_base.flags.insert(HAS_COUNTER_AFFECTING_CHILDREN)
|
||||||
|
} else {
|
||||||
|
self_base.flags.remove(HAS_COUNTER_AFFECTING_CHILDREN)
|
||||||
|
}
|
||||||
|
|
||||||
special_damage
|
special_damage
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reflow_entire_document(self) {
|
fn reflow_entire_document(self) {
|
||||||
let self_base = flow::mut_base(self);
|
let self_base = flow::mut_base(self);
|
||||||
self_base.restyle_damage.insert(RestyleDamage::all());
|
self_base.restyle_damage.insert(rebuild_and_reflow());
|
||||||
self_base.restyle_damage.remove(RECONSTRUCT_FLOW);
|
self_base.restyle_damage.remove(RECONSTRUCT_FLOW);
|
||||||
for kid in self_base.children.iter_mut() {
|
for kid in self_base.children.iter_mut() {
|
||||||
kid.reflow_entire_document();
|
kid.reflow_entire_document();
|
||||||
|
|
|
@ -12,9 +12,8 @@ use flow::{BaseFlow, FlowClass, Flow, MutableFlowUtils, ForceNonfloatedFlag};
|
||||||
use flow::{IS_ABSOLUTELY_POSITIONED};
|
use flow::{IS_ABSOLUTELY_POSITIONED};
|
||||||
use flow;
|
use flow;
|
||||||
use fragment::{CoordinateSystem, Fragment, FragmentBorderBoxIterator, ScannedTextFragmentInfo};
|
use fragment::{CoordinateSystem, Fragment, FragmentBorderBoxIterator, ScannedTextFragmentInfo};
|
||||||
use fragment::{SpecificFragmentInfo};
|
use fragment::{SpecificFragmentInfo, SplitInfo};
|
||||||
use fragment::SplitInfo;
|
use incremental::{REFLOW, REFLOW_OUT_OF_FLOW, RESOLVE_GENERATED_CONTENT};
|
||||||
use incremental::{REFLOW, REFLOW_OUT_OF_FLOW};
|
|
||||||
use layout_debug;
|
use layout_debug;
|
||||||
use model::IntrinsicISizesContribution;
|
use model::IntrinsicISizesContribution;
|
||||||
use text;
|
use text;
|
||||||
|
@ -789,14 +788,22 @@ pub struct InlineFlow {
|
||||||
|
|
||||||
impl InlineFlow {
|
impl InlineFlow {
|
||||||
pub fn from_fragments(fragments: InlineFragments, writing_mode: WritingMode) -> InlineFlow {
|
pub fn from_fragments(fragments: InlineFragments, writing_mode: WritingMode) -> InlineFlow {
|
||||||
InlineFlow {
|
let mut flow = InlineFlow {
|
||||||
base: BaseFlow::new(None, writing_mode, ForceNonfloatedFlag::ForceNonfloated),
|
base: BaseFlow::new(None, writing_mode, ForceNonfloatedFlag::ForceNonfloated),
|
||||||
fragments: fragments,
|
fragments: fragments,
|
||||||
lines: Vec::new(),
|
lines: Vec::new(),
|
||||||
minimum_block_size_above_baseline: Au(0),
|
minimum_block_size_above_baseline: Au(0),
|
||||||
minimum_depth_below_baseline: Au(0),
|
minimum_depth_below_baseline: Au(0),
|
||||||
first_line_indentation: Au(0),
|
first_line_indentation: Au(0),
|
||||||
|
};
|
||||||
|
|
||||||
|
for fragment in flow.fragments.fragments.iter() {
|
||||||
|
if fragment.is_generated_content() {
|
||||||
|
flow.base.restyle_damage.insert(RESOLVE_GENERATED_CONTENT)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
flow
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the distance from the baseline for the logical block-start inline-start corner of
|
/// Returns the distance from the baseline for the logical block-start inline-start corner of
|
||||||
|
@ -1399,6 +1406,12 @@ impl Flow for InlineFlow {
|
||||||
.translate(stacking_context_position))
|
.translate(stacking_context_position))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn mutate_fragments(&mut self, mutator: &mut FnMut(&mut Fragment)) {
|
||||||
|
for fragment in self.fragments.fragments.iter_mut() {
|
||||||
|
(*mutator)(fragment)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for InlineFlow {
|
impl fmt::Debug for InlineFlow {
|
||||||
|
|
|
@ -840,6 +840,14 @@ impl LayoutTask {
|
||||||
layout_debug::begin_trace(layout_root.clone());
|
layout_debug::begin_trace(layout_root.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Resolve generated content.
|
||||||
|
profile(TimeProfilerCategory::LayoutGeneratedContent,
|
||||||
|
self.profiler_metadata(data),
|
||||||
|
self.time_profiler_chan.clone(),
|
||||||
|
|| {
|
||||||
|
sequential::resolve_generated_content(&mut layout_root, &shared_layout_context)
|
||||||
|
});
|
||||||
|
|
||||||
// Perform the primary layout passes over the flow tree to compute the locations of all
|
// Perform the primary layout passes over the flow tree to compute the locations of all
|
||||||
// the boxes.
|
// the boxes.
|
||||||
profile(TimeProfilerCategory::LayoutMain,
|
profile(TimeProfilerCategory::LayoutMain,
|
||||||
|
|
|
@ -67,7 +67,9 @@ pub mod flow;
|
||||||
pub mod flow_list;
|
pub mod flow_list;
|
||||||
pub mod flow_ref;
|
pub mod flow_ref;
|
||||||
pub mod fragment;
|
pub mod fragment;
|
||||||
|
pub mod generated_content;
|
||||||
pub mod layout_task;
|
pub mod layout_task;
|
||||||
|
pub mod incremental;
|
||||||
pub mod inline;
|
pub mod inline;
|
||||||
pub mod list_item;
|
pub mod list_item;
|
||||||
pub mod model;
|
pub mod model;
|
||||||
|
@ -83,7 +85,6 @@ pub mod table_row;
|
||||||
pub mod table_cell;
|
pub mod table_cell;
|
||||||
pub mod text;
|
pub mod text;
|
||||||
pub mod traversal;
|
pub mod traversal;
|
||||||
pub mod incremental;
|
|
||||||
pub mod wrapper;
|
pub mod wrapper;
|
||||||
|
|
||||||
pub mod css {
|
pub mod css {
|
||||||
|
|
|
@ -8,12 +8,13 @@
|
||||||
#![deny(unsafe_blocks)]
|
#![deny(unsafe_blocks)]
|
||||||
|
|
||||||
use block::BlockFlow;
|
use block::BlockFlow;
|
||||||
use construct::FlowConstructor;
|
|
||||||
use context::LayoutContext;
|
use context::LayoutContext;
|
||||||
use display_list_builder::ListItemFlowDisplayListBuilding;
|
use display_list_builder::ListItemFlowDisplayListBuilding;
|
||||||
use floats::FloatKind;
|
use floats::FloatKind;
|
||||||
use flow::{Flow, FlowClass};
|
use flow::{Flow, FlowClass};
|
||||||
use fragment::{Fragment, FragmentBorderBoxIterator};
|
use fragment::{CoordinateSystem, Fragment, FragmentBorderBoxIterator, GeneratedContentInfo};
|
||||||
|
use generated_content;
|
||||||
|
use incremental::RESOLVE_GENERATED_CONTENT;
|
||||||
use wrapper::ThreadSafeLayoutNode;
|
use wrapper::ThreadSafeLayoutNode;
|
||||||
|
|
||||||
use geom::{Point2D, Rect};
|
use geom::{Point2D, Rect};
|
||||||
|
@ -36,19 +37,33 @@ pub struct ListItemFlow {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ListItemFlow {
|
impl ListItemFlow {
|
||||||
pub fn from_node_marker_and_flotation(constructor: &mut FlowConstructor,
|
pub fn from_node_fragments_and_flotation(node: &ThreadSafeLayoutNode,
|
||||||
node: &ThreadSafeLayoutNode,
|
main_fragment: Fragment,
|
||||||
marker_fragment: Option<Fragment>,
|
marker_fragment: Option<Fragment>,
|
||||||
flotation: Option<FloatKind>)
|
flotation: Option<FloatKind>)
|
||||||
-> ListItemFlow {
|
-> ListItemFlow {
|
||||||
ListItemFlow {
|
let mut this = ListItemFlow {
|
||||||
block_flow: if let Some(flotation) = flotation {
|
block_flow: if let Some(flotation) = flotation {
|
||||||
BlockFlow::float_from_node(constructor, node, flotation)
|
BlockFlow::float_from_node_and_fragment(node, main_fragment, flotation)
|
||||||
} else {
|
} else {
|
||||||
BlockFlow::from_node(constructor, node)
|
BlockFlow::from_node_and_fragment(node, main_fragment)
|
||||||
},
|
},
|
||||||
marker: marker_fragment,
|
marker: marker_fragment,
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(ref marker) = this.marker {
|
||||||
|
match marker.style().get_list().list_style_type {
|
||||||
|
list_style_type::T::disc |
|
||||||
|
list_style_type::T::none |
|
||||||
|
list_style_type::T::circle |
|
||||||
|
list_style_type::T::square |
|
||||||
|
list_style_type::T::disclosure_open |
|
||||||
|
list_style_type::T::disclosure_closed => {}
|
||||||
|
_ => this.block_flow.base.restyle_damage.insert(RESOLVE_GENERATED_CONTENT),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,24 +149,59 @@ impl Flow for ListItemFlow {
|
||||||
fn iterate_through_fragment_border_boxes(&self,
|
fn iterate_through_fragment_border_boxes(&self,
|
||||||
iterator: &mut FragmentBorderBoxIterator,
|
iterator: &mut FragmentBorderBoxIterator,
|
||||||
stacking_context_position: &Point2D<Au>) {
|
stacking_context_position: &Point2D<Au>) {
|
||||||
self.block_flow.iterate_through_fragment_border_boxes(iterator, stacking_context_position)
|
self.block_flow.iterate_through_fragment_border_boxes(iterator, stacking_context_position);
|
||||||
|
|
||||||
|
if let Some(ref marker) = self.marker {
|
||||||
|
if iterator.should_process(marker) {
|
||||||
|
iterator.process(
|
||||||
|
marker,
|
||||||
|
&marker.stacking_relative_border_box(&self.block_flow
|
||||||
|
.base
|
||||||
|
.stacking_relative_position,
|
||||||
|
&self.block_flow
|
||||||
|
.base
|
||||||
|
.absolute_position_info
|
||||||
|
.relative_containing_block_size,
|
||||||
|
self.block_flow
|
||||||
|
.base
|
||||||
|
.absolute_position_info
|
||||||
|
.relative_containing_block_mode,
|
||||||
|
CoordinateSystem::Parent)
|
||||||
|
.translate(stacking_context_position));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mutate_fragments(&mut self, mutator: &mut FnMut(&mut Fragment)) {
|
||||||
|
self.block_flow.mutate_fragments(mutator);
|
||||||
|
|
||||||
|
if let Some(ref mut marker) = self.marker {
|
||||||
|
(*mutator)(marker)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the static text to be used for the given value of the `list-style-type` property.
|
/// The kind of content that `list-style-type` results in.
|
||||||
///
|
pub enum ListStyleTypeContent {
|
||||||
/// TODO(pcwalton): Return either a string or a counter descriptor, once we support counters.
|
None,
|
||||||
pub fn static_text_for_list_style_type(list_style_type: list_style_type::T)
|
StaticText(char),
|
||||||
-> Option<&'static str> {
|
GeneratedContent(Box<GeneratedContentInfo>),
|
||||||
// Just to keep things simple, use a nonbreaking space (Unicode 0xa0) to provide the marker
|
}
|
||||||
// separation.
|
|
||||||
match list_style_type {
|
impl ListStyleTypeContent {
|
||||||
list_style_type::T::none => None,
|
/// Returns the content to be used for the given value of the `list-style-type` property.
|
||||||
list_style_type::T::disc => Some("•\u{a0}"),
|
pub fn from_list_style_type(list_style_type: list_style_type::T) -> ListStyleTypeContent {
|
||||||
list_style_type::T::circle => Some("◦\u{a0}"),
|
// Just to keep things simple, use a nonbreaking space (Unicode 0xa0) to provide the marker
|
||||||
list_style_type::T::square => Some("▪\u{a0}"),
|
// separation.
|
||||||
list_style_type::T::disclosure_open => Some("▾\u{a0}"),
|
match list_style_type {
|
||||||
list_style_type::T::disclosure_closed => Some("‣\u{a0}"),
|
list_style_type::T::none => ListStyleTypeContent::None,
|
||||||
|
list_style_type::T::disc | list_style_type::T::circle | list_style_type::T::square |
|
||||||
|
list_style_type::T::disclosure_open | list_style_type::T::disclosure_closed => {
|
||||||
|
let text = generated_content::static_representation(list_style_type);
|
||||||
|
ListStyleTypeContent::StaticText(text)
|
||||||
|
}
|
||||||
|
_ => ListStyleTypeContent::GeneratedContent(box GeneratedContentInfo::ListItem),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,10 +5,11 @@
|
||||||
//! Implements sequential traversals over the DOM and flow trees.
|
//! Implements sequential traversals over the DOM and flow trees.
|
||||||
|
|
||||||
use context::{LayoutContext, SharedLayoutContext};
|
use context::{LayoutContext, SharedLayoutContext};
|
||||||
use flow::{self, Flow, ImmutableFlowUtils, MutableFlowUtils, PostorderFlowTraversal};
|
use flow::{self, Flow, ImmutableFlowUtils, InorderFlowTraversal, MutableFlowUtils};
|
||||||
use flow::{PreorderFlowTraversal};
|
use flow::{PostorderFlowTraversal, PreorderFlowTraversal};
|
||||||
use flow_ref::FlowRef;
|
use flow_ref::FlowRef;
|
||||||
use fragment::FragmentBorderBoxIterator;
|
use fragment::FragmentBorderBoxIterator;
|
||||||
|
use generated_content::ResolveGeneratedContent;
|
||||||
use traversal::{BubbleISizes, RecalcStyleForNode, ConstructFlows};
|
use traversal::{BubbleISizes, RecalcStyleForNode, ConstructFlows};
|
||||||
use traversal::{AssignBSizesAndStoreOverflow, AssignISizes};
|
use traversal::{AssignBSizesAndStoreOverflow, AssignISizes};
|
||||||
use traversal::{ComputeAbsolutePositions, BuildDisplayList};
|
use traversal::{ComputeAbsolutePositions, BuildDisplayList};
|
||||||
|
@ -39,6 +40,24 @@ pub fn traverse_dom_preorder(root: LayoutNode,
|
||||||
doit(root, recalc_style, construct_flows);
|
doit(root, recalc_style, construct_flows);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn resolve_generated_content(root: &mut FlowRef, shared_layout_context: &SharedLayoutContext) {
|
||||||
|
fn doit(flow: &mut Flow, level: u32, traversal: &mut ResolveGeneratedContent) {
|
||||||
|
if !traversal.should_process(flow) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
traversal.process(flow, level);
|
||||||
|
|
||||||
|
for kid in flow::mut_base(flow).children.iter_mut() {
|
||||||
|
doit(kid, level + 1, traversal)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let layout_context = LayoutContext::new(shared_layout_context);
|
||||||
|
let mut traversal = ResolveGeneratedContent::new(&layout_context);
|
||||||
|
doit(&mut **root, 0, &mut traversal)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn traverse_flow_tree_preorder(root: &mut FlowRef,
|
pub fn traverse_flow_tree_preorder(root: &mut FlowRef,
|
||||||
shared_layout_context: &SharedLayoutContext) {
|
shared_layout_context: &SharedLayoutContext) {
|
||||||
fn doit(flow: &mut Flow,
|
fn doit(flow: &mut Flow,
|
||||||
|
|
|
@ -8,7 +8,6 @@
|
||||||
|
|
||||||
use block::{BlockFlow, ISizeAndMarginsComputer, MarginsMayCollapseFlag};
|
use block::{BlockFlow, ISizeAndMarginsComputer, MarginsMayCollapseFlag};
|
||||||
use block::{ISizeConstraintInput, ISizeConstraintSolution};
|
use block::{ISizeConstraintInput, ISizeConstraintSolution};
|
||||||
use construct::FlowConstructor;
|
|
||||||
use context::LayoutContext;
|
use context::LayoutContext;
|
||||||
use floats::FloatKind;
|
use floats::FloatKind;
|
||||||
use flow::{self, Flow, FlowClass, IMPACTED_BY_LEFT_FLOATS, IMPACTED_BY_RIGHT_FLOATS};
|
use flow::{self, Flow, FlowClass, IMPACTED_BY_LEFT_FLOATS, IMPACTED_BY_RIGHT_FLOATS};
|
||||||
|
@ -55,12 +54,12 @@ impl TableFlow {
|
||||||
fragment: Fragment)
|
fragment: Fragment)
|
||||||
-> TableFlow {
|
-> TableFlow {
|
||||||
let mut block_flow = BlockFlow::from_node_and_fragment(node, fragment);
|
let mut block_flow = BlockFlow::from_node_and_fragment(node, fragment);
|
||||||
let table_layout = if block_flow.fragment().style().get_table().table_layout ==
|
let table_layout =
|
||||||
table_layout::T::fixed {
|
if block_flow.fragment().style().get_table().table_layout == table_layout::T::fixed {
|
||||||
TableLayout::Fixed
|
TableLayout::Fixed
|
||||||
} else {
|
} else {
|
||||||
TableLayout::Auto
|
TableLayout::Auto
|
||||||
};
|
};
|
||||||
TableFlow {
|
TableFlow {
|
||||||
block_flow: block_flow,
|
block_flow: block_flow,
|
||||||
column_intrinsic_inline_sizes: Vec::new(),
|
column_intrinsic_inline_sizes: Vec::new(),
|
||||||
|
@ -69,35 +68,17 @@ impl TableFlow {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_node(constructor: &mut FlowConstructor,
|
pub fn float_from_node_and_fragment(node: &ThreadSafeLayoutNode,
|
||||||
node: &ThreadSafeLayoutNode)
|
fragment: Fragment,
|
||||||
-> TableFlow {
|
float_kind: FloatKind)
|
||||||
let mut block_flow = BlockFlow::from_node(constructor, node);
|
-> TableFlow {
|
||||||
let table_layout = if block_flow.fragment().style().get_table().table_layout ==
|
let mut block_flow = BlockFlow::float_from_node_and_fragment(node, fragment, float_kind);
|
||||||
table_layout::T::fixed {
|
let table_layout =
|
||||||
TableLayout::Fixed
|
if block_flow.fragment().style().get_table().table_layout == table_layout::T::fixed {
|
||||||
} else {
|
TableLayout::Fixed
|
||||||
TableLayout::Auto
|
} else {
|
||||||
};
|
TableLayout::Auto
|
||||||
TableFlow {
|
};
|
||||||
block_flow: block_flow,
|
|
||||||
column_intrinsic_inline_sizes: Vec::new(),
|
|
||||||
column_computed_inline_sizes: Vec::new(),
|
|
||||||
table_layout: table_layout
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn float_from_node(constructor: &mut FlowConstructor,
|
|
||||||
node: &ThreadSafeLayoutNode,
|
|
||||||
float_kind: FloatKind)
|
|
||||||
-> TableFlow {
|
|
||||||
let mut block_flow = BlockFlow::float_from_node(constructor, node, float_kind);
|
|
||||||
let table_layout = if block_flow.fragment().style().get_table().table_layout ==
|
|
||||||
table_layout::T::fixed {
|
|
||||||
TableLayout::Fixed
|
|
||||||
} else {
|
|
||||||
TableLayout::Auto
|
|
||||||
};
|
|
||||||
TableFlow {
|
TableFlow {
|
||||||
block_flow: block_flow,
|
block_flow: block_flow,
|
||||||
column_intrinsic_inline_sizes: Vec::new(),
|
column_intrinsic_inline_sizes: Vec::new(),
|
||||||
|
@ -396,6 +377,10 @@ impl Flow for TableFlow {
|
||||||
stacking_context_position: &Point2D<Au>) {
|
stacking_context_position: &Point2D<Au>) {
|
||||||
self.block_flow.iterate_through_fragment_border_boxes(iterator, stacking_context_position)
|
self.block_flow.iterate_through_fragment_border_boxes(iterator, stacking_context_position)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn mutate_fragments(&mut self, mutator: &mut FnMut(&mut Fragment)) {
|
||||||
|
self.block_flow.mutate_fragments(mutator)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for TableFlow {
|
impl fmt::Debug for TableFlow {
|
||||||
|
|
|
@ -7,10 +7,9 @@
|
||||||
#![deny(unsafe_blocks)]
|
#![deny(unsafe_blocks)]
|
||||||
|
|
||||||
use block::BlockFlow;
|
use block::BlockFlow;
|
||||||
use construct::FlowConstructor;
|
|
||||||
use context::LayoutContext;
|
use context::LayoutContext;
|
||||||
use flow::{FlowClass, Flow};
|
use flow::{FlowClass, Flow};
|
||||||
use fragment::FragmentBorderBoxIterator;
|
use fragment::{Fragment, FragmentBorderBoxIterator};
|
||||||
use wrapper::ThreadSafeLayoutNode;
|
use wrapper::ThreadSafeLayoutNode;
|
||||||
|
|
||||||
use geom::{Point2D, Rect};
|
use geom::{Point2D, Rect};
|
||||||
|
@ -26,11 +25,10 @@ pub struct TableCaptionFlow {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TableCaptionFlow {
|
impl TableCaptionFlow {
|
||||||
pub fn from_node(constructor: &mut FlowConstructor,
|
pub fn from_node_and_fragment(node: &ThreadSafeLayoutNode, fragment: Fragment)
|
||||||
node: &ThreadSafeLayoutNode)
|
-> TableCaptionFlow {
|
||||||
-> TableCaptionFlow {
|
|
||||||
TableCaptionFlow {
|
TableCaptionFlow {
|
||||||
block_flow: BlockFlow::from_node(constructor, node)
|
block_flow: BlockFlow::from_node_and_fragment(node, fragment)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -96,6 +94,10 @@ impl Flow for TableCaptionFlow {
|
||||||
stacking_context_position: &Point2D<Au>) {
|
stacking_context_position: &Point2D<Au>) {
|
||||||
self.block_flow.iterate_through_fragment_border_boxes(iterator, stacking_context_position)
|
self.block_flow.iterate_through_fragment_border_boxes(iterator, stacking_context_position)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn mutate_fragments(&mut self, mutator: &mut FnMut(&mut Fragment)) {
|
||||||
|
self.block_flow.mutate_fragments(mutator)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for TableCaptionFlow {
|
impl fmt::Debug for TableCaptionFlow {
|
||||||
|
|
|
@ -178,6 +178,10 @@ impl Flow for TableCellFlow {
|
||||||
stacking_context_position: &Point2D<Au>) {
|
stacking_context_position: &Point2D<Au>) {
|
||||||
self.block_flow.iterate_through_fragment_border_boxes(iterator, stacking_context_position)
|
self.block_flow.iterate_through_fragment_border_boxes(iterator, stacking_context_position)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn mutate_fragments(&mut self, mutator: &mut FnMut(&mut Fragment)) {
|
||||||
|
self.block_flow.mutate_fragments(mutator)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for TableCellFlow {
|
impl fmt::Debug for TableCellFlow {
|
||||||
|
|
|
@ -104,6 +104,8 @@ impl Flow for TableColGroupFlow {
|
||||||
fn iterate_through_fragment_border_boxes(&self,
|
fn iterate_through_fragment_border_boxes(&self,
|
||||||
_: &mut FragmentBorderBoxIterator,
|
_: &mut FragmentBorderBoxIterator,
|
||||||
_: &Point2D<Au>) {}
|
_: &Point2D<Au>) {}
|
||||||
|
|
||||||
|
fn mutate_fragments(&mut self, _: &mut FnMut(&mut Fragment)) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for TableColGroupFlow {
|
impl fmt::Debug for TableColGroupFlow {
|
||||||
|
|
|
@ -8,10 +8,8 @@
|
||||||
|
|
||||||
use block::BlockFlow;
|
use block::BlockFlow;
|
||||||
use block::ISizeAndMarginsComputer;
|
use block::ISizeAndMarginsComputer;
|
||||||
use construct::FlowConstructor;
|
|
||||||
use context::LayoutContext;
|
use context::LayoutContext;
|
||||||
use flow::{FlowClass, Flow, ImmutableFlowUtils};
|
use flow::{self, FlowClass, Flow, ImmutableFlowUtils};
|
||||||
use flow;
|
|
||||||
use fragment::{Fragment, FragmentBorderBoxIterator};
|
use fragment::{Fragment, FragmentBorderBoxIterator};
|
||||||
use layout_debug;
|
use layout_debug;
|
||||||
use table::{ColumnComputedInlineSize, ColumnIntrinsicInlineSize, InternalTable};
|
use table::{ColumnComputedInlineSize, ColumnIntrinsicInlineSize, InternalTable};
|
||||||
|
@ -49,8 +47,7 @@ pub struct CellIntrinsicInlineSize {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TableRowFlow {
|
impl TableRowFlow {
|
||||||
pub fn from_node_and_fragment(node: &ThreadSafeLayoutNode,
|
pub fn from_node_and_fragment(node: &ThreadSafeLayoutNode, fragment: Fragment)
|
||||||
fragment: Fragment)
|
|
||||||
-> TableRowFlow {
|
-> TableRowFlow {
|
||||||
TableRowFlow {
|
TableRowFlow {
|
||||||
block_flow: BlockFlow::from_node_and_fragment(node, fragment),
|
block_flow: BlockFlow::from_node_and_fragment(node, fragment),
|
||||||
|
@ -59,16 +56,6 @@ impl TableRowFlow {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_node(constructor: &mut FlowConstructor,
|
|
||||||
node: &ThreadSafeLayoutNode)
|
|
||||||
-> TableRowFlow {
|
|
||||||
TableRowFlow {
|
|
||||||
block_flow: BlockFlow::from_node(constructor, node),
|
|
||||||
cell_intrinsic_inline_sizes: Vec::new(),
|
|
||||||
column_computed_inline_sizes: Vec::new()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn fragment<'a>(&'a mut self) -> &'a Fragment {
|
pub fn fragment<'a>(&'a mut self) -> &'a Fragment {
|
||||||
&self.block_flow.fragment
|
&self.block_flow.fragment
|
||||||
}
|
}
|
||||||
|
@ -331,6 +318,10 @@ impl Flow for TableRowFlow {
|
||||||
stacking_context_position: &Point2D<Au>) {
|
stacking_context_position: &Point2D<Au>) {
|
||||||
self.block_flow.iterate_through_fragment_border_boxes(iterator, stacking_context_position)
|
self.block_flow.iterate_through_fragment_border_boxes(iterator, stacking_context_position)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn mutate_fragments(&mut self, mutator: &mut FnMut(&mut Fragment)) {
|
||||||
|
self.block_flow.mutate_fragments(mutator)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for TableRowFlow {
|
impl fmt::Debug for TableRowFlow {
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
#![deny(unsafe_blocks)]
|
#![deny(unsafe_blocks)]
|
||||||
|
|
||||||
use block::{BlockFlow, ISizeAndMarginsComputer, MarginsMayCollapseFlag};
|
use block::{BlockFlow, ISizeAndMarginsComputer, MarginsMayCollapseFlag};
|
||||||
use construct::FlowConstructor;
|
|
||||||
use context::LayoutContext;
|
use context::LayoutContext;
|
||||||
use flow::{FlowClass, Flow};
|
use flow::{FlowClass, Flow};
|
||||||
use fragment::{Fragment, FragmentBorderBoxIterator};
|
use fragment::{Fragment, FragmentBorderBoxIterator};
|
||||||
|
@ -45,15 +44,6 @@ impl TableRowGroupFlow {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_node(constructor: &mut FlowConstructor, node: &ThreadSafeLayoutNode)
|
|
||||||
-> TableRowGroupFlow {
|
|
||||||
TableRowGroupFlow {
|
|
||||||
block_flow: BlockFlow::from_node(constructor, node),
|
|
||||||
column_intrinsic_inline_sizes: Vec::new(),
|
|
||||||
column_computed_inline_sizes: Vec::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn fragment<'a>(&'a mut self) -> &'a Fragment {
|
pub fn fragment<'a>(&'a mut self) -> &'a Fragment {
|
||||||
&self.block_flow.fragment
|
&self.block_flow.fragment
|
||||||
}
|
}
|
||||||
|
@ -165,6 +155,10 @@ impl Flow for TableRowGroupFlow {
|
||||||
stacking_context_position: &Point2D<Au>) {
|
stacking_context_position: &Point2D<Au>) {
|
||||||
self.block_flow.iterate_through_fragment_border_boxes(iterator, stacking_context_position)
|
self.block_flow.iterate_through_fragment_border_boxes(iterator, stacking_context_position)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn mutate_fragments(&mut self, mutator: &mut FnMut(&mut Fragment)) {
|
||||||
|
self.block_flow.mutate_fragments(mutator)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for TableRowGroupFlow {
|
impl fmt::Debug for TableRowGroupFlow {
|
||||||
|
|
|
@ -13,8 +13,8 @@
|
||||||
|
|
||||||
#![deny(unsafe_blocks)]
|
#![deny(unsafe_blocks)]
|
||||||
|
|
||||||
use block::{BlockFlow, BlockNonReplaced, FloatNonReplaced, ISizeAndMarginsComputer, MarginsMayCollapseFlag};
|
use block::{BlockFlow, BlockNonReplaced, FloatNonReplaced, ISizeAndMarginsComputer};
|
||||||
use construct::FlowConstructor;
|
use block::{MarginsMayCollapseFlag};
|
||||||
use context::LayoutContext;
|
use context::LayoutContext;
|
||||||
use floats::FloatKind;
|
use floats::FloatKind;
|
||||||
use flow::{FlowClass, Flow, ImmutableFlowUtils};
|
use flow::{FlowClass, Flow, ImmutableFlowUtils};
|
||||||
|
@ -70,23 +70,6 @@ impl TableWrapperFlow {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_node(constructor: &mut FlowConstructor,
|
|
||||||
node: &ThreadSafeLayoutNode)
|
|
||||||
-> TableWrapperFlow {
|
|
||||||
let mut block_flow = BlockFlow::from_node(constructor, node);
|
|
||||||
let table_layout = if block_flow.fragment().style().get_table().table_layout ==
|
|
||||||
table_layout::T::fixed {
|
|
||||||
TableLayout::Fixed
|
|
||||||
} else {
|
|
||||||
TableLayout::Auto
|
|
||||||
};
|
|
||||||
TableWrapperFlow {
|
|
||||||
block_flow: block_flow,
|
|
||||||
column_intrinsic_inline_sizes: vec!(),
|
|
||||||
table_layout: table_layout
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn float_from_node_and_fragment(node: &ThreadSafeLayoutNode,
|
pub fn float_from_node_and_fragment(node: &ThreadSafeLayoutNode,
|
||||||
fragment: Fragment,
|
fragment: Fragment,
|
||||||
float_kind: FloatKind)
|
float_kind: FloatKind)
|
||||||
|
@ -383,6 +366,10 @@ impl Flow for TableWrapperFlow {
|
||||||
stacking_context_position: &Point2D<Au>) {
|
stacking_context_position: &Point2D<Au>) {
|
||||||
self.block_flow.iterate_through_fragment_border_boxes(iterator, stacking_context_position)
|
self.block_flow.iterate_through_fragment_border_boxes(iterator, stacking_context_position)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn mutate_fragments(&mut self, mutator: &mut FnMut(&mut Fragment)) {
|
||||||
|
self.block_flow.mutate_fragments(mutator)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for TableWrapperFlow {
|
impl fmt::Debug for TableWrapperFlow {
|
||||||
|
|
|
@ -13,7 +13,7 @@ use context::LayoutContext;
|
||||||
use flow::{Flow, MutableFlowUtils};
|
use flow::{Flow, MutableFlowUtils};
|
||||||
use flow::{PreorderFlowTraversal, PostorderFlowTraversal};
|
use flow::{PreorderFlowTraversal, PostorderFlowTraversal};
|
||||||
use flow;
|
use flow;
|
||||||
use incremental::{RestyleDamage, BUBBLE_ISIZES, REFLOW, REFLOW_OUT_OF_FLOW};
|
use incremental::{self, BUBBLE_ISIZES, REFLOW, REFLOW_OUT_OF_FLOW, RestyleDamage};
|
||||||
use wrapper::{layout_node_to_unsafe_layout_node, LayoutNode};
|
use wrapper::{layout_node_to_unsafe_layout_node, LayoutNode};
|
||||||
use wrapper::{PostorderNodeMutTraversal, ThreadSafeLayoutNode, UnsafeLayoutNode};
|
use wrapper::{PostorderNodeMutTraversal, ThreadSafeLayoutNode, UnsafeLayoutNode};
|
||||||
use wrapper::{PreorderDomTraversal, PostorderDomTraversal};
|
use wrapper::{PreorderDomTraversal, PostorderDomTraversal};
|
||||||
|
@ -171,7 +171,8 @@ impl<'a> PreorderDomTraversal for RecalcStyleForNode<'a> {
|
||||||
&mut applicable_declarations,
|
&mut applicable_declarations,
|
||||||
&mut shareable);
|
&mut shareable);
|
||||||
} else {
|
} else {
|
||||||
ThreadSafeLayoutNode::new(&node).set_restyle_damage(RestyleDamage::all())
|
ThreadSafeLayoutNode::new(&node).set_restyle_damage(
|
||||||
|
incremental::rebuild_and_reflow())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Perform the CSS cascade.
|
// Perform the CSS cascade.
|
||||||
|
@ -377,3 +378,4 @@ impl<'a> PostorderFlowTraversal for BuildDisplayList<'a> {
|
||||||
flow.build_display_list(self.layout_context);
|
flow.build_display_list(self.layout_context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -67,9 +67,11 @@ use std::marker::ContravariantLifetime;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::sync::mpsc::Sender;
|
use std::sync::mpsc::Sender;
|
||||||
use string_cache::{Atom, Namespace};
|
use string_cache::{Atom, Namespace};
|
||||||
|
use style::computed_values::content::ContentItem;
|
||||||
use style::computed_values::{content, display, white_space};
|
use style::computed_values::{content, display, white_space};
|
||||||
use selectors::parser::{NamespaceConstraint, AttrSelector};
|
use selectors::parser::{NamespaceConstraint, AttrSelector};
|
||||||
use style::legacy::{LengthAttribute, SimpleColorAttribute, UnsignedIntegerAttribute, IntegerAttribute};
|
use style::legacy::{IntegerAttribute, LengthAttribute, SimpleColorAttribute};
|
||||||
|
use style::legacy::{UnsignedIntegerAttribute};
|
||||||
use style::node::{TElement, TElementAttributes, TNode};
|
use style::node::{TElement, TElementAttributes, TNode};
|
||||||
use style::properties::PropertyDeclarationBlock;
|
use style::properties::PropertyDeclarationBlock;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
@ -154,10 +156,11 @@ pub trait TLayoutNode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If this is a text node, copies out the text. If this is not a text node, fails.
|
/// If this is a text node or generated content, copies out its content. If this is not a text
|
||||||
|
/// node, fails.
|
||||||
///
|
///
|
||||||
/// FIXME(pcwalton): Don't copy text. Atomically reference count instead.
|
/// FIXME(pcwalton): This might have too much copying and/or allocation. Profile this.
|
||||||
fn text(&self) -> String;
|
fn text_content(&self) -> Vec<ContentItem>;
|
||||||
|
|
||||||
/// Returns the first child of this node.
|
/// Returns the first child of this node.
|
||||||
fn first_child(&self) -> Option<Self>;
|
fn first_child(&self) -> Option<Self>;
|
||||||
|
@ -214,19 +217,25 @@ impl<'ln> TLayoutNode for LayoutNode<'ln> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn text(&self) -> String {
|
fn text_content(&self) -> Vec<ContentItem> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let text: Option<LayoutJS<Text>> = TextCast::to_layout_js(self.get_jsmanaged());
|
let text: Option<LayoutJS<Text>> = TextCast::to_layout_js(self.get_jsmanaged());
|
||||||
if let Some(text) = text {
|
if let Some(text) = text {
|
||||||
return (*text.unsafe_get()).characterdata().data_for_layout().to_owned();
|
return vec![
|
||||||
|
ContentItem::String((*text.unsafe_get()).characterdata()
|
||||||
|
.data_for_layout()
|
||||||
|
.to_owned())
|
||||||
|
];
|
||||||
}
|
}
|
||||||
let input: Option<LayoutJS<HTMLInputElement>> = HTMLInputElementCast::to_layout_js(self.get_jsmanaged());
|
let input: Option<LayoutJS<HTMLInputElement>> =
|
||||||
|
HTMLInputElementCast::to_layout_js(self.get_jsmanaged());
|
||||||
if let Some(input) = input {
|
if let Some(input) = input {
|
||||||
return input.get_value_for_layout();
|
return vec![ContentItem::String(input.get_value_for_layout())];
|
||||||
}
|
}
|
||||||
let area: Option<LayoutJS<HTMLTextAreaElement>> = HTMLTextAreaElementCast::to_layout_js(self.get_jsmanaged());
|
let area: Option<LayoutJS<HTMLTextAreaElement>> =
|
||||||
|
HTMLTextAreaElementCast::to_layout_js(self.get_jsmanaged());
|
||||||
if let Some(area) = area {
|
if let Some(area) = area {
|
||||||
return area.get_value_for_layout();
|
return vec![ContentItem::String(area.get_value_for_layout())];
|
||||||
}
|
}
|
||||||
|
|
||||||
panic!("not text!")
|
panic!("not text!")
|
||||||
|
@ -661,16 +670,10 @@ impl<'le> TElementAttributes for LayoutElement<'le> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_content(content_list: &content::T) -> String {
|
fn get_content(content_list: &content::T) -> Vec<ContentItem> {
|
||||||
match *content_list {
|
match *content_list {
|
||||||
content::T::Content(ref value) => {
|
content::T::Content(ref value) if !value.is_empty() => (*value).clone(),
|
||||||
let iter = &mut value.clone().into_iter().peekable();
|
_ => vec![],
|
||||||
match iter.next() {
|
|
||||||
Some(content::ContentItem::StringContent(content)) => content,
|
|
||||||
_ => "".to_owned(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => "".to_owned(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -762,7 +765,7 @@ impl<'ln> TLayoutNode for ThreadSafeLayoutNode<'ln> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn text(&self) -> String {
|
fn text_content(&self) -> Vec<ContentItem> {
|
||||||
if self.pseudo != PseudoElementType::Normal {
|
if self.pseudo != PseudoElementType::Normal {
|
||||||
let layout_data_ref = self.borrow_layout_data();
|
let layout_data_ref = self.borrow_layout_data();
|
||||||
let node_layout_data_wrapper = layout_data_ref.as_ref().unwrap();
|
let node_layout_data_wrapper = layout_data_ref.as_ref().unwrap();
|
||||||
|
@ -775,7 +778,7 @@ impl<'ln> TLayoutNode for ThreadSafeLayoutNode<'ln> {
|
||||||
return get_content(&after_style.get_box().content)
|
return get_content(&after_style.get_box().content)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.node.text()
|
self.node.text_content()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -103,6 +103,11 @@ partial interface CSSStyleDeclaration {
|
||||||
[TreatNullAs=EmptyString] attribute DOMString listStyleType;
|
[TreatNullAs=EmptyString] attribute DOMString listStyleType;
|
||||||
[TreatNullAs=EmptyString] attribute DOMString listStyleImage;
|
[TreatNullAs=EmptyString] attribute DOMString listStyleImage;
|
||||||
|
|
||||||
|
[TreatNullAs=EmptyString] attribute DOMString quotes;
|
||||||
|
|
||||||
|
[TreatNullAs=EmptyString] attribute DOMString counterIncrement;
|
||||||
|
[TreatNullAs=EmptyString] attribute DOMString counterReset;
|
||||||
|
|
||||||
[TreatNullAs=EmptyString] attribute DOMString overflow;
|
[TreatNullAs=EmptyString] attribute DOMString overflow;
|
||||||
[TreatNullAs=EmptyString] attribute DOMString overflowX;
|
[TreatNullAs=EmptyString] attribute DOMString overflowX;
|
||||||
[TreatNullAs=EmptyString] attribute DOMString overflowY;
|
[TreatNullAs=EmptyString] attribute DOMString overflowY;
|
||||||
|
|
2
components/servo/Cargo.lock
generated
2
components/servo/Cargo.lock
generated
|
@ -763,7 +763,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "selectors"
|
name = "selectors"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/servo/rust-selectors#1e5bbf16eee3adeec1e911c7eaa8f2be02cd4c67"
|
source = "git+https://github.com/servo/rust-selectors#2a492d522ef596a05c3677bb74bf8a5b73d01855"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bitflags 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"cssparser 0.2.0 (git+https://github.com/servo/rust-cssparser)",
|
"cssparser 0.2.0 (git+https://github.com/servo/rust-cssparser)",
|
||||||
|
|
|
@ -759,86 +759,166 @@ pub mod longhands {
|
||||||
${switch_to_style_struct("Box")}
|
${switch_to_style_struct("Box")}
|
||||||
|
|
||||||
<%self:longhand name="content">
|
<%self:longhand name="content">
|
||||||
pub use self::computed_value::T as SpecifiedValue;
|
use cssparser::Token;
|
||||||
pub use self::computed_value::ContentItem;
|
use std::ascii::AsciiExt;
|
||||||
use cssparser::Token;
|
use values::computed::ComputedValueAsSpecified;
|
||||||
use values::computed::ComputedValueAsSpecified;
|
|
||||||
|
|
||||||
impl ComputedValueAsSpecified for SpecifiedValue {}
|
use super::list_style_type;
|
||||||
|
|
||||||
pub mod computed_value {
|
pub use self::computed_value::T as SpecifiedValue;
|
||||||
use std::borrow::IntoCow;
|
pub use self::computed_value::ContentItem;
|
||||||
use cssparser::{ToCss, Token};
|
|
||||||
use text_writer::{self, TextWriter};
|
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Clone)]
|
impl ComputedValueAsSpecified for SpecifiedValue {}
|
||||||
pub enum ContentItem {
|
|
||||||
StringContent(String),
|
pub mod computed_value {
|
||||||
|
use super::super::list_style_type;
|
||||||
|
|
||||||
|
use cssparser::{self, ToCss};
|
||||||
|
use text_writer::{self, TextWriter};
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq, Clone)]
|
||||||
|
pub enum ContentItem {
|
||||||
|
/// Literal string content.
|
||||||
|
String(String),
|
||||||
|
/// `counter(name, style)`.
|
||||||
|
Counter(String, list_style_type::computed_value::T),
|
||||||
|
/// `counters(name, separator, style)`.
|
||||||
|
Counters(String, String, list_style_type::computed_value::T),
|
||||||
|
/// `open-quote`.
|
||||||
|
OpenQuote,
|
||||||
|
/// `close-quote`.
|
||||||
|
CloseQuote,
|
||||||
|
/// `no-open-quote`.
|
||||||
|
NoOpenQuote,
|
||||||
|
/// `no-close-quote`.
|
||||||
|
NoCloseQuote,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToCss for ContentItem {
|
||||||
|
fn to_css<W>(&self, dest: &mut W) -> text_writer::Result where W: TextWriter {
|
||||||
|
match self {
|
||||||
|
&ContentItem::String(ref s) => {
|
||||||
|
cssparser::serialize_string(&**s, dest)
|
||||||
|
}
|
||||||
|
&ContentItem::Counter(ref s, ref list_style_type) => {
|
||||||
|
try!(dest.write_str("counter("));
|
||||||
|
try!(cssparser::serialize_identifier(&**s, dest));
|
||||||
|
try!(dest.write_str(", "));
|
||||||
|
try!(list_style_type.to_css(dest));
|
||||||
|
dest.write_str(")")
|
||||||
|
}
|
||||||
|
&ContentItem::Counters(ref s, ref separator, ref list_style_type) => {
|
||||||
|
try!(dest.write_str("counter("));
|
||||||
|
try!(cssparser::serialize_identifier(&**s, dest));
|
||||||
|
try!(dest.write_str(", "));
|
||||||
|
try!(cssparser::serialize_string(&**separator, dest));
|
||||||
|
try!(dest.write_str(", "));
|
||||||
|
try!(list_style_type.to_css(dest));
|
||||||
|
dest.write_str(")")
|
||||||
|
}
|
||||||
|
&ContentItem::OpenQuote => dest.write_str("open-quote"),
|
||||||
|
&ContentItem::CloseQuote => dest.write_str("close-quote"),
|
||||||
|
&ContentItem::NoOpenQuote => dest.write_str("no-open-quote"),
|
||||||
|
&ContentItem::NoCloseQuote => dest.write_str("no-close-quote"),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl ToCss for ContentItem {
|
#[allow(non_camel_case_types)]
|
||||||
fn to_css<W>(&self, dest: &mut W) -> text_writer::Result where W: TextWriter {
|
#[derive(PartialEq, Eq, Clone)]
|
||||||
match self {
|
pub enum T {
|
||||||
&ContentItem::StringContent(ref s) => {
|
normal,
|
||||||
Token::QuotedString((&**s).into_cow()).to_css(dest)
|
none,
|
||||||
}
|
Content(Vec<ContentItem>),
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
impl ToCss for T {
|
||||||
|
fn to_css<W>(&self, dest: &mut W) -> text_writer::Result where W: TextWriter {
|
||||||
#[allow(non_camel_case_types)]
|
match self {
|
||||||
#[derive(PartialEq, Eq, Clone)]
|
&T::normal => dest.write_str("normal"),
|
||||||
pub enum T {
|
&T::none => dest.write_str("none"),
|
||||||
normal,
|
&T::Content(ref content) => {
|
||||||
none,
|
let mut iter = content.iter();
|
||||||
Content(Vec<ContentItem>),
|
try!(iter.next().unwrap().to_css(dest));
|
||||||
}
|
for c in iter {
|
||||||
|
try!(dest.write_str(" "));
|
||||||
impl ToCss for T {
|
try!(c.to_css(dest));
|
||||||
fn to_css<W>(&self, dest: &mut W) -> text_writer::Result where W: TextWriter {
|
|
||||||
match self {
|
|
||||||
&T::normal => dest.write_str("normal"),
|
|
||||||
&T::none => dest.write_str("none"),
|
|
||||||
&T::Content(ref content) => {
|
|
||||||
let mut iter = content.iter();
|
|
||||||
try!(iter.next().unwrap().to_css(dest));
|
|
||||||
for c in iter {
|
|
||||||
try!(c.to_css(dest));
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[inline]
|
}
|
||||||
pub fn get_initial_value() -> computed_value::T {
|
#[inline]
|
||||||
computed_value::T::normal
|
pub fn get_initial_value() -> computed_value::T {
|
||||||
}
|
computed_value::T::normal
|
||||||
|
}
|
||||||
|
|
||||||
// normal | none | [ <string> ]+
|
pub fn counter_name_is_illegal(name: &str) -> bool {
|
||||||
// TODO: <uri>, <counter>, attr(<identifier>), open-quote, close-quote, no-open-quote, no-close-quote
|
name.eq_ignore_ascii_case("none") || name.eq_ignore_ascii_case("inherit") ||
|
||||||
pub fn parse(_context: &ParserContext, input: &mut Parser)
|
name.eq_ignore_ascii_case("initial")
|
||||||
-> Result<SpecifiedValue, ()> {
|
}
|
||||||
if input.try(|input| input.expect_ident_matching("normal")).is_ok() {
|
|
||||||
return Ok(SpecifiedValue::normal)
|
// normal | none | [ <string> | <counter> | open-quote | close-quote | no-open-quote |
|
||||||
}
|
// no-close-quote ]+
|
||||||
if input.try(|input| input.expect_ident_matching("none")).is_ok() {
|
// TODO: <uri>, attr(<identifier>)
|
||||||
return Ok(SpecifiedValue::none)
|
pub fn parse(context: &ParserContext, input: &mut Parser)
|
||||||
}
|
-> Result<SpecifiedValue, ()> {
|
||||||
let mut content = vec![];
|
if input.try(|input| input.expect_ident_matching("normal")).is_ok() {
|
||||||
loop {
|
return Ok(SpecifiedValue::normal)
|
||||||
match input.next() {
|
}
|
||||||
Ok(Token::QuotedString(value)) => {
|
if input.try(|input| input.expect_ident_matching("none")).is_ok() {
|
||||||
content.push(ContentItem::StringContent(value.into_owned()))
|
return Ok(SpecifiedValue::none)
|
||||||
}
|
}
|
||||||
Err(()) if !content.is_empty() => {
|
let mut content = vec![];
|
||||||
return Ok(SpecifiedValue::Content(content))
|
loop {
|
||||||
}
|
match input.next() {
|
||||||
_ => return Err(())
|
Ok(Token::QuotedString(value)) => {
|
||||||
|
content.push(ContentItem::String(value.into_owned()))
|
||||||
}
|
}
|
||||||
|
Ok(Token::Function(name)) => {
|
||||||
|
content.push(try!(match_ignore_ascii_case! { name,
|
||||||
|
"counter" => input.parse_nested_block(|input| {
|
||||||
|
let name = try!(input.expect_ident()).into_owned();
|
||||||
|
let style = input.try(|input| {
|
||||||
|
try!(input.expect_comma());
|
||||||
|
list_style_type::parse(context, input)
|
||||||
|
}).unwrap_or(list_style_type::computed_value::T::decimal);
|
||||||
|
Ok(ContentItem::Counter(name, style))
|
||||||
|
}),
|
||||||
|
"counters" => input.parse_nested_block(|input| {
|
||||||
|
let name = try!(input.expect_ident()).into_owned();
|
||||||
|
try!(input.expect_comma());
|
||||||
|
let separator = try!(input.expect_string()).into_owned();
|
||||||
|
let style = input.try(|input| {
|
||||||
|
try!(input.expect_comma());
|
||||||
|
list_style_type::parse(context, input)
|
||||||
|
}).unwrap_or(list_style_type::computed_value::T::decimal);
|
||||||
|
Ok(ContentItem::Counters(name, separator, style))
|
||||||
|
})
|
||||||
|
_ => return Err(())
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
Ok(Token::Ident(ident)) => {
|
||||||
|
match_ignore_ascii_case! { ident,
|
||||||
|
"open-quote" => content.push(ContentItem::OpenQuote),
|
||||||
|
"close-quote" => content.push(ContentItem::CloseQuote),
|
||||||
|
"no-open-quote" => content.push(ContentItem::NoOpenQuote),
|
||||||
|
"no-close-quote" => content.push(ContentItem::NoCloseQuote)
|
||||||
|
_ => return Err(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(_) => break,
|
||||||
|
_ => return Err(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if !content.is_empty() {
|
||||||
|
Ok(SpecifiedValue::Content(content))
|
||||||
|
} else {
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
}
|
||||||
</%self:longhand>
|
</%self:longhand>
|
||||||
|
|
||||||
${new_style_struct("List", is_inherited=True)}
|
${new_style_struct("List", is_inherited=True)}
|
||||||
|
@ -847,14 +927,16 @@ pub mod longhands {
|
||||||
|
|
||||||
// TODO(pcwalton): Implement the full set of counter styles per CSS-COUNTER-STYLES [1] 6.1:
|
// TODO(pcwalton): Implement the full set of counter styles per CSS-COUNTER-STYLES [1] 6.1:
|
||||||
//
|
//
|
||||||
// decimal, decimal-leading-zero, arabic-indic, armenian, upper-armenian, lower-armenian,
|
// decimal-leading-zero, armenian, upper-armenian, lower-armenian, georgian, lower-roman,
|
||||||
// bengali, cambodian, khmer, cjk-decimal, devanagiri, georgian, gujarati, gurmukhi,
|
// upper-roman
|
||||||
// hebrew, kannada, lao, malayalam, mongolian, myanmar, oriya, persian, lower-roman,
|
|
||||||
// upper-roman, telugu, thai, tibetan
|
|
||||||
//
|
//
|
||||||
// [1]: http://dev.w3.org/csswg/css-counter-styles/
|
// [1]: http://dev.w3.org/csswg/css-counter-styles/
|
||||||
${single_keyword("list-style-type",
|
${single_keyword("list-style-type", """
|
||||||
"disc none circle square disclosure-open disclosure-closed")}
|
disc none circle square decimal arabic-indic bengali cambodian cjk-decimal devanagari
|
||||||
|
gujarati gurmukhi kannada khmer lao malayalam mongolian myanmar oriya persian telugu thai
|
||||||
|
tibetan lower-alpha upper-alpha cjk-earthly-branch cjk-heavenly-stem lower-greek hiragana
|
||||||
|
hiragana-iroha katakana katakana-iroha disclosure-open disclosure-closed
|
||||||
|
""")}
|
||||||
|
|
||||||
<%self:longhand name="list-style-image">
|
<%self:longhand name="list-style-image">
|
||||||
use std::borrow::IntoCow;
|
use std::borrow::IntoCow;
|
||||||
|
@ -910,6 +992,143 @@ pub mod longhands {
|
||||||
}
|
}
|
||||||
</%self:longhand>
|
</%self:longhand>
|
||||||
|
|
||||||
|
<%self:longhand name="quotes">
|
||||||
|
use text_writer::{self, TextWriter};
|
||||||
|
use values::computed::ComputedValueAsSpecified;
|
||||||
|
|
||||||
|
use cssparser::{ToCss, Token};
|
||||||
|
use std::borrow::IntoCow;
|
||||||
|
|
||||||
|
pub use self::computed_value::T as SpecifiedValue;
|
||||||
|
|
||||||
|
pub mod computed_value {
|
||||||
|
#[derive(Clone, PartialEq)]
|
||||||
|
pub struct T(pub Vec<(String,String)>);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ComputedValueAsSpecified for SpecifiedValue {}
|
||||||
|
|
||||||
|
impl ToCss for SpecifiedValue {
|
||||||
|
fn to_css<W>(&self, dest: &mut W) -> text_writer::Result where W: TextWriter {
|
||||||
|
let mut first = true;
|
||||||
|
for pair in self.0.iter() {
|
||||||
|
if !first {
|
||||||
|
try!(dest.write_str(" "));
|
||||||
|
}
|
||||||
|
first = false;
|
||||||
|
try!(Token::QuotedString(pair.0.as_slice().into_cow()).to_css(dest));
|
||||||
|
try!(dest.write_str(" "));
|
||||||
|
try!(Token::QuotedString(pair.1.as_slice().into_cow()).to_css(dest));
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn get_initial_value() -> computed_value::T {
|
||||||
|
computed_value::T(vec![
|
||||||
|
("\u{201c}".to_string(), "\u{201d}".to_string()),
|
||||||
|
("\u{2018}".to_string(), "\u{2019}".to_string()),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse(_: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue,()> {
|
||||||
|
if input.try(|input| input.expect_ident_matching("none")).is_ok() {
|
||||||
|
return Ok(SpecifiedValue(Vec::new()))
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut quotes = Vec::new();
|
||||||
|
loop {
|
||||||
|
let first = match input.next() {
|
||||||
|
Ok(Token::QuotedString(value)) => value.into_owned(),
|
||||||
|
Ok(_) => return Err(()),
|
||||||
|
Err(()) => break,
|
||||||
|
};
|
||||||
|
let second = match input.next() {
|
||||||
|
Ok(Token::QuotedString(value)) => value.into_owned(),
|
||||||
|
_ => return Err(()),
|
||||||
|
};
|
||||||
|
quotes.push((first, second))
|
||||||
|
}
|
||||||
|
if !quotes.is_empty() {
|
||||||
|
Ok(SpecifiedValue(quotes))
|
||||||
|
} else {
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</%self:longhand>
|
||||||
|
|
||||||
|
${new_style_struct("Counters", is_inherited=False)}
|
||||||
|
|
||||||
|
<%self:longhand name="counter-increment">
|
||||||
|
use super::content;
|
||||||
|
use text_writer::{self, TextWriter};
|
||||||
|
use values::computed::ComputedValueAsSpecified;
|
||||||
|
|
||||||
|
use cssparser::{ToCss, Token};
|
||||||
|
use std::borrow::{IntoCow, ToOwned};
|
||||||
|
|
||||||
|
pub use self::computed_value::T as SpecifiedValue;
|
||||||
|
|
||||||
|
pub mod computed_value {
|
||||||
|
#[derive(Clone, PartialEq)]
|
||||||
|
pub struct T(pub Vec<(String,i32)>);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn get_initial_value() -> computed_value::T {
|
||||||
|
computed_value::T(Vec::new())
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ComputedValueAsSpecified for SpecifiedValue {}
|
||||||
|
|
||||||
|
impl ToCss for SpecifiedValue {
|
||||||
|
fn to_css<W>(&self, dest: &mut W) -> text_writer::Result where W: TextWriter {
|
||||||
|
let mut first = true;
|
||||||
|
for pair in self.0.iter() {
|
||||||
|
if !first {
|
||||||
|
try!(dest.write_str(" "));
|
||||||
|
}
|
||||||
|
first = false;
|
||||||
|
try!(Token::QuotedString(pair.0.as_slice().into_cow()).to_css(dest));
|
||||||
|
try!(dest.write_str(format!(" {}", pair.1).as_slice()));
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse(_: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue,()> {
|
||||||
|
if input.try(|input| input.expect_ident_matching("none")).is_ok() {
|
||||||
|
return Ok(SpecifiedValue(Vec::new()))
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut counters = Vec::new();
|
||||||
|
loop {
|
||||||
|
let counter_name = match input.next() {
|
||||||
|
Ok(Token::Ident(ident)) => (*ident).to_owned(),
|
||||||
|
Ok(_) => return Err(()),
|
||||||
|
Err(_) => break,
|
||||||
|
};
|
||||||
|
if content::counter_name_is_illegal(counter_name.as_slice()) {
|
||||||
|
return Err(())
|
||||||
|
}
|
||||||
|
let counter_delta = input.try(|input| input.expect_integer()).unwrap_or(1) as i32;
|
||||||
|
counters.push((counter_name, counter_delta))
|
||||||
|
}
|
||||||
|
|
||||||
|
if !counters.is_empty() {
|
||||||
|
Ok(SpecifiedValue(counters))
|
||||||
|
} else {
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</%self:longhand>
|
||||||
|
|
||||||
|
<%self:longhand name="counter-reset">
|
||||||
|
pub use super::counter_increment::{SpecifiedValue, computed_value, get_initial_value};
|
||||||
|
pub use super::counter_increment::{parse};
|
||||||
|
</%self:longhand>
|
||||||
|
|
||||||
// CSS 2.1, Section 13 - Paged media
|
// CSS 2.1, Section 13 - Paged media
|
||||||
|
|
||||||
// CSS 2.1, Section 14 - Colors and Backgrounds
|
// CSS 2.1, Section 14 - Colors and Backgrounds
|
||||||
|
|
|
@ -81,6 +81,7 @@ pub enum TimeProfilerCategory {
|
||||||
LayoutSelectorMatch,
|
LayoutSelectorMatch,
|
||||||
LayoutTreeBuilder,
|
LayoutTreeBuilder,
|
||||||
LayoutDamagePropagate,
|
LayoutDamagePropagate,
|
||||||
|
LayoutGeneratedContent,
|
||||||
LayoutMain,
|
LayoutMain,
|
||||||
LayoutParallelWarmup,
|
LayoutParallelWarmup,
|
||||||
LayoutShaping,
|
LayoutShaping,
|
||||||
|
@ -99,6 +100,7 @@ impl Formatable for TimeProfilerCategory {
|
||||||
TimeProfilerCategory::LayoutStyleRecalc |
|
TimeProfilerCategory::LayoutStyleRecalc |
|
||||||
TimeProfilerCategory::LayoutRestyleDamagePropagation |
|
TimeProfilerCategory::LayoutRestyleDamagePropagation |
|
||||||
TimeProfilerCategory::LayoutNonIncrementalReset |
|
TimeProfilerCategory::LayoutNonIncrementalReset |
|
||||||
|
TimeProfilerCategory::LayoutGeneratedContent |
|
||||||
TimeProfilerCategory::LayoutMain |
|
TimeProfilerCategory::LayoutMain |
|
||||||
TimeProfilerCategory::LayoutDispListBuild |
|
TimeProfilerCategory::LayoutDispListBuild |
|
||||||
TimeProfilerCategory::LayoutShaping |
|
TimeProfilerCategory::LayoutShaping |
|
||||||
|
@ -119,6 +121,7 @@ impl Formatable for TimeProfilerCategory {
|
||||||
TimeProfilerCategory::LayoutSelectorMatch => "Selector Matching",
|
TimeProfilerCategory::LayoutSelectorMatch => "Selector Matching",
|
||||||
TimeProfilerCategory::LayoutTreeBuilder => "Tree Building",
|
TimeProfilerCategory::LayoutTreeBuilder => "Tree Building",
|
||||||
TimeProfilerCategory::LayoutDamagePropagate => "Damage Propagation",
|
TimeProfilerCategory::LayoutDamagePropagate => "Damage Propagation",
|
||||||
|
TimeProfilerCategory::LayoutGeneratedContent => "Generated Content Resolution",
|
||||||
TimeProfilerCategory::LayoutMain => "Primary Layout Pass",
|
TimeProfilerCategory::LayoutMain => "Primary Layout Pass",
|
||||||
TimeProfilerCategory::LayoutParallelWarmup => "Parallel Warmup",
|
TimeProfilerCategory::LayoutParallelWarmup => "Parallel Warmup",
|
||||||
TimeProfilerCategory::LayoutShaping => "Shaping",
|
TimeProfilerCategory::LayoutShaping => "Shaping",
|
||||||
|
|
2
ports/cef/Cargo.lock
generated
2
ports/cef/Cargo.lock
generated
|
@ -771,7 +771,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "selectors"
|
name = "selectors"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/servo/rust-selectors#1e5bbf16eee3adeec1e911c7eaa8f2be02cd4c67"
|
source = "git+https://github.com/servo/rust-selectors#2a492d522ef596a05c3677bb74bf8a5b73d01855"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bitflags 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"cssparser 0.2.0 (git+https://github.com/servo/rust-cssparser)",
|
"cssparser 0.2.0 (git+https://github.com/servo/rust-cssparser)",
|
||||||
|
|
2
ports/gonk/Cargo.lock
generated
2
ports/gonk/Cargo.lock
generated
|
@ -682,7 +682,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "selectors"
|
name = "selectors"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/servo/rust-selectors#1e5bbf16eee3adeec1e911c7eaa8f2be02cd4c67"
|
source = "git+https://github.com/servo/rust-selectors#2a492d522ef596a05c3677bb74bf8a5b73d01855"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bitflags 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"cssparser 0.2.0 (git+https://github.com/servo/rust-cssparser)",
|
"cssparser 0.2.0 (git+https://github.com/servo/rust-cssparser)",
|
||||||
|
|
|
@ -65,6 +65,8 @@ flaky_cpu == append_style_a.html append_style_b.html
|
||||||
== case-insensitive-font-family.html case-insensitive-font-family-ref.html
|
== case-insensitive-font-family.html case-insensitive-font-family-ref.html
|
||||||
== clear_generated_content_table_a.html clear_generated_content_table_ref.html
|
== clear_generated_content_table_a.html clear_generated_content_table_ref.html
|
||||||
== clip_a.html clip_ref.html
|
== clip_a.html clip_ref.html
|
||||||
|
== counters_nested_a.html counters_nested_ref.html
|
||||||
|
== counters_simple_a.html counters_simple_ref.html
|
||||||
== data_img_a.html data_img_b.html
|
== data_img_a.html data_img_b.html
|
||||||
== empty_cells_a.html empty_cells_ref.html
|
== empty_cells_a.html empty_cells_ref.html
|
||||||
== filter_opacity_a.html filter_opacity_ref.html
|
== filter_opacity_a.html filter_opacity_ref.html
|
||||||
|
@ -177,6 +179,9 @@ flaky_cpu == linebreak_simple_a.html linebreak_simple_b.html
|
||||||
== nth_last_of_type_pseudo_a.html nth_last_of_type_pseudo_b.html
|
== nth_last_of_type_pseudo_a.html nth_last_of_type_pseudo_b.html
|
||||||
== nth_of_type_pseudo_a.html nth_of_type_pseudo_b.html
|
== nth_of_type_pseudo_a.html nth_of_type_pseudo_b.html
|
||||||
== object_element_a.html object_element_b.html
|
== object_element_a.html object_element_b.html
|
||||||
|
== ol_japanese_iroha_a.html ol_japanese_iroha_ref.html
|
||||||
|
!= ol_japanese_iroha_bullet_styles.html ol_japanese_iroha_ref.html
|
||||||
|
== ol_simple_a.html ol_simple_ref.html
|
||||||
== only_child_pseudo_a.html only_child_pseudo_b.html
|
== only_child_pseudo_a.html only_child_pseudo_b.html
|
||||||
== only_of_type_pseudo_a.html only_of_type_pseudo_b.html
|
== only_of_type_pseudo_a.html only_of_type_pseudo_b.html
|
||||||
== opacity_simple_a.html opacity_simple_ref.html
|
== opacity_simple_a.html opacity_simple_ref.html
|
||||||
|
@ -220,6 +225,7 @@ experimental != overconstrained_block.html overconstrained_block_ref.html
|
||||||
== pre_ignorable_whitespace_a.html pre_ignorable_whitespace_ref.html
|
== pre_ignorable_whitespace_a.html pre_ignorable_whitespace_ref.html
|
||||||
== pseudo_element_a.html pseudo_element_b.html
|
== pseudo_element_a.html pseudo_element_b.html
|
||||||
== pseudo_inherit.html pseudo_inherit_ref.html
|
== pseudo_inherit.html pseudo_inherit_ref.html
|
||||||
|
== quotes_simple_a.html quotes_simple_ref.html
|
||||||
== root_height_a.html root_height_b.html
|
== root_height_a.html root_height_b.html
|
||||||
== root_margin_collapse_a.html root_margin_collapse_b.html
|
== root_margin_collapse_a.html root_margin_collapse_b.html
|
||||||
== root_pseudo_a.html root_pseudo_b.html
|
== root_pseudo_a.html root_pseudo_b.html
|
||||||
|
|
36
tests/ref/counters_nested_a.html
Normal file
36
tests/ref/counters_nested_a.html
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<!-- Tests that `counters` works with nested counters. -->
|
||||||
|
<style>
|
||||||
|
section {
|
||||||
|
counter-reset: section 0;
|
||||||
|
}
|
||||||
|
h1, h2, h3 {
|
||||||
|
counter-increment: section 1;
|
||||||
|
font-size: 24px;
|
||||||
|
}
|
||||||
|
h1:before, h2:before, h3:before {
|
||||||
|
content: counters(section, ".") ". ";
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<section>
|
||||||
|
<h1>Foo</h1>
|
||||||
|
<section>
|
||||||
|
<h2>Boo</h2>
|
||||||
|
<h2>Quux</h2>
|
||||||
|
<section>
|
||||||
|
<h3>Blah</h3>
|
||||||
|
</section>
|
||||||
|
</section>
|
||||||
|
<h1>Bar</h1>
|
||||||
|
<section></section>
|
||||||
|
<h2>Boo</h2>
|
||||||
|
<h2>Quux</h2>
|
||||||
|
<h1>Baz</h1>
|
||||||
|
</section>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
29
tests/ref/counters_nested_ref.html
Normal file
29
tests/ref/counters_nested_ref.html
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<!-- Tests that `counters` works with nested counters. -->
|
||||||
|
<style>
|
||||||
|
h1, h2, h3 {
|
||||||
|
font-size: 24px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<section>
|
||||||
|
<h1>1. Foo</h1>
|
||||||
|
<section>
|
||||||
|
<h2>1.1. Boo</h2>
|
||||||
|
<h2>1.2. Quux</h2>
|
||||||
|
<section>
|
||||||
|
<h3>1.2.1. Blah</h3>
|
||||||
|
</section>
|
||||||
|
</section>
|
||||||
|
<h1>1.3. Bar</h1>
|
||||||
|
<section></section>
|
||||||
|
<h2>1.1. Boo</h2>
|
||||||
|
<h2>1.2. Quux</h2>
|
||||||
|
<h1>1.3. Baz</h1>
|
||||||
|
</section>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
42
tests/ref/counters_simple_a.html
Normal file
42
tests/ref/counters_simple_a.html
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<!-- Tests that `counter` works. -->
|
||||||
|
<style>
|
||||||
|
h1, h2, h3 {
|
||||||
|
font-size: 24px;
|
||||||
|
}
|
||||||
|
h1 {
|
||||||
|
counter-increment: section 1;
|
||||||
|
counter-reset: subsection 0;
|
||||||
|
}
|
||||||
|
h1:before {
|
||||||
|
content: counter(section) ". ";
|
||||||
|
}
|
||||||
|
h2 {
|
||||||
|
counter-increment: subsection 1;
|
||||||
|
counter-reset: subsubsection 0;
|
||||||
|
}
|
||||||
|
h2:before {
|
||||||
|
content: counter(section) "." counter(subsection) ". ";
|
||||||
|
}
|
||||||
|
h3 {
|
||||||
|
counter-increment: subsubsection;
|
||||||
|
}
|
||||||
|
h3:before {
|
||||||
|
content: counter(section) "." counter(subsection) "." counter(subsubsection) ". ";
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Foo</h1>
|
||||||
|
<h2>Boo</h2>
|
||||||
|
<h2>Quux</h2>
|
||||||
|
<h3>Blah</h3>
|
||||||
|
<h1>Bar</h1>
|
||||||
|
<h2>Boo</h2>
|
||||||
|
<h2>Quux</h2>
|
||||||
|
<h1>Baz</h1>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
22
tests/ref/counters_simple_ref.html
Normal file
22
tests/ref/counters_simple_ref.html
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<!-- Tests that `counter` works. -->
|
||||||
|
<style>
|
||||||
|
h1, h2, h3 {
|
||||||
|
font-size: 24px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>1. Foo</h1>
|
||||||
|
<h2>1.1. Boo</h2>
|
||||||
|
<h2>1.2. Quux</h2>
|
||||||
|
<h3>1.2.1. Blah</h3>
|
||||||
|
<h1>2. Bar</h1>
|
||||||
|
<h2>2.1. Boo</h2>
|
||||||
|
<h2>2.2. Quux</h2>
|
||||||
|
<h1>3. Baz</h1>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
27
tests/ref/ol_japanese_iroha_a.html
Normal file
27
tests/ref/ol_japanese_iroha_a.html
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<!-- Tests that Japanese iroha ordering works in list items. -->
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: "Hiragino Maru Gothic Pro", TakaoPGothic, sans-serif;
|
||||||
|
}
|
||||||
|
ol {
|
||||||
|
list-style-position: inside;
|
||||||
|
list-style-type: hiragana-iroha;
|
||||||
|
}
|
||||||
|
li {
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<ol>
|
||||||
|
<li>Gryffindor</li>
|
||||||
|
<li>Hufflepuff</li>
|
||||||
|
<li>Ravenclaw</li>
|
||||||
|
<li>Slytherin</li>
|
||||||
|
</ol>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
|
|
25
tests/ref/ol_japanese_iroha_bullet_styles.html
Normal file
25
tests/ref/ol_japanese_iroha_bullet_styles.html
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<!-- Ensures that U+3044, U+308D, U+306F, and U+306B are all supported in the current font. -->
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: "Hiragino Maru Gothic Pro", TakaoPGothic, sans-serif;
|
||||||
|
}
|
||||||
|
ol {
|
||||||
|
list-style-position: inside;
|
||||||
|
list-style-type: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<ol>
|
||||||
|
<li>い. Gryffindor</li>
|
||||||
|
<li>い. Hufflepuff</li>
|
||||||
|
<li>い. Ravenclaw</li>
|
||||||
|
<li>い. Slytherin</li>
|
||||||
|
</ol>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
|
|
27
tests/ref/ol_japanese_iroha_ref.html
Normal file
27
tests/ref/ol_japanese_iroha_ref.html
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<!-- Tests that Japanese iroha ordering works in list items.
|
||||||
|
|
||||||
|
FIXME(pcwalton): This shouldn't have a "." after the kana. -->
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: "Hiragino Maru Gothic Pro", TakaoPGothic, sans-serif;
|
||||||
|
}
|
||||||
|
ol {
|
||||||
|
list-style-position: inside;
|
||||||
|
list-style-type: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<ol>
|
||||||
|
<li>い. Gryffindor</li>
|
||||||
|
<li>ろ. Hufflepuff</li>
|
||||||
|
<li>は. Ravenclaw</li>
|
||||||
|
<li>に. Slytherin</li>
|
||||||
|
</ol>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
|
|
19
tests/ref/ol_simple_a.html
Normal file
19
tests/ref/ol_simple_a.html
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<style>
|
||||||
|
li {
|
||||||
|
list-style-type: decimal;
|
||||||
|
list-style-position: inside;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<ol>
|
||||||
|
<li>Foo</li>
|
||||||
|
<li>Bar</li>
|
||||||
|
<li>Baz</li>
|
||||||
|
</ol>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
19
tests/ref/ol_simple_ref.html
Normal file
19
tests/ref/ol_simple_ref.html
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<style>
|
||||||
|
li {
|
||||||
|
list-style-type: none;
|
||||||
|
list-style-position: inside;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<ol>
|
||||||
|
<li>1. Foo</li>
|
||||||
|
<li>2. Bar</li>
|
||||||
|
<li>3. Baz</li>
|
||||||
|
</ol>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
10
tests/ref/quotes_simple_a.html
Normal file
10
tests/ref/quotes_simple_a.html
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<!-- Tests that the initial value of `quotes` works. -->
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
I remember when I first read <q>Hagrid said, <q>You're a wizard, Harry!</q></q>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
11
tests/ref/quotes_simple_ref.html
Normal file
11
tests/ref/quotes_simple_ref.html
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<!-- Tests that the initial value of `quotes` works. -->
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
I remember when I first read “Hagrid said, ‘You're a wizard, Harry!’”
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue