Rustfmt layout crate

This commit is contained in:
Pyfisch 2018-08-24 15:44:25 +02:00
parent 577830de90
commit 349047b096
37 changed files with 7177 additions and 4832 deletions

View file

@ -32,8 +32,7 @@ pub fn update_animation_state<E>(
new_animations_receiver: &Receiver<Animation>, new_animations_receiver: &Receiver<Animation>,
pipeline_id: PipelineId, pipeline_id: PipelineId,
timer: &Timer, timer: &Timer,
) ) where
where
E: TElement, E: TElement,
{ {
let mut new_running_animations = vec![]; let mut new_running_animations = vec![];
@ -66,7 +65,7 @@ where
if running_animations.is_empty() && new_running_animations.is_empty() { if running_animations.is_empty() && new_running_animations.is_empty() {
// Nothing to do. Return early so we don't flood the compositor with // Nothing to do. Return early so we don't flood the compositor with
// `ChangeRunningAnimationsState` messages. // `ChangeRunningAnimationsState` messages.
return return;
} }
let now = timer.seconds(); let now = timer.seconds();
@ -82,28 +81,30 @@ where
let still_running = !running_animation.is_expired() && match running_animation { let still_running = !running_animation.is_expired() && match running_animation {
Animation::Transition(_, started_at, ref frame, _expired) => { Animation::Transition(_, started_at, ref frame, _expired) => {
now < started_at + frame.duration now < started_at + frame.duration
} },
Animation::Keyframes(_, _, _, ref mut state) => { Animation::Keyframes(_, _, _, ref mut state) => {
// This animation is still running, or we need to keep // This animation is still running, or we need to keep
// iterating. // iterating.
now < state.started_at + state.duration || state.tick() now < state.started_at + state.duration || state.tick()
} },
}; };
if still_running { if still_running {
animations_still_running.push(running_animation); animations_still_running.push(running_animation);
continue continue;
} }
if let Animation::Transition(node, _, ref frame, _) = running_animation { if let Animation::Transition(node, _, ref frame, _) = running_animation {
script_chan.send(ConstellationControlMsg::TransitionEnd(node.to_untrusted_node_address(), script_chan
frame.property_animation .send(ConstellationControlMsg::TransitionEnd(
.property_name().into(), node.to_untrusted_node_address(),
frame.duration)) frame.property_animation.property_name().into(),
.unwrap(); frame.duration,
)).unwrap();
} }
expired_animations.entry(*key) expired_animations
.entry(*key)
.or_insert_with(Vec::new) .or_insert_with(Vec::new)
.push(running_animation); .push(running_animation);
} }
@ -125,14 +126,15 @@ where
match newly_transitioning_nodes { match newly_transitioning_nodes {
Some(ref mut nodes) => { Some(ref mut nodes) => {
nodes.push(new_running_animation.node().to_untrusted_node_address()); nodes.push(new_running_animation.node().to_untrusted_node_address());
} },
None => { None => {
warn!("New transition encountered from compositor-initiated layout."); warn!("New transition encountered from compositor-initiated layout.");
} },
} }
} }
running_animations.entry(*new_running_animation.node()) running_animations
.entry(*new_running_animation.node())
.or_insert_with(Vec::new) .or_insert_with(Vec::new)
.push(new_running_animation) .push(new_running_animation)
} }
@ -143,9 +145,11 @@ where
AnimationState::AnimationsPresent AnimationState::AnimationsPresent
}; };
constellation_chan.send(ConstellationMsg::ChangeRunningAnimationsState(pipeline_id, constellation_chan
animation_state)) .send(ConstellationMsg::ChangeRunningAnimationsState(
.unwrap(); pipeline_id,
animation_state,
)).unwrap();
} }
/// Recalculates style for a set of animations. This does *not* run with the DOM /// Recalculates style for a set of animations. This does *not* run with the DOM
@ -154,8 +158,7 @@ pub fn recalc_style_for_animations<E>(
context: &LayoutContext, context: &LayoutContext,
flow: &mut Flow, flow: &mut Flow,
animations: &FxHashMap<OpaqueNode, Vec<Animation>>, animations: &FxHashMap<OpaqueNode, Vec<Animation>>,
) ) where
where
E: TElement, E: TElement,
{ {
let mut damage = RestyleDamage::empty(); let mut damage = RestyleDamage::empty();
@ -170,10 +173,7 @@ where
&ServoMetricsProvider, &ServoMetricsProvider,
); );
let difference = let difference =
RestyleDamage::compute_style_difference( RestyleDamage::compute_style_difference(&old_style, &fragment.style);
&old_style,
&fragment.style,
);
damage |= difference.damage; damage |= difference.damage;
} }
} }

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -32,7 +32,8 @@ pub type LayoutFontContext = FontContext<FontCacheThread>;
thread_local!(static FONT_CONTEXT_KEY: RefCell<Option<LayoutFontContext>> = RefCell::new(None)); thread_local!(static FONT_CONTEXT_KEY: RefCell<Option<LayoutFontContext>> = RefCell::new(None));
pub fn with_thread_local_font_context<F, R>(layout_context: &LayoutContext, f: F) -> R pub fn with_thread_local_font_context<F, R>(layout_context: &LayoutContext, f: F) -> R
where F: FnOnce(&mut LayoutFontContext) -> R where
F: FnOnce(&mut LayoutFontContext) -> R,
{ {
FONT_CONTEXT_KEY.with(|k| { FONT_CONTEXT_KEY.with(|k| {
let mut font_context = k.borrow_mut(); let mut font_context = k.borrow_mut();
@ -69,9 +70,11 @@ pub struct LayoutContext<'a> {
pub font_cache_thread: Mutex<FontCacheThread>, pub font_cache_thread: Mutex<FontCacheThread>,
/// A cache of WebRender image info. /// A cache of WebRender image info.
pub webrender_image_cache: Arc<RwLock<HashMap<(ServoUrl, UsePlaceholder), pub webrender_image_cache: Arc<
WebRenderImageInfo, RwLock<
BuildHasherDefault<FnvHasher>>>>, HashMap<(ServoUrl, UsePlaceholder), WebRenderImageInfo, BuildHasherDefault<FnvHasher>>,
>,
>,
/// Paint worklets /// Paint worklets
pub registered_painters: &'a RegisteredPainters, pub registered_painters: &'a RegisteredPainters,
@ -101,11 +104,12 @@ impl<'a> LayoutContext<'a> {
&self.style_context &self.style_context
} }
pub fn get_or_request_image_or_meta(&self, pub fn get_or_request_image_or_meta(
&self,
node: OpaqueNode, node: OpaqueNode,
url: ServoUrl, url: ServoUrl,
use_placeholder: UsePlaceholder) use_placeholder: UsePlaceholder,
-> Option<ImageOrMetadataAvailable> { ) -> Option<ImageOrMetadataAvailable> {
//XXXjdm For cases where we do not request an image, we still need to //XXXjdm For cases where we do not request an image, we still need to
// ensure the node gets another script-initiated reflow or it // ensure the node gets another script-initiated reflow or it
// won't be requested at all. // won't be requested at all.
@ -116,9 +120,9 @@ impl<'a> LayoutContext<'a> {
}; };
// See if the image is already available // See if the image is already available
let result = self.image_cache.find_image_or_metadata(url.clone(), let result =
use_placeholder, self.image_cache
can_request); .find_image_or_metadata(url.clone(), use_placeholder, can_request);
match result { match result {
Ok(image_or_metadata) => Some(image_or_metadata), Ok(image_or_metadata) => Some(image_or_metadata),
// Image failed to load, so just return nothing // Image failed to load, so just return nothing
@ -130,9 +134,14 @@ impl<'a> LayoutContext<'a> {
node: node.to_untrusted_node_address(), node: node.to_untrusted_node_address(),
id: id, id: id,
}; };
self.pending_images.as_ref().unwrap().lock().unwrap().push(image); self.pending_images
.as_ref()
.unwrap()
.lock()
.unwrap()
.push(image);
None None
} },
// Image has been requested, is still pending. Return no image for this paint loop. // Image has been requested, is still pending. Return no image for this paint loop.
// When the image loads it will trigger a reflow and/or repaint. // When the image loads it will trigger a reflow and/or repaint.
Err(ImageState::Pending(id)) => { Err(ImageState::Pending(id)) => {
@ -148,19 +157,22 @@ impl<'a> LayoutContext<'a> {
pending_images.lock().unwrap().push(image); pending_images.lock().unwrap().push(image);
} }
None None
} },
} }
} }
pub fn get_webrender_image_for_url(&self, pub fn get_webrender_image_for_url(
&self,
node: OpaqueNode, node: OpaqueNode,
url: ServoUrl, url: ServoUrl,
use_placeholder: UsePlaceholder) use_placeholder: UsePlaceholder,
-> Option<WebRenderImageInfo> { ) -> Option<WebRenderImageInfo> {
if let Some(existing_webrender_image) = self.webrender_image_cache if let Some(existing_webrender_image) = self
.webrender_image_cache
.read() .read()
.get(&(url.clone(), use_placeholder)) { .get(&(url.clone(), use_placeholder))
return Some((*existing_webrender_image).clone()) {
return Some((*existing_webrender_image).clone());
} }
match self.get_or_request_image_or_meta(node, url.clone(), use_placeholder) { match self.get_or_request_image_or_meta(node, url.clone(), use_placeholder) {
@ -170,11 +182,10 @@ impl<'a> LayoutContext<'a> {
Some(image_info) Some(image_info)
} else { } else {
let mut webrender_image_cache = self.webrender_image_cache.write(); let mut webrender_image_cache = self.webrender_image_cache.write();
webrender_image_cache.insert((url, use_placeholder), webrender_image_cache.insert((url, use_placeholder), image_info);
image_info);
Some(image_info) Some(image_info)
} }
} },
None | Some(ImageOrMetadataAvailable::MetadataAvailable(_)) => None, None | Some(ImageOrMetadataAvailable::MetadataAvailable(_)) => None,
} }
} }

View file

@ -24,7 +24,6 @@ impl StyleAndLayoutData {
} }
} }
/// Data that layout associates with a node. /// Data that layout associates with a node.
#[repr(C)] #[repr(C)]
pub struct LayoutData { pub struct LayoutData {

View file

@ -444,8 +444,7 @@ fn convert_gradient_stops(
.filter_map(|item| match *item { .filter_map(|item| match *item {
GenericGradientItem::ColorStop(ref stop) => Some(*stop), GenericGradientItem::ColorStop(ref stop) => Some(*stop),
_ => None, _ => None,
}) }).collect::<Vec<_>>();
.collect::<Vec<_>>();
assert!(stop_items.len() >= 2); assert!(stop_items.len() >= 2);

View file

@ -1414,8 +1414,7 @@ impl FragmentDisplayListBuilding for Fragment {
url.clone(), url.clone(),
UsePlaceholder::No, UsePlaceholder::No,
) )
}) }).and_then(|image| {
.and_then(|image| {
build_image_border_details(image, border_style_struct, outset_layout) build_image_border_details(image, border_style_struct, outset_layout)
}), }),
}; };
@ -1957,8 +1956,7 @@ impl FragmentDisplayListBuilding for Fragment {
.send(CanvasMsg::FromLayout( .send(CanvasMsg::FromLayout(
FromLayoutMsg::SendData(sender), FromLayoutMsg::SendData(sender),
canvas_fragment_info.canvas_id.clone(), canvas_fragment_info.canvas_id.clone(),
)) )).unwrap();
.unwrap();
receiver.recv().unwrap().image_key receiver.recv().unwrap().image_key
}, },
None => return, None => return,
@ -2070,9 +2068,11 @@ impl FragmentDisplayListBuilding for Fragment {
// FIXME(pcwalton): Get the real container size. // FIXME(pcwalton): Get the real container size.
let container_size = Size2D::zero(); let container_size = Size2D::zero();
let metrics = &text_fragment.run.font_metrics; let metrics = &text_fragment.run.font_metrics;
let baseline_origin = stacking_relative_content_box.origin + let baseline_origin = stacking_relative_content_box.origin + LogicalPoint::new(
LogicalPoint::new(self.style.writing_mode, Au(0), metrics.ascent) self.style.writing_mode,
.to_physical(self.style.writing_mode, container_size) Au(0),
metrics.ascent,
).to_physical(self.style.writing_mode, container_size)
.to_vector(); .to_vector();
// Base item for all text/shadows // Base item for all text/shadows

View file

@ -513,8 +513,8 @@ impl ClippingRegion {
/// This is a quick, not a precise, test; it can yield false positives. /// This is a quick, not a precise, test; it can yield false positives.
#[inline] #[inline]
pub fn might_intersect_point(&self, point: &LayoutPoint) -> bool { pub fn might_intersect_point(&self, point: &LayoutPoint) -> bool {
self.main.contains(point) && self.main.contains(point) && self
self.complex .complex
.iter() .iter()
.all(|complex| complex.rect.contains(point)) .all(|complex| complex.rect.contains(point))
} }
@ -523,8 +523,8 @@ impl ClippingRegion {
/// otherwise. This is a quick, not a precise, test; it can yield false positives. /// otherwise. This is a quick, not a precise, test; it can yield false positives.
#[inline] #[inline]
pub fn might_intersect_rect(&self, rect: &LayoutRect) -> bool { pub fn might_intersect_rect(&self, rect: &LayoutRect) -> bool {
self.main.intersects(rect) && self.main.intersects(rect) && self
self.complex .complex
.iter() .iter()
.all(|complex| complex.rect.intersects(rect)) .all(|complex| complex.rect.intersects(rect))
} }
@ -532,8 +532,10 @@ impl ClippingRegion {
/// Returns true if this clipping region completely surrounds the given rect. /// Returns true if this clipping region completely surrounds the given rect.
#[inline] #[inline]
pub fn does_not_clip_rect(&self, rect: &LayoutRect) -> bool { pub fn does_not_clip_rect(&self, rect: &LayoutRect) -> bool {
self.main.contains(&rect.origin) && self.main.contains(&rect.bottom_right()) && self.main.contains(&rect.origin) && self.main.contains(&rect.bottom_right()) && self
self.complex.iter().all(|complex| { .complex
.iter()
.all(|complex| {
complex.rect.contains(&rect.origin) && complex.rect.contains(&rect.bottom_right()) complex.rect.contains(&rect.origin) && complex.rect.contains(&rect.bottom_right())
}) })
} }
@ -588,8 +590,7 @@ impl ClippingRegion {
rect: complex.rect.translate(delta), rect: complex.rect.translate(delta),
radii: complex.radii, radii: complex.radii,
mode: complex.mode, mode: complex.mode,
}) }).collect(),
.collect(),
} }
} }

View file

@ -45,25 +45,25 @@ enum AxisSize {
impl AxisSize { impl AxisSize {
/// Generate a new available cross or main axis size from the specified size of the container, /// Generate a new available cross or main axis size from the specified size of the container,
/// containing block size, min constraint, and max constraint /// containing block size, min constraint, and max constraint
pub fn new(size: LengthOrPercentageOrAuto, content_size: Option<Au>, min: LengthOrPercentage, pub fn new(
max: LengthOrPercentageOrNone) -> AxisSize { size: LengthOrPercentageOrAuto,
content_size: Option<Au>,
min: LengthOrPercentage,
max: LengthOrPercentageOrNone,
) -> AxisSize {
match size { match size {
LengthOrPercentageOrAuto::Length(length) => AxisSize::Definite(Au::from(length)), LengthOrPercentageOrAuto::Length(length) => AxisSize::Definite(Au::from(length)),
LengthOrPercentageOrAuto::Percentage(percent) => { LengthOrPercentageOrAuto::Percentage(percent) => match content_size {
match content_size {
Some(size) => AxisSize::Definite(size.scale_by(percent.0)), Some(size) => AxisSize::Definite(size.scale_by(percent.0)),
None => AxisSize::Infinite None => AxisSize::Infinite,
} },
} LengthOrPercentageOrAuto::Calc(calc) => match calc.to_used_value(content_size) {
LengthOrPercentageOrAuto::Calc(calc) => {
match calc.to_used_value(content_size) {
Some(length) => AxisSize::Definite(length), Some(length) => AxisSize::Definite(length),
None => AxisSize::Infinite, None => AxisSize::Infinite,
} },
}
LengthOrPercentageOrAuto::Auto => { LengthOrPercentageOrAuto::Auto => {
AxisSize::MinMax(SizeConstraint::new(content_size, min, max, None)) AxisSize::MinMax(SizeConstraint::new(content_size, min, max, None))
} },
} }
} }
} }
@ -112,7 +112,7 @@ struct FlexItem {
/// Whether the main size has met its constraint. /// Whether the main size has met its constraint.
pub is_frozen: bool, pub is_frozen: bool,
/// True if this flow has property 'visibility::collapse'. /// True if this flow has property 'visibility::collapse'.
pub is_strut: bool pub is_strut: bool,
} }
impl FlexItem { impl FlexItem {
@ -133,7 +133,7 @@ impl FlexItem {
flex_shrink: flex_shrink.into(), flex_shrink: flex_shrink.into(),
order: order, order: order,
is_frozen: false, is_frozen: false,
is_strut: false is_strut: false,
} }
} }
@ -147,41 +147,61 @@ impl FlexItem {
// should change to LengthOrPercentageOrAuto for automatic implied minimal size. // should change to LengthOrPercentageOrAuto for automatic implied minimal size.
// https://drafts.csswg.org/css-flexbox-1/#min-size-auto // https://drafts.csswg.org/css-flexbox-1/#min-size-auto
Direction::Inline => { Direction::Inline => {
let basis = from_flex_basis(block.fragment.style.get_position().flex_basis, let basis = from_flex_basis(
block.fragment.style.get_position().flex_basis,
block.fragment.style.content_inline_size(), block.fragment.style.content_inline_size(),
containing_length); containing_length,
);
// These methods compute auto margins to zero length, which is exactly what we want. // These methods compute auto margins to zero length, which is exactly what we want.
block.fragment.compute_border_and_padding(containing_length); block.fragment.compute_border_and_padding(containing_length);
block.fragment.compute_inline_direction_margins(containing_length); block
block.fragment.compute_block_direction_margins(containing_length); .fragment
.compute_inline_direction_margins(containing_length);
block
.fragment
.compute_block_direction_margins(containing_length);
let (border_padding, margin) = block.fragment.surrounding_intrinsic_inline_size(); let (border_padding, margin) = block.fragment.surrounding_intrinsic_inline_size();
let content_size = block.base.intrinsic_inline_sizes.preferred_inline_size let content_size = block.base.intrinsic_inline_sizes.preferred_inline_size -
- border_padding border_padding -
- margin margin +
+ block.fragment.box_sizing_boundary(direction); block.fragment.box_sizing_boundary(direction);
self.base_size = basis.specified_or_default(content_size); self.base_size = basis.specified_or_default(content_size);
self.max_size = self.max_size = block
block.fragment.style.max_inline_size() .fragment
.style
.max_inline_size()
.to_used_value(containing_length) .to_used_value(containing_length)
.unwrap_or(MAX_AU); .unwrap_or(MAX_AU);
self.min_size = block.fragment.style.min_inline_size().to_used_value(containing_length); self.min_size = block
} .fragment
.style
.min_inline_size()
.to_used_value(containing_length);
},
Direction::Block => { Direction::Block => {
let basis = from_flex_basis(block.fragment.style.get_position().flex_basis, let basis = from_flex_basis(
block.fragment.style.get_position().flex_basis,
block.fragment.style.content_block_size(), block.fragment.style.content_block_size(),
containing_length); containing_length,
let content_size = block.fragment.border_box.size.block );
- block.fragment.border_padding.block_start_end() let content_size = block.fragment.border_box.size.block -
+ block.fragment.box_sizing_boundary(direction); block.fragment.border_padding.block_start_end() +
block.fragment.box_sizing_boundary(direction);
self.base_size = basis.specified_or_default(content_size); self.base_size = basis.specified_or_default(content_size);
self.max_size = self.max_size = block
block.fragment.style.max_block_size() .fragment
.style
.max_block_size()
.to_used_value(containing_length) .to_used_value(containing_length)
.unwrap_or(MAX_AU); .unwrap_or(MAX_AU);
self.min_size = block.fragment.style.min_block_size().to_used_value(containing_length); self.min_size = block
} .fragment
.style
.min_block_size()
.to_used_value(containing_length);
},
} }
} }
@ -192,13 +212,14 @@ impl FlexItem {
let outer_width = match direction { let outer_width = match direction {
Direction::Inline => { Direction::Inline => {
fragment.border_padding.inline_start_end() + fragment.margin.inline_start_end() fragment.border_padding.inline_start_end() + fragment.margin.inline_start_end()
} },
Direction::Block => { Direction::Block => {
fragment.border_padding.block_start_end() + fragment.margin.block_start_end() fragment.border_padding.block_start_end() + fragment.margin.block_start_end()
} },
}; };
max(self.min_size, min(self.base_size, self.max_size)) max(self.min_size, min(self.base_size, self.max_size)) -
- fragment.box_sizing_boundary(direction) + outer_width fragment.box_sizing_boundary(direction) +
outer_width
} }
/// Returns the number of auto margins in given direction. /// Returns the number of auto margins in given direction.
@ -213,7 +234,7 @@ impl FlexItem {
if margin.inline_end == LengthOrPercentageOrAuto::Auto { if margin.inline_end == LengthOrPercentageOrAuto::Auto {
margin_count += 1; margin_count += 1;
} }
} },
Direction::Block => { Direction::Block => {
if margin.block_start == LengthOrPercentageOrAuto::Auto { if margin.block_start == LengthOrPercentageOrAuto::Auto {
margin_count += 1; margin_count += 1;
@ -221,7 +242,7 @@ impl FlexItem {
if margin.block_end == LengthOrPercentageOrAuto::Auto { if margin.block_end == LengthOrPercentageOrAuto::Auto {
margin_count += 1; margin_count += 1;
} }
} },
} }
margin_count margin_count
} }
@ -247,7 +268,7 @@ impl FlexLine {
range: range, range: range,
auto_margin_count: auto_margin_count, auto_margin_count: auto_margin_count,
free_space: free_space, free_space: free_space,
cross_size: Au(0) cross_size: Au(0),
} }
} }
@ -265,8 +286,11 @@ impl FlexLine {
// https://drafts.csswg.org/css-flexbox/#resolve-flexible-lengths // https://drafts.csswg.org/css-flexbox/#resolve-flexible-lengths
for item in items.iter_mut().filter(|i| !(i.is_strut && collapse)) { for item in items.iter_mut().filter(|i| !(i.is_strut && collapse)) {
item.main_size = max(item.min_size, min(item.base_size, item.max_size)); item.main_size = max(item.min_size, min(item.base_size, item.max_size));
if (self.free_space > Au(0) && (item.flex_grow == 0.0 || item.base_size >= item.max_size)) || if (self.free_space > Au(0) &&
(self.free_space < Au(0) && (item.flex_shrink == 0.0 || item.base_size <= item.min_size)) { (item.flex_grow == 0.0 || item.base_size >= item.max_size)) ||
(self.free_space < Au(0) &&
(item.flex_shrink == 0.0 || item.base_size <= item.min_size))
{
item.is_frozen = true; item.is_frozen = true;
} else { } else {
item.is_frozen = false; item.is_frozen = false;
@ -291,12 +315,19 @@ impl FlexLine {
}; };
total_variation = Au(0); total_variation = Au(0);
for item in items.iter_mut().filter(|i| !i.is_frozen).filter(|i| !(i.is_strut && collapse)) { for item in items
.iter_mut()
.filter(|i| !i.is_frozen)
.filter(|i| !(i.is_strut && collapse))
{
// Use this and the 'abs()' below to make the code work in both grow and shrink scenarios. // Use this and the 'abs()' below to make the code work in both grow and shrink scenarios.
let (factor, end_size) = if self.free_space > Au(0) { let (factor, end_size) = if self.free_space > Au(0) {
(item.flex_grow / total_grow, item.max_size) (item.flex_grow / total_grow, item.max_size)
} else { } else {
(item.flex_shrink * item.base_size.0 as f32 / total_scaled, item.min_size) (
item.flex_shrink * item.base_size.0 as f32 / total_scaled,
item.min_size,
)
}; };
let variation = self.free_space.scale_by(factor); let variation = self.free_space.scale_by(factor);
if variation.0.abs() >= (end_size - item.main_size).0.abs() { if variation.0.abs() >= (end_size - item.main_size).0.abs() {
@ -343,13 +374,11 @@ pub struct FlexFlow {
/// True if this flex container can be multiline. /// True if this flex container can be multiline.
is_wrappable: bool, is_wrappable: bool,
/// True if the cross direction is reversed. /// True if the cross direction is reversed.
cross_reverse: bool cross_reverse: bool,
} }
impl FlexFlow { impl FlexFlow {
pub fn from_fragment(fragment: Fragment, pub fn from_fragment(fragment: Fragment, flotation: Option<FloatKind>) -> FlexFlow {
flotation: Option<FloatKind>)
-> FlexFlow {
let main_mode; let main_mode;
let main_reverse; let main_reverse;
let is_wrappable; let is_wrappable;
@ -363,8 +392,7 @@ impl FlexFlow {
FlexDirection::ColumnReverse => (Direction::Block, true), FlexDirection::ColumnReverse => (Direction::Block, true),
}; };
main_mode = mode; main_mode = mode;
main_reverse = main_reverse = reverse == style.writing_mode.is_bidi_ltr();
reverse == style.writing_mode.is_bidi_ltr();
let (wrappable, reverse) = match fragment.style.get_position().flex_wrap { let (wrappable, reverse) = match fragment.style.get_position().flex_wrap {
FlexWrap::Nowrap => (false, false), FlexWrap::Nowrap => (false, false),
FlexWrap::Wrap => (true, false), FlexWrap::Wrap => (true, false),
@ -384,7 +412,7 @@ impl FlexFlow {
items: Vec::new(), items: Vec::new(),
main_reverse: main_reverse, main_reverse: main_reverse,
is_wrappable: is_wrappable, is_wrappable: is_wrappable,
cross_reverse: cross_reverse cross_reverse: cross_reverse,
} }
} }
@ -414,7 +442,10 @@ impl FlexFlow {
let kid = children.get(item.index); let kid = children.get(item.index);
item.init_sizes(kid, container_size, self.main_mode); item.init_sizes(kid, container_size, self.main_mode);
let outer_main_size = item.outer_main_size(kid, self.main_mode); let outer_main_size = item.outer_main_size(kid, self.main_mode);
if total_line_size + outer_main_size > container_size && end != start && self.is_wrappable { if total_line_size + outer_main_size > container_size &&
end != start &&
self.is_wrappable
{
break; break;
} }
margin_count += item.auto_margin_count(kid, self.main_mode); margin_count += item.auto_margin_count(kid, self.main_mode);
@ -439,7 +470,8 @@ impl FlexFlow {
if !fixed_width { if !fixed_width {
for kid in self.block_flow.base.children.iter_mut() { for kid in self.block_flow.base.children.iter_mut() {
let base = kid.mut_base(); let base = kid.mut_base();
let is_absolutely_positioned = base.flags.contains(FlowFlags::IS_ABSOLUTELY_POSITIONED); let is_absolutely_positioned =
base.flags.contains(FlowFlags::IS_ABSOLUTELY_POSITIONED);
if !is_absolutely_positioned { if !is_absolutely_positioned {
let flex_item_inline_sizes = IntrinsicISizes { let flex_item_inline_sizes = IntrinsicISizes {
minimum_inline_size: base.intrinsic_inline_sizes.minimum_inline_size, minimum_inline_size: base.intrinsic_inline_sizes.minimum_inline_size,
@ -465,15 +497,18 @@ impl FlexFlow {
if !fixed_width { if !fixed_width {
for kid in self.block_flow.base.children.iter_mut() { for kid in self.block_flow.base.children.iter_mut() {
let base = kid.mut_base(); let base = kid.mut_base();
let is_absolutely_positioned = base.flags.contains(FlowFlags::IS_ABSOLUTELY_POSITIONED); let is_absolutely_positioned =
base.flags.contains(FlowFlags::IS_ABSOLUTELY_POSITIONED);
if !is_absolutely_positioned { if !is_absolutely_positioned {
computation.content_intrinsic_sizes.minimum_inline_size = computation.content_intrinsic_sizes.minimum_inline_size = max(
max(computation.content_intrinsic_sizes.minimum_inline_size, computation.content_intrinsic_sizes.minimum_inline_size,
base.intrinsic_inline_sizes.minimum_inline_size); base.intrinsic_inline_sizes.minimum_inline_size,
);
computation.content_intrinsic_sizes.preferred_inline_size = computation.content_intrinsic_sizes.preferred_inline_size = max(
max(computation.content_intrinsic_sizes.preferred_inline_size, computation.content_intrinsic_sizes.preferred_inline_size,
base.intrinsic_inline_sizes.preferred_inline_size); base.intrinsic_inline_sizes.preferred_inline_size,
);
} }
} }
} }
@ -483,11 +518,13 @@ impl FlexFlow {
// TODO(zentner): This function needs to be radically different for multi-line flexbox. // TODO(zentner): This function needs to be radically different for multi-line flexbox.
// Currently, this is the core of BlockFlow::propagate_assigned_inline_size_to_children() with // Currently, this is the core of BlockFlow::propagate_assigned_inline_size_to_children() with
// all float and table logic stripped out. // all float and table logic stripped out.
fn block_mode_assign_inline_sizes(&mut self, fn block_mode_assign_inline_sizes(
&mut self,
_layout_context: &LayoutContext, _layout_context: &LayoutContext,
inline_start_content_edge: Au, inline_start_content_edge: Au,
inline_end_content_edge: Au, inline_end_content_edge: Au,
content_inline_size: Au) { content_inline_size: Au,
) {
let _scope = layout_debug_scope!("flex::block_mode_assign_inline_sizes"); let _scope = layout_debug_scope!("flex::block_mode_assign_inline_sizes");
debug!("flex::block_mode_assign_inline_sizes"); debug!("flex::block_mode_assign_inline_sizes");
@ -496,19 +533,22 @@ impl FlexFlow {
let container_block_size = match self.available_main_size { let container_block_size = match self.available_main_size {
AxisSize::Definite(length) => Some(length), AxisSize::Definite(length) => Some(length),
_ => None _ => None,
}; };
let container_inline_size = match self.available_cross_size { let container_inline_size = match self.available_cross_size {
AxisSize::Definite(length) => length, AxisSize::Definite(length) => length,
AxisSize::MinMax(ref constraint) => constraint.clamp(content_inline_size), AxisSize::MinMax(ref constraint) => constraint.clamp(content_inline_size),
AxisSize::Infinite => content_inline_size AxisSize::Infinite => content_inline_size,
}; };
let mut children = self.block_flow.base.children.random_access_mut(); let mut children = self.block_flow.base.children.random_access_mut();
for kid in &mut self.items { for kid in &mut self.items {
let kid_base = children.get(kid.index).mut_base(); let kid_base = children.get(kid.index).mut_base();
kid_base.block_container_explicit_block_size = container_block_size; kid_base.block_container_explicit_block_size = container_block_size;
if kid_base.flags.contains(FlowFlags::INLINE_POSITION_IS_STATIC) { if kid_base
.flags
.contains(FlowFlags::INLINE_POSITION_IS_STATIC)
{
// The inline-start margin edge of the child flow is at our inline-start content // The inline-start margin edge of the child flow is at our inline-start content
// edge, and its inline-size is our content inline-size. // edge, and its inline-size is our content inline-size.
kid_base.position.start.i = kid_base.position.start.i =
@ -525,11 +565,13 @@ impl FlexFlow {
} }
} }
fn inline_mode_assign_inline_sizes(&mut self, fn inline_mode_assign_inline_sizes(
&mut self,
layout_context: &LayoutContext, layout_context: &LayoutContext,
inline_start_content_edge: Au, inline_start_content_edge: Au,
_inline_end_content_edge: Au, _inline_end_content_edge: Au,
content_inline_size: Au) { content_inline_size: Au,
) {
let _scope = layout_debug_scope!("flex::inline_mode_assign_inline_sizes"); let _scope = layout_debug_scope!("flex::inline_mode_assign_inline_sizes");
debug!("inline_mode_assign_inline_sizes"); debug!("inline_mode_assign_inline_sizes");
@ -551,17 +593,25 @@ impl FlexFlow {
self.block_flow.base.position.size.inline = inline_size; self.block_flow.base.position.size.inline = inline_size;
// Calculate non-auto block size to pass to children. // Calculate non-auto block size to pass to children.
let box_border = self.block_flow.fragment.box_sizing_boundary(Direction::Block); let box_border = self
.block_flow
.fragment
.box_sizing_boundary(Direction::Block);
let parent_container_size = let parent_container_size = self
self.block_flow.explicit_block_containing_size(layout_context.shared_context()); .block_flow
.explicit_block_containing_size(layout_context.shared_context());
// https://drafts.csswg.org/css-ui-3/#box-sizing // https://drafts.csswg.org/css-ui-3/#box-sizing
let explicit_content_size = self let explicit_content_size = self
.block_flow .block_flow
.explicit_block_size(parent_container_size) .explicit_block_size(parent_container_size)
.map(|x| max(x - box_border, Au(0))); .map(|x| max(x - box_border, Au(0)));
let containing_block_text_align = let containing_block_text_align = self
self.block_flow.fragment.style().get_inherited_text().text_align; .block_flow
.fragment
.style()
.get_inherited_text()
.text_align;
while let Some(mut line) = self.get_flex_line(inline_size) { while let Some(mut line) = self.get_flex_line(inline_size) {
let items = &mut self.items[line.range.clone()]; let items = &mut self.items[line.range.clone()];
@ -572,32 +622,42 @@ impl FlexFlow {
let item_count = items.len() as i32; let item_count = items.len() as i32;
let mut cur_i = inline_start_content_edge; let mut cur_i = inline_start_content_edge;
let item_interval = if line.free_space >= Au(0) && line.auto_margin_count == 0 { let item_interval = if line.free_space >= Au(0) && line.auto_margin_count == 0 {
match self.block_flow.fragment.style().get_position().justify_content { match self
.block_flow
.fragment
.style()
.get_position()
.justify_content
{
JustifyContent::SpaceBetween => { JustifyContent::SpaceBetween => {
if item_count == 1 { if item_count == 1 {
Au(0) Au(0)
} else { } else {
line.free_space / (item_count - 1) line.free_space / (item_count - 1)
} }
} },
JustifyContent::SpaceAround => { JustifyContent::SpaceAround => line.free_space / item_count,
line.free_space / item_count
}
_ => Au(0), _ => Au(0),
} }
} else { } else {
Au(0) Au(0)
}; };
match self.block_flow.fragment.style().get_position().justify_content { match self
.block_flow
.fragment
.style()
.get_position()
.justify_content
{
// Overflow equally in both ends of line. // Overflow equally in both ends of line.
JustifyContent::Center | JustifyContent::SpaceAround => { JustifyContent::Center | JustifyContent::SpaceAround => {
cur_i += (line.free_space - item_interval * (item_count - 1)) / 2; cur_i += (line.free_space - item_interval * (item_count - 1)) / 2;
} },
JustifyContent::FlexEnd => { JustifyContent::FlexEnd => {
cur_i += line.free_space; cur_i += line.free_space;
} },
_ => {} _ => {},
} }
let mut children = self.block_flow.base.children.random_access_mut(); let mut children = self.block_flow.base.children.random_access_mut();
@ -613,8 +673,7 @@ impl FlexFlow {
block.base.flags.set_text_align(containing_block_text_align); block.base.flags.set_text_align(containing_block_text_align);
let margin = block.fragment.style().logical_margin(); let margin = block.fragment.style().logical_margin();
let auto_len = let auto_len = if line.auto_margin_count == 0 || line.free_space <= Au(0) {
if line.auto_margin_count == 0 || line.free_space <= Au(0) {
Au(0) Au(0)
} else { } else {
line.free_space / line.auto_margin_count line.free_space / line.auto_margin_count
@ -623,9 +682,9 @@ impl FlexFlow {
.specified_or_default(auto_len); .specified_or_default(auto_len);
let margin_inline_end = MaybeAuto::from_style(margin.inline_end, inline_size) let margin_inline_end = MaybeAuto::from_style(margin.inline_end, inline_size)
.specified_or_default(auto_len); .specified_or_default(auto_len);
let item_inline_size = item.main_size let item_inline_size = item.main_size -
- block.fragment.box_sizing_boundary(self.main_mode) block.fragment.box_sizing_boundary(self.main_mode) +
+ block.fragment.border_padding.inline_start_end(); block.fragment.border_padding.inline_start_end();
let item_outer_size = item_inline_size + block.fragment.margin.inline_start_end(); let item_outer_size = item_inline_size + block.fragment.margin.inline_start_end();
block.fragment.margin.inline_start = margin_inline_start; block.fragment.margin.inline_start = margin_inline_start;
@ -669,7 +728,12 @@ impl FlexFlow {
let _scope = layout_debug_scope!("flex::inline_mode_assign_block_size"); let _scope = layout_debug_scope!("flex::inline_mode_assign_block_size");
let line_count = self.lines.len() as i32; let line_count = self.lines.len() as i32;
let line_align = self.block_flow.fragment.style().get_position().align_content; let line_align = self
.block_flow
.fragment
.style()
.get_position()
.align_content;
let mut cur_b = self.block_flow.fragment.border_padding.block_start; let mut cur_b = self.block_flow.fragment.border_padding.block_start;
let mut total_cross_size = Au(0); let mut total_cross_size = Au(0);
let mut line_interval = Au(0); let mut line_interval = Au(0);
@ -679,17 +743,22 @@ impl FlexFlow {
for line in self.lines.iter_mut() { for line in self.lines.iter_mut() {
for item in &self.items[line.range.clone()] { for item in &self.items[line.range.clone()] {
let fragment = &children.get(item.index).as_block().fragment; let fragment = &children.get(item.index).as_block().fragment;
line.cross_size = max(line.cross_size, line.cross_size = max(
fragment.border_box.size.block + line.cross_size,
fragment.margin.block_start_end()); fragment.border_box.size.block + fragment.margin.block_start_end(),
);
} }
total_cross_size += line.cross_size; total_cross_size += line.cross_size;
} }
} }
let box_border = self.block_flow.fragment.box_sizing_boundary(Direction::Block); let box_border = self
let parent_container_size = .block_flow
self.block_flow.explicit_block_containing_size(layout_context.shared_context()); .fragment
.box_sizing_boundary(Direction::Block);
let parent_container_size = self
.block_flow
.explicit_block_containing_size(layout_context.shared_context());
// https://drafts.csswg.org/css-ui-3/#box-sizing // https://drafts.csswg.org/css-ui-3/#box-sizing
let explicit_content_size = self let explicit_content_size = self
.block_flow .block_flow
@ -713,25 +782,25 @@ impl FlexFlow {
} else { } else {
free_space / (line_count - 1) free_space / (line_count - 1)
} }
} },
AlignContent::SpaceAround => { AlignContent::SpaceAround => {
if line_count == 0 { if line_count == 0 {
Au(0) Au(0)
} else { } else {
free_space / line_count free_space / line_count
} }
} },
_ => Au(0), _ => Au(0),
}; };
match line_align { match line_align {
AlignContent::Center | AlignContent::SpaceAround => { AlignContent::Center | AlignContent::SpaceAround => {
cur_b += (free_space - line_interval * (line_count - 1)) / 2; cur_b += (free_space - line_interval * (line_count - 1)) / 2;
} },
AlignContent::FlexEnd => { AlignContent::FlexEnd => {
cur_b += free_space; cur_b += free_space;
} },
_ => {} _ => {},
} }
} }
@ -744,8 +813,9 @@ impl FlexFlow {
let mut margin_block_start = block.fragment.margin.block_start; let mut margin_block_start = block.fragment.margin.block_start;
let mut margin_block_end = block.fragment.margin.block_end; let mut margin_block_end = block.fragment.margin.block_end;
let mut free_space = line.cross_size - block.base.position.size.block let mut free_space = line.cross_size -
- block.fragment.margin.block_start_end(); block.base.position.size.block -
block.fragment.margin.block_start_end();
// The spec is a little vague here, but if I understand it correctly, the outer // The spec is a little vague here, but if I understand it correctly, the outer
// cross size of item should equal to the line size if any auto margin exists. // cross size of item should equal to the line size if any auto margin exists.
@ -758,13 +828,15 @@ impl FlexFlow {
free_space / auto_margin_count free_space / auto_margin_count
}; };
} }
margin_block_end = line.cross_size - margin_block_start - block.base.position.size.block; margin_block_end =
line.cross_size - margin_block_start - block.base.position.size.block;
free_space = Au(0); free_space = Au(0);
} }
let self_align = block.fragment.style().get_position().align_self; let self_align = block.fragment.style().get_position().align_self;
if self_align == AlignSelf::Stretch && if self_align == AlignSelf::Stretch &&
block.fragment.style().content_block_size() == LengthOrPercentageOrAuto::Auto { block.fragment.style().content_block_size() == LengthOrPercentageOrAuto::Auto
{
free_space = Au(0); free_space = Au(0);
block.base.block_container_explicit_block_size = Some(line.cross_size); block.base.block_container_explicit_block_size = Some(line.cross_size);
block.base.position.size.block = block.base.position.size.block =
@ -774,12 +846,12 @@ impl FlexFlow {
// as if it has a fixed cross size, all child blocks should resolve against it. // as if it has a fixed cross size, all child blocks should resolve against it.
// block.assign_block_size(layout_context); // block.assign_block_size(layout_context);
} }
block.base.position.start.b = margin_block_start + block.base.position.start.b = margin_block_start + if !self.cross_reverse {
if !self.cross_reverse {
cur_b cur_b
} else { } else {
self.block_flow.fragment.border_padding.block_start * 2 self.block_flow.fragment.border_padding.block_start * 2 + total_cross_size -
+ total_cross_size - cur_b - line.cross_size cur_b -
line.cross_size
}; };
// TODO(stshine): support baseline alignment. // TODO(stshine): support baseline alignment.
if free_space != Au(0) { if free_space != Au(0) {
@ -788,8 +860,7 @@ impl FlexFlow {
AlignSelf::Center => free_space / 2, AlignSelf::Center => free_space / 2,
_ => Au(0), _ => Au(0),
}; };
block.base.position.start.b += block.base.position.start.b += if !self.cross_reverse {
if !self.cross_reverse {
flex_cross flex_cross
} else { } else {
free_space - flex_cross free_space - flex_cross
@ -798,7 +869,8 @@ impl FlexFlow {
} }
cur_b += line_interval + line.cross_size; cur_b += line_interval + line.cross_size;
} }
let total_block_size = total_cross_size + self.block_flow.fragment.border_padding.block_start_end(); let total_block_size =
total_cross_size + self.block_flow.fragment.border_padding.block_start_end();
self.block_flow.fragment.border_box.size.block = total_block_size; self.block_flow.fragment.border_box.size.block = total_block_size;
self.block_flow.base.position.size.block = total_block_size; self.block_flow.base.position.size.block = total_block_size;
} }
@ -830,24 +902,29 @@ impl Flow for FlexFlow {
} }
fn bubble_inline_sizes(&mut self) { fn bubble_inline_sizes(&mut self) {
let _scope = layout_debug_scope!("flex::bubble_inline_sizes {:x}", let _scope = layout_debug_scope!(
self.block_flow.base.debug_id()); "flex::bubble_inline_sizes {:x}",
self.block_flow.base.debug_id()
);
// Flexbox Section 9.0: Generate anonymous flex items: // Flexbox Section 9.0: Generate anonymous flex items:
// This part was handled in the flow constructor. // This part was handled in the flow constructor.
// Flexbox Section 9.1: Re-order flex items according to their order. // Flexbox Section 9.1: Re-order flex items according to their order.
// FIXME(stshine): This should be done during flow construction. // FIXME(stshine): This should be done during flow construction.
let mut items: Vec<FlexItem> = let mut items: Vec<FlexItem> = self
self.block_flow .block_flow
.base .base
.children .children
.iter() .iter()
.enumerate() .enumerate()
.filter(|&(_, flow)| { .filter(|&(_, flow)| {
!flow.as_block().base.flags.contains(FlowFlags::IS_ABSOLUTELY_POSITIONED) !flow
}) .as_block()
.map(|(index, flow)| FlexItem::new(index, flow)) .base
.flags
.contains(FlowFlags::IS_ABSOLUTELY_POSITIONED)
}).map(|(index, flow)| FlexItem::new(index, flow))
.collect(); .collect();
items.sort_by_key(|item| item.order); items.sort_by_key(|item| item.order);
@ -855,47 +932,66 @@ impl Flow for FlexFlow {
match self.main_mode { match self.main_mode {
Direction::Inline => self.inline_mode_bubble_inline_sizes(), Direction::Inline => self.inline_mode_bubble_inline_sizes(),
Direction::Block => self.block_mode_bubble_inline_sizes() Direction::Block => self.block_mode_bubble_inline_sizes(),
} }
} }
fn assign_inline_sizes(&mut self, layout_context: &LayoutContext) { fn assign_inline_sizes(&mut self, layout_context: &LayoutContext) {
let _scope = layout_debug_scope!("flex::assign_inline_sizes {:x}", self.block_flow.base.debug_id()); let _scope = layout_debug_scope!(
"flex::assign_inline_sizes {:x}",
self.block_flow.base.debug_id()
);
debug!("assign_inline_sizes"); debug!("assign_inline_sizes");
if !self.block_flow.base.restyle_damage.intersects(ServoRestyleDamage::REFLOW_OUT_OF_FLOW | if !self
ServoRestyleDamage::REFLOW) { .block_flow
return .base
.restyle_damage
.intersects(ServoRestyleDamage::REFLOW_OUT_OF_FLOW | ServoRestyleDamage::REFLOW)
{
return;
} }
self.block_flow.initialize_container_size_for_root(layout_context.shared_context()); self.block_flow
.initialize_container_size_for_root(layout_context.shared_context());
// Our inline-size was set to the inline-size of the containing block by the flow's parent. // Our inline-size was set to the inline-size of the containing block by the flow's parent.
// Now compute the real value. // Now compute the real value.
let containing_block_inline_size = self.block_flow.base.block_container_inline_size; let containing_block_inline_size = self.block_flow.base.block_container_inline_size;
self.block_flow.compute_used_inline_size(layout_context.shared_context(), self.block_flow.compute_used_inline_size(
containing_block_inline_size); layout_context.shared_context(),
containing_block_inline_size,
);
if self.block_flow.base.flags.is_float() { if self.block_flow.base.flags.is_float() {
self.block_flow.float.as_mut().unwrap().containing_inline_size = containing_block_inline_size self.block_flow
.float
.as_mut()
.unwrap()
.containing_inline_size = containing_block_inline_size
} }
let (available_block_size, available_inline_size) = { let (available_block_size, available_inline_size) = {
let style = &self.block_flow.fragment.style; let style = &self.block_flow.fragment.style;
let (specified_block_size, specified_inline_size) = if style.writing_mode.is_vertical() { let (specified_block_size, specified_inline_size) = if style.writing_mode.is_vertical()
{
(style.get_position().width, style.get_position().height) (style.get_position().width, style.get_position().height)
} else { } else {
(style.get_position().height, style.get_position().width) (style.get_position().height, style.get_position().width)
}; };
let available_inline_size = AxisSize::new(specified_inline_size, let available_inline_size = AxisSize::new(
specified_inline_size,
Some(self.block_flow.base.block_container_inline_size), Some(self.block_flow.base.block_container_inline_size),
style.min_inline_size(), style.min_inline_size(),
style.max_inline_size()); style.max_inline_size(),
);
let available_block_size = AxisSize::new(specified_block_size, let available_block_size = AxisSize::new(
specified_block_size,
self.block_flow.base.block_container_explicit_block_size, self.block_flow.base.block_container_explicit_block_size,
style.min_block_size(), style.min_block_size(),
style.max_block_size()); style.max_block_size(),
);
(available_block_size, available_inline_size) (available_block_size, available_inline_size)
}; };
@ -903,37 +999,46 @@ impl Flow for FlexFlow {
let inline_start_content_edge = self.block_flow.fragment.border_box.start.i + let inline_start_content_edge = self.block_flow.fragment.border_box.start.i +
self.block_flow.fragment.border_padding.inline_start; self.block_flow.fragment.border_padding.inline_start;
debug!("inline_start_content_edge = {:?}", inline_start_content_edge); debug!(
"inline_start_content_edge = {:?}",
inline_start_content_edge
);
let padding_and_borders = self.block_flow.fragment.border_padding.inline_start_end(); let padding_and_borders = self.block_flow.fragment.border_padding.inline_start_end();
// Distance from the inline-end margin edge to the inline-end content edge. // Distance from the inline-end margin edge to the inline-end content edge.
let inline_end_content_edge = let inline_end_content_edge = self.block_flow.fragment.margin.inline_end +
self.block_flow.fragment.margin.inline_end +
self.block_flow.fragment.border_padding.inline_end; self.block_flow.fragment.border_padding.inline_end;
debug!("padding_and_borders = {:?}", padding_and_borders); debug!("padding_and_borders = {:?}", padding_and_borders);
debug!("self.block_flow.fragment.border_box.size.inline = {:?}", debug!(
self.block_flow.fragment.border_box.size.inline); "self.block_flow.fragment.border_box.size.inline = {:?}",
let content_inline_size = self.block_flow.fragment.border_box.size.inline - padding_and_borders; self.block_flow.fragment.border_box.size.inline
);
let content_inline_size =
self.block_flow.fragment.border_box.size.inline - padding_and_borders;
match self.main_mode { match self.main_mode {
Direction::Inline => { Direction::Inline => {
self.available_main_size = available_inline_size; self.available_main_size = available_inline_size;
self.available_cross_size = available_block_size; self.available_cross_size = available_block_size;
self.inline_mode_assign_inline_sizes(layout_context, self.inline_mode_assign_inline_sizes(
layout_context,
inline_start_content_edge, inline_start_content_edge,
inline_end_content_edge, inline_end_content_edge,
content_inline_size) content_inline_size,
} )
},
Direction::Block => { Direction::Block => {
self.available_main_size = available_block_size; self.available_main_size = available_block_size;
self.available_cross_size = available_inline_size; self.available_cross_size = available_inline_size;
self.block_mode_assign_inline_sizes(layout_context, self.block_mode_assign_inline_sizes(
layout_context,
inline_start_content_edge, inline_start_content_edge,
inline_end_content_edge, inline_end_content_edge,
content_inline_size) content_inline_size,
} )
},
} }
} }
@ -941,31 +1046,37 @@ impl Flow for FlexFlow {
match self.main_mode { match self.main_mode {
Direction::Inline => { Direction::Inline => {
self.inline_mode_assign_block_size(layout_context); self.inline_mode_assign_block_size(layout_context);
let block_start = AdjoiningMargins::from_margin(self.block_flow.fragment.margin.block_start); let block_start =
let block_end = AdjoiningMargins::from_margin(self.block_flow.fragment.margin.block_end); AdjoiningMargins::from_margin(self.block_flow.fragment.margin.block_start);
self.block_flow.base.collapsible_margins = CollapsibleMargins::Collapse(block_start, block_end); let block_end =
AdjoiningMargins::from_margin(self.block_flow.fragment.margin.block_end);
self.block_flow.base.collapsible_margins =
CollapsibleMargins::Collapse(block_start, block_end);
// TODO(stshine): assign proper static position for absolute descendants. // TODO(stshine): assign proper static position for absolute descendants.
if (&*self as &Flow).contains_roots_of_absolute_flow_tree() { if (&*self as &Flow).contains_roots_of_absolute_flow_tree() {
// Assign block-sizes for all flows in this absolute flow tree. // Assign block-sizes for all flows in this absolute flow tree.
// This is preorder because the block-size of an absolute flow may depend on // This is preorder because the block-size of an absolute flow may depend on
// the block-size of its containing block, which may also be an absolute flow. // the block-size of its containing block, which may also be an absolute flow.
let assign_abs_b_sizes = AbsoluteAssignBSizesTraversal(layout_context.shared_context()); let assign_abs_b_sizes =
AbsoluteAssignBSizesTraversal(layout_context.shared_context());
assign_abs_b_sizes.traverse_absolute_flows(&mut *self); assign_abs_b_sizes.traverse_absolute_flows(&mut *self);
} }
} },
Direction::Block =>{ Direction::Block => {
self.block_flow self.block_flow.assign_block_size_block_base(
.assign_block_size_block_base(layout_context, layout_context,
None, None,
MarginsMayCollapseFlag::MarginsMayNotCollapse); MarginsMayCollapseFlag::MarginsMayNotCollapse,
);
self.block_mode_assign_block_size(); self.block_mode_assign_block_size();
} },
} }
} }
fn compute_stacking_relative_position(&mut self, layout_context: &LayoutContext) { fn compute_stacking_relative_position(&mut self, layout_context: &LayoutContext) {
self.block_flow.compute_stacking_relative_position(layout_context) self.block_flow
.compute_stacking_relative_position(layout_context)
} }
fn place_float_if_applicable<'a>(&mut self) { fn place_float_if_applicable<'a>(&mut self) {
@ -973,11 +1084,13 @@ impl Flow for FlexFlow {
} }
fn update_late_computed_inline_position_if_necessary(&mut self, inline_position: Au) { fn update_late_computed_inline_position_if_necessary(&mut self, inline_position: Au) {
self.block_flow.update_late_computed_inline_position_if_necessary(inline_position) self.block_flow
.update_late_computed_inline_position_if_necessary(inline_position)
} }
fn update_late_computed_block_position_if_necessary(&mut self, block_position: Au) { fn update_late_computed_block_position_if_necessary(&mut self, block_position: Au) {
self.block_flow.update_late_computed_block_position_if_necessary(block_position) self.block_flow
.update_late_computed_block_position_if_necessary(block_position)
} }
fn build_display_list(&mut self, state: &mut DisplayListBuildState) { fn build_display_list(&mut self, state: &mut DisplayListBuildState) {
@ -1008,11 +1121,17 @@ impl Flow for FlexFlow {
self.block_flow.generated_containing_block_size(flow) self.block_flow.generated_containing_block_size(flow)
} }
fn iterate_through_fragment_border_boxes(&self, fn iterate_through_fragment_border_boxes(
&self,
iterator: &mut FragmentBorderBoxIterator, iterator: &mut FragmentBorderBoxIterator,
level: i32, level: i32,
stacking_context_position: &Point2D<Au>) { stacking_context_position: &Point2D<Au>,
self.block_flow.iterate_through_fragment_border_boxes(iterator, level, stacking_context_position); ) {
self.block_flow.iterate_through_fragment_border_boxes(
iterator,
level,
stacking_context_position,
);
} }
fn mutate_fragments(&mut self, mutator: &mut FnMut(&mut Fragment)) { fn mutate_fragments(&mut self, mutator: &mut FnMut(&mut Fragment)) {

View file

@ -16,7 +16,7 @@ use style::values::computed::LengthOrPercentageOrAuto;
#[derive(Clone, Copy, Debug, Serialize)] #[derive(Clone, Copy, Debug, Serialize)]
pub enum FloatKind { pub enum FloatKind {
Left, Left,
Right Right,
} }
impl FloatKind { impl FloatKind {
@ -78,7 +78,12 @@ impl FloatList {
impl fmt::Debug for FloatList { impl fmt::Debug for FloatList {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "max_block_start={:?} floats={}", self.max_block_start, self.floats.len())?; write!(
f,
"max_block_start={:?} floats={}",
self.max_block_start,
self.floats.len()
)?;
for float in self.floats.iter() { for float in self.floats.iter() {
write!(f, " {:?}", float)?; write!(f, " {:?}", float)?;
} }
@ -95,22 +100,29 @@ pub struct PlacementInfo {
/// The maximum inline-end position of the float, generally determined by the containing block. /// The maximum inline-end position of the float, generally determined by the containing block.
pub max_inline_size: Au, pub max_inline_size: Au,
/// The kind of float. /// The kind of float.
pub kind: FloatKind pub kind: FloatKind,
} }
impl fmt::Debug for PlacementInfo { impl fmt::Debug for PlacementInfo {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, write!(
f,
"size={:?} ceiling={:?} max_inline_size={:?} kind={:?}", "size={:?} ceiling={:?} max_inline_size={:?} kind={:?}",
self.size, self.size, self.ceiling, self.max_inline_size, self.kind
self.ceiling, )
self.max_inline_size,
self.kind)
} }
} }
fn range_intersect(block_start_1: Au, block_end_1: Au, block_start_2: Au, block_end_2: Au) -> (Au, Au) { fn range_intersect(
(max(block_start_1, block_start_2), min(block_end_1, block_end_2)) block_start_1: Au,
block_end_1: Au,
block_start_2: Au,
block_end_2: Au,
) -> (Au, Au) {
(
max(block_start_1, block_start_2),
min(block_end_1, block_end_2),
)
} }
/// Encapsulates information about floats. This is optimized to avoid allocation if there are /// Encapsulates information about floats. This is optimized to avoid allocation if there are
@ -162,8 +174,12 @@ impl Floats {
/// with inline-size small enough that it doesn't collide with any floats. max_x is the /// with inline-size small enough that it doesn't collide with any floats. max_x is the
/// inline-size beyond which floats have no effect. (Generally this is the containing block /// inline-size beyond which floats have no effect. (Generally this is the containing block
/// inline-size.) /// inline-size.)
pub fn available_rect(&self, block_start: Au, block_size: Au, max_x: Au) pub fn available_rect(
-> Option<LogicalRect<Au>> { &self,
block_start: Au,
block_size: Au,
max_x: Au,
) -> Option<LogicalRect<Au>> {
let list = &self.list; let list = &self.list;
let block_start = block_start - self.offset.block; let block_start = block_start - self.offset.block;
@ -186,30 +202,38 @@ impl Floats {
debug!("float_pos: {:?}, float_size: {:?}", float_pos, float_size); debug!("float_pos: {:?}, float_size: {:?}", float_pos, float_size);
match float.kind { match float.kind {
FloatKind::Left if float_pos.i + float_size.inline > max_inline_start && FloatKind::Left
if float_pos.i + float_size.inline > max_inline_start &&
float_pos.b + float_size.block > block_start && float_pos.b + float_size.block > block_start &&
float_pos.b < block_start + block_size => { float_pos.b < block_start + block_size =>
{
max_inline_start = float_pos.i + float_size.inline; max_inline_start = float_pos.i + float_size.inline;
l_block_start = Some(float_pos.b); l_block_start = Some(float_pos.b);
l_block_end = Some(float_pos.b + float_size.block); l_block_end = Some(float_pos.b + float_size.block);
debug!("available_rect: collision with inline_start float: new \ debug!(
"available_rect: collision with inline_start float: new \
max_inline_start is {:?}", max_inline_start is {:?}",
max_inline_start); max_inline_start
);
} }
FloatKind::Right if float_pos.i < min_inline_end && FloatKind::Right
if float_pos.i < min_inline_end &&
float_pos.b + float_size.block > block_start && float_pos.b + float_size.block > block_start &&
float_pos.b < block_start + block_size => { float_pos.b < block_start + block_size =>
{
min_inline_end = float_pos.i; min_inline_end = float_pos.i;
r_block_start = Some(float_pos.b); r_block_start = Some(float_pos.b);
r_block_end = Some(float_pos.b + float_size.block); r_block_end = Some(float_pos.b + float_size.block);
debug!("available_rect: collision with inline_end float: new min_inline_end \ debug!(
"available_rect: collision with inline_end float: new min_inline_end \
is {:?}", is {:?}",
min_inline_end); min_inline_end
);
} }
FloatKind::Left | FloatKind::Right => {} FloatKind::Left | FloatKind::Right => {},
} }
} }
@ -217,24 +241,27 @@ impl Floats {
// If there are floats on both sides, take the intersection of the // If there are floats on both sides, take the intersection of the
// two areas. Also make sure we never return a block-start smaller than the // two areas. Also make sure we never return a block-start smaller than the
// given upper bound. // given upper bound.
let (block_start, block_end) = match (r_block_start, let (block_start, block_end) =
r_block_end, match (r_block_start, r_block_end, l_block_start, l_block_end) {
l_block_start, (
l_block_end) { Some(r_block_start),
(Some(r_block_start), Some(r_block_end), Some(l_block_start), Some(l_block_end)) => { Some(r_block_end),
range_intersect(max(block_start, r_block_start), Some(l_block_start),
Some(l_block_end),
) => range_intersect(
max(block_start, r_block_start),
r_block_end, r_block_end,
max(block_start, l_block_start), max(block_start, l_block_start),
l_block_end) l_block_end,
} ),
(None, None, Some(l_block_start), Some(l_block_end)) => { (None, None, Some(l_block_start), Some(l_block_end)) => {
(max(block_start, l_block_start), l_block_end) (max(block_start, l_block_start), l_block_end)
} },
(Some(r_block_start), Some(r_block_end), None, None) => { (Some(r_block_start), Some(r_block_end), None, None) => {
(max(block_start, r_block_start), r_block_end) (max(block_start, r_block_start), r_block_end)
} },
(None, None, None, None) => return None, (None, None, None, None) => return None,
_ => panic!("Reached unreachable state when computing float area") _ => panic!("Reached unreachable state when computing float area"),
}; };
// FIXME(eatkinson): This assertion is too strong and fails in some cases. It is OK to // FIXME(eatkinson): This assertion is too strong and fails in some cases. It is OK to
@ -244,11 +271,13 @@ impl Floats {
assert!(block_start <= block_end, "Float position error"); assert!(block_start <= block_end, "Float position error");
Some(LogicalRect::new(self.writing_mode, Some(LogicalRect::new(
self.writing_mode,
max_inline_start + self.offset.inline, max_inline_start + self.offset.inline,
block_start + self.offset.block, block_start + self.offset.block,
min_inline_end - max_inline_start, min_inline_end - max_inline_start,
block_end - block_start)) block_end - block_start,
))
} }
/// Adds a new float to the list. /// Adds a new float to the list.
@ -260,7 +289,7 @@ impl Floats {
Some(max_block_start) => max(info.ceiling, max_block_start + self.offset.block), Some(max_block_start) => max(info.ceiling, max_block_start + self.offset.block),
}, },
max_inline_size: info.max_inline_size, max_inline_size: info.max_inline_size,
kind: info.kind kind: info.kind,
}; };
debug!("add_float: added float with info {:?}", new_info); debug!("add_float: added float with info {:?}", new_info);
@ -271,7 +300,7 @@ impl Floats {
self.place_between_floats(&new_info).start - self.offset, self.place_between_floats(&new_info).start - self.offset,
info.size, info.size,
), ),
kind: info.kind kind: info.kind,
}; };
self.list.floats = self.list.floats.prepend_elem(new_float); self.list.floats = self.list.floats.prepend_elem(new_float);
@ -284,8 +313,12 @@ impl Floats {
/// Given the three sides of the bounding rectangle in the block-start direction, finds the /// Given the three sides of the bounding rectangle in the block-start direction, finds the
/// largest block-size that will result in the rectangle not colliding with any floats. Returns /// largest block-size that will result in the rectangle not colliding with any floats. Returns
/// `None` if that block-size is infinite. /// `None` if that block-size is infinite.
fn max_block_size_for_bounds(&self, inline_start: Au, block_start: Au, inline_size: Au) fn max_block_size_for_bounds(
-> Option<Au> { &self,
inline_start: Au,
block_start: Au,
inline_size: Au,
) -> Option<Au> {
let list = &self.list; let list = &self.list;
let block_start = block_start - self.offset.block; let block_start = block_start - self.offset.block;
@ -295,7 +328,8 @@ impl Floats {
for float in list.floats.iter() { for float in list.floats.iter() {
if float.bounds.start.b + float.bounds.size.block > block_start && if float.bounds.start.b + float.bounds.size.block > block_start &&
float.bounds.start.i + float.bounds.size.inline > inline_start && float.bounds.start.i + float.bounds.size.inline > inline_start &&
float.bounds.start.i < inline_start + inline_size { float.bounds.start.i < inline_start + inline_size
{
let new_y = float.bounds.start.b; let new_y = float.bounds.start.b;
max_block_size = Some(min(max_block_size.unwrap_or(new_y), new_y)); max_block_size = Some(min(max_block_size.unwrap_or(new_y), new_y));
} }
@ -318,85 +352,88 @@ impl Floats {
Au(0), Au(0),
info.ceiling, info.ceiling,
info.max_inline_size, info.max_inline_size,
MAX_AU) MAX_AU,
} )
},
FloatKind::Right => { FloatKind::Right => {
return LogicalRect::new( return LogicalRect::new(
self.writing_mode, self.writing_mode,
info.max_inline_size - info.size.inline, info.max_inline_size - info.size.inline,
info.ceiling, info.ceiling,
info.max_inline_size, info.max_inline_size,
MAX_AU) MAX_AU,
} )
},
} }
} }
// Can't go any higher than previous floats or previous elements in the document. // Can't go any higher than previous floats or previous elements in the document.
let mut float_b = info.ceiling; let mut float_b = info.ceiling;
loop { loop {
let maybe_location = self.available_rect(float_b, let maybe_location =
info.size.block, self.available_rect(float_b, info.size.block, info.max_inline_size);
info.max_inline_size); debug!(
debug!("place_float: got available rect: {:?} for block-pos: {:?}", "place_float: got available rect: {:?} for block-pos: {:?}",
maybe_location, maybe_location, float_b
float_b); );
match maybe_location { match maybe_location {
// If there are no floats blocking us, return the current location // If there are no floats blocking us, return the current location
// TODO(eatkinson): integrate with overflow // TODO(eatkinson): integrate with overflow
None => { None => {
return match info.kind { return match info.kind {
FloatKind::Left => { FloatKind::Left => LogicalRect::new(
LogicalRect::new(
self.writing_mode, self.writing_mode,
Au(0), Au(0),
float_b, float_b,
info.max_inline_size, info.max_inline_size,
MAX_AU) MAX_AU,
} ),
FloatKind::Right => { FloatKind::Right => LogicalRect::new(
LogicalRect::new(
self.writing_mode, self.writing_mode,
info.max_inline_size - info.size.inline, info.max_inline_size - info.size.inline,
float_b, float_b,
info.max_inline_size, info.max_inline_size,
MAX_AU) MAX_AU,
} ),
}
} }
},
Some(rect) => { Some(rect) => {
assert_ne!(rect.start.b + rect.size.block, float_b, assert_ne!(
"Non-terminating float placement"); rect.start.b + rect.size.block,
float_b,
"Non-terminating float placement"
);
// Place here if there is enough room // Place here if there is enough room
if rect.size.inline >= info.size.inline { if rect.size.inline >= info.size.inline {
let block_size = self.max_block_size_for_bounds(rect.start.i, let block_size = self.max_block_size_for_bounds(
rect.start.i,
rect.start.b, rect.start.b,
rect.size.inline); rect.size.inline,
);
let block_size = block_size.unwrap_or(MAX_AU); let block_size = block_size.unwrap_or(MAX_AU);
return match info.kind { return match info.kind {
FloatKind::Left => { FloatKind::Left => LogicalRect::new(
LogicalRect::new(
self.writing_mode, self.writing_mode,
rect.start.i, rect.start.i,
float_b, float_b,
rect.size.inline, rect.size.inline,
block_size) block_size,
} ),
FloatKind::Right => { FloatKind::Right => LogicalRect::new(
LogicalRect::new(
self.writing_mode, self.writing_mode,
rect.start.i + rect.size.inline - info.size.inline, rect.start.i + rect.size.inline - info.size.inline,
float_b, float_b,
rect.size.inline, rect.size.inline,
block_size) block_size,
} ),
} };
} }
// Try to place at the next-lowest location. // Try to place at the next-lowest location.
// Need to be careful of fencepost errors. // Need to be careful of fencepost errors.
float_b = rect.start.b + rect.size.block; float_b = rect.start.b + rect.size.block;
} },
} }
} }
} }
@ -411,8 +448,8 @@ impl Floats {
(ClearType::Both, _) => { (ClearType::Both, _) => {
let b = self.offset.block + float.bounds.start.b + float.bounds.size.block; let b = self.offset.block + float.bounds.start.b + float.bounds.size.block;
clearance = max(clearance, b); clearance = max(clearance, b);
} },
_ => {} _ => {},
} }
} }
clearance clearance
@ -486,14 +523,20 @@ impl SpeculatedFloatPlacement {
} }
} }
self.left = max(self.left, block_flow.base.speculated_float_placement_in.left); self.left = max(
self.right = max(self.right, block_flow.base.speculated_float_placement_in.right); self.left,
block_flow.base.speculated_float_placement_in.left,
);
self.right = max(
self.right,
block_flow.base.speculated_float_placement_in.right,
);
} }
} }
let base_flow = flow.base(); let base_flow = flow.base();
if !base_flow.flags.is_float() { if !base_flow.flags.is_float() {
return return;
} }
let mut float_inline_size = base_flow.intrinsic_inline_sizes.preferred_inline_size; let mut float_inline_size = base_flow.intrinsic_inline_sizes.preferred_inline_size;
@ -504,7 +547,8 @@ impl SpeculatedFloatPlacement {
// that the layout traversal logic will know that objects later in the document // that the layout traversal logic will know that objects later in the document
// might flow around this float. // might flow around this float.
if let LengthOrPercentageOrAuto::Percentage(percentage) = if let LengthOrPercentageOrAuto::Percentage(percentage) =
flow.as_block().fragment.style.content_inline_size() { flow.as_block().fragment.style.content_inline_size()
{
if percentage.0 > 0.0 { if percentage.0 > 0.0 {
float_inline_size = Au::from_px(1) float_inline_size = Au::from_px(1)
} }
@ -513,7 +557,7 @@ impl SpeculatedFloatPlacement {
} }
match base_flow.flags.float_kind() { match base_flow.flags.float_kind() {
StyleFloat::None => {} StyleFloat::None => {},
StyleFloat::Left => self.left = self.left + float_inline_size, StyleFloat::Left => self.left = self.left + float_inline_size,
StyleFloat::Right => self.right = self.right + float_inline_size, StyleFloat::Right => self.right = self.right + float_inline_size,
} }
@ -522,17 +566,18 @@ impl SpeculatedFloatPlacement {
/// Given a flow, computes the speculated inline size of the floats in of its first child. /// Given a flow, computes the speculated inline size of the floats in of its first child.
pub fn compute_floats_in_for_first_child(parent_flow: &mut Flow) -> SpeculatedFloatPlacement { pub fn compute_floats_in_for_first_child(parent_flow: &mut Flow) -> SpeculatedFloatPlacement {
if !parent_flow.is_block_like() { if !parent_flow.is_block_like() {
return parent_flow.base().speculated_float_placement_in return parent_flow.base().speculated_float_placement_in;
} }
let parent_block_flow = parent_flow.as_block(); let parent_block_flow = parent_flow.as_block();
if parent_block_flow.formatting_context_type() != FormattingContextType::None { if parent_block_flow.formatting_context_type() != FormattingContextType::None {
return SpeculatedFloatPlacement::zero() return SpeculatedFloatPlacement::zero();
} }
let mut placement = parent_block_flow.base.speculated_float_placement_in; let mut placement = parent_block_flow.base.speculated_float_placement_in;
let speculated_inline_content_edge_offsets = let speculated_inline_content_edge_offsets = parent_block_flow
parent_block_flow.fragment.guess_inline_content_edge_offsets(); .fragment
.guess_inline_content_edge_offsets();
if speculated_inline_content_edge_offsets.start > Au(0) { if speculated_inline_content_edge_offsets.start > Au(0) {
placement.left = if placement.left > speculated_inline_content_edge_offsets.start { placement.left = if placement.left > speculated_inline_content_edge_offsets.start {
@ -552,4 +597,3 @@ impl SpeculatedFloatPlacement {
placement placement
} }
} }

View file

@ -251,11 +251,15 @@ pub trait Flow: HasBaseFlow + fmt::Debug + Sync + Send + 'static {
/// and return a new flow similar to `self` with the rest of the content. /// and return a new flow similar to `self` with the rest of the content.
/// ///
/// The default is to make a flow "atomic": it can not be fragmented. /// The default is to make a flow "atomic": it can not be fragmented.
fn fragment(&mut self, fn fragment(
&mut self,
layout_context: &LayoutContext, layout_context: &LayoutContext,
_fragmentation_context: Option<FragmentationContext>) _fragmentation_context: Option<FragmentationContext>,
-> Option<Arc<Flow>> { ) -> Option<Arc<Flow>> {
fn recursive_assign_block_size<F: ?Sized + Flow + GetBaseFlow>(flow: &mut F, ctx: &LayoutContext) { fn recursive_assign_block_size<F: ?Sized + Flow + GetBaseFlow>(
flow: &mut F,
ctx: &LayoutContext,
) {
for child in flow.mut_base().child_iter_mut() { for child in flow.mut_base().child_iter_mut() {
recursive_assign_block_size(child, ctx) recursive_assign_block_size(child, ctx)
} }
@ -277,17 +281,20 @@ pub trait Flow: HasBaseFlow + fmt::Debug + Sync + Send + 'static {
/// `parent_thread_id` is the thread ID of the parent. This is used for the layout tinting /// `parent_thread_id` is the thread ID of the parent. This is used for the layout tinting
/// debug mode; if the block size of this flow was determined by its parent, we should treat /// debug mode; if the block size of this flow was determined by its parent, we should treat
/// it as laid out by its parent. /// it as laid out by its parent.
fn assign_block_size_for_inorder_child_if_necessary(&mut self, fn assign_block_size_for_inorder_child_if_necessary(
&mut self,
layout_context: &LayoutContext, layout_context: &LayoutContext,
parent_thread_id: u8, parent_thread_id: u8,
_content_box: LogicalRect<Au>) _content_box: LogicalRect<Au>,
-> bool { ) -> bool {
let might_have_floats_in_or_out = self.base().might_have_floats_in() || let might_have_floats_in_or_out =
self.base().might_have_floats_out(); self.base().might_have_floats_in() || self.base().might_have_floats_out();
if might_have_floats_in_or_out { if might_have_floats_in_or_out {
self.mut_base().thread_id = parent_thread_id; self.mut_base().thread_id = parent_thread_id;
self.assign_block_size(layout_context); self.assign_block_size(layout_context);
self.mut_base().restyle_damage.remove(ServoRestyleDamage::REFLOW_OUT_OF_FLOW | ServoRestyleDamage::REFLOW); self.mut_base()
.restyle_damage
.remove(ServoRestyleDamage::REFLOW_OUT_OF_FLOW | ServoRestyleDamage::REFLOW);
} }
might_have_floats_in_or_out might_have_floats_in_or_out
} }
@ -295,23 +302,32 @@ pub trait Flow: HasBaseFlow + fmt::Debug + Sync + Send + 'static {
fn get_overflow_in_parent_coordinates(&self) -> Overflow { fn get_overflow_in_parent_coordinates(&self) -> Overflow {
// FIXME(#2795): Get the real container size. // FIXME(#2795): Get the real container size.
let container_size = Size2D::zero(); let container_size = Size2D::zero();
let position = self.base().position.to_physical(self.base().writing_mode, container_size); let position = self
.base()
.position
.to_physical(self.base().writing_mode, container_size);
let mut overflow = self.base().overflow; let mut overflow = self.base().overflow;
match self.class() { match self.class() {
FlowClass::Block | FlowClass::TableCaption | FlowClass::TableCell => {} FlowClass::Block | FlowClass::TableCaption | FlowClass::TableCell => {},
_ => { _ => {
overflow.translate(&position.origin.to_vector()); overflow.translate(&position.origin.to_vector());
return overflow; return overflow;
} },
} }
let border_box = self.as_block().fragment.stacking_relative_border_box( let border_box = self.as_block().fragment.stacking_relative_border_box(
&self.base().stacking_relative_position, &self.base().stacking_relative_position,
&self.base().early_absolute_position_info.relative_containing_block_size, &self
self.base().early_absolute_position_info.relative_containing_block_mode, .base()
CoordinateSystem::Own); .early_absolute_position_info
.relative_containing_block_size,
self.base()
.early_absolute_position_info
.relative_containing_block_mode,
CoordinateSystem::Own,
);
if StyleOverflow::Visible != self.as_block().fragment.style.get_box().overflow_x { if StyleOverflow::Visible != self.as_block().fragment.style.get_box().overflow_x {
overflow.paint.origin.x = Au(0); overflow.paint.origin.x = Au(0);
overflow.paint.size.width = border_box.size.width; overflow.paint.size.width = border_box.size.width;
@ -325,24 +341,35 @@ pub trait Flow: HasBaseFlow + fmt::Debug + Sync + Send + 'static {
overflow.scroll.size.height = border_box.size.height; overflow.scroll.size.height = border_box.size.height;
} }
if !self.as_block().fragment.establishes_stacking_context() || if !self.as_block().fragment.establishes_stacking_context() || self
self.as_block().fragment.style.get_box().transform.0.is_empty() { .as_block()
.fragment
.style
.get_box()
.transform
.0
.is_empty()
{
overflow.translate(&position.origin.to_vector()); overflow.translate(&position.origin.to_vector());
return overflow; return overflow;
} }
// TODO: Take into account 3d transforms, even though it's a fairly // TODO: Take into account 3d transforms, even though it's a fairly
// uncommon case. // uncommon case.
let transform_2d = self.as_block() let transform_2d = self
.as_block()
.fragment .fragment
.transform_matrix(&position) .transform_matrix(&position)
.unwrap_or(LayoutTransform::identity()) .unwrap_or(LayoutTransform::identity())
.to_2d().to_untyped(); .to_2d()
.to_untyped();
let transformed_overflow = Overflow { let transformed_overflow = Overflow {
paint: f32_rect_to_au_rect(transform_2d.transform_rect( paint: f32_rect_to_au_rect(
&au_rect_to_f32_rect(overflow.paint))), transform_2d.transform_rect(&au_rect_to_f32_rect(overflow.paint)),
scroll: f32_rect_to_au_rect(transform_2d.transform_rect( ),
&au_rect_to_f32_rect(overflow.scroll))), scroll: f32_rect_to_au_rect(
transform_2d.transform_rect(&au_rect_to_f32_rect(overflow.scroll)),
),
}; };
// TODO: We are taking the union of the overflow and transformed overflow here, which // TODO: We are taking the union of the overflow and transformed overflow here, which
@ -369,14 +396,12 @@ pub trait Flow: HasBaseFlow + fmt::Debug + Sync + Send + 'static {
// Calculate overflow on a per-fragment basis. // Calculate overflow on a per-fragment basis.
let mut overflow = self.compute_overflow(); let mut overflow = self.compute_overflow();
match self.class() { match self.class() {
FlowClass::Block | FlowClass::Block | FlowClass::TableCaption | FlowClass::TableCell => {
FlowClass::TableCaption |
FlowClass::TableCell => {
for kid in self.mut_base().children.iter_mut() { for kid in self.mut_base().children.iter_mut() {
overflow.union(&kid.get_overflow_in_parent_coordinates()); overflow.union(&kid.get_overflow_in_parent_coordinates());
} }
} },
_ => {} _ => {},
} }
self.mut_base().overflow = overflow self.mut_base().overflow = overflow
} }
@ -396,17 +421,21 @@ pub trait Flow: HasBaseFlow + fmt::Debug + Sync + Send + 'static {
/// Iterates through border boxes of all of this flow's fragments. /// Iterates through border boxes of all of this flow's fragments.
/// Level provides a zero based index indicating the current /// Level provides a zero based index indicating the current
/// depth of the flow tree during fragment iteration. /// depth of the flow tree during fragment iteration.
fn iterate_through_fragment_border_boxes(&self, fn iterate_through_fragment_border_boxes(
&self,
iterator: &mut FragmentBorderBoxIterator, iterator: &mut FragmentBorderBoxIterator,
level: i32, level: i32,
stacking_context_position: &Point2D<Au>); stacking_context_position: &Point2D<Au>,
);
/// Mutably iterates through fragments in this flow. /// Mutably iterates through fragments in this flow.
fn mutate_fragments(&mut self, mutator: &mut FnMut(&mut Fragment)); fn mutate_fragments(&mut self, mutator: &mut FnMut(&mut Fragment));
fn compute_collapsible_block_start_margin(&mut self, fn compute_collapsible_block_start_margin(
&mut self,
_layout_context: &mut LayoutContext, _layout_context: &mut LayoutContext,
_margin_collapse_info: &mut MarginCollapseInfo) { _margin_collapse_info: &mut MarginCollapseInfo,
) {
// The default implementation is a no-op. // The default implementation is a no-op.
} }
@ -436,8 +465,10 @@ pub trait Flow: HasBaseFlow + fmt::Debug + Sync + Send + 'static {
} }
fn contains_positioned_fragments(&self) -> bool { fn contains_positioned_fragments(&self) -> bool {
self.contains_relatively_positioned_fragments() || self.contains_relatively_positioned_fragments() || self
self.base().flags.contains(FlowFlags::IS_ABSOLUTELY_POSITIONED) .base()
.flags
.contains(FlowFlags::IS_ABSOLUTELY_POSITIONED)
} }
fn contains_relatively_positioned_fragments(&self) -> bool { fn contains_relatively_positioned_fragments(&self) -> bool {
@ -476,7 +507,7 @@ pub trait Flow: HasBaseFlow + fmt::Debug + Sync + Send + 'static {
/// Print any extra children (such as fragments) contained in this Flow /// Print any extra children (such as fragments) contained in this Flow
/// for debugging purposes. Any items inserted into the tree will become /// for debugging purposes. Any items inserted into the tree will become
/// children of this flow. /// children of this flow.
fn print_extra_flow_children(&self, _: &mut PrintTree) { } fn print_extra_flow_children(&self, _: &mut PrintTree) {}
fn clipping_and_scrolling(&self) -> ClippingAndScrolling { fn clipping_and_scrolling(&self) -> ClippingAndScrolling {
match self.base().clipping_and_scrolling { match self.base().clipping_and_scrolling {
@ -566,8 +597,10 @@ pub trait MutableOwnedFlowUtils {
/// </span> /// </span>
/// </div> /// </div>
/// ``` /// ```
fn take_applicable_absolute_descendants(&mut self, fn take_applicable_absolute_descendants(
absolute_descendants: &mut AbsoluteDescendants); &mut self,
absolute_descendants: &mut AbsoluteDescendants,
);
} }
#[derive(Clone, Copy, Debug, PartialEq, Serialize)] #[derive(Clone, Copy, Debug, PartialEq, Serialize)]
@ -590,9 +623,15 @@ pub enum FlowClass {
impl FlowClass { impl FlowClass {
fn is_block_like(self) -> bool { fn is_block_like(self) -> bool {
match self { match self {
FlowClass::Block | FlowClass::ListItem | FlowClass::Table | FlowClass::TableRowGroup | FlowClass::Block |
FlowClass::TableRow | FlowClass::TableCaption | FlowClass::TableCell | FlowClass::ListItem |
FlowClass::TableWrapper | FlowClass::Flex => true, FlowClass::Table |
FlowClass::TableRowGroup |
FlowClass::TableRow |
FlowClass::TableCaption |
FlowClass::TableCell |
FlowClass::TableWrapper |
FlowClass::Flex => true,
_ => false, _ => false,
} }
} }
@ -776,7 +815,9 @@ pub struct AbsoluteDescendantIter<'a> {
impl<'a> Iterator for AbsoluteDescendantIter<'a> { impl<'a> Iterator for AbsoluteDescendantIter<'a> {
type Item = &'a mut Flow; type Item = &'a mut Flow;
fn next(&mut self) -> Option<&'a mut Flow> { fn next(&mut self) -> Option<&'a mut Flow> {
self.iter.next().map(|info| FlowRef::deref_mut(&mut info.flow)) self.iter
.next()
.map(|info| FlowRef::deref_mut(&mut info.flow))
} }
fn size_hint(&self) -> (usize, Option<usize>) { fn size_hint(&self) -> (usize, Option<usize>) {
@ -953,7 +994,8 @@ impl fmt::Debug for BaseFlow {
"".to_owned() "".to_owned()
}; };
write!(f, write!(
f,
"\nsc={:?}\ "\nsc={:?}\
\npos={:?}{}{}\ \npos={:?}{}{}\
\nfloatspec-in={:?}\ \nfloatspec-in={:?}\
@ -961,14 +1003,23 @@ impl fmt::Debug for BaseFlow {
\noverflow={:?}{}{}{}", \noverflow={:?}{}{}{}",
self.stacking_context_id, self.stacking_context_id,
self.position, self.position,
if self.flags.contains(FlowFlags::FLOATS_LEFT) { "FL" } else { "" }, if self.flags.contains(FlowFlags::FLOATS_LEFT) {
if self.flags.contains(FlowFlags::FLOATS_RIGHT) { "FR" } else { "" }, "FL"
} else {
""
},
if self.flags.contains(FlowFlags::FLOATS_RIGHT) {
"FR"
} else {
""
},
self.speculated_float_placement_in, self.speculated_float_placement_in,
self.speculated_float_placement_out, self.speculated_float_placement_out,
self.overflow, self.overflow,
child_count_string, child_count_string,
absolute_descendants_string, absolute_descendants_string,
damage_string) damage_string
)
} }
} }
@ -976,7 +1027,10 @@ impl Serialize for BaseFlow {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> { fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let mut serializer = serializer.serialize_struct("base", 5)?; let mut serializer = serializer.serialize_struct("base", 5)?;
serializer.serialize_field("id", &self.debug_id())?; serializer.serialize_field("id", &self.debug_id())?;
serializer.serialize_field("stacking_relative_position", &self.stacking_relative_position)?; serializer.serialize_field(
"stacking_relative_position",
&self.stacking_relative_position,
)?;
serializer.serialize_field("intrinsic_inline_sizes", &self.intrinsic_inline_sizes)?; serializer.serialize_field("intrinsic_inline_sizes", &self.intrinsic_inline_sizes)?;
serializer.serialize_field("position", &self.position)?; serializer.serialize_field("position", &self.position)?;
serializer.serialize_field("children", &self.children)?; serializer.serialize_field("children", &self.children)?;
@ -996,10 +1050,11 @@ pub enum ForceNonfloatedFlag {
impl BaseFlow { impl BaseFlow {
#[inline] #[inline]
pub fn new(style: Option<&ComputedValues>, pub fn new(
style: Option<&ComputedValues>,
writing_mode: WritingMode, writing_mode: WritingMode,
force_nonfloated: ForceNonfloatedFlag) force_nonfloated: ForceNonfloatedFlag,
-> BaseFlow { ) -> BaseFlow {
let mut flags = FlowFlags::empty(); let mut flags = FlowFlags::empty();
match style { match style {
Some(style) => { Some(style) => {
@ -1013,41 +1068,47 @@ impl BaseFlow {
let logical_position = style.logical_position(); let logical_position = style.logical_position();
if logical_position.inline_start == LengthOrPercentageOrAuto::Auto && if logical_position.inline_start == LengthOrPercentageOrAuto::Auto &&
logical_position.inline_end == LengthOrPercentageOrAuto::Auto { logical_position.inline_end == LengthOrPercentageOrAuto::Auto
{
flags.insert(FlowFlags::INLINE_POSITION_IS_STATIC); flags.insert(FlowFlags::INLINE_POSITION_IS_STATIC);
} }
if logical_position.block_start == LengthOrPercentageOrAuto::Auto && if logical_position.block_start == LengthOrPercentageOrAuto::Auto &&
logical_position.block_end == LengthOrPercentageOrAuto::Auto { logical_position.block_end == LengthOrPercentageOrAuto::Auto
{
flags.insert(FlowFlags::BLOCK_POSITION_IS_STATIC); flags.insert(FlowFlags::BLOCK_POSITION_IS_STATIC);
} }
} },
_ => flags.insert(FlowFlags::BLOCK_POSITION_IS_STATIC | FlowFlags::INLINE_POSITION_IS_STATIC), _ => flags.insert(
FlowFlags::BLOCK_POSITION_IS_STATIC | FlowFlags::INLINE_POSITION_IS_STATIC,
),
} }
if force_nonfloated == ForceNonfloatedFlag::FloatIfNecessary { if force_nonfloated == ForceNonfloatedFlag::FloatIfNecessary {
match style.get_box().float { match style.get_box().float {
Float::None => {} Float::None => {},
Float::Left => flags.insert(FlowFlags::FLOATS_LEFT), Float::Left => flags.insert(FlowFlags::FLOATS_LEFT),
Float::Right => flags.insert(FlowFlags::FLOATS_RIGHT), Float::Right => flags.insert(FlowFlags::FLOATS_RIGHT),
} }
} }
match style.get_box().clear { match style.get_box().clear {
Clear::None => {} Clear::None => {},
Clear::Left => flags.insert(FlowFlags::CLEARS_LEFT), Clear::Left => flags.insert(FlowFlags::CLEARS_LEFT),
Clear::Right => flags.insert(FlowFlags::CLEARS_RIGHT), Clear::Right => flags.insert(FlowFlags::CLEARS_RIGHT),
Clear::Both => { Clear::Both => {
flags.insert(FlowFlags::CLEARS_LEFT); flags.insert(FlowFlags::CLEARS_LEFT);
flags.insert(FlowFlags::CLEARS_RIGHT); flags.insert(FlowFlags::CLEARS_RIGHT);
} },
} }
if !style.get_counters().counter_reset.is_empty() || if !style.get_counters().counter_reset.is_empty() ||
!style.get_counters().counter_increment.is_empty() { !style.get_counters().counter_increment.is_empty()
{
flags.insert(FlowFlags::AFFECTS_COUNTERS) flags.insert(FlowFlags::AFFECTS_COUNTERS)
} }
} },
None => flags.insert(FlowFlags::BLOCK_POSITION_IS_STATIC | FlowFlags::INLINE_POSITION_IS_STATIC), None => flags
.insert(FlowFlags::BLOCK_POSITION_IS_STATIC | FlowFlags::INLINE_POSITION_IS_STATIC),
} }
// New flows start out as fully damaged. // New flows start out as fully damaged.
@ -1089,17 +1150,24 @@ impl BaseFlow {
pub fn update_flags_if_needed(&mut self, style: &ComputedValues) { pub fn update_flags_if_needed(&mut self, style: &ComputedValues) {
// For absolutely-positioned flows, changes to top/bottom/left/right can cause these flags // For absolutely-positioned flows, changes to top/bottom/left/right can cause these flags
// to get out of date: // to get out of date:
if self.restyle_damage.contains(ServoRestyleDamage::REFLOW_OUT_OF_FLOW) { if self
.restyle_damage
.contains(ServoRestyleDamage::REFLOW_OUT_OF_FLOW)
{
// Note: We don't need to check whether IS_ABSOLUTELY_POSITIONED has changed, because // Note: We don't need to check whether IS_ABSOLUTELY_POSITIONED has changed, because
// changes to the 'position' property trigger flow reconstruction. // changes to the 'position' property trigger flow reconstruction.
if self.flags.contains(FlowFlags::IS_ABSOLUTELY_POSITIONED) { if self.flags.contains(FlowFlags::IS_ABSOLUTELY_POSITIONED) {
let logical_position = style.logical_position(); let logical_position = style.logical_position();
self.flags.set(FlowFlags::INLINE_POSITION_IS_STATIC, self.flags.set(
FlowFlags::INLINE_POSITION_IS_STATIC,
logical_position.inline_start == LengthOrPercentageOrAuto::Auto && logical_position.inline_start == LengthOrPercentageOrAuto::Auto &&
logical_position.inline_end == LengthOrPercentageOrAuto::Auto); logical_position.inline_end == LengthOrPercentageOrAuto::Auto,
self.flags.set(FlowFlags::BLOCK_POSITION_IS_STATIC, );
self.flags.set(
FlowFlags::BLOCK_POSITION_IS_STATIC,
logical_position.block_start == LengthOrPercentageOrAuto::Auto && logical_position.block_start == LengthOrPercentageOrAuto::Auto &&
logical_position.block_end == LengthOrPercentageOrAuto::Auto); logical_position.block_end == LengthOrPercentageOrAuto::Auto,
);
} }
} }
} }
@ -1108,8 +1176,10 @@ impl BaseFlow {
pub fn clone_with_children(&self, children: FlowList) -> BaseFlow { pub fn clone_with_children(&self, children: FlowList) -> BaseFlow {
BaseFlow { BaseFlow {
children: children, children: children,
restyle_damage: self.restyle_damage | ServoRestyleDamage::REPAINT | restyle_damage: self.restyle_damage |
ServoRestyleDamage::REFLOW_OUT_OF_FLOW | ServoRestyleDamage::REFLOW, ServoRestyleDamage::REPAINT |
ServoRestyleDamage::REFLOW_OUT_OF_FLOW |
ServoRestyleDamage::REFLOW,
parallel: FlowParallelInfo::new(), parallel: FlowParallelInfo::new(),
floats: self.floats.clone(), floats: self.floats.clone(),
abs_descendants: self.abs_descendants.clone(), abs_descendants: self.abs_descendants.clone(),
@ -1138,8 +1208,10 @@ impl BaseFlow {
return self as *const BaseFlow as usize; return self as *const BaseFlow as usize;
} }
pub fn collect_stacking_contexts_for_children(&mut self, pub fn collect_stacking_contexts_for_children(
state: &mut StackingContextCollectionState) { &mut self,
state: &mut StackingContextCollectionState,
) {
for kid in self.children.iter_mut() { for kid in self.children.iter_mut() {
kid.collect_stacking_contexts(state); kid.collect_stacking_contexts(state);
} }
@ -1157,15 +1229,17 @@ impl BaseFlow {
self.speculated_float_placement_out.right > Au(0) self.speculated_float_placement_out.right > Au(0)
} }
/// Compute the fragment position relative to the parent stacking context. If the fragment /// Compute the fragment position relative to the parent stacking context. If the fragment
/// itself establishes a stacking context, then the origin of its position will be (0, 0) /// itself establishes a stacking context, then the origin of its position will be (0, 0)
/// for the purposes of this computation. /// for the purposes of this computation.
pub fn stacking_relative_border_box_for_display_list(&self, fragment: &Fragment) -> Rect<Au> { pub fn stacking_relative_border_box_for_display_list(&self, fragment: &Fragment) -> Rect<Au> {
fragment.stacking_relative_border_box( fragment.stacking_relative_border_box(
&self.stacking_relative_position, &self.stacking_relative_position,
&self.early_absolute_position_info.relative_containing_block_size, &self
self.early_absolute_position_info.relative_containing_block_mode, .early_absolute_position_info
.relative_containing_block_size,
self.early_absolute_position_info
.relative_containing_block_mode,
CoordinateSystem::Own, CoordinateSystem::Own,
) )
} }
@ -1182,8 +1256,10 @@ impl<'a> ImmutableFlowUtils for &'a Flow {
/// table-column-group flow, or table-caption flow. /// table-column-group flow, or table-caption flow.
fn is_proper_table_child(self) -> bool { fn is_proper_table_child(self) -> bool {
match self.class() { match self.class() {
FlowClass::TableRow | FlowClass::TableRowGroup | FlowClass::TableRow |
FlowClass::TableColGroup | FlowClass::TableCaption => true, FlowClass::TableRowGroup |
FlowClass::TableColGroup |
FlowClass::TableCaption => true,
_ => false, _ => false,
} }
} }
@ -1239,9 +1315,13 @@ impl<'a> ImmutableFlowUtils for &'a Flow {
/// Returns true if this flow is one of table-related flows. /// Returns true if this flow is one of table-related flows.
fn is_table_kind(self) -> bool { fn is_table_kind(self) -> bool {
match self.class() { match self.class() {
FlowClass::TableWrapper | FlowClass::Table | FlowClass::TableWrapper |
FlowClass::TableColGroup | FlowClass::TableRowGroup | FlowClass::Table |
FlowClass::TableRow | FlowClass::TableCaption | FlowClass::TableCell => true, FlowClass::TableColGroup |
FlowClass::TableRowGroup |
FlowClass::TableRow |
FlowClass::TableCaption |
FlowClass::TableCell => true,
_ => false, _ => false,
} }
} }
@ -1268,7 +1348,7 @@ impl<'a> ImmutableFlowUtils for &'a Flow {
FlowClass::Block | FlowClass::TableCaption | FlowClass::TableCell => { FlowClass::Block | FlowClass::TableCaption | FlowClass::TableCell => {
// FIXME: Actually check the type of the node // FIXME: Actually check the type of the node
self.child_count() != 0 self.child_count() != 0
} },
_ => false, _ => false,
} }
} }
@ -1307,13 +1387,13 @@ impl<'a> ImmutableFlowUtils for &'a Flow {
fn floats_might_flow_through(self) -> bool { fn floats_might_flow_through(self) -> bool {
if !self.base().might_have_floats_in() && !self.base().might_have_floats_out() { if !self.base().might_have_floats_in() && !self.base().might_have_floats_out() {
return false return false;
} }
if self.is_root() { if self.is_root() {
return false return false;
} }
if !self.is_block_like() { if !self.is_block_like() {
return true return true;
} }
self.as_block().formatting_context_type() == FormattingContextType::None self.as_block().formatting_context_type() == FormattingContextType::None
} }
@ -1322,12 +1402,16 @@ impl<'a> ImmutableFlowUtils for &'a Flow {
for kid in self.base().children.iter().rev() { for kid in self.base().children.iter().rev() {
if kid.is_inline_flow() { if kid.is_inline_flow() {
if let Some(baseline_offset) = kid.as_inline().baseline_offset_of_last_line() { if let Some(baseline_offset) = kid.as_inline().baseline_offset_of_last_line() {
return Some(kid.base().position.start.b + baseline_offset) return Some(kid.base().position.start.b + baseline_offset);
} }
} }
if kid.is_block_like() && !kid.base().flags.contains(FlowFlags::IS_ABSOLUTELY_POSITIONED) { if kid.is_block_like() && !kid
.base()
.flags
.contains(FlowFlags::IS_ABSOLUTELY_POSITIONED)
{
if let Some(baseline_offset) = kid.baseline_offset_of_last_line_box_in_flow() { if let Some(baseline_offset) = kid.baseline_offset_of_last_line_box_in_flow() {
return Some(kid.base().position.start.b + baseline_offset) return Some(kid.base().position.start.b + baseline_offset);
} }
} }
} }
@ -1374,17 +1458,19 @@ impl MutableOwnedFlowUtils for FlowRef {
/// </span> /// </span>
/// </div> /// </div>
/// ``` /// ```
fn take_applicable_absolute_descendants(&mut self, fn take_applicable_absolute_descendants(
absolute_descendants: &mut AbsoluteDescendants) { &mut self,
absolute_descendants: &mut AbsoluteDescendants,
) {
let mut applicable_absolute_descendants = AbsoluteDescendants::new(); let mut applicable_absolute_descendants = AbsoluteDescendants::new();
for absolute_descendant in absolute_descendants.descendant_links.iter() { for absolute_descendant in absolute_descendants.descendant_links.iter() {
if absolute_descendant.has_reached_containing_block { if absolute_descendant.has_reached_containing_block {
applicable_absolute_descendants.push(absolute_descendant.flow.clone()); applicable_absolute_descendants.push(absolute_descendant.flow.clone());
} }
} }
absolute_descendants.descendant_links.retain(|descendant| { absolute_descendants
!descendant.has_reached_containing_block .descendant_links
}); .retain(|descendant| !descendant.has_reached_containing_block);
let this = self.clone(); let this = self.clone();
let base = FlowRef::deref_mut(self).mut_base(); let base = FlowRef::deref_mut(self).mut_base();
@ -1412,9 +1498,7 @@ pub struct ContainingBlockLink {
impl ContainingBlockLink { impl ContainingBlockLink {
fn new() -> ContainingBlockLink { fn new() -> ContainingBlockLink {
ContainingBlockLink { ContainingBlockLink { link: None }
link: None,
}
} }
fn set(&mut self, link: FlowRef) { fn set(&mut self, link: FlowRef) {
@ -1424,34 +1508,38 @@ impl ContainingBlockLink {
#[inline] #[inline]
pub fn generated_containing_block_size(&self, for_flow: OpaqueFlow) -> LogicalSize<Au> { pub fn generated_containing_block_size(&self, for_flow: OpaqueFlow) -> LogicalSize<Au> {
match self.link { match self.link {
None => { None => panic!(
panic!("Link to containing block not established; perhaps you forgot to call \ "Link to containing block not established; perhaps you forgot to call \
`set_absolute_descendants`?") `set_absolute_descendants`?"
} ),
Some(ref link) => { Some(ref link) => {
let flow = link.upgrade().unwrap(); let flow = link.upgrade().unwrap();
flow.generated_containing_block_size(for_flow) flow.generated_containing_block_size(for_flow)
} },
} }
} }
#[inline] #[inline]
pub fn explicit_block_containing_size(&self, shared_context: &SharedStyleContext) -> Option<Au> { pub fn explicit_block_containing_size(
&self,
shared_context: &SharedStyleContext,
) -> Option<Au> {
match self.link { match self.link {
None => { None => panic!(
panic!("Link to containing block not established; perhaps you forgot to call \ "Link to containing block not established; perhaps you forgot to call \
`set_absolute_descendants`?") `set_absolute_descendants`?"
} ),
Some(ref link) => { Some(ref link) => {
let flow = link.upgrade().unwrap(); let flow = link.upgrade().unwrap();
if flow.is_block_like() { if flow.is_block_like() {
flow.as_block().explicit_block_containing_size(shared_context) flow.as_block()
.explicit_block_containing_size(shared_context)
} else if flow.is_inline_flow() { } else if flow.is_inline_flow() {
Some(flow.as_inline().minimum_line_metrics.space_above_baseline) Some(flow.as_inline().minimum_line_metrics.space_above_baseline)
} else { } else {
None None
} }
} },
} }
} }
} }

View file

@ -38,10 +38,13 @@ impl Serialize for FlowList {
FlowClass::TableRow => to_value(f.as_table_row()).unwrap(), FlowClass::TableRow => to_value(f.as_table_row()).unwrap(),
FlowClass::TableCell => to_value(f.as_table_cell()).unwrap(), FlowClass::TableCell => to_value(f.as_table_cell()).unwrap(),
FlowClass::Flex => to_value(f.as_flex()).unwrap(), FlowClass::Flex => to_value(f.as_flex()).unwrap(),
FlowClass::ListItem | FlowClass::TableColGroup | FlowClass::TableCaption | FlowClass::ListItem |
FlowClass::Multicol | FlowClass::MulticolColumn => { FlowClass::TableColGroup |
FlowClass::TableCaption |
FlowClass::Multicol |
FlowClass::MulticolColumn => {
Value::Null // Not implemented yet Value::Null // Not implemented yet
} },
}; };
flow_val.insert("data".to_owned(), data); flow_val.insert("data".to_owned(), data);
serializer.serialize_element(&flow_val)?; serializer.serialize_element(&flow_val)?;
@ -152,7 +155,7 @@ impl FlowList {
#[inline] #[inline]
pub fn split_off(&mut self, i: usize) -> Self { pub fn split_off(&mut self, i: usize) -> Self {
FlowList { FlowList {
flows: self.flows.split_off(i) flows: self.flows.split_off(i),
} }
} }
} }

View file

@ -8,7 +8,6 @@
//! be superfluous. This design is largely duplicating logic of Arc<T> and //! be superfluous. This design is largely duplicating logic of Arc<T> and
//! Weak<T>; please see comments there for details. //! Weak<T>; please see comments there for details.
use flow::Flow; use flow::Flow;
use std::ops::Deref; use std::ops::Deref;
use std::sync::{Arc, Weak}; use std::sync::{Arc, Weak};
@ -63,4 +62,3 @@ impl WeakFlowRef {
self.0.upgrade().map(FlowRef) self.0.upgrade().map(FlowRef)
} }
} }

File diff suppressed because it is too large Load diff

View file

@ -25,73 +25,103 @@ use text::TextRunScanner;
use traversal::InorderFlowTraversal; use traversal::InorderFlowTraversal;
// Decimal styles per CSS-COUNTER-STYLES § 6.1: // Decimal styles per CSS-COUNTER-STYLES § 6.1:
static DECIMAL: [char; 10] = [ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' ]; static DECIMAL: [char; 10] = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
// TODO(pcwalton): `decimal-leading-zero` // TODO(pcwalton): `decimal-leading-zero`
static ARABIC_INDIC: [char; 10] = [ '٠', '١', '٢', '٣', '٤', '٥', '٦', '٧', '٨', '٩' ]; static ARABIC_INDIC: [char; 10] = ['٠', '١', '٢', '٣', '٤', '٥', '٦', '٧', '٨', '٩'];
// TODO(pcwalton): `armenian`, `upper-armenian`, `lower-armenian` // TODO(pcwalton): `armenian`, `upper-armenian`, `lower-armenian`
static BENGALI: [char; 10] = [ '', '১', '২', '৩', '', '৫', '৬', '', '৮', '৯' ]; static BENGALI: [char; 10] = [
static CAMBODIAN: [char; 10] = [ '០', '១', '២', '៣', '៤', '៥', '៦', '៧', '៨', '៩' ]; '', '১', '২', '৩', '', '৫', '৬', '', '৮', '৯',
];
static CAMBODIAN: [char; 10] = [
'០', '១', '២', '៣', '៤', '៥', '៦', '៧', '៨', '៩',
];
// TODO(pcwalton): Suffix for CJK decimal. // TODO(pcwalton): Suffix for CJK decimal.
static CJK_DECIMAL: [char; 10] = [ '', '一', '二', '三', '四', '五', '六', '七', '八', '九' ]; static CJK_DECIMAL: [char; 10] = [
static DEVANAGARI: [char; 10] = [ '', '१', '२', '३', '४', '५', '६', '७', '८', '९' ]; '', '一', '二', '三', '四', '五', '六', '七', '八', '九',
];
static DEVANAGARI: [char; 10] = [
'', '१', '२', '३', '४', '५', '६', '७', '८', '९',
];
// TODO(pcwalton): `georgian` // TODO(pcwalton): `georgian`
static GUJARATI: [char; 10] = ['', '૧', '૨', '૩', '૪', '૫', '૬', '૭', '૮', '૯']; static GUJARATI: [char; 10] = [
static GURMUKHI: [char; 10] = ['', '', '੨', '੩', '', '੫', '੬', '੭', '੮', '੯']; '', '૧', '૨', '૩', '૪', '૫', '૬', '૭', '૮', '૯',
];
static GURMUKHI: [char; 10] = [
'', '', '੨', '੩', '', '੫', '੬', '੭', '੮', '੯',
];
// TODO(pcwalton): `hebrew` // TODO(pcwalton): `hebrew`
static KANNADA: [char; 10] = ['', '೧', '೨', '೩', '೪', '೫', '೬', '೭', '೮', '೯']; static KANNADA: [char; 10] = [
static LAO: [char; 10] = ['', '໑', '໒', '໓', '໔', '໕', '໖', '໗', '໘', '໙']; '', '೧', '೨', '೩', '೪', '೫', '೬', '೭', '೮', '೯',
static MALAYALAM: [char; 10] = ['', '൧', '൨', '൩', '൪', '൫', '൬', '', '൮', '൯']; ];
static MONGOLIAN: [char; 10] = ['᠐', '᠑', '᠒', '᠓', '᠔', '᠕', '᠖', '᠗', '᠘', '᠙']; static LAO: [char; 10] = [
static MYANMAR: [char; 10] = ['', '၁', '၂', '၃', '၄', '၅', '၆', '၇', '၈', '၉']; '', '໑', '໒', '໓', '໔', '໕', '໖', '໗', '໘', '໙',
static ORIYA: [char; 10] = ['', '୧', '', '୩', '୪', '୫', '୬', '୭', '୮', '୯']; ];
static MALAYALAM: [char; 10] = [
'', '൧', '൨', '൩', '൪', '൫', '൬', '', '൮', '൯',
];
static MONGOLIAN: [char; 10] = [
'᠐', '᠑', '᠒', '᠓', '᠔', '᠕', '᠖', '᠗', '᠘', '᠙',
];
static MYANMAR: [char; 10] = [
'', '၁', '၂', '၃', '၄', '၅', '၆', '၇', '၈', '၉',
];
static ORIYA: [char; 10] = [
'', '୧', '', '୩', '୪', '୫', '୬', '୭', '୮', '୯',
];
static PERSIAN: [char; 10] = ['۰', '۱', '۲', '۳', '۴', '۵', '۶', '۷', '۸', '۹']; static PERSIAN: [char; 10] = ['۰', '۱', '۲', '۳', '۴', '۵', '۶', '۷', '۸', '۹'];
// TODO(pcwalton): `lower-roman`, `upper-roman` // TODO(pcwalton): `lower-roman`, `upper-roman`
static TELUGU: [char; 10] = ['', '౧', '౨', '౩', '౪', '౫', '౬', '౭', '౮', '౯']; static TELUGU: [char; 10] = [
static THAI: [char; 10] = ['', '๑', '๒', '๓', '๔', '๕', '๖', '๗', '๘', '๙']; '', '౧', '౨', '౩', '౪', '౫', '౬', '౭', '౮', '౯',
static TIBETAN: [char; 10] = ['༠', '༡', '༢', '༣', '༤', '༥', '༦', '༧', '༨', '༩']; ];
static THAI: [char; 10] = [
'', '๑', '๒', '๓', '๔', '๕', '๖', '๗', '๘', '๙',
];
static TIBETAN: [char; 10] = [
'༠', '༡', '༢', '༣', '༤', '༥', '༦', '༧', '༨', '༩',
];
// Alphabetic styles per CSS-COUNTER-STYLES § 6.2: // Alphabetic styles per CSS-COUNTER-STYLES § 6.2:
static LOWER_ALPHA: [char; 26] = [ static LOWER_ALPHA: [char; 26] = [
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', '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' 't', 'u', 'v', 'w', 'x', 'y', 'z',
]; ];
static UPPER_ALPHA: [char; 26] = [ static UPPER_ALPHA: [char; 26] = [
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', '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' 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
]; ];
static CJK_EARTHLY_BRANCH: [char; 12] = [ static CJK_EARTHLY_BRANCH: [char; 12] = [
'子', '丑', '寅', '卯', '辰', '巳', '午', '未', '申', '酉', '戌', '亥' '子', '丑', '寅', '卯', '辰', '巳', '午', '未', '申', '酉', '戌', '亥',
]; ];
static CJK_HEAVENLY_STEM: [char; 10] = [ static CJK_HEAVENLY_STEM: [char; 10] = [
'甲', '乙', '丙', '丁', '戊', '己', '庚', '辛', '壬', '癸' '甲', '乙', '丙', '丁', '戊', '己', '庚', '辛', '壬', '癸',
]; ];
static LOWER_GREEK: [char; 24] = [ static LOWER_GREEK: [char; 24] = [
'α', 'β', 'γ', 'δ', 'ε', 'ζ', 'η', 'θ', 'ι', 'κ', 'λ', 'μ', 'ν', 'ξ', 'ο', 'π', 'ρ', 'σ', 'τ', 'α', 'β', 'γ', 'δ', 'ε', 'ζ', 'η', 'θ', 'ι', 'κ', 'λ', 'μ', 'ν', 'ξ', 'ο', 'π',
'υ', 'φ', 'χ', 'ψ', 'ω' 'ρ', 'σ', 'τ', 'υ', 'φ', 'χ', 'ψ', 'ω',
]; ];
static HIRAGANA: [char; 48] = [ static HIRAGANA: [char; 48] = [
'あ', 'い', 'う', 'え', 'お', 'か', 'き', 'く', 'け', 'こ', 'さ', 'し', 'す', 'せ', 'そ', 'あ', 'い', 'う', 'え', 'お', 'か', 'き', 'く', 'け', 'こ', 'さ', 'し', 'す',
'た', 'ち', 'つ', 'て', 'と', 'な', 'に', 'ぬ', 'ね', 'の', 'は', 'ひ', 'ふ', 'へ', 'ほ', 'せ', 'そ', 'た', 'ち', 'つ', 'て', 'と', 'な', 'に', 'ぬ', 'ね', 'の', 'は',
'ま', 'み', 'む', 'め', 'も', 'や', 'ゆ', 'よ', 'ら', 'り', 'る', 'れ', 'ろ', 'ひ', 'ふ', 'へ', 'ほ', 'ま', 'み', 'む', 'め', 'も', 'や', 'ゆ', 'よ', 'ら',
'わ', 'ゐ', 'ゑ', 'を', 'ん' 'り', 'る', 'れ', 'ろ', 'わ', 'ゐ', 'ゑ', 'を', 'ん',
]; ];
static HIRAGANA_IROHA: [char; 47] = [ static HIRAGANA_IROHA: [char; 47] = [
'い', 'ろ', 'は', 'に', 'ほ', 'へ', 'と', 'ち', 'り', 'ぬ', 'る', 'を', 'わ', 'か', 'よ', 'い', 'ろ', 'は', 'に', 'ほ', 'へ', 'と', 'ち', 'り', 'ぬ', 'る', 'を', 'わ',
'た', 'れ', 'そ', 'つ', 'ね', 'な', 'ら', 'む', 'う', 'ゐ', 'の', 'お', 'く', 'や', 'ま', 'か', 'よ', 'た', 'れ', 'そ', 'つ', 'ね', 'な', 'ら', 'む', 'う', 'ゐ', 'の',
'け', 'ふ', 'こ', 'え', 'て', 'あ', 'さ', 'き', 'ゆ', 'め', 'み', 'し', 'ゑ', 'お', 'く', 'や', 'ま', 'け', 'ふ', 'こ', 'え', 'て', 'あ', 'さ', 'き', 'ゆ',
'ひ', 'も', 'せ', 'す' 'め', 'み', 'し', 'ゑ', 'ひ', 'も', 'せ', 'す',
]; ];
static KATAKANA: [char; 48] = [ static KATAKANA: [char; 48] = [
'ア', 'イ', 'ウ', 'エ', 'オ', 'カ', 'キ', 'ク', 'ケ', 'コ', 'サ', 'シ', 'ス', 'セ', 'ソ', 'ア', 'イ', 'ウ', 'エ', 'オ', 'カ', 'キ', 'ク', 'ケ', 'コ', 'サ', 'シ', 'ス',
'タ', 'チ', 'ツ', 'テ', 'ト', 'ナ', 'ニ', 'ヌ', 'ネ', '', 'ハ', 'ヒ', 'フ', 'ヘ', 'ホ', 'セ', 'ソ', 'タ', 'チ', 'ツ', 'テ', 'ト', 'ナ', 'ニ', 'ヌ', 'ネ', '', 'ハ',
'マ', 'ミ', 'ム', 'メ', 'モ', 'ヤ', 'ユ', 'ヨ', 'ラ', 'リ', 'ル', 'レ', 'ロ', 'ヒ', 'フ', 'ヘ', 'ホ', 'マ', 'ミ', 'ム', 'メ', 'モ', 'ヤ', 'ユ', 'ヨ', 'ラ',
'ワ', 'ヰ', 'ヱ', 'ヲ', 'ン' 'リ', 'ル', 'レ', 'ロ', 'ワ', 'ヰ', 'ヱ', 'ヲ', 'ン',
]; ];
static KATAKANA_IROHA: [char; 47] = [ static KATAKANA_IROHA: [char; 47] = [
'イ', 'ロ', 'ハ', 'ニ', 'ホ', 'ヘ', 'ト', 'チ', 'リ', 'ヌ', 'ル', 'ヲ', 'ワ', 'カ', 'ヨ', 'イ', 'ロ', 'ハ', 'ニ', 'ホ', 'ヘ', 'ト', 'チ', 'リ', 'ヌ', 'ル', 'ヲ', 'ワ',
'タ', 'レ', 'ソ', 'ツ', 'ネ', 'ナ', 'ラ', 'ム', 'ウ', 'ヰ', '', 'オ', 'ク', 'ヤ', 'マ', 'カ', 'ヨ', 'タ', 'レ', 'ソ', 'ツ', 'ネ', 'ナ', 'ラ', 'ム', 'ウ', 'ヰ', '',
'ケ', 'フ', 'コ', 'エ', 'テ', 'ア', 'サ', 'キ', 'ユ', 'メ', 'ミ', 'シ', 'ヱ', 'オ', 'ク', 'ヤ', 'マ', 'ケ', 'フ', 'コ', 'エ', 'テ', 'ア', 'サ', 'キ', 'ユ',
'ヒ', 'モ', 'セ', 'ス' 'メ', 'ミ', 'シ', 'ヱ', 'ヒ', 'モ', 'セ', 'ス',
]; ];
/// The generated content resolution traversal. /// The generated content resolution traversal.
@ -132,8 +162,12 @@ impl<'a> InorderFlowTraversal for ResolveGeneratedContent<'a> {
#[inline] #[inline]
fn should_process_subtree(&mut self, flow: &mut Flow) -> bool { fn should_process_subtree(&mut self, flow: &mut Flow) -> bool {
flow.base().restyle_damage.intersects(ServoRestyleDamage::RESOLVE_GENERATED_CONTENT) || flow.base()
flow.base().flags.intersects(FlowFlags::AFFECTS_COUNTERS | FlowFlags::HAS_COUNTER_AFFECTING_CHILDREN) .restyle_damage
.intersects(ServoRestyleDamage::RESOLVE_GENERATED_CONTENT) ||
flow.base().flags.intersects(
FlowFlags::AFFECTS_COUNTERS | FlowFlags::HAS_COUNTER_AFFECTING_CHILDREN,
)
} }
} }
@ -168,81 +202,97 @@ impl<'a, 'b> ResolveGeneratedContentFragmentMutator<'a, 'b> {
if let SpecificFragmentInfo::GeneratedContent(ref mut info) = fragment.specific { if let SpecificFragmentInfo::GeneratedContent(ref mut info) = fragment.specific {
info info
} else { } else {
return return;
}; };
match **info { match **info {
GeneratedContentInfo::ListItem => { GeneratedContentInfo::ListItem => {
new_info = self.traversal.list_item.render(self.traversal.layout_context, new_info = self.traversal.list_item.render(
self.traversal.layout_context,
fragment.node, fragment.node,
fragment.pseudo.clone(), fragment.pseudo.clone(),
fragment.style.clone(), fragment.style.clone(),
list_style_type, list_style_type,
RenderingMode::Suffix(".\u{00a0}")) RenderingMode::Suffix(".\u{00a0}"),
} )
},
GeneratedContentInfo::Empty | GeneratedContentInfo::Empty |
GeneratedContentInfo::ContentItem(ContentItem::String(_)) => { GeneratedContentInfo::ContentItem(ContentItem::String(_)) => {
// Nothing to do here. // Nothing to do here.
} },
GeneratedContentInfo::ContentItem(ContentItem::Counter(ref counter_name, GeneratedContentInfo::ContentItem(ContentItem::Counter(
counter_style)) => { ref counter_name,
counter_style,
)) => {
let temporary_counter = Counter::new(); let temporary_counter = Counter::new();
let counter = self.traversal let counter = self
.traversal
.counters .counters
.get(&*counter_name.0) .get(&*counter_name.0)
.unwrap_or(&temporary_counter); .unwrap_or(&temporary_counter);
new_info = counter.render(self.traversal.layout_context, new_info = counter.render(
self.traversal.layout_context,
fragment.node, fragment.node,
fragment.pseudo.clone(), fragment.pseudo.clone(),
fragment.style.clone(), fragment.style.clone(),
counter_style, counter_style,
RenderingMode::Plain) RenderingMode::Plain,
} )
GeneratedContentInfo::ContentItem(ContentItem::Counters(ref counter_name, },
GeneratedContentInfo::ContentItem(ContentItem::Counters(
ref counter_name,
ref separator, ref separator,
counter_style)) => { counter_style,
)) => {
let temporary_counter = Counter::new(); let temporary_counter = Counter::new();
let counter = self.traversal let counter = self
.traversal
.counters .counters
.get(&*counter_name.0) .get(&*counter_name.0)
.unwrap_or(&temporary_counter); .unwrap_or(&temporary_counter);
new_info = counter.render(self.traversal.layout_context, new_info = counter.render(
self.traversal.layout_context,
fragment.node, fragment.node,
fragment.pseudo, fragment.pseudo,
fragment.style.clone(), fragment.style.clone(),
counter_style, counter_style,
RenderingMode::All(&separator)); RenderingMode::All(&separator),
} );
},
GeneratedContentInfo::ContentItem(ContentItem::OpenQuote) => { GeneratedContentInfo::ContentItem(ContentItem::OpenQuote) => {
new_info = render_text(self.traversal.layout_context, new_info = render_text(
self.traversal.layout_context,
fragment.node, fragment.node,
fragment.pseudo, fragment.pseudo,
fragment.style.clone(), fragment.style.clone(),
self.quote(&*fragment.style, false)); self.quote(&*fragment.style, false),
);
self.traversal.quote += 1 self.traversal.quote += 1
} },
GeneratedContentInfo::ContentItem(ContentItem::CloseQuote) => { GeneratedContentInfo::ContentItem(ContentItem::CloseQuote) => {
if self.traversal.quote >= 1 { if self.traversal.quote >= 1 {
self.traversal.quote -= 1 self.traversal.quote -= 1
} }
new_info = render_text(self.traversal.layout_context, new_info = render_text(
self.traversal.layout_context,
fragment.node, fragment.node,
fragment.pseudo, fragment.pseudo,
fragment.style.clone(), fragment.style.clone(),
self.quote(&*fragment.style, true)); self.quote(&*fragment.style, true),
} );
},
GeneratedContentInfo::ContentItem(ContentItem::NoOpenQuote) => { GeneratedContentInfo::ContentItem(ContentItem::NoOpenQuote) => {
self.traversal.quote += 1 self.traversal.quote += 1
} },
GeneratedContentInfo::ContentItem(ContentItem::NoCloseQuote) => { GeneratedContentInfo::ContentItem(ContentItem::NoCloseQuote) => {
if self.traversal.quote >= 1 { if self.traversal.quote >= 1 {
self.traversal.quote -= 1 self.traversal.quote -= 1
} }
} },
GeneratedContentInfo::ContentItem(ContentItem::Url(..)) => { GeneratedContentInfo::ContentItem(ContentItem::Url(..)) => {
unreachable!("Servo doesn't parse content: url(..) yet") unreachable!("Servo doesn't parse content: url(..) yet")
} },
} }
}; };
@ -252,7 +302,7 @@ impl<'a, 'b> ResolveGeneratedContentFragmentMutator<'a, 'b> {
// so that it isn't processed again on the next layout. FIXME (mbrubeck): When // so that it isn't processed again on the next layout. FIXME (mbrubeck): When
// processing an inline flow, this traversal should be allowed to insert or remove // processing an inline flow, this traversal should be allowed to insert or remove
// fragments. Then we can just remove these fragments rather than adding placeholders. // fragments. Then we can just remove these fragments rather than adding placeholders.
None => SpecificFragmentInfo::GeneratedContent(Box::new(GeneratedContentInfo::Empty)) None => SpecificFragmentInfo::GeneratedContent(Box::new(GeneratedContentInfo::Empty)),
}; };
} }
@ -263,9 +313,12 @@ impl<'a, 'b> ResolveGeneratedContentFragmentMutator<'a, 'b> {
} }
match list_style_type { match list_style_type {
ListStyleType::Disc | ListStyleType::None | ListStyleType::Circle | ListStyleType::Disc |
ListStyleType::Square | ListStyleType::DisclosureOpen | ListStyleType::None |
ListStyleType::DisclosureClosed => {} ListStyleType::Circle |
ListStyleType::Square |
ListStyleType::DisclosureOpen |
ListStyleType::DisclosureClosed => {},
_ => self.traversal.list_item.increment(self.level, 1), _ => self.traversal.list_item.increment(self.level, 1),
} }
@ -279,24 +332,28 @@ impl<'a, 'b> ResolveGeneratedContentFragmentMutator<'a, 'b> {
let counter_name = &*pair.name.0; let counter_name = &*pair.name.0;
if let Some(ref mut counter) = self.traversal.counters.get_mut(counter_name) { if let Some(ref mut counter) = self.traversal.counters.get_mut(counter_name) {
counter.reset(self.level, pair.value); counter.reset(self.level, pair.value);
continue continue;
} }
let mut counter = Counter::new(); let mut counter = Counter::new();
counter.reset(self.level, pair.value); counter.reset(self.level, pair.value);
self.traversal.counters.insert(counter_name.to_owned(), counter); self.traversal
.counters
.insert(counter_name.to_owned(), counter);
} }
for pair in &*fragment.style().get_counters().counter_increment { for pair in &*fragment.style().get_counters().counter_increment {
let counter_name = &*pair.name.0; let counter_name = &*pair.name.0;
if let Some(ref mut counter) = self.traversal.counters.get_mut(counter_name) { if let Some(ref mut counter) = self.traversal.counters.get_mut(counter_name) {
counter.increment(self.level, pair.value); counter.increment(self.level, pair.value);
continue continue;
} }
let mut counter = Counter::new(); let mut counter = Counter::new();
counter.increment(self.level, pair.value); counter.increment(self.level, pair.value);
self.traversal.counters.insert(counter_name.to_owned(), counter); self.traversal
.counters
.insert(counter_name.to_owned(), counter);
} }
self.incremented = true self.incremented = true
@ -305,10 +362,10 @@ impl<'a, 'b> ResolveGeneratedContentFragmentMutator<'a, 'b> {
fn quote(&self, style: &ComputedValues, close: bool) -> String { fn quote(&self, style: &ComputedValues, close: bool) -> String {
let quotes = &style.get_list().quotes; let quotes = &style.get_list().quotes;
if quotes.0.is_empty() { if quotes.0.is_empty() {
return String::new() return String::new();
} }
let &(ref open_quote, ref close_quote) = let &(ref open_quote, ref close_quote) = if self.traversal.quote as usize >= quotes.0.len()
if self.traversal.quote as usize >= quotes.0.len() { {
quotes.0.last().unwrap() quotes.0.last().unwrap()
} else { } else {
&quotes.0[self.traversal.quote as usize] &quotes.0[self.traversal.quote as usize]
@ -329,9 +386,7 @@ struct Counter {
impl Counter { impl Counter {
fn new() -> Counter { fn new() -> Counter {
Counter { Counter { values: Vec::new() }
values: Vec::new(),
}
} }
fn reset(&mut self, level: u32, value: i32) { fn reset(&mut self, level: u32, value: i32) {
@ -339,7 +394,7 @@ impl Counter {
if let Some(ref mut existing_value) = self.values.last_mut() { if let Some(ref mut existing_value) = self.values.last_mut() {
if level == existing_value.level { if level == existing_value.level {
existing_value.value = value; existing_value.value = value;
return return;
} }
} }
@ -359,7 +414,7 @@ impl Counter {
fn increment(&mut self, level: u32, amount: i32) { fn increment(&mut self, level: u32, amount: i32) {
if let Some(ref mut value) = self.values.last_mut() { if let Some(ref mut value) = self.values.last_mut() {
value.value += amount; value.value += amount;
return return;
} }
self.values.push(CounterValue { self.values.push(CounterValue {
@ -368,14 +423,15 @@ impl Counter {
}) })
} }
fn render(&self, fn render(
&self,
layout_context: &LayoutContext, layout_context: &LayoutContext,
node: OpaqueNode, node: OpaqueNode,
pseudo: PseudoElementType, pseudo: PseudoElementType,
style: ::ServoArc<ComputedValues>, style: ::ServoArc<ComputedValues>,
list_style_type: ListStyleType, list_style_type: ListStyleType,
mode: RenderingMode) mode: RenderingMode,
-> Option<SpecificFragmentInfo> { ) -> Option<SpecificFragmentInfo> {
let mut string = String::new(); let mut string = String::new();
match mode { match mode {
RenderingMode::Plain => { RenderingMode::Plain => {
@ -384,7 +440,7 @@ impl Counter {
None => 0, None => 0,
}; };
push_representation(value, list_style_type, &mut string) push_representation(value, list_style_type, &mut string)
} },
RenderingMode::Suffix(suffix) => { RenderingMode::Suffix(suffix) => {
let value = match self.values.last() { let value = match self.values.last() {
Some(ref value) => value.value, Some(ref value) => value.value,
@ -392,7 +448,7 @@ impl Counter {
}; };
push_representation(value, list_style_type, &mut string); push_representation(value, list_style_type, &mut string);
string.push_str(suffix) string.push_str(suffix)
} },
RenderingMode::All(separator) => { RenderingMode::All(separator) => {
let mut first = true; let mut first = true;
for value in &self.values { for value in &self.values {
@ -402,7 +458,7 @@ impl Counter {
first = false; first = false;
push_representation(value.value, list_style_type, &mut string) push_representation(value.value, list_style_type, &mut string)
} }
} },
} }
if string.is_empty() { if string.is_empty() {
@ -432,22 +488,26 @@ struct CounterValue {
} }
/// Creates fragment info for a literal string. /// Creates fragment info for a literal string.
fn render_text(layout_context: &LayoutContext, fn render_text(
layout_context: &LayoutContext,
node: OpaqueNode, node: OpaqueNode,
pseudo: PseudoElementType, pseudo: PseudoElementType,
style: ::ServoArc<ComputedValues>, style: ::ServoArc<ComputedValues>,
string: String) string: String,
-> Option<SpecificFragmentInfo> { ) -> Option<SpecificFragmentInfo> {
let mut fragments = LinkedList::new(); let mut fragments = LinkedList::new();
let info = SpecificFragmentInfo::UnscannedText( let info = SpecificFragmentInfo::UnscannedText(Box::new(UnscannedTextFragmentInfo::new(
Box::new(UnscannedTextFragmentInfo::new(string.into_boxed_str(), None)) string.into_boxed_str(),
); None,
fragments.push_back(Fragment::from_opaque_node_and_style(node, )));
fragments.push_back(Fragment::from_opaque_node_and_style(
node,
pseudo, pseudo,
style.clone(), style.clone(),
style, style,
RestyleDamage::rebuild_and_reflow(), RestyleDamage::rebuild_and_reflow(),
info)); info,
));
// FIXME(pcwalton): This should properly handle multiple marker fragments. This could happen // FIXME(pcwalton): This should properly handle multiple marker fragments. This could happen
// due to text run splitting. // due to text run splitting.
let fragments = with_thread_local_font_context(layout_context, |font_context| { let fragments = with_thread_local_font_context(layout_context, |font_context| {
@ -464,39 +524,28 @@ fn render_text(layout_context: &LayoutContext,
/// `list-style-type` onto the given string. /// `list-style-type` onto the given string.
fn push_representation(value: i32, list_style_type: ListStyleType, accumulator: &mut String) { fn push_representation(value: i32, list_style_type: ListStyleType, accumulator: &mut String) {
match list_style_type { match list_style_type {
ListStyleType::None => {} ListStyleType::None => {},
ListStyleType::Disc | ListStyleType::Disc |
ListStyleType::Circle | ListStyleType::Circle |
ListStyleType::Square | ListStyleType::Square |
ListStyleType::DisclosureOpen | ListStyleType::DisclosureOpen |
ListStyleType::DisclosureClosed => { ListStyleType::DisclosureClosed => accumulator.push(static_representation(list_style_type)),
accumulator.push(static_representation(list_style_type))
}
ListStyleType::Decimal => push_numeric_representation(value, &DECIMAL, accumulator), ListStyleType::Decimal => push_numeric_representation(value, &DECIMAL, accumulator),
ListStyleType::ArabicIndic => { ListStyleType::ArabicIndic => {
push_numeric_representation(value, &ARABIC_INDIC, accumulator) push_numeric_representation(value, &ARABIC_INDIC, accumulator)
} },
ListStyleType::Bengali => push_numeric_representation(value, &BENGALI, accumulator), ListStyleType::Bengali => push_numeric_representation(value, &BENGALI, accumulator),
ListStyleType::Cambodian | ListStyleType::Cambodian | ListStyleType::Khmer => {
ListStyleType::Khmer => {
push_numeric_representation(value, &CAMBODIAN, accumulator) push_numeric_representation(value, &CAMBODIAN, accumulator)
} },
ListStyleType::CjkDecimal => { ListStyleType::CjkDecimal => push_numeric_representation(value, &CJK_DECIMAL, accumulator),
push_numeric_representation(value, &CJK_DECIMAL, accumulator) ListStyleType::Devanagari => push_numeric_representation(value, &DEVANAGARI, accumulator),
}
ListStyleType::Devanagari => {
push_numeric_representation(value, &DEVANAGARI, accumulator)
}
ListStyleType::Gujarati => push_numeric_representation(value, &GUJARATI, accumulator), ListStyleType::Gujarati => push_numeric_representation(value, &GUJARATI, accumulator),
ListStyleType::Gurmukhi => push_numeric_representation(value, &GURMUKHI, accumulator), ListStyleType::Gurmukhi => push_numeric_representation(value, &GURMUKHI, accumulator),
ListStyleType::Kannada => push_numeric_representation(value, &KANNADA, accumulator), ListStyleType::Kannada => push_numeric_representation(value, &KANNADA, accumulator),
ListStyleType::Lao => push_numeric_representation(value, &LAO, accumulator), ListStyleType::Lao => push_numeric_representation(value, &LAO, accumulator),
ListStyleType::Malayalam => { ListStyleType::Malayalam => push_numeric_representation(value, &MALAYALAM, accumulator),
push_numeric_representation(value, &MALAYALAM, accumulator) ListStyleType::Mongolian => push_numeric_representation(value, &MONGOLIAN, accumulator),
}
ListStyleType::Mongolian => {
push_numeric_representation(value, &MONGOLIAN, accumulator)
}
ListStyleType::Myanmar => push_numeric_representation(value, &MYANMAR, accumulator), ListStyleType::Myanmar => push_numeric_representation(value, &MYANMAR, accumulator),
ListStyleType::Oriya => push_numeric_representation(value, &ORIYA, accumulator), ListStyleType::Oriya => push_numeric_representation(value, &ORIYA, accumulator),
ListStyleType::Persian => push_numeric_representation(value, &PERSIAN, accumulator), ListStyleType::Persian => push_numeric_representation(value, &PERSIAN, accumulator),
@ -505,31 +554,27 @@ fn push_representation(value: i32, list_style_type: ListStyleType, accumulator:
ListStyleType::Tibetan => push_numeric_representation(value, &TIBETAN, accumulator), ListStyleType::Tibetan => push_numeric_representation(value, &TIBETAN, accumulator),
ListStyleType::LowerAlpha => { ListStyleType::LowerAlpha => {
push_alphabetic_representation(value, &LOWER_ALPHA, accumulator) push_alphabetic_representation(value, &LOWER_ALPHA, accumulator)
} },
ListStyleType::UpperAlpha => { ListStyleType::UpperAlpha => {
push_alphabetic_representation(value, &UPPER_ALPHA, accumulator) push_alphabetic_representation(value, &UPPER_ALPHA, accumulator)
} },
ListStyleType::CjkEarthlyBranch => { ListStyleType::CjkEarthlyBranch => {
push_alphabetic_representation(value, &CJK_EARTHLY_BRANCH, accumulator) push_alphabetic_representation(value, &CJK_EARTHLY_BRANCH, accumulator)
} },
ListStyleType::CjkHeavenlyStem => { ListStyleType::CjkHeavenlyStem => {
push_alphabetic_representation(value, &CJK_HEAVENLY_STEM, accumulator) push_alphabetic_representation(value, &CJK_HEAVENLY_STEM, accumulator)
} },
ListStyleType::LowerGreek => { ListStyleType::LowerGreek => {
push_alphabetic_representation(value, &LOWER_GREEK, accumulator) push_alphabetic_representation(value, &LOWER_GREEK, accumulator)
} },
ListStyleType::Hiragana => { ListStyleType::Hiragana => push_alphabetic_representation(value, &HIRAGANA, accumulator),
push_alphabetic_representation(value, &HIRAGANA, accumulator)
}
ListStyleType::HiraganaIroha => { ListStyleType::HiraganaIroha => {
push_alphabetic_representation(value, &HIRAGANA_IROHA, accumulator) push_alphabetic_representation(value, &HIRAGANA_IROHA, accumulator)
} },
ListStyleType::Katakana => { ListStyleType::Katakana => push_alphabetic_representation(value, &KATAKANA, accumulator),
push_alphabetic_representation(value, &KATAKANA, accumulator)
}
ListStyleType::KatakanaIroha => { ListStyleType::KatakanaIroha => {
push_alphabetic_representation(value, &KATAKANA_IROHA, accumulator) push_alphabetic_representation(value, &KATAKANA_IROHA, accumulator)
} },
} }
} }
@ -572,7 +617,7 @@ fn push_numeric_representation(value: i32, system: &[char], accumulator: &mut St
// Step 1. // Step 1.
if abs_value == 0 { if abs_value == 0 {
accumulator.push(system[0]); accumulator.push(system[0]);
return return;
} }
// Step 2. // Step 2.

View file

@ -11,7 +11,7 @@ use style::servo::restyle_damage::ServoRestyleDamage;
#[derive(Clone, Copy, PartialEq)] #[derive(Clone, Copy, PartialEq)]
pub enum RelayoutMode { pub enum RelayoutMode {
Incremental, Incremental,
Force Force,
} }
bitflags! { bitflags! {
@ -30,7 +30,10 @@ pub trait LayoutDamageComputation {
impl<'a> LayoutDamageComputation for &'a mut Flow { impl<'a> LayoutDamageComputation for &'a mut Flow {
fn compute_layout_damage(self) -> SpecialRestyleDamage { fn compute_layout_damage(self) -> SpecialRestyleDamage {
let mut special_damage = SpecialRestyleDamage::empty(); let mut special_damage = SpecialRestyleDamage::empty();
let is_absolutely_positioned = self.base().flags.contains(FlowFlags::IS_ABSOLUTELY_POSITIONED); let is_absolutely_positioned = self
.base()
.flags
.contains(FlowFlags::IS_ABSOLUTELY_POSITIONED);
// In addition to damage, we use this phase to compute whether nodes affect CSS counters. // In addition to damage, we use this phase to compute whether nodes affect CSS counters.
let mut has_counter_affecting_children = false; let mut has_counter_affecting_children = false;
@ -41,35 +44,47 @@ impl<'a> LayoutDamageComputation for &'a mut Flow {
let parent_damage = self_base.restyle_damage; let parent_damage = self_base.restyle_damage;
for kid in self_base.children.iter_mut() { for kid in self_base.children.iter_mut() {
let child_is_absolutely_positioned = let child_is_absolutely_positioned = kid
kid.base().flags.contains(FlowFlags::IS_ABSOLUTELY_POSITIONED); .base()
.flags
.contains(FlowFlags::IS_ABSOLUTELY_POSITIONED);
kid.mut_base().restyle_damage.insert( kid.mut_base().restyle_damage.insert(
parent_damage.damage_for_child(is_absolutely_positioned, parent_damage
child_is_absolutely_positioned)); .damage_for_child(is_absolutely_positioned, child_is_absolutely_positioned),
);
{ {
let kid: &mut Flow = kid; let kid: &mut Flow = kid;
special_damage.insert(kid.compute_layout_damage()); special_damage.insert(kid.compute_layout_damage());
} }
self_base.restyle_damage self_base.restyle_damage.insert(
.insert(kid.base().restyle_damage.damage_for_parent( kid.base()
child_is_absolutely_positioned)); .restyle_damage
.damage_for_parent(child_is_absolutely_positioned),
);
has_counter_affecting_children = has_counter_affecting_children || has_counter_affecting_children =
kid.base().flags.intersects(FlowFlags::AFFECTS_COUNTERS | has_counter_affecting_children || kid.base().flags.intersects(
FlowFlags::HAS_COUNTER_AFFECTING_CHILDREN); FlowFlags::AFFECTS_COUNTERS | FlowFlags::HAS_COUNTER_AFFECTING_CHILDREN,
);
} }
} }
let self_base = self.mut_base(); let self_base = self.mut_base();
if self_base.flags.float_kind() != Float::None && if self_base.flags.float_kind() != Float::None && self_base
self_base.restyle_damage.intersects(ServoRestyleDamage::REFLOW) { .restyle_damage
.intersects(ServoRestyleDamage::REFLOW)
{
special_damage.insert(SpecialRestyleDamage::REFLOW_ENTIRE_DOCUMENT); special_damage.insert(SpecialRestyleDamage::REFLOW_ENTIRE_DOCUMENT);
} }
if has_counter_affecting_children { if has_counter_affecting_children {
self_base.flags.insert(FlowFlags::HAS_COUNTER_AFFECTING_CHILDREN) self_base
.flags
.insert(FlowFlags::HAS_COUNTER_AFFECTING_CHILDREN)
} else { } else {
self_base.flags.remove(FlowFlags::HAS_COUNTER_AFFECTING_CHILDREN) self_base
.flags
.remove(FlowFlags::HAS_COUNTER_AFFECTING_CHILDREN)
} }
special_damage special_damage
@ -77,8 +92,12 @@ impl<'a> LayoutDamageComputation for &'a mut Flow {
fn reflow_entire_document(self) { fn reflow_entire_document(self) {
let self_base = self.mut_base(); let self_base = self.mut_base();
self_base.restyle_damage.insert(RestyleDamage::rebuild_and_reflow()); self_base
self_base.restyle_damage.remove(ServoRestyleDamage::RECONSTRUCT_FLOW); .restyle_damage
.insert(RestyleDamage::rebuild_and_reflow());
self_base
.restyle_damage
.remove(ServoRestyleDamage::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();
} }

File diff suppressed because it is too large Load diff

View file

@ -47,7 +47,7 @@ impl ScopeData {
name: name, name: name,
pre: pre, pre: pre,
post: Value::Null, post: Value::Null,
children: vec!(), children: vec![],
} }
} }
} }

View file

@ -14,7 +14,8 @@ extern crate fnv;
extern crate fxhash; extern crate fxhash;
extern crate gfx; extern crate gfx;
extern crate gfx_traits; extern crate gfx_traits;
#[macro_use] extern crate html5ever; #[macro_use]
extern crate html5ever;
extern crate ipc_channel; extern crate ipc_channel;
extern crate libc; extern crate libc;
#[macro_use] #[macro_use]
@ -30,7 +31,8 @@ extern crate range;
extern crate rayon; extern crate rayon;
extern crate script_layout_interface; extern crate script_layout_interface;
extern crate script_traits; extern crate script_traits;
#[macro_use] extern crate serde; #[macro_use]
extern crate serde;
extern crate serde_json; extern crate serde_json;
extern crate servo_arc; extern crate servo_arc;
extern crate servo_atoms; extern crate servo_atoms;

View file

@ -40,10 +40,11 @@ pub struct ListItemFlow {
} }
impl ListItemFlow { impl ListItemFlow {
pub fn from_fragments_and_flotation(main_fragment: Fragment, pub fn from_fragments_and_flotation(
main_fragment: Fragment,
marker_fragments: Vec<Fragment>, marker_fragments: Vec<Fragment>,
flotation: Option<FloatKind>) flotation: Option<FloatKind>,
-> ListItemFlow { ) -> ListItemFlow {
let mut this = ListItemFlow { let mut this = ListItemFlow {
block_flow: BlockFlow::from_fragment_and_float_kind(main_fragment, flotation), block_flow: BlockFlow::from_fragment_and_float_kind(main_fragment, flotation),
marker_fragments: marker_fragments, marker_fragments: marker_fragments,
@ -56,8 +57,12 @@ impl ListItemFlow {
ListStyleType::Circle | ListStyleType::Circle |
ListStyleType::Square | ListStyleType::Square |
ListStyleType::DisclosureOpen | ListStyleType::DisclosureOpen |
ListStyleType::DisclosureClosed => {} ListStyleType::DisclosureClosed => {},
_ => this.block_flow.base.restyle_damage.insert(ServoRestyleDamage::RESOLVE_GENERATED_CONTENT), _ => this
.block_flow
.base
.restyle_damage
.insert(ServoRestyleDamage::RESOLVE_GENERATED_CONTENT),
} }
} }
@ -77,20 +82,29 @@ impl ListItemFlow {
let available_rect = base.floats.available_rect( let available_rect = base.floats.available_rect(
-base.position.size.block, -base.position.size.block,
base.position.size.block, base.position.size.block,
base.block_container_inline_size); base.block_container_inline_size,
let mut marker_inline_start = available_rect.unwrap_or(self.block_flow.fragment.border_box).start.i; );
let mut marker_inline_start = available_rect
.unwrap_or(self.block_flow.fragment.border_box)
.start
.i;
for marker in self.marker_fragments.iter_mut().rev() { for marker in self.marker_fragments.iter_mut().rev() {
let container_block_size = let container_block_size = self
self.block_flow.explicit_block_containing_size(layout_context.shared_context()); .block_flow
marker.assign_replaced_inline_size_if_necessary(base.block_container_inline_size, container_block_size); .explicit_block_containing_size(layout_context.shared_context());
marker.assign_replaced_inline_size_if_necessary(
base.block_container_inline_size,
container_block_size,
);
// Do this now. There's no need to do this in bubble-widths, since markers do not // Do this now. There's no need to do this in bubble-widths, since markers do not
// contribute to the inline size of this flow. // contribute to the inline size of this flow.
let intrinsic_inline_sizes = marker.compute_intrinsic_inline_sizes(); let intrinsic_inline_sizes = marker.compute_intrinsic_inline_sizes();
marker.border_box.size.inline = marker.border_box.size.inline = intrinsic_inline_sizes
intrinsic_inline_sizes.content_intrinsic_sizes.preferred_inline_size; .content_intrinsic_sizes
.preferred_inline_size;
marker_inline_start = marker_inline_start - marker.border_box.size.inline; marker_inline_start = marker_inline_start - marker.border_box.size.inline;
marker.border_box.start.i = marker_inline_start; marker.border_box.start.i = marker_inline_start;
} }
@ -99,18 +113,22 @@ impl ListItemFlow {
fn assign_marker_block_sizes(&mut self, layout_context: &LayoutContext) { fn assign_marker_block_sizes(&mut self, layout_context: &LayoutContext) {
// FIXME(pcwalton): Do this during flow construction, like `InlineFlow` does? // FIXME(pcwalton): Do this during flow construction, like `InlineFlow` does?
let marker_line_metrics = with_thread_local_font_context(layout_context, |font_context| { let marker_line_metrics = with_thread_local_font_context(layout_context, |font_context| {
InlineFlow::minimum_line_metrics_for_fragments(&self.marker_fragments, InlineFlow::minimum_line_metrics_for_fragments(
&self.marker_fragments,
font_context, font_context,
&*self.block_flow.fragment.style) &*self.block_flow.fragment.style,
)
}); });
for marker in &mut self.marker_fragments { for marker in &mut self.marker_fragments {
marker.assign_replaced_block_size_if_necessary(); marker.assign_replaced_block_size_if_necessary();
let marker_inline_metrics = marker.aligned_inline_metrics(layout_context, let marker_inline_metrics = marker.aligned_inline_metrics(
layout_context,
&marker_line_metrics, &marker_line_metrics,
Some(&marker_line_metrics)); Some(&marker_line_metrics),
marker.border_box.start.b = marker_line_metrics.space_above_baseline - );
marker_inline_metrics.ascent; marker.border_box.start.b =
marker_line_metrics.space_above_baseline - marker_inline_metrics.ascent;
} }
} }
} }
@ -144,7 +162,8 @@ impl Flow for ListItemFlow {
} }
fn compute_stacking_relative_position(&mut self, layout_context: &LayoutContext) { fn compute_stacking_relative_position(&mut self, layout_context: &LayoutContext) {
self.block_flow.compute_stacking_relative_position(layout_context) self.block_flow
.compute_stacking_relative_position(layout_context)
} }
fn place_float_if_applicable<'a>(&mut self) { fn place_float_if_applicable<'a>(&mut self) {
@ -160,11 +179,13 @@ impl Flow for ListItemFlow {
} }
fn update_late_computed_inline_position_if_necessary(&mut self, inline_position: Au) { fn update_late_computed_inline_position_if_necessary(&mut self, inline_position: Au) {
self.block_flow.update_late_computed_inline_position_if_necessary(inline_position) self.block_flow
.update_late_computed_inline_position_if_necessary(inline_position)
} }
fn update_late_computed_block_position_if_necessary(&mut self, block_position: Au) { fn update_late_computed_block_position_if_necessary(&mut self, block_position: Au) {
self.block_flow.update_late_computed_block_position_if_necessary(block_position) self.block_flow
.update_late_computed_block_position_if_necessary(block_position)
} }
fn build_display_list(&mut self, state: &mut DisplayListBuildState) { fn build_display_list(&mut self, state: &mut DisplayListBuildState) {
@ -181,9 +202,17 @@ impl Flow for ListItemFlow {
fn compute_overflow(&self) -> Overflow { fn compute_overflow(&self) -> Overflow {
let mut overflow = self.block_flow.compute_overflow(); let mut overflow = self.block_flow.compute_overflow();
let flow_size = self.block_flow.base.position.size.to_physical(self.block_flow.base.writing_mode); let flow_size = self
let relative_containing_block_size = .block_flow
&self.block_flow.base.early_absolute_position_info.relative_containing_block_size; .base
.position
.size
.to_physical(self.block_flow.base.writing_mode);
let relative_containing_block_size = &self
.block_flow
.base
.early_absolute_position_info
.relative_containing_block_size;
for fragment in &self.marker_fragments { for fragment in &self.marker_fragments {
overflow.union(&fragment.compute_overflow(&flow_size, &relative_containing_block_size)) overflow.union(&fragment.compute_overflow(&flow_size, &relative_containing_block_size))
@ -200,23 +229,28 @@ impl Flow for ListItemFlow {
self.block_flow.positioning() self.block_flow.positioning()
} }
fn iterate_through_fragment_border_boxes(&self, fn iterate_through_fragment_border_boxes(
&self,
iterator: &mut FragmentBorderBoxIterator, iterator: &mut FragmentBorderBoxIterator,
level: i32, level: i32,
stacking_context_position: &Point2D<Au>) { stacking_context_position: &Point2D<Au>,
self.block_flow.iterate_through_fragment_border_boxes(iterator, ) {
self.block_flow.iterate_through_fragment_border_boxes(
iterator,
level, level,
stacking_context_position); stacking_context_position,
);
for marker in &self.marker_fragments { for marker in &self.marker_fragments {
if iterator.should_process(marker) { if iterator.should_process(marker) {
iterator.process( iterator.process(
marker, marker,
level, level,
&marker.stacking_relative_border_box(&self.block_flow &marker
.base .stacking_relative_border_box(
.stacking_relative_position, &self.block_flow.base.stacking_relative_position,
&self.block_flow &self
.block_flow
.base .base
.early_absolute_position_info .early_absolute_position_info
.relative_containing_block_size, .relative_containing_block_size,
@ -224,8 +258,9 @@ impl Flow for ListItemFlow {
.base .base
.early_absolute_position_info .early_absolute_position_info
.relative_containing_block_mode, .relative_containing_block_mode,
CoordinateSystem::Own) CoordinateSystem::Own,
.translate(&stacking_context_position.to_vector())); ).translate(&stacking_context_position.to_vector()),
);
} }
} }
} }
@ -260,7 +295,7 @@ impl ListStyleTypeContent {
ListStyleType::DisclosureClosed => { ListStyleType::DisclosureClosed => {
let text = generated_content::static_representation(list_style_type); let text = generated_content::static_representation(list_style_type);
ListStyleTypeContent::StaticText(text) ListStyleTypeContent::StaticText(text)
} },
_ => ListStyleTypeContent::GeneratedContent(Box::new(GeneratedContentInfo::ListItem)), _ => ListStyleTypeContent::GeneratedContent(Box::new(GeneratedContentInfo::ListItem)),
} }
} }

View file

@ -126,21 +126,22 @@ impl MarginCollapseInfo {
} }
} }
pub fn finish_and_compute_collapsible_margins(mut self, pub fn finish_and_compute_collapsible_margins(
mut self,
fragment: &Fragment, fragment: &Fragment,
containing_block_size: Option<Au>, containing_block_size: Option<Au>,
can_collapse_block_end_margin_with_kids: bool, can_collapse_block_end_margin_with_kids: bool,
mut may_collapse_through: bool) mut may_collapse_through: bool,
-> (CollapsibleMargins, Au) { ) -> (CollapsibleMargins, Au) {
let state = match self.state { let state = match self.state {
MarginCollapseState::AccumulatingCollapsibleTopMargin => { MarginCollapseState::AccumulatingCollapsibleTopMargin => {
may_collapse_through = may_collapse_through && may_collapse_through =
match fragment.style().content_block_size() { may_collapse_through && match fragment.style().content_block_size() {
LengthOrPercentageOrAuto::Auto => true, LengthOrPercentageOrAuto::Auto => true,
LengthOrPercentageOrAuto::Length(l) => l.px() == 0., LengthOrPercentageOrAuto::Length(l) => l.px() == 0.,
LengthOrPercentageOrAuto::Percentage(v) => { LengthOrPercentageOrAuto::Percentage(v) => {
v.0 == 0. || containing_block_size.is_none() v.0 == 0. || containing_block_size.is_none()
} },
LengthOrPercentageOrAuto::Calc(_) => false, LengthOrPercentageOrAuto::Calc(_) => false,
}; };
@ -156,14 +157,14 @@ impl MarginCollapseInfo {
// If the fragment has non-zero min-block-size, margins may not // If the fragment has non-zero min-block-size, margins may not
// collapse through it. // collapse through it.
FinalMarginState::BottomMarginCollapses FinalMarginState::BottomMarginCollapses
} },
} }
} else { } else {
// If the fragment has an explicitly specified block-size, margins may not // If the fragment has an explicitly specified block-size, margins may not
// collapse through it. // collapse through it.
FinalMarginState::BottomMarginCollapses FinalMarginState::BottomMarginCollapses
} }
} },
MarginCollapseState::AccumulatingMarginIn => FinalMarginState::BottomMarginCollapses, MarginCollapseState::AccumulatingMarginIn => FinalMarginState::BottomMarginCollapses,
}; };
@ -174,27 +175,41 @@ impl MarginCollapseInfo {
match state { match state {
FinalMarginState::MarginsCollapseThrough => { FinalMarginState::MarginsCollapseThrough => {
let advance = self.block_start_margin.collapse(); let advance = self.block_start_margin.collapse();
self.margin_in.union(AdjoiningMargins::from_margin(block_end_margin)); self.margin_in
(CollapsibleMargins::Collapse(self.block_start_margin, self.margin_in), .union(AdjoiningMargins::from_margin(block_end_margin));
advance) (
} CollapsibleMargins::Collapse(self.block_start_margin, self.margin_in),
advance,
)
},
FinalMarginState::BottomMarginCollapses => { FinalMarginState::BottomMarginCollapses => {
let advance = self.margin_in.collapse(); let advance = self.margin_in.collapse();
self.margin_in.union(AdjoiningMargins::from_margin(block_end_margin)); self.margin_in
(CollapsibleMargins::Collapse(self.block_start_margin, self.margin_in), .union(AdjoiningMargins::from_margin(block_end_margin));
advance) (
} CollapsibleMargins::Collapse(self.block_start_margin, self.margin_in),
advance,
)
},
} }
} else { } else {
match state { match state {
FinalMarginState::MarginsCollapseThrough => { FinalMarginState::MarginsCollapseThrough => {
self.block_start_margin.union(AdjoiningMargins::from_margin(block_end_margin)); self.block_start_margin
(CollapsibleMargins::CollapseThrough(self.block_start_margin), Au(0)) .union(AdjoiningMargins::from_margin(block_end_margin));
} (
CollapsibleMargins::CollapseThrough(self.block_start_margin),
Au(0),
)
},
FinalMarginState::BottomMarginCollapses => { FinalMarginState::BottomMarginCollapses => {
self.margin_in.union(AdjoiningMargins::from_margin(block_end_margin)); self.margin_in
(CollapsibleMargins::Collapse(self.block_start_margin, self.margin_in), Au(0)) .union(AdjoiningMargins::from_margin(block_end_margin));
} (
CollapsibleMargins::Collapse(self.block_start_margin, self.margin_in),
Au(0),
)
},
} }
} }
} }
@ -206,7 +221,7 @@ impl MarginCollapseInfo {
// needs to be positioned relative to our *border box*, not our margin box. See // needs to be positioned relative to our *border box*, not our margin box. See
// `tests/ref/float_under_top_margin_a.html`. // `tests/ref/float_under_top_margin_a.html`.
Au(0) Au(0)
} },
MarginCollapseState::AccumulatingMarginIn => self.margin_in.collapse(), MarginCollapseState::AccumulatingMarginIn => self.margin_in.collapse(),
} }
} }
@ -214,78 +229,99 @@ impl MarginCollapseInfo {
/// Adds the child's potentially collapsible block-start margin to the current margin state and /// Adds the child's potentially collapsible block-start margin to the current margin state and
/// advances the Y offset by the appropriate amount to handle that margin. Returns the amount /// advances the Y offset by the appropriate amount to handle that margin. Returns the amount
/// that should be added to the Y offset during block layout. /// that should be added to the Y offset during block layout.
pub fn advance_block_start_margin(&mut self, pub fn advance_block_start_margin(
&mut self,
child_collapsible_margins: &CollapsibleMargins, child_collapsible_margins: &CollapsibleMargins,
can_collapse_block_start_margin: bool) can_collapse_block_start_margin: bool,
-> Au { ) -> Au {
if !can_collapse_block_start_margin { if !can_collapse_block_start_margin {
self.state = MarginCollapseState::AccumulatingMarginIn self.state = MarginCollapseState::AccumulatingMarginIn
} }
match (self.state, *child_collapsible_margins) { match (self.state, *child_collapsible_margins) {
(MarginCollapseState::AccumulatingCollapsibleTopMargin, (
CollapsibleMargins::None(block_start, _)) => { MarginCollapseState::AccumulatingCollapsibleTopMargin,
CollapsibleMargins::None(block_start, _),
) => {
self.state = MarginCollapseState::AccumulatingMarginIn; self.state = MarginCollapseState::AccumulatingMarginIn;
block_start block_start
} },
(MarginCollapseState::AccumulatingCollapsibleTopMargin, (
CollapsibleMargins::Collapse(block_start, _)) => { MarginCollapseState::AccumulatingCollapsibleTopMargin,
CollapsibleMargins::Collapse(block_start, _),
) => {
self.block_start_margin.union(block_start); self.block_start_margin.union(block_start);
self.state = MarginCollapseState::AccumulatingMarginIn; self.state = MarginCollapseState::AccumulatingMarginIn;
Au(0) Au(0)
} },
(MarginCollapseState::AccumulatingMarginIn, (
CollapsibleMargins::None(block_start, _)) => { MarginCollapseState::AccumulatingMarginIn,
CollapsibleMargins::None(block_start, _),
) => {
let previous_margin_value = self.margin_in.collapse(); let previous_margin_value = self.margin_in.collapse();
self.margin_in = AdjoiningMargins::new(); self.margin_in = AdjoiningMargins::new();
previous_margin_value + block_start previous_margin_value + block_start
} },
(MarginCollapseState::AccumulatingMarginIn, (
CollapsibleMargins::Collapse(block_start, _)) => { MarginCollapseState::AccumulatingMarginIn,
CollapsibleMargins::Collapse(block_start, _),
) => {
self.margin_in.union(block_start); self.margin_in.union(block_start);
let margin_value = self.margin_in.collapse(); let margin_value = self.margin_in.collapse();
self.margin_in = AdjoiningMargins::new(); self.margin_in = AdjoiningMargins::new();
margin_value margin_value
} },
(_, CollapsibleMargins::CollapseThrough(_)) => { (_, CollapsibleMargins::CollapseThrough(_)) => {
// For now, we ignore this; this will be handled by `advance_block_end_margin` // For now, we ignore this; this will be handled by `advance_block_end_margin`
// below. // below.
Au(0) Au(0)
} },
} }
} }
/// Adds the child's potentially collapsible block-end margin to the current margin state and /// Adds the child's potentially collapsible block-end margin to the current margin state and
/// advances the Y offset by the appropriate amount to handle that margin. Returns the amount /// advances the Y offset by the appropriate amount to handle that margin. Returns the amount
/// that should be added to the Y offset during block layout. /// that should be added to the Y offset during block layout.
pub fn advance_block_end_margin(&mut self, child_collapsible_margins: &CollapsibleMargins) pub fn advance_block_end_margin(
-> Au { &mut self,
child_collapsible_margins: &CollapsibleMargins,
) -> Au {
match (self.state, *child_collapsible_margins) { match (self.state, *child_collapsible_margins) {
(MarginCollapseState::AccumulatingCollapsibleTopMargin, CollapsibleMargins::None(..)) | (
(MarginCollapseState::AccumulatingCollapsibleTopMargin, MarginCollapseState::AccumulatingCollapsibleTopMargin,
CollapsibleMargins::Collapse(..)) => { CollapsibleMargins::None(..),
) |
(
MarginCollapseState::AccumulatingCollapsibleTopMargin,
CollapsibleMargins::Collapse(..),
) => {
// Can't happen because the state will have been replaced with // Can't happen because the state will have been replaced with
// `MarginCollapseState::AccumulatingMarginIn` above. // `MarginCollapseState::AccumulatingMarginIn` above.
panic!("should not be accumulating collapsible block_start margins anymore!") panic!("should not be accumulating collapsible block_start margins anymore!")
} },
(MarginCollapseState::AccumulatingCollapsibleTopMargin, (
CollapsibleMargins::CollapseThrough(margin)) => { MarginCollapseState::AccumulatingCollapsibleTopMargin,
CollapsibleMargins::CollapseThrough(margin),
) => {
self.block_start_margin.union(margin); self.block_start_margin.union(margin);
Au(0) Au(0)
} },
(MarginCollapseState::AccumulatingMarginIn, (MarginCollapseState::AccumulatingMarginIn, CollapsibleMargins::None(_, block_end)) => {
CollapsibleMargins::None(_, block_end)) => {
assert_eq!(self.margin_in.most_positive, Au(0)); assert_eq!(self.margin_in.most_positive, Au(0));
assert_eq!(self.margin_in.most_negative, Au(0)); assert_eq!(self.margin_in.most_negative, Au(0));
block_end block_end
} },
(MarginCollapseState::AccumulatingMarginIn, (
CollapsibleMargins::Collapse(_, block_end)) | MarginCollapseState::AccumulatingMarginIn,
(MarginCollapseState::AccumulatingMarginIn, CollapsibleMargins::Collapse(_, block_end),
CollapsibleMargins::CollapseThrough(block_end)) => { ) |
(
MarginCollapseState::AccumulatingMarginIn,
CollapsibleMargins::CollapseThrough(block_end),
) => {
self.margin_in.union(block_end); self.margin_in.union(block_end);
Au(0) Au(0)
} },
} }
} }
} }
@ -309,7 +345,11 @@ pub struct IntrinsicISizes {
impl fmt::Debug for IntrinsicISizes { impl fmt::Debug for IntrinsicISizes {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "min={:?}, pref={:?}", self.minimum_inline_size, self.preferred_inline_size) write!(
f,
"min={:?}, pref={:?}",
self.minimum_inline_size, self.preferred_inline_size
)
} }
} }
@ -358,8 +398,10 @@ impl IntrinsicISizesContribution {
/// FIXME(pcwalton): This is incorrect when the inline fragment contains forced line breaks /// FIXME(pcwalton): This is incorrect when the inline fragment contains forced line breaks
/// (e.g. `<br>` or `white-space: pre`). /// (e.g. `<br>` or `white-space: pre`).
pub fn union_inline(&mut self, sizes: &IntrinsicISizes) { pub fn union_inline(&mut self, sizes: &IntrinsicISizes) {
self.content_intrinsic_sizes.minimum_inline_size = self.content_intrinsic_sizes.minimum_inline_size = max(
max(self.content_intrinsic_sizes.minimum_inline_size, sizes.minimum_inline_size); self.content_intrinsic_sizes.minimum_inline_size,
sizes.minimum_inline_size,
);
self.content_intrinsic_sizes.preferred_inline_size = self.content_intrinsic_sizes.preferred_inline_size =
self.content_intrinsic_sizes.preferred_inline_size + sizes.preferred_inline_size self.content_intrinsic_sizes.preferred_inline_size + sizes.preferred_inline_size
} }
@ -382,10 +424,14 @@ impl IntrinsicISizesContribution {
/// ///
/// This is used when contributing the intrinsic sizes for individual fragments. /// This is used when contributing the intrinsic sizes for individual fragments.
pub fn union_block(&mut self, sizes: &IntrinsicISizes) { pub fn union_block(&mut self, sizes: &IntrinsicISizes) {
self.content_intrinsic_sizes.minimum_inline_size = self.content_intrinsic_sizes.minimum_inline_size = max(
max(self.content_intrinsic_sizes.minimum_inline_size, sizes.minimum_inline_size); self.content_intrinsic_sizes.minimum_inline_size,
self.content_intrinsic_sizes.preferred_inline_size = sizes.minimum_inline_size,
max(self.content_intrinsic_sizes.preferred_inline_size, sizes.preferred_inline_size) );
self.content_intrinsic_sizes.preferred_inline_size = max(
self.content_intrinsic_sizes.preferred_inline_size,
sizes.preferred_inline_size,
)
} }
} }
@ -398,17 +444,16 @@ pub enum MaybeAuto {
impl MaybeAuto { impl MaybeAuto {
#[inline] #[inline]
pub fn from_style(length: LengthOrPercentageOrAuto, containing_length: Au) pub fn from_style(length: LengthOrPercentageOrAuto, containing_length: Au) -> MaybeAuto {
-> MaybeAuto {
match length { match length {
LengthOrPercentageOrAuto::Auto => MaybeAuto::Auto, LengthOrPercentageOrAuto::Auto => MaybeAuto::Auto,
LengthOrPercentageOrAuto::Percentage(percent) => { LengthOrPercentageOrAuto::Percentage(percent) => {
MaybeAuto::Specified(containing_length.scale_by(percent.0)) MaybeAuto::Specified(containing_length.scale_by(percent.0))
} },
LengthOrPercentageOrAuto::Calc(calc) => { LengthOrPercentageOrAuto::Calc(calc) => {
MaybeAuto::from_option(calc.to_used_value(Some(containing_length))) MaybeAuto::from_option(calc.to_used_value(Some(containing_length)))
} },
LengthOrPercentageOrAuto::Length(length) => MaybeAuto::Specified(Au::from(length)) LengthOrPercentageOrAuto::Length(length) => MaybeAuto::Specified(Au::from(length)),
} }
} }
@ -442,7 +487,10 @@ impl MaybeAuto {
} }
#[inline] #[inline]
pub fn map<F>(&self, mapper: F) -> MaybeAuto where F: FnOnce(Au) -> Au { pub fn map<F>(&self, mapper: F) -> MaybeAuto
where
F: FnOnce(Au) -> Au,
{
match *self { match *self {
MaybeAuto::Auto => MaybeAuto::Auto, MaybeAuto::Auto => MaybeAuto::Auto,
MaybeAuto::Specified(value) => MaybeAuto::Specified(mapper(value)), MaybeAuto::Specified(value) => MaybeAuto::Specified(mapper(value)),
@ -453,15 +501,17 @@ impl MaybeAuto {
/// Receive an optional container size and return used value for width or height. /// Receive an optional container size and return used value for width or height.
/// ///
/// `style_length`: content size as given in the CSS. /// `style_length`: content size as given in the CSS.
pub fn style_length(style_length: LengthOrPercentageOrAuto, pub fn style_length(
container_size: Option<Au>) -> MaybeAuto { style_length: LengthOrPercentageOrAuto,
container_size: Option<Au>,
) -> MaybeAuto {
match container_size { match container_size {
Some(length) => MaybeAuto::from_style(style_length, length), Some(length) => MaybeAuto::from_style(style_length, length),
None => if let LengthOrPercentageOrAuto::Length(length) = style_length { None => if let LengthOrPercentageOrAuto::Length(length) = style_length {
MaybeAuto::Specified(Au::from(length)) MaybeAuto::Specified(Au::from(length))
} else { } else {
MaybeAuto::Auto MaybeAuto::Auto
} },
} }
} }
@ -475,25 +525,37 @@ pub fn style_length(style_length: LengthOrPercentageOrAuto,
/// [1]: https://drafts.csswg.org/css-backgrounds-3/#border-radius /// [1]: https://drafts.csswg.org/css-backgrounds-3/#border-radius
pub fn specified_border_radius( pub fn specified_border_radius(
radius: BorderCornerRadius, radius: BorderCornerRadius,
containing_size: Size2D<Au>) containing_size: Size2D<Au>,
-> Size2D<Au> ) -> Size2D<Au> {
{
let w = radius.0.width().to_used_value(containing_size.width); let w = radius.0.width().to_used_value(containing_size.width);
let h = radius.0.height().to_used_value(containing_size.height); let h = radius.0.height().to_used_value(containing_size.height);
Size2D::new(w, h) Size2D::new(w, h)
} }
#[inline] #[inline]
pub fn padding_from_style(style: &ComputedValues, pub fn padding_from_style(
style: &ComputedValues,
containing_block_inline_size: Au, containing_block_inline_size: Au,
writing_mode: WritingMode) writing_mode: WritingMode,
-> LogicalMargin<Au> { ) -> LogicalMargin<Au> {
let padding_style = style.get_padding(); let padding_style = style.get_padding();
LogicalMargin::from_physical(writing_mode, SideOffsets2D::new( LogicalMargin::from_physical(
padding_style.padding_top.to_used_value(containing_block_inline_size), writing_mode,
padding_style.padding_right.to_used_value(containing_block_inline_size), SideOffsets2D::new(
padding_style.padding_bottom.to_used_value(containing_block_inline_size), padding_style
padding_style.padding_left.to_used_value(containing_block_inline_size))) .padding_top
.to_used_value(containing_block_inline_size),
padding_style
.padding_right
.to_used_value(containing_block_inline_size),
padding_style
.padding_bottom
.to_used_value(containing_block_inline_size),
padding_style
.padding_left
.to_used_value(containing_block_inline_size),
),
)
} }
/// Returns the explicitly-specified margin lengths from the given style. Percentage and auto /// Returns the explicitly-specified margin lengths from the given style. Percentage and auto
@ -501,14 +563,20 @@ pub fn padding_from_style(style: &ComputedValues,
/// ///
/// This is used when calculating intrinsic inline sizes. /// This is used when calculating intrinsic inline sizes.
#[inline] #[inline]
pub fn specified_margin_from_style(style: &ComputedValues, pub fn specified_margin_from_style(
writing_mode: WritingMode) -> LogicalMargin<Au> { style: &ComputedValues,
writing_mode: WritingMode,
) -> LogicalMargin<Au> {
let margin_style = style.get_margin(); let margin_style = style.get_margin();
LogicalMargin::from_physical(writing_mode, SideOffsets2D::new( LogicalMargin::from_physical(
writing_mode,
SideOffsets2D::new(
MaybeAuto::from_style(margin_style.margin_top, Au(0)).specified_or_zero(), MaybeAuto::from_style(margin_style.margin_top, Au(0)).specified_or_zero(),
MaybeAuto::from_style(margin_style.margin_right, Au(0)).specified_or_zero(), MaybeAuto::from_style(margin_style.margin_right, Au(0)).specified_or_zero(),
MaybeAuto::from_style(margin_style.margin_bottom, Au(0)).specified_or_zero(), MaybeAuto::from_style(margin_style.margin_bottom, Au(0)).specified_or_zero(),
MaybeAuto::from_style(margin_style.margin_left, Au(0)).specified_or_zero())) MaybeAuto::from_style(margin_style.margin_left, Au(0)).specified_or_zero(),
),
)
} }
/// A min-size and max-size constraint. The constructor has a optional `border` /// A min-size and max-size constraint. The constructor has a optional `border`
@ -523,17 +591,19 @@ pub struct SizeConstraint {
impl SizeConstraint { impl SizeConstraint {
/// Create a `SizeConstraint` for an axis. /// Create a `SizeConstraint` for an axis.
pub fn new(container_size: Option<Au>, pub fn new(
container_size: Option<Au>,
min_size: LengthOrPercentage, min_size: LengthOrPercentage,
max_size: LengthOrPercentageOrNone, max_size: LengthOrPercentageOrNone,
border: Option<Au>) -> SizeConstraint { border: Option<Au>,
) -> SizeConstraint {
let mut min_size = match container_size { let mut min_size = match container_size {
Some(container_size) => min_size.to_used_value(container_size), Some(container_size) => min_size.to_used_value(container_size),
None => if let LengthOrPercentage::Length(length) = min_size { None => if let LengthOrPercentage::Length(length) = min_size {
Au::from(length) Au::from(length)
} else { } else {
Au(0) Au(0)
} },
}; };
let mut max_size = match container_size { let mut max_size = match container_size {
@ -542,7 +612,7 @@ impl SizeConstraint {
Some(Au::from(length)) Some(Au::from(length))
} else { } else {
None None
} },
}; };
// Make sure max size is not smaller than min size. // Make sure max size is not smaller than min size.
max_size = max_size.map(|x| max(x, min_size)); max_size = max_size.map(|x| max(x, min_size));
@ -554,7 +624,7 @@ impl SizeConstraint {
SizeConstraint { SizeConstraint {
min_size: min_size, min_size: min_size,
max_size: max_size max_size: max_size,
} }
} }
@ -565,7 +635,7 @@ impl SizeConstraint {
} else { } else {
match self.max_size { match self.max_size {
Some(max_size) if max_size < other => max_size, Some(max_size) if max_size < other => max_size,
_ => other _ => other,
} }
} }
} }

View file

@ -85,7 +85,10 @@ impl Flow for MulticolFlow {
} }
fn assign_inline_sizes(&mut self, layout_context: &LayoutContext) { fn assign_inline_sizes(&mut self, layout_context: &LayoutContext) {
debug!("assign_inline_sizes({}): assigning inline_size for flow", "multicol"); debug!(
"assign_inline_sizes({}): assigning inline_size for flow",
"multicol"
);
let shared_context = layout_context.shared_context(); let shared_context = layout_context.shared_context();
self.block_flow.compute_inline_sizes(shared_context); self.block_flow.compute_inline_sizes(shared_context);
@ -94,8 +97,7 @@ impl Flow for MulticolFlow {
self.block_flow.fragment.border_padding.inline_start; self.block_flow.fragment.border_padding.inline_start;
// Distance from the inline-end margin edge to the inline-end content edge. // Distance from the inline-end margin edge to the inline-end content edge.
let inline_end_content_edge = let inline_end_content_edge = self.block_flow.fragment.margin.inline_end +
self.block_flow.fragment.margin.inline_end +
self.block_flow.fragment.border_padding.inline_end; self.block_flow.fragment.border_padding.inline_end;
self.block_flow.assign_inline_sizes(layout_context); self.block_flow.assign_inline_sizes(layout_context);
@ -107,15 +109,19 @@ impl Flow for MulticolFlow {
let style = &self.block_flow.fragment.style; let style = &self.block_flow.fragment.style;
let column_gap = match style.get_position().column_gap { let column_gap = match style.get_position().column_gap {
Either::First(len) => len.0.to_pixel_length(content_inline_size).into(), Either::First(len) => len.0.to_pixel_length(content_inline_size).into(),
Either::Second(_normal) => self.block_flow.fragment.style.get_font().font_size.size(), Either::Second(_normal) => {
self.block_flow.fragment.style.get_font().font_size.size()
},
}; };
let column_style = style.get_column(); let column_style = style.get_column();
let mut column_count; let mut column_count;
if let Either::First(column_width) = column_style.column_width { if let Either::First(column_width) = column_style.column_width {
let column_width = Au::from(column_width); let column_width = Au::from(column_width);
column_count = column_count = max(
max(1, (content_inline_size + column_gap).0 / (column_width + column_gap).0); 1,
(content_inline_size + column_gap).0 / (column_width + column_gap).0,
);
if let ColumnCount::Integer(specified_column_count) = column_style.column_count { if let ColumnCount::Integer(specified_column_count) = column_style.column_count {
column_count = min(column_count, specified_column_count.0 as i32); column_count = min(column_count, specified_column_count.0 as i32);
} }
@ -125,16 +131,22 @@ impl Flow for MulticolFlow {
_ => unreachable!(), _ => unreachable!(),
} }
} }
column_width = column_width = max(
max(Au(0), (content_inline_size + column_gap) / column_count - column_gap); Au(0),
(content_inline_size + column_gap) / column_count - column_gap,
);
self.column_pitch = column_width + column_gap; self.column_pitch = column_width + column_gap;
} }
self.block_flow.fragment.border_box.size.inline = content_inline_size + padding_and_borders; self.block_flow.fragment.border_box.size.inline = content_inline_size + padding_and_borders;
self.block_flow.propagate_assigned_inline_size_to_children( self.block_flow.propagate_assigned_inline_size_to_children(
shared_context, inline_start_content_edge, inline_end_content_edge, column_width, shared_context,
|_, _, _, _, _, _| {}); inline_start_content_edge,
inline_end_content_edge,
column_width,
|_, _, _, _, _, _| {},
);
} }
fn assign_block_size(&mut self, ctx: &LayoutContext) { fn assign_block_size(&mut self, ctx: &LayoutContext) {
@ -156,7 +168,7 @@ impl Flow for MulticolFlow {
ctx.shared_context().viewport_size(), ctx.shared_context().viewport_size(),
).block ).block
} }
} },
}); });
// Before layout, everything is in a single "column" // Before layout, everything is in a single "column"
@ -167,17 +179,20 @@ impl Flow for MulticolFlow {
self.block_flow.assign_block_size(ctx); self.block_flow.assign_block_size(ctx);
loop { loop {
let remaining = Arc::get_mut(&mut column).unwrap().fragment(ctx, fragmentation_context); let remaining = Arc::get_mut(&mut column)
.unwrap()
.fragment(ctx, fragmentation_context);
self.block_flow.base.children.push_back_arc(column); self.block_flow.base.children.push_back_arc(column);
column = match remaining { column = match remaining {
Some(remaining) => remaining, Some(remaining) => remaining,
None => break None => break,
}; };
} }
} }
fn compute_stacking_relative_position(&mut self, layout_context: &LayoutContext) { fn compute_stacking_relative_position(&mut self, layout_context: &LayoutContext) {
self.block_flow.compute_stacking_relative_position(layout_context); self.block_flow
.compute_stacking_relative_position(layout_context);
let pitch = LogicalSize::new(self.block_flow.base.writing_mode, self.column_pitch, Au(0)); let pitch = LogicalSize::new(self.block_flow.base.writing_mode, self.column_pitch, Au(0));
let pitch = pitch.to_physical(self.block_flow.base.writing_mode); let pitch = pitch.to_physical(self.block_flow.base.writing_mode);
for (i, child) in self.block_flow.base.children.iter_mut().enumerate() { for (i, child) in self.block_flow.base.children.iter_mut().enumerate() {
@ -187,11 +202,13 @@ impl Flow for MulticolFlow {
} }
fn update_late_computed_inline_position_if_necessary(&mut self, inline_position: Au) { fn update_late_computed_inline_position_if_necessary(&mut self, inline_position: Au) {
self.block_flow.update_late_computed_inline_position_if_necessary(inline_position) self.block_flow
.update_late_computed_inline_position_if_necessary(inline_position)
} }
fn update_late_computed_block_position_if_necessary(&mut self, block_position: Au) { fn update_late_computed_block_position_if_necessary(&mut self, block_position: Au) {
self.block_flow.update_late_computed_block_position_if_necessary(block_position) self.block_flow
.update_late_computed_block_position_if_necessary(block_position)
} }
fn build_display_list(&mut self, state: &mut DisplayListBuildState) { fn build_display_list(&mut self, state: &mut DisplayListBuildState) {
@ -223,11 +240,17 @@ impl Flow for MulticolFlow {
self.block_flow.generated_containing_block_size(flow) self.block_flow.generated_containing_block_size(flow)
} }
fn iterate_through_fragment_border_boxes(&self, fn iterate_through_fragment_border_boxes(
&self,
iterator: &mut FragmentBorderBoxIterator, iterator: &mut FragmentBorderBoxIterator,
level: i32, level: i32,
stacking_context_position: &Point2D<Au>) { stacking_context_position: &Point2D<Au>,
self.block_flow.iterate_through_fragment_border_boxes(iterator, level, stacking_context_position); ) {
self.block_flow.iterate_through_fragment_border_boxes(
iterator,
level,
stacking_context_position,
);
} }
fn mutate_fragments(&mut self, mutator: &mut FnMut(&mut Fragment)) { fn mutate_fragments(&mut self, mutator: &mut FnMut(&mut Fragment)) {
@ -257,7 +280,10 @@ impl Flow for MulticolColumnFlow {
} }
fn assign_inline_sizes(&mut self, layout_context: &LayoutContext) { fn assign_inline_sizes(&mut self, layout_context: &LayoutContext) {
debug!("assign_inline_sizes({}): assigning inline_size for flow", "multicol column"); debug!(
"assign_inline_sizes({}): assigning inline_size for flow",
"multicol column"
);
self.block_flow.assign_inline_sizes(layout_context); self.block_flow.assign_inline_sizes(layout_context);
} }
@ -266,22 +292,27 @@ impl Flow for MulticolColumnFlow {
self.block_flow.assign_block_size(ctx); self.block_flow.assign_block_size(ctx);
} }
fn fragment(&mut self, layout_context: &LayoutContext, fn fragment(
fragmentation_context: Option<FragmentationContext>) &mut self,
-> Option<Arc<Flow>> { layout_context: &LayoutContext,
fragmentation_context: Option<FragmentationContext>,
) -> Option<Arc<Flow>> {
Flow::fragment(&mut self.block_flow, layout_context, fragmentation_context) Flow::fragment(&mut self.block_flow, layout_context, fragmentation_context)
} }
fn compute_stacking_relative_position(&mut self, layout_context: &LayoutContext) { fn compute_stacking_relative_position(&mut self, layout_context: &LayoutContext) {
self.block_flow.compute_stacking_relative_position(layout_context) self.block_flow
.compute_stacking_relative_position(layout_context)
} }
fn update_late_computed_inline_position_if_necessary(&mut self, inline_position: Au) { fn update_late_computed_inline_position_if_necessary(&mut self, inline_position: Au) {
self.block_flow.update_late_computed_inline_position_if_necessary(inline_position) self.block_flow
.update_late_computed_inline_position_if_necessary(inline_position)
} }
fn update_late_computed_block_position_if_necessary(&mut self, block_position: Au) { fn update_late_computed_block_position_if_necessary(&mut self, block_position: Au) {
self.block_flow.update_late_computed_block_position_if_necessary(block_position) self.block_flow
.update_late_computed_block_position_if_necessary(block_position)
} }
fn build_display_list(&mut self, state: &mut DisplayListBuildState) { fn build_display_list(&mut self, state: &mut DisplayListBuildState) {
@ -313,11 +344,17 @@ impl Flow for MulticolColumnFlow {
self.block_flow.generated_containing_block_size(flow) self.block_flow.generated_containing_block_size(flow)
} }
fn iterate_through_fragment_border_boxes(&self, fn iterate_through_fragment_border_boxes(
&self,
iterator: &mut FragmentBorderBoxIterator, iterator: &mut FragmentBorderBoxIterator,
level: i32, level: i32,
stacking_context_position: &Point2D<Au>) { stacking_context_position: &Point2D<Au>,
self.block_flow.iterate_through_fragment_border_boxes(iterator, level, stacking_context_position); ) {
self.block_flow.iterate_through_fragment_border_boxes(
iterator,
level,
stacking_context_position,
);
} }
fn mutate_fragments(&mut self, mutator: &mut FnMut(&mut Fragment)) { fn mutate_fragments(&mut self, mutator: &mut FnMut(&mut Fragment)) {

View file

@ -70,56 +70,57 @@ impl FlowParallelInfo {
/// ///
/// The only communication between siblings is that they both /// The only communication between siblings is that they both
/// fetch-and-subtract the parent's children count. /// fetch-and-subtract the parent's children count.
fn bottom_up_flow(mut unsafe_flow: UnsafeFlow, fn bottom_up_flow(mut unsafe_flow: UnsafeFlow, assign_bsize_traversal: &AssignBSizes) {
assign_bsize_traversal: &AssignBSizes) {
loop { loop {
// Get a real flow. // Get a real flow.
let flow: &mut Flow = unsafe { let flow: &mut Flow = unsafe { mem::transmute(unsafe_flow) };
mem::transmute(unsafe_flow)
};
// Perform the appropriate traversal. // Perform the appropriate traversal.
if assign_bsize_traversal.should_process(flow) { if assign_bsize_traversal.should_process(flow) {
assign_bsize_traversal.process(flow); assign_bsize_traversal.process(flow);
} }
let base = flow.mut_base(); let base = flow.mut_base();
// Reset the count of children for the next layout traversal. // Reset the count of children for the next layout traversal.
base.parallel.children_count.store(base.children.len() as isize, base.parallel
Ordering::Relaxed); .children_count
.store(base.children.len() as isize, Ordering::Relaxed);
// Possibly enqueue the parent. // Possibly enqueue the parent.
let unsafe_parent = base.parallel.parent; let unsafe_parent = base.parallel.parent;
if unsafe_parent == null_unsafe_flow() { if unsafe_parent == null_unsafe_flow() {
// We're done! // We're done!
break break;
} }
// No, we're not at the root yet. Then are we the last child // No, we're not at the root yet. Then are we the last child
// of our parent to finish processing? If so, we can continue // of our parent to finish processing? If so, we can continue
// on with our parent; otherwise, we've gotta wait. // on with our parent; otherwise, we've gotta wait.
let parent: &mut Flow = unsafe { let parent: &mut Flow = unsafe { &mut *(unsafe_parent.0 as *mut Flow) };
&mut *(unsafe_parent.0 as *mut Flow)
};
let parent_base = parent.mut_base(); let parent_base = parent.mut_base();
if parent_base.parallel.children_count.fetch_sub(1, Ordering::Relaxed) == 1 { if parent_base
.parallel
.children_count
.fetch_sub(1, Ordering::Relaxed) ==
1
{
// We were the last child of our parent. Reflow our parent. // We were the last child of our parent. Reflow our parent.
unsafe_flow = unsafe_parent unsafe_flow = unsafe_parent
} else { } else {
// Stop. // Stop.
break break;
} }
} }
} }
fn top_down_flow<'scope>(unsafe_flows: &[UnsafeFlow], fn top_down_flow<'scope>(
unsafe_flows: &[UnsafeFlow],
pool: &'scope rayon::ThreadPool, pool: &'scope rayon::ThreadPool,
scope: &rayon::Scope<'scope>, scope: &rayon::Scope<'scope>,
assign_isize_traversal: &'scope AssignISizes, assign_isize_traversal: &'scope AssignISizes,
assign_bsize_traversal: &'scope AssignBSizes) assign_bsize_traversal: &'scope AssignBSizes,
{ ) {
let mut discovered_child_flows = FlowList::new(); let mut discovered_child_flows = FlowList::new();
for unsafe_flow in unsafe_flows { for unsafe_flow in unsafe_flows {
@ -127,8 +128,7 @@ fn top_down_flow<'scope>(unsafe_flows: &[UnsafeFlow],
unsafe { unsafe {
// Get a real flow. // Get a real flow.
let flow: &mut Flow = mem::transmute(*unsafe_flow); let flow: &mut Flow = mem::transmute(*unsafe_flow);
flow.mut_base().thread_id = flow.mut_base().thread_id = pool.current_thread_index().unwrap() as u8;
pool.current_thread_index().unwrap() as u8;
if assign_isize_traversal.should_process(flow) { if assign_isize_traversal.should_process(flow) {
// Perform the appropriate traversal. // Perform the appropriate traversal.
@ -149,16 +149,18 @@ fn top_down_flow<'scope>(unsafe_flows: &[UnsafeFlow],
} }
if discovered_child_flows.is_empty() { if discovered_child_flows.is_empty() {
return return;
} }
if discovered_child_flows.len() <= CHUNK_SIZE { if discovered_child_flows.len() <= CHUNK_SIZE {
// We can handle all the children in this work unit. // We can handle all the children in this work unit.
top_down_flow(&discovered_child_flows, top_down_flow(
&discovered_child_flows,
pool, pool,
scope, scope,
&assign_isize_traversal, &assign_isize_traversal,
&assign_bsize_traversal); &assign_bsize_traversal,
);
} else { } else {
// Spawn a new work unit for each chunk after the first. // Spawn a new work unit for each chunk after the first.
let mut chunks = discovered_child_flows.chunks(CHUNK_SIZE); let mut chunks = discovered_child_flows.chunks(CHUNK_SIZE);
@ -166,11 +168,23 @@ fn top_down_flow<'scope>(unsafe_flows: &[UnsafeFlow],
for chunk in chunks { for chunk in chunks {
let nodes = chunk.iter().cloned().collect::<FlowList>(); let nodes = chunk.iter().cloned().collect::<FlowList>();
scope.spawn(move |scope| { scope.spawn(move |scope| {
top_down_flow(&nodes, pool, scope, &assign_isize_traversal, &assign_bsize_traversal); top_down_flow(
&nodes,
pool,
scope,
&assign_isize_traversal,
&assign_bsize_traversal,
);
}); });
} }
if let Some(chunk) = first_chunk { if let Some(chunk) = first_chunk {
top_down_flow(chunk, pool, scope, &assign_isize_traversal, &assign_bsize_traversal); top_down_flow(
chunk,
pool,
scope,
&assign_isize_traversal,
&assign_bsize_traversal,
);
} }
} }
} }
@ -181,22 +195,39 @@ pub fn reflow(
profiler_metadata: Option<TimerMetadata>, profiler_metadata: Option<TimerMetadata>,
time_profiler_chan: time::ProfilerChan, time_profiler_chan: time::ProfilerChan,
context: &LayoutContext, context: &LayoutContext,
queue: &rayon::ThreadPool) { queue: &rayon::ThreadPool,
) {
if opts::get().bubble_inline_sizes_separately { if opts::get().bubble_inline_sizes_separately {
let bubble_inline_sizes = BubbleISizes { layout_context: &context }; let bubble_inline_sizes = BubbleISizes {
layout_context: &context,
};
bubble_inline_sizes.traverse(root); bubble_inline_sizes.traverse(root);
} }
let assign_isize_traversal = &AssignISizes { layout_context: &context }; let assign_isize_traversal = &AssignISizes {
let assign_bsize_traversal = &AssignBSizes { layout_context: &context }; layout_context: &context,
};
let assign_bsize_traversal = &AssignBSizes {
layout_context: &context,
};
let nodes = [UnsafeFlow(root)]; let nodes = [UnsafeFlow(root)];
queue.install(move || { queue.install(move || {
rayon::scope(move |scope| { rayon::scope(move |scope| {
profile(time::ProfilerCategory::LayoutParallelWarmup, profile(
profiler_metadata, time_profiler_chan, move || { time::ProfilerCategory::LayoutParallelWarmup,
top_down_flow(&nodes, queue, scope, assign_isize_traversal, assign_bsize_traversal); profiler_metadata,
}); time_profiler_chan,
move || {
top_down_flow(
&nodes,
queue,
scope,
assign_isize_traversal,
assign_bsize_traversal,
);
},
);
}); });
}); });
} }

View file

@ -18,7 +18,10 @@ struct PersistentListEntry<T> {
type PersistentListLink<T> = Option<Arc<PersistentListEntry<T>>>; type PersistentListLink<T> = Option<Arc<PersistentListEntry<T>>>;
impl<T> PersistentList<T> where T: Send + Sync { impl<T> PersistentList<T>
where
T: Send + Sync,
{
#[inline] #[inline]
pub fn new() -> PersistentList<T> { pub fn new() -> PersistentList<T> {
PersistentList { PersistentList {
@ -58,7 +61,10 @@ impl<T> PersistentList<T> where T: Send + Sync {
} }
} }
impl<T> Clone for PersistentList<T> where T: Send + Sync { impl<T> Clone for PersistentList<T>
where
T: Send + Sync,
{
fn clone(&self) -> PersistentList<T> { fn clone(&self) -> PersistentList<T> {
// This establishes the persistent nature of this list: we can clone a list by just cloning // This establishes the persistent nature of this list: we can clone a list by just cloning
// its head. // its head.
@ -69,11 +75,17 @@ impl<T> Clone for PersistentList<T> where T: Send + Sync {
} }
} }
pub struct PersistentListIterator<'a, T> where T: 'a + Send + Sync { pub struct PersistentListIterator<'a, T>
where
T: 'a + Send + Sync,
{
entry: Option<&'a PersistentListEntry<T>>, entry: Option<&'a PersistentListEntry<T>>,
} }
impl<'a, T> Iterator for PersistentListIterator<'a, T> where T: Send + Sync + 'static { impl<'a, T> Iterator for PersistentListIterator<'a, T>
where
T: Send + Sync + 'static,
{
type Item = &'a T; type Item = &'a T;
#[inline] #[inline]

View file

@ -94,13 +94,24 @@ pub struct LayoutRPCImpl(pub Arc<Mutex<LayoutThreadData>>);
// https://drafts.csswg.org/cssom-view/#overflow-directions // https://drafts.csswg.org/cssom-view/#overflow-directions
fn overflow_direction(writing_mode: &WritingMode) -> OverflowDirection { fn overflow_direction(writing_mode: &WritingMode) -> OverflowDirection {
match (writing_mode.block_flow_direction(), writing_mode.inline_base_direction()) { match (
writing_mode.block_flow_direction(),
writing_mode.inline_base_direction(),
) {
(BlockFlowDirection::TopToBottom, InlineBaseDirection::LeftToRight) | (BlockFlowDirection::TopToBottom, InlineBaseDirection::LeftToRight) |
(BlockFlowDirection::LeftToRight, InlineBaseDirection::LeftToRight) => OverflowDirection::RightAndDown, (BlockFlowDirection::LeftToRight, InlineBaseDirection::LeftToRight) => {
OverflowDirection::RightAndDown
},
(BlockFlowDirection::TopToBottom, InlineBaseDirection::RightToLeft) | (BlockFlowDirection::TopToBottom, InlineBaseDirection::RightToLeft) |
(BlockFlowDirection::RightToLeft, InlineBaseDirection::LeftToRight) => OverflowDirection::LeftAndDown, (BlockFlowDirection::RightToLeft, InlineBaseDirection::LeftToRight) => {
(BlockFlowDirection::RightToLeft, InlineBaseDirection::RightToLeft) => OverflowDirection::LeftAndUp, OverflowDirection::LeftAndDown
(BlockFlowDirection::LeftToRight, InlineBaseDirection::RightToLeft) => OverflowDirection::RightAndUp },
(BlockFlowDirection::RightToLeft, InlineBaseDirection::RightToLeft) => {
OverflowDirection::LeftAndUp
},
(BlockFlowDirection::LeftToRight, InlineBaseDirection::RightToLeft) => {
OverflowDirection::RightAndUp
},
} }
} }
@ -130,20 +141,24 @@ impl LayoutRPC for LayoutRPCImpl {
let &LayoutRPCImpl(ref rw_data) = self; let &LayoutRPCImpl(ref rw_data) = self;
let rw_data = rw_data.lock().unwrap(); let rw_data = rw_data.lock().unwrap();
NodeGeometryResponse { NodeGeometryResponse {
client_rect: rw_data.client_rect_response client_rect: rw_data.client_rect_response,
} }
} }
fn node_scroll_area(&self) -> NodeGeometryResponse { fn node_scroll_area(&self) -> NodeGeometryResponse {
NodeGeometryResponse { NodeGeometryResponse {
client_rect: self.0.lock().unwrap().scroll_area_response client_rect: self.0.lock().unwrap().scroll_area_response,
} }
} }
fn node_scroll_id(&self) -> NodeScrollIdResponse { fn node_scroll_id(&self) -> NodeScrollIdResponse {
NodeScrollIdResponse(self.0.lock() NodeScrollIdResponse(
.unwrap().scroll_id_response self.0
.expect("scroll id is not correctly fetched")) .lock()
.unwrap()
.scroll_id_response
.expect("scroll id is not correctly fetched"),
)
} }
/// Retrieves the resolved value for a CSS style property. /// Retrieves the resolved value for a CSS style property.
@ -187,7 +202,7 @@ impl UnioningFragmentBorderBoxIterator {
fn new(node_address: OpaqueNode) -> UnioningFragmentBorderBoxIterator { fn new(node_address: OpaqueNode) -> UnioningFragmentBorderBoxIterator {
UnioningFragmentBorderBoxIterator { UnioningFragmentBorderBoxIterator {
node_address: node_address, node_address: node_address,
rect: None rect: None,
} }
} }
} }
@ -195,12 +210,8 @@ impl UnioningFragmentBorderBoxIterator {
impl FragmentBorderBoxIterator for UnioningFragmentBorderBoxIterator { impl FragmentBorderBoxIterator for UnioningFragmentBorderBoxIterator {
fn process(&mut self, _: &Fragment, _: i32, border_box: &Rect<Au>) { fn process(&mut self, _: &Fragment, _: i32, border_box: &Rect<Au>) {
self.rect = match self.rect { self.rect = match self.rect {
Some(rect) => { Some(rect) => Some(rect.union(border_box)),
Some(rect.union(border_box)) None => Some(*border_box),
}
None => {
Some(*border_box)
}
}; };
} }
@ -237,12 +248,12 @@ enum Side {
Left, Left,
Right, Right,
Bottom, Bottom,
Top Top,
} }
enum MarginPadding { enum MarginPadding {
Margin, Margin,
Padding Padding,
} }
enum PositionProperty { enum PositionProperty {
@ -270,9 +281,11 @@ struct PositionRetrievingFragmentBorderBoxIterator {
} }
impl PositionRetrievingFragmentBorderBoxIterator { impl PositionRetrievingFragmentBorderBoxIterator {
fn new(node_address: OpaqueNode, fn new(
node_address: OpaqueNode,
property: PositionProperty, property: PositionProperty,
position: Point2D<Au>) -> PositionRetrievingFragmentBorderBoxIterator { position: Point2D<Au>,
) -> PositionRetrievingFragmentBorderBoxIterator {
PositionRetrievingFragmentBorderBoxIterator { PositionRetrievingFragmentBorderBoxIterator {
node_address: node_address, node_address: node_address,
position: position, position: position,
@ -284,9 +297,10 @@ impl PositionRetrievingFragmentBorderBoxIterator {
impl FragmentBorderBoxIterator for PositionRetrievingFragmentBorderBoxIterator { impl FragmentBorderBoxIterator for PositionRetrievingFragmentBorderBoxIterator {
fn process(&mut self, fragment: &Fragment, _: i32, border_box: &Rect<Au>) { fn process(&mut self, fragment: &Fragment, _: i32, border_box: &Rect<Au>) {
let border_padding = fragment.border_padding.to_physical(fragment.style.writing_mode); let border_padding = fragment
self.result = .border_padding
Some(match self.property { .to_physical(fragment.style.writing_mode);
self.result = Some(match self.property {
PositionProperty::Left => self.position.x, PositionProperty::Left => self.position.x,
PositionProperty::Top => self.position.y, PositionProperty::Top => self.position.y,
PositionProperty::Width => border_box.size.width - border_padding.horizontal(), PositionProperty::Width => border_box.size.width - border_padding.horizontal(),
@ -313,8 +327,12 @@ struct MarginRetrievingFragmentBorderBoxIterator {
} }
impl MarginRetrievingFragmentBorderBoxIterator { impl MarginRetrievingFragmentBorderBoxIterator {
fn new(node_address: OpaqueNode, side: Side, margin_padding: fn new(
MarginPadding, writing_mode: WritingMode) -> MarginRetrievingFragmentBorderBoxIterator { node_address: OpaqueNode,
side: Side,
margin_padding: MarginPadding,
writing_mode: WritingMode,
) -> MarginRetrievingFragmentBorderBoxIterator {
MarginRetrievingFragmentBorderBoxIterator { MarginRetrievingFragmentBorderBoxIterator {
node_address: node_address, node_address: node_address,
side: side, side: side,
@ -329,13 +347,13 @@ impl FragmentBorderBoxIterator for MarginRetrievingFragmentBorderBoxIterator {
fn process(&mut self, fragment: &Fragment, _: i32, _: &Rect<Au>) { fn process(&mut self, fragment: &Fragment, _: i32, _: &Rect<Au>) {
let rect = match self.margin_padding { let rect = match self.margin_padding {
MarginPadding::Margin => &fragment.margin, MarginPadding::Margin => &fragment.margin,
MarginPadding::Padding => &fragment.border_padding MarginPadding::Padding => &fragment.border_padding,
}; };
self.result = Some(match self.side { self.result = Some(match self.side {
Side::Left => rect.left(self.writing_mode), Side::Left => rect.left(self.writing_mode),
Side::Right => rect.right(self.writing_mode), Side::Right => rect.right(self.writing_mode),
Side::Bottom => rect.bottom(self.writing_mode), Side::Bottom => rect.bottom(self.writing_mode),
Side::Top => rect.top(self.writing_mode) Side::Top => rect.top(self.writing_mode),
}); });
} }
@ -345,7 +363,9 @@ impl FragmentBorderBoxIterator for MarginRetrievingFragmentBorderBoxIterator {
} }
pub fn process_content_box_request<N: LayoutNode>( pub fn process_content_box_request<N: LayoutNode>(
requested_node: N, layout_root: &mut Flow) -> Option<Rect<Au>> { requested_node: N,
layout_root: &mut Flow,
) -> Option<Rect<Au>> {
// FIXME(pcwalton): This has not been updated to handle the stacking context relative // FIXME(pcwalton): This has not been updated to handle the stacking context relative
// stuff. So the position is wrong in most cases. // stuff. So the position is wrong in most cases.
let mut iterator = UnioningFragmentBorderBoxIterator::new(requested_node.opaque()); let mut iterator = UnioningFragmentBorderBoxIterator::new(requested_node.opaque());
@ -353,8 +373,10 @@ pub fn process_content_box_request<N: LayoutNode>(
iterator.rect iterator.rect
} }
pub fn process_content_boxes_request<N: LayoutNode>(requested_node: N, layout_root: &mut Flow) pub fn process_content_boxes_request<N: LayoutNode>(
-> Vec<Rect<Au>> { requested_node: N,
layout_root: &mut Flow,
) -> Vec<Rect<Au>> {
// FIXME(pcwalton): This has not been updated to handle the stacking context relative // FIXME(pcwalton): This has not been updated to handle the stacking context relative
// stuff. So the position is wrong in most cases. // stuff. So the position is wrong in most cases.
let mut iterator = CollectingFragmentBorderBoxIterator::new(requested_node.opaque()); let mut iterator = CollectingFragmentBorderBoxIterator::new(requested_node.opaque());
@ -371,7 +393,7 @@ impl FragmentLocatingFragmentIterator {
fn new(node_address: OpaqueNode) -> FragmentLocatingFragmentIterator { fn new(node_address: OpaqueNode) -> FragmentLocatingFragmentIterator {
FragmentLocatingFragmentIterator { FragmentLocatingFragmentIterator {
node_address: node_address, node_address: node_address,
client_rect: Rect::zero() client_rect: Rect::zero(),
} }
} }
} }
@ -382,7 +404,7 @@ struct UnioningFragmentScrollAreaIterator {
origin_rect: Rect<i32>, origin_rect: Rect<i32>,
level: Option<i32>, level: Option<i32>,
is_child: bool, is_child: bool,
overflow_direction: OverflowDirection overflow_direction: OverflowDirection,
} }
impl UnioningFragmentScrollAreaIterator { impl UnioningFragmentScrollAreaIterator {
@ -394,7 +416,7 @@ impl UnioningFragmentScrollAreaIterator {
level: None, level: None,
is_child: false, is_child: false,
// FIXME(#20867) // FIXME(#20867)
overflow_direction: OverflowDirection::RightAndDown overflow_direction: OverflowDirection::RightAndDown,
} }
} }
} }
@ -469,29 +491,38 @@ impl FragmentBorderBoxIterator for UnioningFragmentScrollAreaIterator {
let (left_border, right_border) = (left_border.px(), right_border.px()); let (left_border, right_border) = (left_border.px(), right_border.px());
let (top_border, bottom_border) = (top_border.px(), bottom_border.px()); let (top_border, bottom_border) = (top_border.px(), bottom_border.px());
let right_padding = (border_box.size.width.to_f32_px() - right_border - left_border) as i32; let right_padding = (border_box.size.width.to_f32_px() - right_border - left_border) as i32;
let bottom_padding = (border_box.size.height.to_f32_px() - bottom_border - top_border) as i32; let bottom_padding =
(border_box.size.height.to_f32_px() - bottom_border - top_border) as i32;
let top_padding = top_border as i32; let top_padding = top_border as i32;
let left_padding = left_border as i32; let left_padding = left_border as i32;
match self.level { match self.level {
Some(start_level) if level <= start_level => { self.is_child = false; } Some(start_level) if level <= start_level => {
self.is_child = false;
},
Some(_) => { Some(_) => {
let padding = Rect::new(Point2D::new(left_padding, top_padding), let padding = Rect::new(
Size2D::new(right_padding, bottom_padding)); Point2D::new(left_padding, top_padding),
Size2D::new(right_padding, bottom_padding),
);
let top_margin = fragment.margin.top(fragment.style.writing_mode).to_px(); let top_margin = fragment.margin.top(fragment.style.writing_mode).to_px();
let left_margin = fragment.margin.left(fragment.style.writing_mode).to_px(); let left_margin = fragment.margin.left(fragment.style.writing_mode).to_px();
let bottom_margin = fragment.margin.bottom(fragment.style.writing_mode).to_px(); let bottom_margin = fragment.margin.bottom(fragment.style.writing_mode).to_px();
let right_margin = fragment.margin.right(fragment.style.writing_mode).to_px(); let right_margin = fragment.margin.right(fragment.style.writing_mode).to_px();
let margin = Rect::new(Point2D::new(left_margin, top_margin), let margin = Rect::new(
Size2D::new(right_margin, bottom_margin)); Point2D::new(left_margin, top_margin),
Size2D::new(right_margin, bottom_margin),
);
self.union_rect = self.union_rect.union(&margin).union(&padding); self.union_rect = self.union_rect.union(&margin).union(&padding);
} },
None => { None => {
self.level = Some(level); self.level = Some(level);
self.is_child = true; self.is_child = true;
self.overflow_direction = overflow_direction(&fragment.style.writing_mode); self.overflow_direction = overflow_direction(&fragment.style.writing_mode);
self.origin_rect = Rect::new(Point2D::new(left_padding, top_padding), self.origin_rect = Rect::new(
Size2D::new(right_padding, bottom_padding)); Point2D::new(left_padding, top_padding),
Size2D::new(right_padding, bottom_padding),
);
}, },
}; };
} }
@ -509,8 +540,11 @@ impl FragmentBorderBoxIterator for ParentOffsetBorderBoxIterator {
// for its parent. Remove all nodes at this level or // for its parent. Remove all nodes at this level or
// higher, as they can't be parents of this node. // higher, as they can't be parents of this node.
self.parent_nodes.truncate(level as usize); self.parent_nodes.truncate(level as usize);
assert_eq!(self.parent_nodes.len(), level as usize, assert_eq!(
"Skipped at least one level in the flow tree!"); self.parent_nodes.len(),
level as usize,
"Skipped at least one level in the flow tree!"
);
} }
if !fragment.is_primary_fragment() { if !fragment.is_primary_fragment() {
@ -530,8 +564,10 @@ impl FragmentBorderBoxIterator for ParentOffsetBorderBoxIterator {
// Found the fragment in the flow tree that matches the // Found the fragment in the flow tree that matches the
// DOM node being looked for. // DOM node being looked for.
assert!(self.node_offset_box.is_none(), assert!(
"Node was being treated as inline, but it has an associated fragment!"); self.node_offset_box.is_none(),
"Node was being treated as inline, but it has an associated fragment!"
);
self.has_processed_node = true; self.has_processed_node = true;
self.node_offset_box = Some(NodeOffsetBoxInfo { self.node_offset_box = Some(NodeOffsetBoxInfo {
@ -544,7 +580,10 @@ impl FragmentBorderBoxIterator for ParentOffsetBorderBoxIterator {
self.parent_nodes.clear(); self.parent_nodes.clear();
} }
} else if let Some(node) = fragment.inline_context.as_ref().and_then(|inline_context| { } else if let Some(node) = fragment.inline_context.as_ref().and_then(|inline_context| {
inline_context.nodes.iter().find(|node| node.address == self.node_address) inline_context
.nodes
.iter()
.find(|node| node.address == self.node_address)
}) { }) {
// TODO: Handle cases where the `offsetParent` is an inline // TODO: Handle cases where the `offsetParent` is an inline
// element. This will likely be impossible until // element. This will likely be impossible until
@ -554,7 +593,9 @@ impl FragmentBorderBoxIterator for ParentOffsetBorderBoxIterator {
// contains the DOM node we're looking for, i.e. the node // contains the DOM node we're looking for, i.e. the node
// is inline and contains this fragment. // is inline and contains this fragment.
match self.node_offset_box { match self.node_offset_box {
Some(NodeOffsetBoxInfo { ref mut rectangle, .. }) => { Some(NodeOffsetBoxInfo {
ref mut rectangle, ..
}) => {
*rectangle = rectangle.union(border_box); *rectangle = rectangle.union(border_box);
}, },
None => { None => {
@ -571,7 +612,10 @@ impl FragmentBorderBoxIterator for ParentOffsetBorderBoxIterator {
}, },
} }
if node.flags.contains(InlineFragmentNodeFlags::LAST_FRAGMENT_OF_ELEMENT) { if node
.flags
.contains(InlineFragmentNodeFlags::LAST_FRAGMENT_OF_ELEMENT)
{
self.has_processed_node = true; self.has_processed_node = true;
} }
} else if self.node_offset_box.is_none() { } else if self.node_offset_box.is_none() {
@ -580,9 +624,11 @@ impl FragmentBorderBoxIterator for ParentOffsetBorderBoxIterator {
// it's at level 1 (below the root node)? // it's at level 1 (below the root node)?
let is_body_element = level == 1; let is_body_element = level == 1;
let is_valid_parent = match (is_body_element, let is_valid_parent = match (
is_body_element,
fragment.style.get_box().position, fragment.style.get_box().position,
&fragment.specific) { &fragment.specific,
) {
// Spec says it's valid if any of these are true: // Spec says it's valid if any of these are true:
// 1) Is the body element // 1) Is the body element
// 2) Is static position *and* is a table or table cell // 2) Is static position *and* is a table or table cell
@ -600,7 +646,9 @@ impl FragmentBorderBoxIterator for ParentOffsetBorderBoxIterator {
}; };
let parent_info = if is_valid_parent { let parent_info = if is_valid_parent {
let border_width = fragment.border_width().to_physical(fragment.style.writing_mode); let border_width = fragment
.border_width()
.to_physical(fragment.style.writing_mode);
Some(ParentBorderBoxInfo { Some(ParentBorderBoxInfo {
node_address: fragment.node, node_address: fragment.node,
@ -619,9 +667,10 @@ impl FragmentBorderBoxIterator for ParentOffsetBorderBoxIterator {
} }
} }
pub fn process_node_geometry_request<N: LayoutNode>(
pub fn process_node_geometry_request<N: LayoutNode>(requested_node: N, layout_root: &mut Flow) requested_node: N,
-> Rect<i32> { layout_root: &mut Flow,
) -> Rect<i32> {
let mut iterator = FragmentLocatingFragmentIterator::new(requested_node.opaque()); let mut iterator = FragmentLocatingFragmentIterator::new(requested_node.opaque());
sequential::iterate_through_flow_tree_fragment_border_boxes(layout_root, &mut iterator); sequential::iterate_through_flow_tree_fragment_border_boxes(layout_root, &mut iterator);
iterator.client_rect iterator.client_rect
@ -629,28 +678,41 @@ pub fn process_node_geometry_request<N: LayoutNode>(requested_node: N, layout_ro
pub fn process_node_scroll_id_request<N: LayoutNode>( pub fn process_node_scroll_id_request<N: LayoutNode>(
id: PipelineId, id: PipelineId,
requested_node: N requested_node: N,
) -> ExternalScrollId { ) -> ExternalScrollId {
let layout_node = requested_node.to_threadsafe(); let layout_node = requested_node.to_threadsafe();
layout_node.generate_scroll_id(id) layout_node.generate_scroll_id(id)
} }
/// https://drafts.csswg.org/cssom-view/#scrolling-area /// https://drafts.csswg.org/cssom-view/#scrolling-area
pub fn process_node_scroll_area_request< N: LayoutNode>(requested_node: N, layout_root: &mut Flow) pub fn process_node_scroll_area_request<N: LayoutNode>(
-> Rect<i32> { requested_node: N,
layout_root: &mut Flow,
) -> Rect<i32> {
let mut iterator = UnioningFragmentScrollAreaIterator::new(requested_node.opaque()); let mut iterator = UnioningFragmentScrollAreaIterator::new(requested_node.opaque());
sequential::iterate_through_flow_tree_fragment_border_boxes(layout_root, &mut iterator); sequential::iterate_through_flow_tree_fragment_border_boxes(layout_root, &mut iterator);
match iterator.overflow_direction { match iterator.overflow_direction {
OverflowDirection::RightAndDown => { OverflowDirection::RightAndDown => {
let right = max(iterator.union_rect.size.width, iterator.origin_rect.size.width); let right = max(
let bottom = max(iterator.union_rect.size.height, iterator.origin_rect.size.height); iterator.union_rect.size.width,
iterator.origin_rect.size.width,
);
let bottom = max(
iterator.union_rect.size.height,
iterator.origin_rect.size.height,
);
Rect::new(iterator.origin_rect.origin, Size2D::new(right, bottom)) Rect::new(iterator.origin_rect.origin, Size2D::new(right, bottom))
}, },
OverflowDirection::LeftAndDown => { OverflowDirection::LeftAndDown => {
let bottom = max(iterator.union_rect.size.height, iterator.origin_rect.size.height); let bottom = max(
iterator.union_rect.size.height,
iterator.origin_rect.size.height,
);
let left = min(iterator.union_rect.origin.x, iterator.origin_rect.origin.x); let left = min(iterator.union_rect.origin.x, iterator.origin_rect.origin.x);
Rect::new(Point2D::new(left, iterator.origin_rect.origin.y), Rect::new(
Size2D::new(iterator.origin_rect.size.width, bottom)) Point2D::new(left, iterator.origin_rect.origin.y),
Size2D::new(iterator.origin_rect.size.width, bottom),
)
}, },
OverflowDirection::LeftAndUp => { OverflowDirection::LeftAndUp => {
let top = min(iterator.union_rect.origin.y, iterator.origin_rect.origin.y); let top = min(iterator.union_rect.origin.y, iterator.origin_rect.origin.y);
@ -659,21 +721,29 @@ pub fn process_node_scroll_area_request< N: LayoutNode>(requested_node: N, layou
}, },
OverflowDirection::RightAndUp => { OverflowDirection::RightAndUp => {
let top = min(iterator.union_rect.origin.y, iterator.origin_rect.origin.y); let top = min(iterator.union_rect.origin.y, iterator.origin_rect.origin.y);
let right = max(iterator.union_rect.size.width, iterator.origin_rect.size.width); let right = max(
Rect::new(Point2D::new(iterator.origin_rect.origin.x, top), iterator.union_rect.size.width,
Size2D::new(right, iterator.origin_rect.size.height)) iterator.origin_rect.size.width,
} );
Rect::new(
Point2D::new(iterator.origin_rect.origin.x, top),
Size2D::new(right, iterator.origin_rect.size.height),
)
},
} }
} }
/// Return the resolved value of property for a given (pseudo)element. /// Return the resolved value of property for a given (pseudo)element.
/// <https://drafts.csswg.org/cssom/#resolved-value> /// <https://drafts.csswg.org/cssom/#resolved-value>
pub fn process_resolved_style_request<'a, N>(context: &LayoutContext, pub fn process_resolved_style_request<'a, N>(
context: &LayoutContext,
node: N, node: N,
pseudo: &Option<PseudoElement>, pseudo: &Option<PseudoElement>,
property: &PropertyId, property: &PropertyId,
layout_root: &mut Flow) -> String layout_root: &mut Flow,
where N: LayoutNode, ) -> String
where
N: LayoutNode,
{ {
use style::stylist::RuleInclusion; use style::stylist::RuleInclusion;
use style::traversal::resolve_style; use style::traversal::resolve_style;
@ -700,15 +770,13 @@ pub fn process_resolved_style_request<'a, N>(context: &LayoutContext,
let styles = resolve_style(&mut context, element, RuleInclusion::All, pseudo.as_ref()); let styles = resolve_style(&mut context, element, RuleInclusion::All, pseudo.as_ref());
let style = styles.primary(); let style = styles.primary();
let longhand_id = match *property { let longhand_id = match *property {
PropertyId::LonghandAlias(id, _) | PropertyId::LonghandAlias(id, _) | PropertyId::Longhand(id) => id,
PropertyId::Longhand(id) => id,
// Firefox returns blank strings for the computed value of shorthands, // Firefox returns blank strings for the computed value of shorthands,
// so this should be web-compatible. // so this should be web-compatible.
PropertyId::ShorthandAlias(..) | PropertyId::ShorthandAlias(..) | PropertyId::Shorthand(_) => return String::new(),
PropertyId::Shorthand(_) => return String::new(),
PropertyId::Custom(ref name) => { PropertyId::Custom(ref name) => {
return style.computed_value_to_string(PropertyDeclarationId::Custom(name)) return style.computed_value_to_string(PropertyDeclarationId::Custom(name))
} },
}; };
// No need to care about used values here, since we're on a display: none // No need to care about used values here, since we're on a display: none
@ -735,7 +803,7 @@ where
Some(PseudoElement::Selection) => None, Some(PseudoElement::Selection) => None,
// FIXME(emilio): What about the other pseudos? Probably they shouldn't // FIXME(emilio): What about the other pseudos? Probably they shouldn't
// just return the element's style! // just return the element's style!
_ => Some(layout_el) _ => Some(layout_el),
}; };
let layout_el = match layout_el { let layout_el = match layout_el {
@ -744,29 +812,24 @@ where
// the element itself in this case, Firefox uses the resolved value. // the element itself in this case, Firefox uses the resolved value.
// https://www.w3.org/Bugs/Public/show_bug.cgi?id=29006 // https://www.w3.org/Bugs/Public/show_bug.cgi?id=29006
return String::new(); return String::new();
} },
Some(layout_el) => layout_el Some(layout_el) => layout_el,
}; };
let style = &*layout_el.resolved_style(); let style = &*layout_el.resolved_style();
let longhand_id = match *property { let longhand_id = match *property {
PropertyId::LonghandAlias(id, _) | PropertyId::LonghandAlias(id, _) | PropertyId::Longhand(id) => id,
PropertyId::Longhand(id) => id,
// Firefox returns blank strings for the computed value of shorthands, // Firefox returns blank strings for the computed value of shorthands,
// so this should be web-compatible. // so this should be web-compatible.
PropertyId::ShorthandAlias(..) | PropertyId::ShorthandAlias(..) | PropertyId::Shorthand(_) => return String::new(),
PropertyId::Shorthand(_) => return String::new(),
PropertyId::Custom(ref name) => { PropertyId::Custom(ref name) => {
return style.computed_value_to_string(PropertyDeclarationId::Custom(name)) return style.computed_value_to_string(PropertyDeclarationId::Custom(name))
} },
}; };
let positioned = match style.get_box().position { let positioned = match style.get_box().position {
Position::Relative | Position::Relative | Position::Sticky | Position::Fixed | Position::Absolute => true,
Position::Sticky | _ => false,
Position::Fixed |
Position::Absolute => true,
_ => false
}; };
//TODO: determine whether requested property applies to the element. //TODO: determine whether requested property applies to the element.
@ -780,15 +843,20 @@ where
layout_el: <N::ConcreteThreadSafeLayoutNode as ThreadSafeLayoutNode>::ConcreteThreadSafeLayoutElement, layout_el: <N::ConcreteThreadSafeLayoutNode as ThreadSafeLayoutNode>::ConcreteThreadSafeLayoutElement,
layout_root: &mut Flow, layout_root: &mut Flow,
requested_node: N, requested_node: N,
longhand_id: LonghandId) -> String { longhand_id: LonghandId,
) -> String
{
let maybe_data = layout_el.borrow_layout_data(); let maybe_data = layout_el.borrow_layout_data();
let position = maybe_data.map_or(Point2D::zero(), |data| { let position = maybe_data.map_or(Point2D::zero(), |data| {
match (*data).flow_construction_result { match (*data).flow_construction_result {
ConstructionResult::Flow(ref flow_ref, _) => ConstructionResult::Flow(ref flow_ref, _) => flow_ref
flow_ref.deref().base().stacking_relative_position.to_point(), .deref()
.base()
.stacking_relative_position
.to_point(),
// TODO(dzbarsky) search parents until we find node with a flow ref. // TODO(dzbarsky) search parents until we find node with a flow ref.
// https://github.com/servo/servo/issues/8307 // https://github.com/servo/servo/issues/8307
_ => Point2D::zero() _ => Point2D::zero(),
} }
}); });
let property = match longhand_id { let property = match longhand_id {
@ -798,24 +866,32 @@ where
LonghandId::Right => PositionProperty::Right, LonghandId::Right => PositionProperty::Right,
LonghandId::Width => PositionProperty::Width, LonghandId::Width => PositionProperty::Width,
LonghandId::Height => PositionProperty::Height, LonghandId::Height => PositionProperty::Height,
_ => unreachable!() _ => unreachable!(),
}; };
let mut iterator = let mut iterator = PositionRetrievingFragmentBorderBoxIterator::new(
PositionRetrievingFragmentBorderBoxIterator::new(requested_node.opaque(), requested_node.opaque(),
property, property,
position); position,
sequential::iterate_through_flow_tree_fragment_border_boxes(layout_root, );
&mut iterator); sequential::iterate_through_flow_tree_fragment_border_boxes(layout_root, &mut iterator);
iterator.result.map(|r| r.to_css_string()).unwrap_or(String::new()) iterator
.result
.map(|r| r.to_css_string())
.unwrap_or(String::new())
} }
// TODO: we will return neither the computed nor used value for margin and padding. // TODO: we will return neither the computed nor used value for margin and padding.
match longhand_id { match longhand_id {
LonghandId::MarginBottom | LonghandId::MarginTop | LonghandId::MarginBottom |
LonghandId::MarginLeft | LonghandId::MarginRight | LonghandId::MarginTop |
LonghandId::PaddingBottom | LonghandId::PaddingTop | LonghandId::MarginLeft |
LonghandId::PaddingLeft | LonghandId::PaddingRight LonghandId::MarginRight |
if applies && style.get_box().display != Display::None => { LonghandId::PaddingBottom |
LonghandId::PaddingTop |
LonghandId::PaddingLeft |
LonghandId::PaddingRight
if applies && style.get_box().display != Display::None =>
{
let (margin_padding, side) = match longhand_id { let (margin_padding, side) = match longhand_id {
LonghandId::MarginBottom => (MarginPadding::Margin, Side::Bottom), LonghandId::MarginBottom => (MarginPadding::Margin, Side::Bottom),
LonghandId::MarginTop => (MarginPadding::Margin, Side::Top), LonghandId::MarginTop => (MarginPadding::Margin, Side::Top),
@ -825,40 +901,50 @@ where
LonghandId::PaddingTop => (MarginPadding::Padding, Side::Top), LonghandId::PaddingTop => (MarginPadding::Padding, Side::Top),
LonghandId::PaddingLeft => (MarginPadding::Padding, Side::Left), LonghandId::PaddingLeft => (MarginPadding::Padding, Side::Left),
LonghandId::PaddingRight => (MarginPadding::Padding, Side::Right), LonghandId::PaddingRight => (MarginPadding::Padding, Side::Right),
_ => unreachable!() _ => unreachable!(),
}; };
let mut iterator = let mut iterator = MarginRetrievingFragmentBorderBoxIterator::new(
MarginRetrievingFragmentBorderBoxIterator::new(requested_node.opaque(), requested_node.opaque(),
side, side,
margin_padding, margin_padding,
style.writing_mode); style.writing_mode,
sequential::iterate_through_flow_tree_fragment_border_boxes(layout_root, );
&mut iterator); sequential::iterate_through_flow_tree_fragment_border_boxes(layout_root, &mut iterator);
iterator.result.map(|r| r.to_css_string()).unwrap_or(String::new()) iterator
}, .result
.map(|r| r.to_css_string())
.unwrap_or(String::new())
}
LonghandId::Bottom | LonghandId::Top | LonghandId::Right | LonghandId::Left LonghandId::Bottom | LonghandId::Top | LonghandId::Right | LonghandId::Left
if applies && positioned && style.get_box().display != Display::None => { if applies && positioned && style.get_box().display != Display::None =>
{
used_value_for_position_property(layout_el, layout_root, requested_node, longhand_id) used_value_for_position_property(layout_el, layout_root, requested_node, longhand_id)
} },
LonghandId::Width | LonghandId::Height LonghandId::Width | LonghandId::Height
if applies && style.get_box().display != Display::None => { if applies && style.get_box().display != Display::None =>
{
used_value_for_position_property(layout_el, layout_root, requested_node, longhand_id) used_value_for_position_property(layout_el, layout_root, requested_node, longhand_id)
} },
// FIXME: implement used value computation for line-height // FIXME: implement used value computation for line-height
_ => { _ => style.computed_value_to_string(PropertyDeclarationId::Longhand(longhand_id)),
style.computed_value_to_string(PropertyDeclarationId::Longhand(longhand_id))
}
} }
} }
pub fn process_offset_parent_query<N: LayoutNode>(requested_node: N, layout_root: &mut Flow) pub fn process_offset_parent_query<N: LayoutNode>(
-> OffsetParentResponse { requested_node: N,
layout_root: &mut Flow,
) -> OffsetParentResponse {
let mut iterator = ParentOffsetBorderBoxIterator::new(requested_node.opaque()); let mut iterator = ParentOffsetBorderBoxIterator::new(requested_node.opaque());
sequential::iterate_through_flow_tree_fragment_border_boxes(layout_root, &mut iterator); sequential::iterate_through_flow_tree_fragment_border_boxes(layout_root, &mut iterator);
let node_offset_box = iterator.node_offset_box; let node_offset_box = iterator.node_offset_box;
let parent_info = iterator.parent_nodes.into_iter().rev().filter_map(|info| info).next(); let parent_info = iterator
.parent_nodes
.into_iter()
.rev()
.filter_map(|info| info)
.next();
match (node_offset_box, parent_info) { match (node_offset_box, parent_info) {
(Some(node_offset_box), Some(parent_info)) => { (Some(node_offset_box), Some(parent_info)) => {
let origin = node_offset_box.offset - parent_info.origin.to_vector(); let origin = node_offset_box.offset - parent_info.origin.to_vector();
@ -867,15 +953,12 @@ pub fn process_offset_parent_query<N: LayoutNode>(requested_node: N, layout_root
node_address: Some(parent_info.node_address.to_untrusted_node_address()), node_address: Some(parent_info.node_address.to_untrusted_node_address()),
rect: Rect::new(origin, size), rect: Rect::new(origin, size),
} }
} },
_ => { _ => OffsetParentResponse::empty(),
OffsetParentResponse::empty()
}
} }
} }
pub fn process_style_query<N: LayoutNode>(requested_node: N) pub fn process_style_query<N: LayoutNode>(requested_node: N) -> StyleResponse {
-> StyleResponse {
let element = requested_node.as_element().unwrap(); let element = requested_node.as_element().unwrap();
let data = element.borrow_data(); let data = element.borrow_data();
@ -888,8 +971,10 @@ enum InnerTextItem {
} }
// https://html.spec.whatwg.org/multipage/#the-innertext-idl-attribute // https://html.spec.whatwg.org/multipage/#the-innertext-idl-attribute
pub fn process_element_inner_text_query<N: LayoutNode>(node: N, pub fn process_element_inner_text_query<N: LayoutNode>(
indexable_text: &IndexableText) -> String { node: N,
indexable_text: &IndexableText,
) -> String {
// Step 1. // Step 1.
let mut results = Vec::new(); let mut results = Vec::new();
// Step 2. // Step 2.
@ -923,7 +1008,7 @@ pub fn process_element_inner_text_query<N: LayoutNode>(node: N,
if count > max_req_line_break_count { if count > max_req_line_break_count {
max_req_line_break_count = count; max_req_line_break_count = count;
} }
} },
} }
} }
inner_text.into_iter().collect() inner_text.into_iter().collect()
@ -931,22 +1016,21 @@ pub fn process_element_inner_text_query<N: LayoutNode>(node: N,
// https://html.spec.whatwg.org/multipage/#inner-text-collection-steps // https://html.spec.whatwg.org/multipage/#inner-text-collection-steps
#[allow(unsafe_code)] #[allow(unsafe_code)]
fn inner_text_collection_steps<N: LayoutNode>(node: N, fn inner_text_collection_steps<N: LayoutNode>(
node: N,
indexable_text: &IndexableText, indexable_text: &IndexableText,
results: &mut Vec<InnerTextItem>) { results: &mut Vec<InnerTextItem>,
) {
let mut items = Vec::new(); let mut items = Vec::new();
for child in node.traverse_preorder() { for child in node.traverse_preorder() {
let node = match child.type_id() { let node = match child.type_id() {
LayoutNodeType::Text => { LayoutNodeType::Text => child.parent_node().unwrap(),
child.parent_node().unwrap()
},
_ => child, _ => child,
}; };
let element_data = unsafe { let element_data = unsafe {
node.get_style_and_layout_data().map(|d| { node.get_style_and_layout_data()
&(*(d.ptr.as_ptr() as *mut StyleData)).element_data .map(|d| &(*(d.ptr.as_ptr() as *mut StyleData)).element_data)
})
}; };
if element_data.is_none() { if element_data.is_none() {
@ -980,15 +1064,16 @@ fn inner_text_collection_steps<N: LayoutNode>(node: N,
}, },
LayoutNodeType::Element(LayoutElementType::HTMLBRElement) => { LayoutNodeType::Element(LayoutElementType::HTMLBRElement) => {
// Step 5. // Step 5.
items.push(InnerTextItem::Text(String::from("\u{000A}" /* line feed */))); items.push(InnerTextItem::Text(String::from(
"\u{000A}", /* line feed */
)));
}, },
LayoutNodeType::Element(LayoutElementType::HTMLParagraphElement) => { LayoutNodeType::Element(LayoutElementType::HTMLParagraphElement) => {
// Step 8. // Step 8.
items.insert(0, InnerTextItem::RequiredLineBreakCount(2)); items.insert(0, InnerTextItem::RequiredLineBreakCount(2));
items.push(InnerTextItem::RequiredLineBreakCount(2)); items.push(InnerTextItem::RequiredLineBreakCount(2));
} },
_ => {}, _ => {},
} }
match display { match display {

View file

@ -25,10 +25,12 @@ pub fn resolve_generated_content(root: &mut Flow, layout_context: &LayoutContext
/// Run the main layout passes sequentially. /// Run the main layout passes sequentially.
pub fn reflow(root: &mut Flow, layout_context: &LayoutContext, relayout_mode: RelayoutMode) { pub fn reflow(root: &mut Flow, layout_context: &LayoutContext, relayout_mode: RelayoutMode) {
fn doit(flow: &mut Flow, fn doit(
flow: &mut Flow,
assign_inline_sizes: AssignISizes, assign_inline_sizes: AssignISizes,
assign_block_sizes: AssignBSizes, assign_block_sizes: AssignBSizes,
relayout_mode: RelayoutMode) { relayout_mode: RelayoutMode,
) {
// Force reflow children during this traversal. This is needed when we failed // Force reflow children during this traversal. This is needed when we failed
// the float speculation of a block formatting context and need to fix it. // the float speculation of a block formatting context and need to fix it.
if relayout_mode == RelayoutMode::Force { if relayout_mode == RelayoutMode::Force {
@ -67,42 +69,47 @@ pub fn reflow(root: &mut Flow, layout_context: &LayoutContext, relayout_mode: Re
doit(root, assign_inline_sizes, assign_block_sizes, relayout_mode); doit(root, assign_inline_sizes, assign_block_sizes, relayout_mode);
} }
pub fn build_display_list_for_subtree<'a>(flow_root: &mut Flow, pub fn build_display_list_for_subtree<'a>(
layout_context: &'a LayoutContext) flow_root: &mut Flow,
-> DisplayListBuildState<'a> { layout_context: &'a LayoutContext,
) -> DisplayListBuildState<'a> {
let mut state = StackingContextCollectionState::new(layout_context.id); let mut state = StackingContextCollectionState::new(layout_context.id);
flow_root.collect_stacking_contexts(&mut state); flow_root.collect_stacking_contexts(&mut state);
let state = DisplayListBuildState::new(layout_context, state); let state = DisplayListBuildState::new(layout_context, state);
let mut build_display_list = BuildDisplayList { let mut build_display_list = BuildDisplayList { state: state };
state: state,
};
build_display_list.traverse(flow_root); build_display_list.traverse(flow_root);
build_display_list.state build_display_list.state
} }
pub fn iterate_through_flow_tree_fragment_border_boxes(root: &mut Flow, iterator: &mut FragmentBorderBoxIterator) { pub fn iterate_through_flow_tree_fragment_border_boxes(
fn doit(flow: &mut Flow, root: &mut Flow,
iterator: &mut FragmentBorderBoxIterator,
) {
fn doit(
flow: &mut Flow,
level: i32, level: i32,
iterator: &mut FragmentBorderBoxIterator, iterator: &mut FragmentBorderBoxIterator,
stacking_context_position: &Point2D<Au>) { stacking_context_position: &Point2D<Au>,
) {
flow.iterate_through_fragment_border_boxes(iterator, level, stacking_context_position); flow.iterate_through_fragment_border_boxes(iterator, level, stacking_context_position);
for kid in flow.mut_base().child_iter_mut() { for kid in flow.mut_base().child_iter_mut() {
let mut stacking_context_position = *stacking_context_position; let mut stacking_context_position = *stacking_context_position;
if kid.is_block_flow() && kid.as_block().fragment.establishes_stacking_context() { if kid.is_block_flow() && kid.as_block().fragment.establishes_stacking_context() {
stacking_context_position = Point2D::new(kid.as_block().fragment.margin.inline_start, Au(0)) + stacking_context_position =
Point2D::new(kid.as_block().fragment.margin.inline_start, Au(0)) +
kid.base().stacking_relative_position + kid.base().stacking_relative_position +
stacking_context_position.to_vector(); stacking_context_position.to_vector();
let relative_position = kid.as_block() let relative_position = kid
.as_block()
.stacking_relative_border_box(CoordinateSystem::Own); .stacking_relative_border_box(CoordinateSystem::Own);
if let Some(matrix) = kid.as_block() if let Some(matrix) = kid.as_block().fragment.transform_matrix(&relative_position) {
.fragment
.transform_matrix(&relative_position) {
let transform_matrix = matrix.transform_point2d(&LayoutPoint::zero()).unwrap(); let transform_matrix = matrix.transform_point2d(&LayoutPoint::zero()).unwrap();
stacking_context_position = stacking_context_position + stacking_context_position = stacking_context_position + Vector2D::new(
Vector2D::new(Au::from_f32_px(transform_matrix.x), Au::from_f32_px(transform_matrix.x),
Au::from_f32_px(transform_matrix.y)) Au::from_f32_px(transform_matrix.y),
)
} }
} }
doit(kid, level + 1, iterator, &stacking_context_position); doit(kid, level + 1, iterator, &stacking_context_position);
@ -113,7 +120,11 @@ pub fn iterate_through_flow_tree_fragment_border_boxes(root: &mut Flow, iterator
} }
pub fn store_overflow(layout_context: &LayoutContext, flow: &mut Flow) { pub fn store_overflow(layout_context: &LayoutContext, flow: &mut Flow) {
if !flow.base().restyle_damage.contains(ServoRestyleDamage::STORE_OVERFLOW) { if !flow
.base()
.restyle_damage
.contains(ServoRestyleDamage::STORE_OVERFLOW)
{
return; return;
} }
@ -132,13 +143,21 @@ pub fn store_overflow(layout_context: &LayoutContext, flow: &mut Flow) {
/// given flow. This is needed to speculatively calculate the inline sizes of block formatting /// given flow. This is needed to speculatively calculate the inline sizes of block formatting
/// contexts. The speculation typically succeeds, but if it doesn't we have to lay it out again. /// contexts. The speculation typically succeeds, but if it doesn't we have to lay it out again.
pub fn guess_float_placement(flow: &mut Flow) { pub fn guess_float_placement(flow: &mut Flow) {
if !flow.base().restyle_damage.intersects(ServoRestyleDamage::REFLOW) { if !flow
.base()
.restyle_damage
.intersects(ServoRestyleDamage::REFLOW)
{
return; return;
} }
let mut floats_in = SpeculatedFloatPlacement::compute_floats_in_for_first_child(flow); let mut floats_in = SpeculatedFloatPlacement::compute_floats_in_for_first_child(flow);
for kid in flow.mut_base().child_iter_mut() { for kid in flow.mut_base().child_iter_mut() {
if kid.base().flags.contains(FlowFlags::IS_ABSOLUTELY_POSITIONED) { if kid
.base()
.flags
.contains(FlowFlags::IS_ABSOLUTELY_POSITIONED)
{
// Do not propagate floats in or out, but do propogate between kids. // Do not propagate floats in or out, but do propogate between kids.
guess_float_placement(kid); guess_float_placement(kid);
} else { } else {

View file

@ -79,7 +79,7 @@ impl TableFlow {
column_computed_inline_sizes: Vec::new(), column_computed_inline_sizes: Vec::new(),
collapsed_inline_direction_border_widths_for_table: Vec::new(), collapsed_inline_direction_border_widths_for_table: Vec::new(),
collapsed_block_direction_border_widths_for_table: Vec::new(), collapsed_block_direction_border_widths_for_table: Vec::new(),
table_layout: table_layout table_layout: table_layout,
} }
} }
@ -89,8 +89,8 @@ impl TableFlow {
fn update_automatic_column_inline_sizes( fn update_automatic_column_inline_sizes(
parent_inline_sizes: &mut Vec<ColumnIntrinsicInlineSize>, parent_inline_sizes: &mut Vec<ColumnIntrinsicInlineSize>,
child_cell_inline_sizes: &[CellIntrinsicInlineSize], child_cell_inline_sizes: &[CellIntrinsicInlineSize],
surrounding_size: Au) surrounding_size: Au,
-> IntrinsicISizes { ) -> IntrinsicISizes {
let mut total_inline_sizes = IntrinsicISizes { let mut total_inline_sizes = IntrinsicISizes {
minimum_inline_size: surrounding_size, minimum_inline_size: surrounding_size,
preferred_inline_size: surrounding_size, preferred_inline_size: surrounding_size,
@ -117,8 +117,10 @@ impl TableFlow {
} else { } else {
let column_size = &child_cell_inline_size.column_size; let column_size = &child_cell_inline_size.column_size;
*parent_sizes = ColumnIntrinsicInlineSize { *parent_sizes = ColumnIntrinsicInlineSize {
minimum_length: cmp::max(parent_sizes.minimum_length, minimum_length: cmp::max(
column_size.minimum_length), parent_sizes.minimum_length,
column_size.minimum_length,
),
percentage: parent_sizes.greatest_percentage(column_size), percentage: parent_sizes.greatest_percentage(column_size),
preferred: cmp::max(parent_sizes.preferred, column_size.preferred), preferred: cmp::max(parent_sizes.preferred, column_size.preferred),
constrained: parent_sizes.constrained || column_size.constrained, constrained: parent_sizes.constrained || column_size.constrained,
@ -158,12 +160,14 @@ impl TableFlow {
/// Updates the minimum and preferred inline-size calculation for a single row. This is /// Updates the minimum and preferred inline-size calculation for a single row. This is
/// factored out into a separate function because we process children of rowgroups too. /// factored out into a separate function because we process children of rowgroups too.
fn update_column_inline_sizes_for_row(row: &TableRowFlow, fn update_column_inline_sizes_for_row(
row: &TableRowFlow,
column_inline_sizes: &mut Vec<ColumnIntrinsicInlineSize>, column_inline_sizes: &mut Vec<ColumnIntrinsicInlineSize>,
computation: &mut IntrinsicISizesContribution, computation: &mut IntrinsicISizesContribution,
first_row: bool, first_row: bool,
table_layout: TableLayout, table_layout: TableLayout,
surrounding_inline_size: Au) { surrounding_inline_size: Au,
) {
// Read column inline-sizes from the table-row, and assign inline-size=0 for the columns // Read column inline-sizes from the table-row, and assign inline-size=0 for the columns
// not defined in the column group. // not defined in the column group.
// //
@ -178,13 +182,14 @@ impl TableFlow {
column_inline_sizes.push(cell_inline_size.column_size); column_inline_sizes.push(cell_inline_size.column_size);
} }
} }
} },
TableLayout::Auto => { TableLayout::Auto => {
computation.union_block(&TableFlow::update_automatic_column_inline_sizes( computation.union_block(&TableFlow::update_automatic_column_inline_sizes(
column_inline_sizes, column_inline_sizes,
&row.cell_intrinsic_inline_sizes, &row.cell_intrinsic_inline_sizes,
surrounding_inline_size)) surrounding_inline_size,
} ))
},
} }
} }
@ -207,21 +212,31 @@ impl TableFlow {
fn column_styles(&self) -> Vec<ColumnStyle> { fn column_styles(&self) -> Vec<ColumnStyle> {
let mut styles = vec![]; let mut styles = vec![];
for group in self.block_flow.base.child_iter() for group in self
.filter(|kid| kid.is_table_colgroup()) { .block_flow
.base
.child_iter()
.filter(|kid| kid.is_table_colgroup())
{
// XXXManishearth these as_foo methods should return options // XXXManishearth these as_foo methods should return options
// so that we can filter_map // so that we can filter_map
let group = group.as_table_colgroup(); let group = group.as_table_colgroup();
let colgroup_style = group.fragment.as_ref() let colgroup_style = group.fragment.as_ref().map(|f| f.style());
.map(|f| f.style());
// The colgroup's span attribute is only relevant when // The colgroup's span attribute is only relevant when
// it has no children // it has no children
// https://html.spec.whatwg.org/multipage/#forming-a-table // https://html.spec.whatwg.org/multipage/#forming-a-table
if group.cols.is_empty() { if group.cols.is_empty() {
let span = group.fragment.as_ref() let span = group
.map(|f| f.column_span()).unwrap_or(1); .fragment
styles.push(ColumnStyle { span, colgroup_style, col_style: None }); .as_ref()
.map(|f| f.column_span())
.unwrap_or(1);
styles.push(ColumnStyle {
span,
colgroup_style,
col_style: None,
});
} else { } else {
for col in &group.cols { for col in &group.cols {
// XXXManishearth Arc-cloning colgroup_style is suboptimal // XXXManishearth Arc-cloning colgroup_style is suboptimal
@ -267,13 +282,21 @@ impl Flow for TableFlow {
/// The maximum min/pref inline-sizes of each column are set from the rows for the automatic /// The maximum min/pref inline-sizes of each column are set from the rows for the automatic
/// table layout calculation. /// table layout calculation.
fn bubble_inline_sizes(&mut self) { fn bubble_inline_sizes(&mut self) {
let _scope = layout_debug_scope!("table::bubble_inline_sizes {:x}", let _scope = layout_debug_scope!(
self.block_flow.base.debug_id()); "table::bubble_inline_sizes {:x}",
self.block_flow.base.debug_id()
);
// Get column inline sizes from colgroups // Get column inline sizes from colgroups
for kid in self.block_flow.base.child_iter_mut().filter(|kid| kid.is_table_colgroup()) { for kid in self
.block_flow
.base
.child_iter_mut()
.filter(|kid| kid.is_table_colgroup())
{
for specified_inline_size in &kid.as_mut_table_colgroup().inline_sizes { for specified_inline_size in &kid.as_mut_table_colgroup().inline_sizes {
self.column_intrinsic_inline_sizes.push(ColumnIntrinsicInlineSize { self.column_intrinsic_inline_sizes
.push(ColumnIntrinsicInlineSize {
minimum_length: match *specified_inline_size { minimum_length: match *specified_inline_size {
LengthOrPercentageOrAuto::Auto | LengthOrPercentageOrAuto::Auto |
LengthOrPercentageOrAuto::Calc(_) | LengthOrPercentageOrAuto::Calc(_) |
@ -295,17 +318,23 @@ impl Flow for TableFlow {
self.collapsed_inline_direction_border_widths_for_table = Vec::new(); self.collapsed_inline_direction_border_widths_for_table = Vec::new();
self.collapsed_block_direction_border_widths_for_table = vec![Au(0)]; self.collapsed_block_direction_border_widths_for_table = vec![Au(0)];
let collapsing_borders = self.block_flow let collapsing_borders = self
.block_flow
.fragment .fragment
.style .style
.get_inherited_table() .get_inherited_table()
.border_collapse == border_collapse::T::Collapse; .border_collapse ==
border_collapse::T::Collapse;
let table_inline_collapsed_borders = if collapsing_borders { let table_inline_collapsed_borders = if collapsing_borders {
Some(TableInlineCollapsedBorders { Some(TableInlineCollapsedBorders {
start: CollapsedBorder::inline_start(&*self.block_flow.fragment.style, start: CollapsedBorder::inline_start(
CollapsedBorderProvenance::FromTable), &*self.block_flow.fragment.style,
end: CollapsedBorder::inline_end(&*self.block_flow.fragment.style, CollapsedBorderProvenance::FromTable,
CollapsedBorderProvenance::FromTable), ),
end: CollapsedBorder::inline_end(
&*self.block_flow.fragment.style,
CollapsedBorderProvenance::FromTable,
),
}) })
} else { } else {
None None
@ -315,7 +344,8 @@ impl Flow for TableFlow {
let mut previous_collapsed_block_end_borders = let mut previous_collapsed_block_end_borders =
PreviousBlockCollapsedBorders::FromTable(CollapsedBorder::block_start( PreviousBlockCollapsedBorders::FromTable(CollapsedBorder::block_start(
&*self.block_flow.fragment.style, &*self.block_flow.fragment.style,
CollapsedBorderProvenance::FromTable)); CollapsedBorderProvenance::FromTable,
));
let mut first_row = true; let mut first_row = true;
let (border_padding, _) = self.block_flow.fragment.surrounding_intrinsic_inline_size(); let (border_padding, _) = self.block_flow.fragment.surrounding_intrinsic_inline_size();
@ -328,40 +358,42 @@ impl Flow for TableFlow {
&mut computation, &mut computation,
first_row, first_row,
self.table_layout, self.table_layout,
border_padding); border_padding,
);
if collapsing_borders { if collapsing_borders {
let next_index_and_sibling = iterator.peek(); let next_index_and_sibling = iterator.peek();
let next_collapsed_borders_in_block_direction = let next_collapsed_borders_in_block_direction = match next_index_and_sibling {
match next_index_and_sibling { Some(next_sibling) => NextBlockCollapsedBorders::FromNextRow(
Some(next_sibling) => { &next_sibling
NextBlockCollapsedBorders::FromNextRow( .as_table_row()
&next_sibling.as_table_row()
.preliminary_collapsed_borders .preliminary_collapsed_borders
.block_start) .block_start,
} ),
None => { None => NextBlockCollapsedBorders::FromTable(CollapsedBorder::block_end(
NextBlockCollapsedBorders::FromTable( &*self.block_flow.fragment.style,
CollapsedBorder::block_end(&*self.block_flow.fragment.style, CollapsedBorderProvenance::FromTable,
CollapsedBorderProvenance::FromTable)) )),
}
}; };
perform_border_collapse_for_row(row, perform_border_collapse_for_row(
row,
table_inline_collapsed_borders.as_ref().unwrap(), table_inline_collapsed_borders.as_ref().unwrap(),
previous_collapsed_block_end_borders, previous_collapsed_block_end_borders,
next_collapsed_borders_in_block_direction, next_collapsed_borders_in_block_direction,
&mut self.collapsed_inline_direction_border_widths_for_table, &mut self.collapsed_inline_direction_border_widths_for_table,
&mut self.collapsed_block_direction_border_widths_for_table); &mut self.collapsed_block_direction_border_widths_for_table,
);
previous_collapsed_block_end_borders = previous_collapsed_block_end_borders =
PreviousBlockCollapsedBorders::FromPreviousRow( PreviousBlockCollapsedBorders::FromPreviousRow(
row.final_collapsed_borders.block_end.clone()); row.final_collapsed_borders.block_end.clone(),
);
} }
first_row = false first_row = false
}; }
} }
let total_horizontal_spacing = self.total_horizontal_spacing(); let total_horizontal_spacing = self.total_horizontal_spacing();
let mut style_specified_intrinsic_inline_size = let mut style_specified_intrinsic_inline_size = self
self.block_flow .block_flow
.fragment .fragment
.style_specified_intrinsic_inline_size() .style_specified_intrinsic_inline_size()
.finish(); .finish();
@ -376,9 +408,14 @@ impl Flow for TableFlow {
/// Recursively (top-down) determines the actual inline-size of child contexts and fragments. /// Recursively (top-down) determines the actual inline-size of child contexts and fragments.
/// When called on this context, the context has had its inline-size set by the parent context. /// When called on this context, the context has had its inline-size set by the parent context.
fn assign_inline_sizes(&mut self, layout_context: &LayoutContext) { fn assign_inline_sizes(&mut self, layout_context: &LayoutContext) {
let _scope = layout_debug_scope!("table::assign_inline_sizes {:x}", let _scope = layout_debug_scope!(
self.block_flow.base.debug_id()); "table::assign_inline_sizes {:x}",
debug!("assign_inline_sizes({}): assigning inline_size for flow", "table"); self.block_flow.base.debug_id()
);
debug!(
"assign_inline_sizes({}): assigning inline_size for flow",
"table"
);
let shared_context = layout_context.shared_context(); let shared_context = layout_context.shared_context();
// The position was set to the containing block by the flow's parent. // The position was set to the containing block by the flow's parent.
@ -396,9 +433,11 @@ impl Flow for TableFlow {
} }
let inline_size_computer = InternalTable; let inline_size_computer = InternalTable;
inline_size_computer.compute_used_inline_size(&mut self.block_flow, inline_size_computer.compute_used_inline_size(
&mut self.block_flow,
shared_context, shared_context,
containing_block_inline_size); containing_block_inline_size,
);
let inline_start_content_edge = self.block_flow.fragment.border_padding.inline_start; let inline_start_content_edge = self.block_flow.fragment.border_padding.inline_start;
let inline_end_content_edge = self.block_flow.fragment.border_padding.inline_end; let inline_end_content_edge = self.block_flow.fragment.border_padding.inline_end;
@ -406,7 +445,8 @@ impl Flow for TableFlow {
let spacing_per_cell = self.spacing(); let spacing_per_cell = self.spacing();
let total_horizontal_spacing = self.total_horizontal_spacing(); let total_horizontal_spacing = self.total_horizontal_spacing();
let content_inline_size = self.block_flow.fragment.border_box.size.inline - let content_inline_size = self.block_flow.fragment.border_box.size.inline -
padding_and_borders - total_horizontal_spacing; padding_and_borders -
total_horizontal_spacing;
let mut remaining_inline_size = content_inline_size; let mut remaining_inline_size = content_inline_size;
match self.table_layout { match self.table_layout {
@ -416,32 +456,32 @@ impl Flow for TableFlow {
// https://drafts.csswg.org/css2/tables.html#fixed-table-layout // https://drafts.csswg.org/css2/tables.html#fixed-table-layout
for column_inline_size in &self.column_intrinsic_inline_sizes { for column_inline_size in &self.column_intrinsic_inline_sizes {
if column_inline_size.constrained { if column_inline_size.constrained {
self.column_computed_inline_sizes.push(ColumnComputedInlineSize { self.column_computed_inline_sizes
.push(ColumnComputedInlineSize {
size: column_inline_size.minimum_length, size: column_inline_size.minimum_length,
}); });
remaining_inline_size -= column_inline_size.minimum_length; remaining_inline_size -= column_inline_size.minimum_length;
} else if column_inline_size.percentage != 0.0 { } else if column_inline_size.percentage != 0.0 {
let size = remaining_inline_size.scale_by(column_inline_size.percentage); let size = remaining_inline_size.scale_by(column_inline_size.percentage);
self.column_computed_inline_sizes.push(ColumnComputedInlineSize { self.column_computed_inline_sizes
size: size, .push(ColumnComputedInlineSize { size: size });
});
remaining_inline_size -= size; remaining_inline_size -= size;
} else { } else {
// Set the size to 0 now, distribute the remaining widths later // Set the size to 0 now, distribute the remaining widths later
self.column_computed_inline_sizes.push(ColumnComputedInlineSize { self.column_computed_inline_sizes
size: Au(0), .push(ColumnComputedInlineSize { size: Au(0) });
});
} }
} }
// Distribute remaining content inline size // Distribute remaining content inline size
if unspecified_inline_sizes_indices.len() > 0 { if unspecified_inline_sizes_indices.len() > 0 {
for &index in &unspecified_inline_sizes_indices { for &index in &unspecified_inline_sizes_indices {
self.column_computed_inline_sizes[index].size = self.column_computed_inline_sizes[index].size = remaining_inline_size
remaining_inline_size.scale_by(1.0 / unspecified_inline_sizes_indices.len() as f32); .scale_by(1.0 / unspecified_inline_sizes_indices.len() as f32);
} }
} else { } else {
let total_minimum_size = self.column_intrinsic_inline_sizes let total_minimum_size = self
.column_intrinsic_inline_sizes
.iter() .iter()
.filter(|size| size.constrained) .filter(|size| size.constrained)
.map(|size| size.minimum_length.0 as f32) .map(|size| size.minimum_length.0 as f32)
@ -453,20 +493,23 @@ impl Flow for TableFlow {
remaining_inline_size.scale_by(inline_size as f32 / total_minimum_size); remaining_inline_size.scale_by(inline_size as f32 / total_minimum_size);
} }
} }
} },
_ => { _ => {
// The table wrapper already computed the inline-sizes and propagated them down // The table wrapper already computed the inline-sizes and propagated them down
// to us. // to us.
} },
} }
let column_computed_inline_sizes = &self.column_computed_inline_sizes; let column_computed_inline_sizes = &self.column_computed_inline_sizes;
let collapsed_inline_direction_border_widths_for_table = let collapsed_inline_direction_border_widths_for_table =
&self.collapsed_inline_direction_border_widths_for_table; &self.collapsed_inline_direction_border_widths_for_table;
let mut collapsed_block_direction_border_widths_for_table = let mut collapsed_block_direction_border_widths_for_table = self
self.collapsed_block_direction_border_widths_for_table.iter().peekable(); .collapsed_block_direction_border_widths_for_table
.iter()
.peekable();
let mut incoming_rowspan = vec![]; let mut incoming_rowspan = vec![];
self.block_flow.propagate_assigned_inline_size_to_children(shared_context, self.block_flow.propagate_assigned_inline_size_to_children(
shared_context,
inline_start_content_edge, inline_start_content_edge,
inline_end_content_edge, inline_end_content_edge,
content_inline_size, content_inline_size,
@ -481,29 +524,35 @@ impl Flow for TableFlow {
writing_mode, writing_mode,
column_computed_inline_sizes, column_computed_inline_sizes,
&spacing_per_cell, &spacing_per_cell,
&mut incoming_rowspan); &mut incoming_rowspan,
);
if child_flow.is_table_row() { if child_flow.is_table_row() {
let child_table_row = child_flow.as_mut_table_row(); let child_table_row = child_flow.as_mut_table_row();
child_table_row.populate_collapsed_border_spacing( child_table_row.populate_collapsed_border_spacing(
collapsed_inline_direction_border_widths_for_table, collapsed_inline_direction_border_widths_for_table,
&mut collapsed_block_direction_border_widths_for_table); &mut collapsed_block_direction_border_widths_for_table,
);
} else if child_flow.is_table_rowgroup() { } else if child_flow.is_table_rowgroup() {
let child_table_rowgroup = child_flow.as_mut_table_rowgroup(); let child_table_rowgroup = child_flow.as_mut_table_rowgroup();
child_table_rowgroup.populate_collapsed_border_spacing( child_table_rowgroup.populate_collapsed_border_spacing(
collapsed_inline_direction_border_widths_for_table, collapsed_inline_direction_border_widths_for_table,
&mut collapsed_block_direction_border_widths_for_table); &mut collapsed_block_direction_border_widths_for_table,
);
} }
}); },
);
} }
fn assign_block_size(&mut self, lc: &LayoutContext) { fn assign_block_size(&mut self, lc: &LayoutContext) {
debug!("assign_block_size: assigning block_size for table"); debug!("assign_block_size: assigning block_size for table");
let vertical_spacing = self.spacing().vertical(); let vertical_spacing = self.spacing().vertical();
self.block_flow.assign_block_size_for_table_like_flow(vertical_spacing, lc) self.block_flow
.assign_block_size_for_table_like_flow(vertical_spacing, lc)
} }
fn compute_stacking_relative_position(&mut self, layout_context: &LayoutContext) { fn compute_stacking_relative_position(&mut self, layout_context: &LayoutContext) {
self.block_flow.compute_stacking_relative_position(layout_context) self.block_flow
.compute_stacking_relative_position(layout_context)
} }
fn generated_containing_block_size(&self, flow: OpaqueFlow) -> LogicalSize<Au> { fn generated_containing_block_size(&self, flow: OpaqueFlow) -> LogicalSize<Au> {
@ -511,24 +560,29 @@ impl Flow for TableFlow {
} }
fn update_late_computed_inline_position_if_necessary(&mut self, inline_position: Au) { fn update_late_computed_inline_position_if_necessary(&mut self, inline_position: Au) {
self.block_flow.update_late_computed_inline_position_if_necessary(inline_position) self.block_flow
.update_late_computed_inline_position_if_necessary(inline_position)
} }
fn update_late_computed_block_position_if_necessary(&mut self, block_position: Au) { fn update_late_computed_block_position_if_necessary(&mut self, block_position: Au) {
self.block_flow.update_late_computed_block_position_if_necessary(block_position) self.block_flow
.update_late_computed_block_position_if_necessary(block_position)
} }
fn build_display_list(&mut self, state: &mut DisplayListBuildState) { fn build_display_list(&mut self, state: &mut DisplayListBuildState) {
let border_painting_mode = match self.block_flow let border_painting_mode = match self
.block_flow
.fragment .fragment
.style .style
.get_inherited_table() .get_inherited_table()
.border_collapse { .border_collapse
{
border_collapse::T::Separate => BorderPaintingMode::Separate, border_collapse::T::Separate => BorderPaintingMode::Separate,
border_collapse::T::Collapse => BorderPaintingMode::Hidden, border_collapse::T::Collapse => BorderPaintingMode::Hidden,
}; };
self.block_flow.build_display_list_for_block(state, border_painting_mode); self.block_flow
.build_display_list_for_block(state, border_painting_mode);
let iter = TableCellStyleIterator::new(&self); let iter = TableCellStyleIterator::new(&self);
for style in iter { for style in iter {
@ -538,8 +592,10 @@ impl Flow for TableFlow {
fn collect_stacking_contexts(&mut self, state: &mut StackingContextCollectionState) { fn collect_stacking_contexts(&mut self, state: &mut StackingContextCollectionState) {
// Stacking contexts are collected by the table wrapper. // Stacking contexts are collected by the table wrapper.
self.block_flow.collect_stacking_contexts_for_block(state, self.block_flow.collect_stacking_contexts_for_block(
StackingContextCollectionFlags::NEVER_CREATES_STACKING_CONTEXT); state,
StackingContextCollectionFlags::NEVER_CREATES_STACKING_CONTEXT,
);
} }
fn repair_style(&mut self, new_style: &::ServoArc<ComputedValues>) { fn repair_style(&mut self, new_style: &::ServoArc<ComputedValues>) {
@ -550,11 +606,17 @@ impl Flow for TableFlow {
self.block_flow.compute_overflow() self.block_flow.compute_overflow()
} }
fn iterate_through_fragment_border_boxes(&self, fn iterate_through_fragment_border_boxes(
&self,
iterator: &mut FragmentBorderBoxIterator, iterator: &mut FragmentBorderBoxIterator,
level: i32, level: i32,
stacking_context_position: &Point2D<Au>) { stacking_context_position: &Point2D<Au>,
self.block_flow.iterate_through_fragment_border_boxes(iterator, level, stacking_context_position) ) {
self.block_flow.iterate_through_fragment_border_boxes(
iterator,
level,
stacking_context_position,
)
} }
fn mutate_fragments(&mut self, mutator: &mut FnMut(&mut Fragment)) { fn mutate_fragments(&mut self, mutator: &mut FnMut(&mut Fragment)) {
@ -592,15 +654,16 @@ impl ISizeAndMarginsComputer for InternalTable {
&self, &self,
block: &mut BlockFlow, block: &mut BlockFlow,
shared_context: &SharedStyleContext, shared_context: &SharedStyleContext,
parent_flow_inline_size: Au parent_flow_inline_size: Au,
) { ) {
let mut input = self.compute_inline_size_constraint_inputs(block, let mut input = self.compute_inline_size_constraint_inputs(
block,
parent_flow_inline_size, parent_flow_inline_size,
shared_context); shared_context,
);
// Tables are always at least as wide as their minimum inline size. // Tables are always at least as wide as their minimum inline size.
let minimum_inline_size = let minimum_inline_size = block.base.intrinsic_inline_sizes.minimum_inline_size -
block.base.intrinsic_inline_sizes.minimum_inline_size -
block.fragment.border_padding.inline_start_end(); block.fragment.border_padding.inline_start_end();
input.available_inline_size = cmp::max(input.available_inline_size, minimum_inline_size); input.available_inline_size = cmp::max(input.available_inline_size, minimum_inline_size);
@ -609,8 +672,11 @@ impl ISizeAndMarginsComputer for InternalTable {
} }
/// Solve the inline-size and margins constraints for this block flow. /// Solve the inline-size and margins constraints for this block flow.
fn solve_inline_size_constraints(&self, _: &mut BlockFlow, input: &ISizeConstraintInput) fn solve_inline_size_constraints(
-> ISizeConstraintSolution { &self,
_: &mut BlockFlow,
input: &ISizeConstraintInput,
) -> ISizeConstraintSolution {
ISizeConstraintSolution::new(input.available_inline_size, Au(0), Au(0)) ISizeConstraintSolution::new(input.available_inline_size, Au(0), Au(0))
} }
} }
@ -697,20 +763,28 @@ impl<T> VecExt<T> for Vec<T> {
/// Updates the border styles in the block direction for a single row. This function should /// Updates the border styles in the block direction for a single row. This function should
/// only be called if border collapsing is on. It is factored out into a separate function /// only be called if border collapsing is on. It is factored out into a separate function
/// because we process children of rowgroups too. /// because we process children of rowgroups too.
fn perform_border_collapse_for_row(child_table_row: &mut TableRowFlow, fn perform_border_collapse_for_row(
child_table_row: &mut TableRowFlow,
table_inline_borders: &TableInlineCollapsedBorders, table_inline_borders: &TableInlineCollapsedBorders,
previous_block_borders: PreviousBlockCollapsedBorders, previous_block_borders: PreviousBlockCollapsedBorders,
next_block_borders: NextBlockCollapsedBorders, next_block_borders: NextBlockCollapsedBorders,
inline_spacing: &mut Vec<Au>, inline_spacing: &mut Vec<Au>,
block_spacing: &mut Vec<Au>) { block_spacing: &mut Vec<Au>,
) {
// TODO mbrubeck: Take rowspan and colspan into account. // TODO mbrubeck: Take rowspan and colspan into account.
let number_of_borders_inline_direction = child_table_row.preliminary_collapsed_borders.inline.len(); let number_of_borders_inline_direction =
child_table_row.preliminary_collapsed_borders.inline.len();
// Compute interior inline borders. // Compute interior inline borders.
for (i, this_inline_border) in child_table_row.preliminary_collapsed_borders for (i, this_inline_border) in child_table_row
.preliminary_collapsed_borders
.inline .inline
.iter_mut() .iter_mut()
.enumerate() { .enumerate()
child_table_row.final_collapsed_borders.inline.push_or_set(i, *this_inline_border); {
child_table_row
.final_collapsed_borders
.inline
.push_or_set(i, *this_inline_border);
if i == 0 { if i == 0 {
child_table_row.final_collapsed_borders.inline[i].combine(&table_inline_borders.start); child_table_row.final_collapsed_borders.inline[i].combine(&table_inline_borders.start);
} else if i + 1 == number_of_borders_inline_direction { } else if i + 1 == number_of_borders_inline_direction {
@ -718,22 +792,28 @@ fn perform_border_collapse_for_row(child_table_row: &mut TableRowFlow,
} }
let inline_spacing = inline_spacing.get_mut_or_push(i, Au(0)); let inline_spacing = inline_spacing.get_mut_or_push(i, Au(0));
*inline_spacing = cmp::max(*inline_spacing, child_table_row.final_collapsed_borders.inline[i].width) *inline_spacing = cmp::max(
*inline_spacing,
child_table_row.final_collapsed_borders.inline[i].width,
)
} }
// Compute block-start borders. // Compute block-start borders.
let block_start_borders = &mut child_table_row.final_collapsed_borders.block_start; let block_start_borders = &mut child_table_row.final_collapsed_borders.block_start;
*block_start_borders = child_table_row.preliminary_collapsed_borders.block_start.clone(); *block_start_borders = child_table_row
.preliminary_collapsed_borders
.block_start
.clone();
for (i, this_border) in block_start_borders.iter_mut().enumerate() { for (i, this_border) in block_start_borders.iter_mut().enumerate() {
match previous_block_borders { match previous_block_borders {
PreviousBlockCollapsedBorders::FromPreviousRow(ref previous_block_borders) => { PreviousBlockCollapsedBorders::FromPreviousRow(ref previous_block_borders) => {
if previous_block_borders.len() > i { if previous_block_borders.len() > i {
this_border.combine(&previous_block_borders[i]); this_border.combine(&previous_block_borders[i]);
} }
} },
PreviousBlockCollapsedBorders::FromTable(table_border) => { PreviousBlockCollapsedBorders::FromTable(table_border) => {
this_border.combine(&table_border); this_border.combine(&table_border);
} },
} }
} }
@ -741,20 +821,22 @@ fn perform_border_collapse_for_row(child_table_row: &mut TableRowFlow,
let next_block = &mut child_table_row.final_collapsed_borders.block_end; let next_block = &mut child_table_row.final_collapsed_borders.block_end;
block_spacing.push(Au(0)); block_spacing.push(Au(0));
let block_spacing = block_spacing.last_mut().unwrap(); let block_spacing = block_spacing.last_mut().unwrap();
for (i, this_block_border) in child_table_row.preliminary_collapsed_borders for (i, this_block_border) in child_table_row
.preliminary_collapsed_borders
.block_end .block_end
.iter() .iter()
.enumerate() { .enumerate()
{
let next_block = next_block.push_or_set(i, *this_block_border); let next_block = next_block.push_or_set(i, *this_block_border);
match next_block_borders { match next_block_borders {
NextBlockCollapsedBorders::FromNextRow(next_block_borders) => { NextBlockCollapsedBorders::FromNextRow(next_block_borders) => {
if next_block_borders.len() > i { if next_block_borders.len() > i {
next_block.combine(&next_block_borders[i]) next_block.combine(&next_block_borders[i])
} }
} },
NextBlockCollapsedBorders::FromTable(ref next_block_borders) => { NextBlockCollapsedBorders::FromTable(ref next_block_borders) => {
next_block.combine(next_block_borders); next_block.combine(next_block_borders);
} },
} }
*block_spacing = cmp::max(*block_spacing, next_block.width) *block_spacing = cmp::max(*block_spacing, next_block.width)
} }
@ -764,27 +846,41 @@ fn perform_border_collapse_for_row(child_table_row: &mut TableRowFlow,
/// rowgroups. /// rowgroups.
pub trait TableLikeFlow { pub trait TableLikeFlow {
/// Lays out the rows of a table. /// Lays out the rows of a table.
fn assign_block_size_for_table_like_flow(&mut self, block_direction_spacing: Au, fn assign_block_size_for_table_like_flow(
layout_context: &LayoutContext); &mut self,
block_direction_spacing: Au,
layout_context: &LayoutContext,
);
} }
impl TableLikeFlow for BlockFlow { impl TableLikeFlow for BlockFlow {
fn assign_block_size_for_table_like_flow(&mut self, block_direction_spacing: Au, fn assign_block_size_for_table_like_flow(
layout_context: &LayoutContext) { &mut self,
debug_assert!(self.fragment.style.get_inherited_table().border_collapse == block_direction_spacing: Au,
border_collapse::T::Separate || block_direction_spacing == Au(0)); layout_context: &LayoutContext,
) {
debug_assert!(
self.fragment.style.get_inherited_table().border_collapse ==
border_collapse::T::Separate ||
block_direction_spacing == Au(0)
);
fn border_spacing_for_row(fragment: &Fragment, row: &TableRowFlow, fn border_spacing_for_row(
block_direction_spacing: Au) -> Au { fragment: &Fragment,
row: &TableRowFlow,
block_direction_spacing: Au,
) -> Au {
match fragment.style.get_inherited_table().border_collapse { match fragment.style.get_inherited_table().border_collapse {
border_collapse::T::Separate => block_direction_spacing, border_collapse::T::Separate => block_direction_spacing,
border_collapse::T::Collapse => { border_collapse::T::Collapse => row.collapsed_border_spacing.block_start,
row.collapsed_border_spacing.block_start
}
} }
} }
if self.base.restyle_damage.contains(ServoRestyleDamage::REFLOW) { if self
.base
.restyle_damage
.contains(ServoRestyleDamage::REFLOW)
{
let mut sizes = vec![Default::default()]; let mut sizes = vec![Default::default()];
// The amount of border spacing up to and including this row, // The amount of border spacing up to and including this row,
// but not including the spacing beneath it // but not including the spacing beneath it
@ -803,14 +899,16 @@ impl TableLikeFlow for BlockFlow {
first = false; first = false;
continue; continue;
} }
cumulative_border_spacing += cumulative_border_spacing += border_spacing_for_row(
border_spacing_for_row(&self.fragment, kid.as_table_row(), &self.fragment,
block_direction_spacing); kid.as_table_row(),
block_direction_spacing,
);
sizes.push(TableRowSizeData { sizes.push(TableRowSizeData {
// we haven't calculated sizes yet // we haven't calculated sizes yet
size: Au(0), size: Au(0),
cumulative_border_spacing, cumulative_border_spacing,
rowgroup_id rowgroup_id,
}); });
} else if kid.is_table_rowgroup() && !first { } else if kid.is_table_rowgroup() && !first {
rowgroup_id += 1; rowgroup_id += 1;
@ -822,17 +920,17 @@ impl TableLikeFlow for BlockFlow {
let mut i = 0; let mut i = 0;
for kid in self.base.child_iter_mut() { for kid in self.base.child_iter_mut() {
if kid.is_table_row() { if kid.is_table_row() {
let size = kid.as_mut_table_row() let size = kid.as_mut_table_row().compute_block_size_table_row_base(
.compute_block_size_table_row_base(layout_context, layout_context,
&mut incoming_rowspan_data, &mut incoming_rowspan_data,
&sizes, &sizes,
i); i,
);
sizes[i].size = size; sizes[i].size = size;
i += 1; i += 1;
} }
} }
// Our current border-box position. // Our current border-box position.
let block_start_border_padding = self.fragment.border_padding.block_start; let block_start_border_padding = self.fragment.border_padding.block_start;
let mut current_block_offset = block_start_border_padding; let mut current_block_offset = block_start_border_padding;
@ -848,12 +946,12 @@ impl TableLikeFlow for BlockFlow {
has_rows = true; has_rows = true;
let row = kid.as_mut_table_row(); let row = kid.as_mut_table_row();
row.assign_block_size_to_self_and_children(&sizes, i); row.assign_block_size_to_self_and_children(&sizes, i);
row.mut_base().restyle_damage row.mut_base().restyle_damage.remove(
.remove(ServoRestyleDamage::REFLOW_OUT_OF_FLOW | ServoRestyleDamage::REFLOW_OUT_OF_FLOW | ServoRestyleDamage::REFLOW,
ServoRestyleDamage::REFLOW); );
current_block_offset = current_block_offset + current_block_offset =
border_spacing_for_row(&self.fragment, row, current_block_offset +
block_direction_spacing); border_spacing_for_row(&self.fragment, row, block_direction_spacing);
i += 1; i += 1;
} }
@ -873,12 +971,12 @@ impl TableLikeFlow for BlockFlow {
let mut block_size = current_block_offset - block_start_border_padding; let mut block_size = current_block_offset - block_start_border_padding;
let mut candidate_block_size_iterator = CandidateBSizeIterator::new( let mut candidate_block_size_iterator = CandidateBSizeIterator::new(
&self.fragment, &self.fragment,
self.base.block_container_explicit_block_size); self.base.block_container_explicit_block_size,
);
while let Some(candidate_block_size) = candidate_block_size_iterator.next() { while let Some(candidate_block_size) = candidate_block_size_iterator.next() {
candidate_block_size_iterator.candidate_value = candidate_block_size_iterator.candidate_value = match candidate_block_size {
match candidate_block_size {
MaybeAuto::Auto => block_size, MaybeAuto::Auto => block_size,
MaybeAuto::Specified(value) => value MaybeAuto::Specified(value) => value,
}; };
} }
@ -889,8 +987,11 @@ impl TableLikeFlow for BlockFlow {
current_block_offset = current_block_offset + delta; current_block_offset = current_block_offset + delta;
// Take border, padding, and spacing into account. // Take border, padding, and spacing into account.
let block_end_offset = self.fragment.border_padding.block_end + let block_end_offset = self.fragment.border_padding.block_end + if has_rows {
if has_rows { block_direction_spacing } else { Au(0) }; block_direction_spacing
} else {
Au(0)
};
current_block_offset = current_block_offset + block_end_offset; current_block_offset = current_block_offset + block_end_offset;
// Now that `current_block_offset` is at the block-end of the border box, compute the // Now that `current_block_offset` is at the block-end of the border box, compute the
@ -910,7 +1011,9 @@ impl TableLikeFlow for BlockFlow {
} }
} }
self.base.restyle_damage.remove(ServoRestyleDamage::REFLOW_OUT_OF_FLOW | ServoRestyleDamage::REFLOW); self.base
.restyle_damage
.remove(ServoRestyleDamage::REFLOW_OUT_OF_FLOW | ServoRestyleDamage::REFLOW);
} }
} }
@ -937,7 +1040,7 @@ enum NextBlockCollapsedBorders<'a> {
/// provides the Fragment for rowgroups if any /// provides the Fragment for rowgroups if any
struct TableRowAndGroupIterator<'a> { struct TableRowAndGroupIterator<'a> {
kids: FlowListIterator<'a>, kids: FlowListIterator<'a>,
group: Option<(&'a Fragment, FlowListIterator<'a>)> group: Option<(&'a Fragment, FlowListIterator<'a>)>,
} }
impl<'a> TableRowAndGroupIterator<'a> { impl<'a> TableRowAndGroupIterator<'a> {
@ -956,7 +1059,7 @@ impl<'a> Iterator for TableRowAndGroupIterator<'a> {
// If we're inside a rowgroup, iterate through the rowgroup's children. // If we're inside a rowgroup, iterate through the rowgroup's children.
if let Some(ref mut group) = self.group { if let Some(ref mut group) = self.group {
if let Some(grandkid) = group.1.next() { if let Some(grandkid) = group.1.next() {
return Some((Some(group.0), grandkid.as_table_row())) return Some((Some(group.0), grandkid.as_table_row()));
} }
} }
// Otherwise, iterate through the table's children. // Otherwise, iterate through the table's children.
@ -973,8 +1076,8 @@ impl<'a> Iterator for TableRowAndGroupIterator<'a> {
} else { } else {
self.next() // Skip children that are not rows or rowgroups self.next() // Skip children that are not rows or rowgroups
} }
} },
None => None None => None,
} }
} }
} }
@ -983,7 +1086,7 @@ impl<'a> Iterator for TableRowAndGroupIterator<'a> {
/// provides the Fragment for rowgroups if any /// provides the Fragment for rowgroups if any
struct MutTableRowAndGroupIterator<'a> { struct MutTableRowAndGroupIterator<'a> {
kids: MutFlowListIterator<'a>, kids: MutFlowListIterator<'a>,
group: Option<(&'a Fragment, MutFlowListIterator<'a>)> group: Option<(&'a Fragment, MutFlowListIterator<'a>)>,
} }
impl<'a> MutTableRowAndGroupIterator<'a> { impl<'a> MutTableRowAndGroupIterator<'a> {
@ -1002,7 +1105,7 @@ impl<'a> Iterator for MutTableRowAndGroupIterator<'a> {
// If we're inside a rowgroup, iterate through the rowgroup's children. // If we're inside a rowgroup, iterate through the rowgroup's children.
if let Some(ref mut group) = self.group { if let Some(ref mut group) = self.group {
if let Some(grandkid) = group.1.next() { if let Some(grandkid) = group.1.next() {
return Some((Some(group.0), grandkid.as_mut_table_row())) return Some((Some(group.0), grandkid.as_mut_table_row()));
} }
} }
// Otherwise, iterate through the table's children. // Otherwise, iterate through the table's children.
@ -1019,8 +1122,8 @@ impl<'a> Iterator for MutTableRowAndGroupIterator<'a> {
} else { } else {
self.next() // Skip children that are not rows or rowgroups self.next() // Skip children that are not rows or rowgroups
} }
} },
None => None None => None,
} }
} }
} }
@ -1052,7 +1155,6 @@ struct TableCellStyleIterator<'table> {
row_iterator: TableRowAndGroupIterator<'table>, row_iterator: TableRowAndGroupIterator<'table>,
row_info: Option<TableCellStyleIteratorRowInfo<'table>>, row_info: Option<TableCellStyleIteratorRowInfo<'table>>,
column_index: TableCellColumnIndexData, column_index: TableCellColumnIndexData,
} }
struct TableCellStyleIteratorRowInfo<'table> { struct TableCellStyleIteratorRowInfo<'table> {
@ -1069,13 +1171,15 @@ impl<'table> TableCellStyleIterator<'table> {
Some(TableCellStyleIteratorRowInfo { Some(TableCellStyleIteratorRowInfo {
row: &row, row: &row,
rowgroup: group, rowgroup: group,
cell_iterator: row.block_flow.base.child_iter() cell_iterator: row.block_flow.base.child_iter(),
}) })
} else { } else {
None None
}; };
TableCellStyleIterator { TableCellStyleIterator {
column_styles, row_iterator, row_info, column_styles,
row_iterator,
row_info,
column_index: Default::default(), column_index: Default::default(),
} }
} }
@ -1118,14 +1222,12 @@ impl TableCellColumnIndexData {
fn advance(&mut self, amount: u32, column_styles: &[ColumnStyle]) { fn advance(&mut self, amount: u32, column_styles: &[ColumnStyle]) {
self.absolute += amount; self.absolute += amount;
self.relative_offset += amount; self.relative_offset += amount;
if let Some(mut current_col) = if let Some(mut current_col) = column_styles.get(self.relative as usize) {
column_styles.get(self.relative as usize) {
while self.relative_offset >= current_col.span { while self.relative_offset >= current_col.span {
// move to the next column // move to the next column
self.relative += 1; self.relative += 1;
self.relative_offset -= current_col.span; self.relative_offset -= current_col.span;
if let Some(column_style) = if let Some(column_style) = column_styles.get(self.relative as usize) {
column_styles.get(self.relative as usize) {
current_col = column_style; current_col = column_style;
} else { } else {
// we ran out of column_styles, // we ran out of column_styles,
@ -1144,7 +1246,11 @@ impl<'table> Iterator for TableCellStyleIterator<'table> {
// FIXME We do this awkward .take() followed by shoving it back in // FIXME We do this awkward .take() followed by shoving it back in
// because without NLL the row_info borrow lasts too long // because without NLL the row_info borrow lasts too long
if let Some(mut row_info) = self.row_info.take() { if let Some(mut row_info) = self.row_info.take() {
if let Some(rowspan) = row_info.row.incoming_rowspan.get(self.column_index.absolute as usize) { if let Some(rowspan) = row_info
.row
.incoming_rowspan
.get(self.column_index.absolute as usize)
{
// we are not allowed to use this column as a starting point. Try the next one. // we are not allowed to use this column as a starting point. Try the next one.
if *rowspan > 1 { if *rowspan > 1 {
self.column_index.advance(1, &self.column_styles); self.column_index.advance(1, &self.column_styles);
@ -1159,9 +1265,14 @@ impl<'table> Iterator for TableCellStyleIterator<'table> {
let row_style = row_info.row.block_flow.fragment.style(); let row_style = row_info.row.block_flow.fragment.style();
let cell = cell.as_table_cell(); let cell = cell.as_table_cell();
let (col_style, colgroup_style) = if let Some(column_style) = let (col_style, colgroup_style) = if let Some(column_style) =
self.column_styles.get(self.column_index.relative as usize) { self.column_styles.get(self.column_index.relative as usize)
let styles = (column_style.col_style.clone(), column_style.colgroup_style.clone()); {
self.column_index.advance(cell.column_span, &self.column_styles); let styles = (
column_style.col_style.clone(),
column_style.colgroup_style.clone(),
);
self.column_index
.advance(cell.column_span, &self.column_styles);
styles styles
} else { } else {
@ -1175,14 +1286,14 @@ impl<'table> Iterator for TableCellStyleIterator<'table> {
col_style, col_style,
rowgroup_style, rowgroup_style,
row_style, row_style,
}) });
} else { } else {
// next row // next row
if let Some((group, row)) = self.row_iterator.next() { if let Some((group, row)) = self.row_iterator.next() {
self.row_info = Some(TableCellStyleIteratorRowInfo { self.row_info = Some(TableCellStyleIteratorRowInfo {
row: &row, row: &row,
rowgroup: group, rowgroup: group,
cell_iterator: row.block_flow.base.child_iter() cell_iterator: row.block_flow.base.child_iter(),
}); });
self.column_index = Default::default(); self.column_index = Default::default();
self.next() self.next()
@ -1203,17 +1314,29 @@ impl<'table> TableCellStyleInfo<'table> {
fn build_display_list(&self, mut state: &mut DisplayListBuildState) { fn build_display_list(&self, mut state: &mut DisplayListBuildState) {
use style::computed_values::visibility::T as Visibility; use style::computed_values::visibility::T as Visibility;
if !self.cell.visible || self.cell.block_flow.fragment.style() if !self.cell.visible ||
.get_inherited_box().visibility != Visibility::Visible { self.cell
return .block_flow
.fragment
.style()
.get_inherited_box()
.visibility !=
Visibility::Visible
{
return;
} }
let border_painting_mode = match self.cell.block_flow let border_painting_mode = match self
.cell
.block_flow
.fragment .fragment
.style .style
.get_inherited_table() .get_inherited_table()
.border_collapse { .border_collapse
{
border_collapse::T::Separate => BorderPaintingMode::Separate, border_collapse::T::Separate => BorderPaintingMode::Separate,
border_collapse::T::Collapse => BorderPaintingMode::Collapse(&self.cell.collapsed_borders), border_collapse::T::Collapse => {
BorderPaintingMode::Collapse(&self.cell.collapsed_borders)
},
}; };
{ {
let cell_flow = &self.cell.block_flow; let cell_flow = &self.cell.block_flow;
@ -1227,7 +1350,9 @@ impl<'table> TableCellStyleInfo<'table> {
} }
let background_color = sty.resolve_color(background.background_color); let background_color = sty.resolve_color(background.background_color);
cell_flow.build_display_list_for_background_if_applicable_with_background( cell_flow.build_display_list_for_background_if_applicable_with_background(
state, background, background_color state,
background,
background_color,
); );
}; };
@ -1243,6 +1368,8 @@ impl<'table> TableCellStyleInfo<'table> {
build_dl(self.row_style, &mut state); build_dl(self.row_style, &mut state);
} }
// the restyle damage will be set in TableCellFlow::build_display_list() // the restyle damage will be set in TableCellFlow::build_display_list()
self.cell.block_flow.build_display_list_for_block_no_damage(state, border_painting_mode) self.cell
.block_flow
.build_display_list_for_block_no_damage(state, border_painting_mode)
} }
} }

View file

@ -58,7 +58,10 @@ impl Flow for TableCaptionFlow {
} }
fn assign_inline_sizes(&mut self, layout_context: &LayoutContext) { fn assign_inline_sizes(&mut self, layout_context: &LayoutContext) {
debug!("assign_inline_sizes({}): assigning inline_size for flow", "table_caption"); debug!(
"assign_inline_sizes({}): assigning inline_size for flow",
"table_caption"
);
self.block_flow.assign_inline_sizes(layout_context); self.block_flow.assign_inline_sizes(layout_context);
} }
@ -68,15 +71,18 @@ impl Flow for TableCaptionFlow {
} }
fn compute_stacking_relative_position(&mut self, layout_context: &LayoutContext) { fn compute_stacking_relative_position(&mut self, layout_context: &LayoutContext) {
self.block_flow.compute_stacking_relative_position(layout_context) self.block_flow
.compute_stacking_relative_position(layout_context)
} }
fn update_late_computed_inline_position_if_necessary(&mut self, inline_position: Au) { fn update_late_computed_inline_position_if_necessary(&mut self, inline_position: Au) {
self.block_flow.update_late_computed_inline_position_if_necessary(inline_position) self.block_flow
.update_late_computed_inline_position_if_necessary(inline_position)
} }
fn update_late_computed_block_position_if_necessary(&mut self, block_position: Au) { fn update_late_computed_block_position_if_necessary(&mut self, block_position: Au) {
self.block_flow.update_late_computed_block_position_if_necessary(block_position) self.block_flow
.update_late_computed_block_position_if_necessary(block_position)
} }
fn build_display_list(&mut self, state: &mut DisplayListBuildState) { fn build_display_list(&mut self, state: &mut DisplayListBuildState) {
@ -85,8 +91,8 @@ impl Flow for TableCaptionFlow {
} }
fn collect_stacking_contexts(&mut self, state: &mut StackingContextCollectionState) { fn collect_stacking_contexts(&mut self, state: &mut StackingContextCollectionState) {
self.block_flow.collect_stacking_contexts_for_block(state, self.block_flow
StackingContextCollectionFlags::empty()); .collect_stacking_contexts_for_block(state, StackingContextCollectionFlags::empty());
} }
fn repair_style(&mut self, new_style: &::ServoArc<ComputedValues>) { fn repair_style(&mut self, new_style: &::ServoArc<ComputedValues>) {
@ -109,11 +115,17 @@ impl Flow for TableCaptionFlow {
self.block_flow.generated_containing_block_size(flow) self.block_flow.generated_containing_block_size(flow)
} }
fn iterate_through_fragment_border_boxes(&self, fn iterate_through_fragment_border_boxes(
&self,
iterator: &mut FragmentBorderBoxIterator, iterator: &mut FragmentBorderBoxIterator,
level: i32, level: i32,
stacking_context_position: &Point2D<Au>) { stacking_context_position: &Point2D<Au>,
self.block_flow.iterate_through_fragment_border_boxes(iterator, level, stacking_context_position) ) {
self.block_flow.iterate_through_fragment_border_boxes(
iterator,
level,
stacking_context_position,
)
} }
fn mutate_fragments(&mut self, mutator: &mut FnMut(&mut Fragment)) { fn mutate_fragments(&mut self, mutator: &mut FnMut(&mut Fragment)) {

View file

@ -63,7 +63,10 @@ impl TableCellFlow {
} }
pub fn from_node_fragment_and_visibility_flag<N: ThreadSafeLayoutNode>( pub fn from_node_fragment_and_visibility_flag<N: ThreadSafeLayoutNode>(
node: &N, fragment: Fragment, visible: bool) -> TableCellFlow { node: &N,
fragment: Fragment,
visible: bool,
) -> TableCellFlow {
TableCellFlow { TableCellFlow {
block_flow: BlockFlow::from_fragment(fragment), block_flow: BlockFlow::from_fragment(fragment),
collapsed_borders: CollapsedBordersForCell::new(), collapsed_borders: CollapsedBordersForCell::new(),
@ -90,7 +93,8 @@ impl TableCellFlow {
let remaining = self.block_flow.assign_block_size_block_base( let remaining = self.block_flow.assign_block_size_block_base(
layout_context, layout_context,
None, None,
MarginsMayCollapseFlag::MarginsMayNotCollapse); MarginsMayCollapseFlag::MarginsMayNotCollapse,
);
debug_assert!(remaining.is_none()); debug_assert!(remaining.is_none());
} }
@ -102,12 +106,14 @@ impl TableCellFlow {
for kid in self.base().children.iter() { for kid in self.base().children.iter() {
let kid_base = kid.base(); let kid_base = kid.base();
if kid_base.flags.contains(FlowFlags::IS_ABSOLUTELY_POSITIONED) { if kid_base.flags.contains(FlowFlags::IS_ABSOLUTELY_POSITIONED) {
continue continue;
} }
let start = kid_base.position.start.b - let start = kid_base.position.start.b - kid_base
kid_base.collapsible_margins.block_start_margin_for_noncollapsible_context(); .collapsible_margins
let end = kid_base.position.start.b + kid_base.position.size.block + .block_start_margin_for_noncollapsible_context();
kid_base.collapsible_margins.block_end_margin_for_noncollapsible_context(); let end = kid_base.position.start.b + kid_base.position.size.block + kid_base
.collapsible_margins
.block_end_margin_for_noncollapsible_context();
match extents { match extents {
Some((ref mut first_start, ref mut last_end)) => { Some((ref mut first_start, ref mut last_end)) => {
if start < *first_start { if start < *first_start {
@ -116,7 +122,7 @@ impl TableCellFlow {
if end > *last_end { if end > *last_end {
*last_end = end *last_end = end
} }
} },
None => extents = Some((start, end)), None => extents = Some((start, end)),
} }
} }
@ -138,7 +144,7 @@ impl TableCellFlow {
_ => Au(0), _ => Au(0),
}; };
if offset == Au(0) { if offset == Au(0) {
return return;
} }
for kid in self.mut_base().children.iter_mut() { for kid in self.mut_base().children.iter_mut() {
@ -154,9 +160,8 @@ impl TableCellFlow {
// Call after block size calculation // Call after block size calculation
pub fn total_block_size(&mut self) -> Au { pub fn total_block_size(&mut self) -> Au {
// TODO: Percentage block-size // TODO: Percentage block-size
let specified = MaybeAuto::from_style(self.fragment().style() let specified = MaybeAuto::from_style(self.fragment().style().content_block_size(), Au(0))
.content_block_size(), .specified_or_zero();
Au(0)).specified_or_zero();
specified + self.fragment().border_padding.block_start_end() specified + self.fragment().border_padding.block_start_end()
} }
} }
@ -185,23 +190,46 @@ impl Flow for TableCellFlow {
/// Minimum/preferred inline-sizes set by this function are used in automatic table layout /// Minimum/preferred inline-sizes set by this function are used in automatic table layout
/// calculation. /// calculation.
fn bubble_inline_sizes(&mut self) { fn bubble_inline_sizes(&mut self) {
let _scope = layout_debug_scope!("table_cell::bubble_inline_sizes {:x}", let _scope = layout_debug_scope!(
self.block_flow.base.debug_id()); "table_cell::bubble_inline_sizes {:x}",
self.block_flow.base.debug_id()
);
self.block_flow.bubble_inline_sizes_for_block(true); self.block_flow.bubble_inline_sizes_for_block(true);
let specified_inline_size = MaybeAuto::from_style(self.block_flow let specified_inline_size = MaybeAuto::from_style(
.fragment self.block_flow.fragment.style().content_inline_size(),
.style() Au(0),
.content_inline_size(), ).specified_or_zero();
Au(0)).specified_or_zero(); if self
if self.block_flow.base.intrinsic_inline_sizes.minimum_inline_size < .block_flow
specified_inline_size { .base
self.block_flow.base.intrinsic_inline_sizes.minimum_inline_size = specified_inline_size .intrinsic_inline_sizes
.minimum_inline_size <
specified_inline_size
{
self.block_flow
.base
.intrinsic_inline_sizes
.minimum_inline_size = specified_inline_size
} }
if self.block_flow.base.intrinsic_inline_sizes.preferred_inline_size < if self
self.block_flow.base.intrinsic_inline_sizes.minimum_inline_size { .block_flow
self.block_flow.base.intrinsic_inline_sizes.preferred_inline_size = .base
self.block_flow.base.intrinsic_inline_sizes.minimum_inline_size; .intrinsic_inline_sizes
.preferred_inline_size <
self.block_flow
.base
.intrinsic_inline_sizes
.minimum_inline_size
{
self.block_flow
.base
.intrinsic_inline_sizes
.preferred_inline_size = self
.block_flow
.base
.intrinsic_inline_sizes
.minimum_inline_size;
} }
} }
@ -209,35 +237,42 @@ impl Flow for TableCellFlow {
/// When called on this context, the context has had its inline-size set by the parent table /// When called on this context, the context has had its inline-size set by the parent table
/// row. /// row.
fn assign_inline_sizes(&mut self, layout_context: &LayoutContext) { fn assign_inline_sizes(&mut self, layout_context: &LayoutContext) {
let _scope = layout_debug_scope!("table_cell::assign_inline_sizes {:x}", let _scope = layout_debug_scope!(
self.block_flow.base.debug_id()); "table_cell::assign_inline_sizes {:x}",
debug!("assign_inline_sizes({}): assigning inline_size for flow", "table_cell"); self.block_flow.base.debug_id()
);
debug!(
"assign_inline_sizes({}): assigning inline_size for flow",
"table_cell"
);
let shared_context = layout_context.shared_context(); let shared_context = layout_context.shared_context();
// The position was set to the column inline-size by the parent flow, table row flow. // The position was set to the column inline-size by the parent flow, table row flow.
let containing_block_inline_size = self.block_flow.base.block_container_inline_size; let containing_block_inline_size = self.block_flow.base.block_container_inline_size;
let inline_size_computer = InternalTable; let inline_size_computer = InternalTable;
inline_size_computer.compute_used_inline_size(&mut self.block_flow, inline_size_computer.compute_used_inline_size(
&mut self.block_flow,
shared_context, shared_context,
containing_block_inline_size); containing_block_inline_size,
);
let inline_start_content_edge = let inline_start_content_edge = self.block_flow.fragment.border_box.start.i +
self.block_flow.fragment.border_box.start.i +
self.block_flow.fragment.border_padding.inline_start; self.block_flow.fragment.border_padding.inline_start;
let inline_end_content_edge = let inline_end_content_edge = self.block_flow.base.block_container_inline_size -
self.block_flow.base.block_container_inline_size -
self.block_flow.fragment.border_padding.inline_start_end() - self.block_flow.fragment.border_padding.inline_start_end() -
self.block_flow.fragment.border_box.size.inline; self.block_flow.fragment.border_box.size.inline;
let padding_and_borders = self.block_flow.fragment.border_padding.inline_start_end(); let padding_and_borders = self.block_flow.fragment.border_padding.inline_start_end();
let content_inline_size = let content_inline_size =
self.block_flow.fragment.border_box.size.inline - padding_and_borders; self.block_flow.fragment.border_box.size.inline - padding_and_borders;
self.block_flow.propagate_assigned_inline_size_to_children(shared_context, self.block_flow.propagate_assigned_inline_size_to_children(
shared_context,
inline_start_content_edge, inline_start_content_edge,
inline_end_content_edge, inline_end_content_edge,
content_inline_size, content_inline_size,
|_, _, _, _, _, _| {}); |_, _, _, _, _, _| {},
);
} }
fn assign_block_size(&mut self, layout_context: &LayoutContext) { fn assign_block_size(&mut self, layout_context: &LayoutContext) {
@ -246,15 +281,18 @@ impl Flow for TableCellFlow {
} }
fn compute_stacking_relative_position(&mut self, layout_context: &LayoutContext) { fn compute_stacking_relative_position(&mut self, layout_context: &LayoutContext) {
self.block_flow.compute_stacking_relative_position(layout_context) self.block_flow
.compute_stacking_relative_position(layout_context)
} }
fn update_late_computed_inline_position_if_necessary(&mut self, inline_position: Au) { fn update_late_computed_inline_position_if_necessary(&mut self, inline_position: Au) {
self.block_flow.update_late_computed_inline_position_if_necessary(inline_position) self.block_flow
.update_late_computed_inline_position_if_necessary(inline_position)
} }
fn update_late_computed_block_position_if_necessary(&mut self, block_position: Au) { fn update_late_computed_block_position_if_necessary(&mut self, block_position: Au) {
self.block_flow.update_late_computed_block_position_if_necessary(block_position) self.block_flow
.update_late_computed_block_position_if_necessary(block_position)
} }
fn build_display_list(&mut self, _: &mut DisplayListBuildState) { fn build_display_list(&mut self, _: &mut DisplayListBuildState) {
@ -264,12 +302,15 @@ impl Flow for TableCellFlow {
// we skip setting the damage in TableCellStyleInfo::build_display_list() // we skip setting the damage in TableCellStyleInfo::build_display_list()
// because we only have immutable access // because we only have immutable access
self.block_flow.fragment.restyle_damage.remove(ServoRestyleDamage::REPAINT); self.block_flow
.fragment
.restyle_damage
.remove(ServoRestyleDamage::REPAINT);
} }
fn collect_stacking_contexts(&mut self, state: &mut StackingContextCollectionState) { fn collect_stacking_contexts(&mut self, state: &mut StackingContextCollectionState) {
self.block_flow.collect_stacking_contexts_for_block(state, self.block_flow
StackingContextCollectionFlags::empty()); .collect_stacking_contexts_for_block(state, StackingContextCollectionFlags::empty());
} }
fn repair_style(&mut self, new_style: &::ServoArc<ComputedValues>) { fn repair_style(&mut self, new_style: &::ServoArc<ComputedValues>) {
@ -292,11 +333,17 @@ impl Flow for TableCellFlow {
self.block_flow.generated_containing_block_size(flow) self.block_flow.generated_containing_block_size(flow)
} }
fn iterate_through_fragment_border_boxes(&self, fn iterate_through_fragment_border_boxes(
&self,
iterator: &mut FragmentBorderBoxIterator, iterator: &mut FragmentBorderBoxIterator,
level: i32, level: i32,
stacking_context_position: &Point2D<Au>) { stacking_context_position: &Point2D<Au>,
self.block_flow.iterate_through_fragment_border_boxes(iterator, level, stacking_context_position) ) {
self.block_flow.iterate_through_fragment_border_boxes(
iterator,
level,
stacking_context_position,
)
} }
fn mutate_fragments(&mut self, mutator: &mut FnMut(&mut Fragment)) { fn mutate_fragments(&mut self, mutator: &mut FnMut(&mut Fragment)) {
@ -379,47 +426,49 @@ impl CollapsedBordersForCell {
} }
} }
pub fn adjust_border_bounds_for_painting(&self, pub fn adjust_border_bounds_for_painting(
&self,
border_bounds: &mut Rect<Au>, border_bounds: &mut Rect<Au>,
writing_mode: WritingMode) { writing_mode: WritingMode,
) {
let inline_start_divisor = if self.should_paint_inline_start_border() { let inline_start_divisor = if self.should_paint_inline_start_border() {
2 2
} else { } else {
-2 -2
}; };
let inline_start_offset = self.inline_start_width / 2 + self.inline_start_border.width / let inline_start_offset =
inline_start_divisor; self.inline_start_width / 2 + self.inline_start_border.width / inline_start_divisor;
let inline_end_divisor = if self.should_paint_inline_end_border() { let inline_end_divisor = if self.should_paint_inline_end_border() {
2 2
} else { } else {
-2 -2
}; };
let inline_end_offset = self.inline_end_width / 2 + self.inline_end_border.width / let inline_end_offset =
inline_end_divisor; self.inline_end_width / 2 + self.inline_end_border.width / inline_end_divisor;
let block_start_divisor = if self.should_paint_block_start_border() { let block_start_divisor = if self.should_paint_block_start_border() {
2 2
} else { } else {
-2 -2
}; };
let block_start_offset = self.block_start_width / 2 + self.block_start_border.width / let block_start_offset =
block_start_divisor; self.block_start_width / 2 + self.block_start_border.width / block_start_divisor;
let block_end_divisor = if self.should_paint_block_end_border() { let block_end_divisor = if self.should_paint_block_end_border() {
2 2
} else { } else {
-2 -2
}; };
let block_end_offset = self.block_end_width / 2 + self.block_end_border.width / let block_end_offset =
block_end_divisor; self.block_end_width / 2 + self.block_end_border.width / block_end_divisor;
// FIXME(pcwalton): Get the real container size. // FIXME(pcwalton): Get the real container size.
let mut logical_bounds = let mut logical_bounds =
LogicalRect::from_physical(writing_mode, *border_bounds, Size2D::new(Au(0), Au(0))); LogicalRect::from_physical(writing_mode, *border_bounds, Size2D::new(Au(0), Au(0)));
logical_bounds.start.i = logical_bounds.start.i - inline_start_offset; logical_bounds.start.i = logical_bounds.start.i - inline_start_offset;
logical_bounds.start.b = logical_bounds.start.b - block_start_offset; logical_bounds.start.b = logical_bounds.start.b - block_start_offset;
logical_bounds.size.inline = logical_bounds.size.inline + inline_start_offset + logical_bounds.size.inline =
inline_end_offset; logical_bounds.size.inline + inline_start_offset + inline_end_offset;
logical_bounds.size.block = logical_bounds.size.block + block_start_offset + logical_bounds.size.block =
block_end_offset; logical_bounds.size.block + block_start_offset + block_end_offset;
*border_bounds = logical_bounds.to_physical(writing_mode, Size2D::new(Au(0), Au(0))) *border_bounds = logical_bounds.to_physical(writing_mode, Size2D::new(Au(0), Au(0)))
} }
@ -427,19 +476,24 @@ impl CollapsedBordersForCell {
&self, &self,
border_colors: &mut SideOffsets2D<Color>, border_colors: &mut SideOffsets2D<Color>,
border_styles: &mut SideOffsets2D<BorderStyle>, border_styles: &mut SideOffsets2D<BorderStyle>,
writing_mode: WritingMode) { writing_mode: WritingMode,
let logical_border_colors = LogicalMargin::new(writing_mode, ) {
let logical_border_colors = LogicalMargin::new(
writing_mode,
self.block_start_border.color, self.block_start_border.color,
self.inline_end_border.color, self.inline_end_border.color,
self.block_end_border.color, self.block_end_border.color,
self.inline_start_border.color); self.inline_start_border.color,
);
*border_colors = logical_border_colors.to_physical(writing_mode); *border_colors = logical_border_colors.to_physical(writing_mode);
let logical_border_styles = LogicalMargin::new(writing_mode, let logical_border_styles = LogicalMargin::new(
writing_mode,
self.block_start_border.style, self.block_start_border.style,
self.inline_end_border.style, self.inline_end_border.style,
self.block_end_border.style, self.block_end_border.style,
self.inline_start_border.style); self.inline_start_border.style,
);
*border_styles = logical_border_styles.to_physical(writing_mode); *border_styles = logical_border_styles.to_physical(writing_mode);
} }
} }

View file

@ -43,12 +43,14 @@ impl TableColGroupFlow {
pub fn from_fragments(fragment: Fragment, fragments: Vec<Fragment>) -> TableColGroupFlow { pub fn from_fragments(fragment: Fragment, fragments: Vec<Fragment>) -> TableColGroupFlow {
let writing_mode = fragment.style().writing_mode; let writing_mode = fragment.style().writing_mode;
TableColGroupFlow { TableColGroupFlow {
base: BaseFlow::new(Some(fragment.style()), base: BaseFlow::new(
Some(fragment.style()),
writing_mode, writing_mode,
ForceNonfloatedFlag::ForceNonfloated), ForceNonfloatedFlag::ForceNonfloated,
),
fragment: Some(fragment), fragment: Some(fragment),
cols: fragments, cols: fragments,
inline_sizes: vec!(), inline_sizes: vec![],
} }
} }
} }
@ -67,8 +69,10 @@ impl Flow for TableColGroupFlow {
} }
fn bubble_inline_sizes(&mut self) { fn bubble_inline_sizes(&mut self) {
let _scope = layout_debug_scope!("table_colgroup::bubble_inline_sizes {:x}", let _scope = layout_debug_scope!(
self.base.debug_id()); "table_colgroup::bubble_inline_sizes {:x}",
self.base.debug_id()
);
for fragment in &self.cols { for fragment in &self.cols {
// Retrieve the specified value from the appropriate CSS property. // Retrieve the specified value from the appropriate CSS property.
@ -81,19 +85,17 @@ impl Flow for TableColGroupFlow {
/// Table column inline-sizes are assigned in the table flow and propagated to table row flows /// Table column inline-sizes are assigned in the table flow and propagated to table row flows
/// and/or rowgroup flows. Therefore, table colgroup flows do not need to assign inline-sizes. /// and/or rowgroup flows. Therefore, table colgroup flows do not need to assign inline-sizes.
fn assign_inline_sizes(&mut self, _: &LayoutContext) { fn assign_inline_sizes(&mut self, _: &LayoutContext) {}
}
/// Table columns do not have block-size. /// Table columns do not have block-size.
fn assign_block_size(&mut self, _: &LayoutContext) { fn assign_block_size(&mut self, _: &LayoutContext) {}
}
fn update_late_computed_inline_position_if_necessary(&mut self, _: Au) {} fn update_late_computed_inline_position_if_necessary(&mut self, _: Au) {}
fn update_late_computed_block_position_if_necessary(&mut self, _: Au) {} fn update_late_computed_block_position_if_necessary(&mut self, _: Au) {}
// Table columns are invisible. // Table columns are invisible.
fn build_display_list(&mut self, _: &mut DisplayListBuildState) { } fn build_display_list(&mut self, _: &mut DisplayListBuildState) {}
fn collect_stacking_contexts(&mut self, state: &mut StackingContextCollectionState) { fn collect_stacking_contexts(&mut self, state: &mut StackingContextCollectionState) {
self.base.stacking_context_id = state.current_stacking_context_id; self.base.stacking_context_id = state.current_stacking_context_id;
@ -110,10 +112,13 @@ impl Flow for TableColGroupFlow {
panic!("Table column groups can't be containing blocks!") panic!("Table column groups can't be containing blocks!")
} }
fn iterate_through_fragment_border_boxes(&self, fn iterate_through_fragment_border_boxes(
&self,
_: &mut FragmentBorderBoxIterator, _: &mut FragmentBorderBoxIterator,
_: i32, _: i32,
_: &Point2D<Au>) {} _: &Point2D<Au>,
) {
}
fn mutate_fragments(&mut self, _: &mut FnMut(&mut Fragment)) {} fn mutate_fragments(&mut self, _: &mut FnMut(&mut Fragment)) {}
} }

View file

@ -89,7 +89,6 @@ pub struct CellIntrinsicInlineSize {
pub row_span: u32, pub row_span: u32,
} }
impl TableRowFlow { impl TableRowFlow {
pub fn from_fragment(fragment: Fragment) -> TableRowFlow { pub fn from_fragment(fragment: Fragment) -> TableRowFlow {
let writing_mode = fragment.style().writing_mode; let writing_mode = fragment.style().writing_mode;
@ -111,14 +110,19 @@ impl TableRowFlow {
/// TODO(pcwalton): This doesn't handle floats and positioned elements right. /// TODO(pcwalton): This doesn't handle floats and positioned elements right.
/// ///
/// Returns the block size /// Returns the block size
pub fn compute_block_size_table_row_base<'a>(&'a mut self, layout_context: &LayoutContext, pub fn compute_block_size_table_row_base<'a>(
&'a mut self,
layout_context: &LayoutContext,
incoming_rowspan_data: &mut Vec<Au>, incoming_rowspan_data: &mut Vec<Au>,
border_info: &[TableRowSizeData], border_info: &[TableRowSizeData],
row_index: usize) -> Au { row_index: usize,
fn include_sizes_from_previous_rows(col: &mut usize, ) -> Au {
fn include_sizes_from_previous_rows(
col: &mut usize,
incoming_rowspan: &[u32], incoming_rowspan: &[u32],
incoming_rowspan_data: &mut Vec<Au>, incoming_rowspan_data: &mut Vec<Au>,
max_block_size: &mut Au) { max_block_size: &mut Au,
) {
while let Some(span) = incoming_rowspan.get(*col) { while let Some(span) = incoming_rowspan.get(*col) {
if *span == 1 { if *span == 1 {
break; break;
@ -141,19 +145,28 @@ impl TableRowFlow {
// all cells). // all cells).
let mut max_block_size = Au(0); let mut max_block_size = Au(0);
let thread_id = self.block_flow.base.thread_id; let thread_id = self.block_flow.base.thread_id;
let content_box = self.block_flow.base.position let content_box = self.block_flow.base.position -
- self.block_flow.fragment.border_padding self.block_flow.fragment.border_padding -
- self.block_flow.fragment.margin; self.block_flow.fragment.margin;
let mut col = 0; let mut col = 0;
for kid in self.block_flow.base.child_iter_mut() { for kid in self.block_flow.base.child_iter_mut() {
include_sizes_from_previous_rows(&mut col, &self.incoming_rowspan, include_sizes_from_previous_rows(
incoming_rowspan_data, &mut max_block_size); &mut col,
&self.incoming_rowspan,
incoming_rowspan_data,
&mut max_block_size,
);
kid.place_float_if_applicable(); kid.place_float_if_applicable();
debug_assert!(!kid.base().flags.is_float(), "table cells should never float"); debug_assert!(
kid.assign_block_size_for_inorder_child_if_necessary(layout_context, !kid.base().flags.is_float(),
"table cells should never float"
);
kid.assign_block_size_for_inorder_child_if_necessary(
layout_context,
thread_id, thread_id,
content_box); content_box,
);
let mut row_span; let mut row_span;
let column_span; let column_span;
@ -172,7 +185,8 @@ impl TableRowFlow {
if incoming_rowspan_data.len() <= col { if incoming_rowspan_data.len() <= col {
incoming_rowspan_data.resize(col + 1, Au(0)); incoming_rowspan_data.resize(col + 1, Au(0));
} }
let border_sizes_spanned = get_spanned_border_size(border_info, row_index, &mut row_span); let border_sizes_spanned =
get_spanned_border_size(border_info, row_index, &mut row_span);
cell_block_size_pressure -= border_sizes_spanned; cell_block_size_pressure -= border_sizes_spanned;
@ -186,31 +200,39 @@ impl TableRowFlow {
max_block_size = max(max_block_size, cell_block_size_pressure); max_block_size = max(max_block_size, cell_block_size_pressure);
col += column_span; col += column_span;
} }
include_sizes_from_previous_rows(&mut col, &self.incoming_rowspan, incoming_rowspan_data, &mut max_block_size); include_sizes_from_previous_rows(
&mut col,
&self.incoming_rowspan,
incoming_rowspan_data,
&mut max_block_size,
);
let mut block_size = max_block_size; let mut block_size = max_block_size;
// TODO: Percentage block-size // TODO: Percentage block-size
block_size = match MaybeAuto::from_style(self.block_flow block_size = match MaybeAuto::from_style(
.fragment self.block_flow.fragment.style().content_block_size(),
.style() Au(0),
.content_block_size(), ) {
Au(0)) {
MaybeAuto::Auto => block_size, MaybeAuto::Auto => block_size,
MaybeAuto::Specified(value) => max(value, block_size), MaybeAuto::Specified(value) => max(value, block_size),
}; };
block_size block_size
} }
pub fn assign_block_size_to_self_and_children(&mut self, sizes: &[TableRowSizeData], index: usize) { pub fn assign_block_size_to_self_and_children(
&mut self,
sizes: &[TableRowSizeData],
index: usize,
) {
// Assign the block-size of kid fragments, which is the same value as own block-size. // Assign the block-size of kid fragments, which is the same value as own block-size.
let block_size = sizes[index].size; let block_size = sizes[index].size;
for kid in self.block_flow.base.child_iter_mut() { for kid in self.block_flow.base.child_iter_mut() {
let child_table_cell = kid.as_mut_table_cell(); let child_table_cell = kid.as_mut_table_cell();
let block_size = if child_table_cell.row_span != 1 { let block_size = if child_table_cell.row_span != 1 {
let mut row_span = child_table_cell.row_span; let mut row_span = child_table_cell.row_span;
let border_sizes_spanned = let border_sizes_spanned = get_spanned_border_size(sizes, index, &mut row_span);
get_spanned_border_size(sizes, index, &mut row_span); let row_sizes = sizes[index..]
let row_sizes = sizes[index..].iter() .iter()
.take(row_span as usize) .take(row_span as usize)
.fold(Au(0), |accum, r| accum + r.size); .fold(Au(0), |accum, r| accum + r.size);
row_sizes + border_sizes_spanned row_sizes + border_sizes_spanned
@ -232,16 +254,12 @@ impl TableRowFlow {
// Write in the size of the relative containing block for children. (This // Write in the size of the relative containing block for children. (This
// information is also needed to handle RTL.) // information is also needed to handle RTL.)
child_table_cell.block_flow.base.early_absolute_position_info = child_table_cell
EarlyAbsolutePositionInfo { .block_flow
relative_containing_block_size: self.block_flow .base
.fragment .early_absolute_position_info = EarlyAbsolutePositionInfo {
.content_box() relative_containing_block_size: self.block_flow.fragment.content_box().size,
.size, relative_containing_block_mode: self.block_flow.fragment.style().writing_mode,
relative_containing_block_mode: self.block_flow
.fragment
.style()
.writing_mode,
}; };
} }
@ -255,20 +273,26 @@ impl TableRowFlow {
pub fn populate_collapsed_border_spacing<'a, I>( pub fn populate_collapsed_border_spacing<'a, I>(
&mut self, &mut self,
collapsed_inline_direction_border_widths_for_table: &[Au], collapsed_inline_direction_border_widths_for_table: &[Au],
collapsed_block_direction_border_widths_for_table: &mut Peekable<I>) collapsed_block_direction_border_widths_for_table: &mut Peekable<I>,
where I: Iterator<Item=&'a Au> { ) where
I: Iterator<Item = &'a Au>,
{
self.collapsed_border_spacing.inline.clear(); self.collapsed_border_spacing.inline.clear();
self.collapsed_border_spacing self.collapsed_border_spacing.inline.extend(
.inline collapsed_inline_direction_border_widths_for_table
.extend(collapsed_inline_direction_border_widths_for_table.into_iter().map(|x| *x)); .into_iter()
.map(|x| *x),
);
if let Some(collapsed_block_direction_border_width_for_table) = if let Some(collapsed_block_direction_border_width_for_table) =
collapsed_block_direction_border_widths_for_table.next() { collapsed_block_direction_border_widths_for_table.next()
{
self.collapsed_border_spacing.block_start = self.collapsed_border_spacing.block_start =
*collapsed_block_direction_border_width_for_table *collapsed_block_direction_border_width_for_table
} }
if let Some(collapsed_block_direction_border_width_for_table) = if let Some(collapsed_block_direction_border_width_for_table) =
collapsed_block_direction_border_widths_for_table.peek() { collapsed_block_direction_border_widths_for_table.peek()
{
self.collapsed_border_spacing.block_end = self.collapsed_border_spacing.block_end =
**collapsed_block_direction_border_width_for_table **collapsed_block_direction_border_width_for_table
} }
@ -308,7 +332,8 @@ fn get_spanned_border_size(sizes: &[TableRowSizeData], row_index: usize, row_spa
if sizes[last_row_idx].rowgroup_id != sizes[row_index].rowgroup_id { if sizes[last_row_idx].rowgroup_id != sizes[row_index].rowgroup_id {
// XXXManishearth this loop can be avoided by also storing // XXXManishearth this loop can be avoided by also storing
// a "last_rowgroup_at" index so we can leapfrog back quickly // a "last_rowgroup_at" index so we can leapfrog back quickly
*row_span = sizes[row_index..last_row_idx + 1].iter() *row_span = sizes[row_index..last_row_idx + 1]
.iter()
.position(|s| s.rowgroup_id != sizes[row_index].rowgroup_id) .position(|s| s.rowgroup_id != sizes[row_index].rowgroup_id)
.unwrap() as u32; .unwrap() as u32;
last_row_idx = row_index + *row_span as usize - 1; last_row_idx = row_index + *row_span as usize - 1;
@ -345,20 +370,26 @@ impl Flow for TableRowFlow {
/// The specified column inline-sizes of children cells are used in fixed table layout /// The specified column inline-sizes of children cells are used in fixed table layout
/// calculation. /// calculation.
fn bubble_inline_sizes(&mut self) { fn bubble_inline_sizes(&mut self) {
let _scope = layout_debug_scope!("table_row::bubble_inline_sizes {:x}", let _scope = layout_debug_scope!(
self.block_flow.base.debug_id()); "table_row::bubble_inline_sizes {:x}",
self.block_flow.base.debug_id()
);
// Bubble up the specified inline-sizes from child table cells. // Bubble up the specified inline-sizes from child table cells.
let (mut min_inline_size, mut pref_inline_size) = (Au(0), Au(0)); let (mut min_inline_size, mut pref_inline_size) = (Au(0), Au(0));
let collapsing_borders = self.block_flow let collapsing_borders = self
.block_flow
.fragment .fragment
.style() .style()
.get_inherited_table() .get_inherited_table()
.border_collapse == BorderCollapse::Collapse; .border_collapse ==
BorderCollapse::Collapse;
let row_style = &*self.block_flow.fragment.style; let row_style = &*self.block_flow.fragment.style;
self.preliminary_collapsed_borders.reset( self.preliminary_collapsed_borders
CollapsedBorder::inline_start(&row_style, .reset(CollapsedBorder::inline_start(
CollapsedBorderProvenance::FromTableRow)); &row_style,
CollapsedBorderProvenance::FromTableRow,
));
{ {
let children_count = self.block_flow.base.children.len(); let children_count = self.block_flow.base.children.len();
@ -373,7 +404,8 @@ impl Flow for TableRowFlow {
let child_row_span; let child_row_span;
{ {
let child_table_cell = kid.as_mut_table_cell(); let child_table_cell = kid.as_mut_table_cell();
child_specified_inline_size = child_table_cell.block_flow child_specified_inline_size = child_table_cell
.block_flow
.fragment .fragment
.style .style
.content_inline_size(); .content_inline_size();
@ -388,7 +420,8 @@ impl Flow for TableRowFlow {
i, i,
child_table_cell, child_table_cell,
&mut iterator, &mut iterator,
&mut self.preliminary_collapsed_borders) &mut self.preliminary_collapsed_borders,
)
} }
} }
@ -401,7 +434,7 @@ impl Flow for TableRowFlow {
LengthOrPercentageOrAuto::Calc(_) | LengthOrPercentageOrAuto::Calc(_) |
LengthOrPercentageOrAuto::Percentage(_) => { LengthOrPercentageOrAuto::Percentage(_) => {
child_base.intrinsic_inline_sizes.minimum_inline_size child_base.intrinsic_inline_sizes.minimum_inline_size
} },
LengthOrPercentageOrAuto::Length(length) => Au::from(length), LengthOrPercentageOrAuto::Length(length) => Au::from(length),
}, },
percentage: match child_specified_inline_size { percentage: match child_specified_inline_size {
@ -420,7 +453,8 @@ impl Flow for TableRowFlow {
}; };
min_inline_size = min_inline_size + child_column_inline_size.minimum_length; min_inline_size = min_inline_size + child_column_inline_size.minimum_length;
pref_inline_size = pref_inline_size + child_column_inline_size.preferred; pref_inline_size = pref_inline_size + child_column_inline_size.preferred;
self.cell_intrinsic_inline_sizes.push(CellIntrinsicInlineSize { self.cell_intrinsic_inline_sizes
.push(CellIntrinsicInlineSize {
column_size: child_column_inline_size, column_size: child_column_inline_size,
column_span: child_column_span, column_span: child_column_span,
row_span: child_row_span, row_span: child_row_span,
@ -428,15 +462,25 @@ impl Flow for TableRowFlow {
} }
} }
self.block_flow.base.intrinsic_inline_sizes.minimum_inline_size = min_inline_size; self.block_flow
self.block_flow.base.intrinsic_inline_sizes.preferred_inline_size = max(min_inline_size, .base
pref_inline_size); .intrinsic_inline_sizes
.minimum_inline_size = min_inline_size;
self.block_flow
.base
.intrinsic_inline_sizes
.preferred_inline_size = max(min_inline_size, pref_inline_size);
} }
fn assign_inline_sizes(&mut self, layout_context: &LayoutContext) { fn assign_inline_sizes(&mut self, layout_context: &LayoutContext) {
let _scope = layout_debug_scope!("table_row::assign_inline_sizes {:x}", let _scope = layout_debug_scope!(
self.block_flow.base.debug_id()); "table_row::assign_inline_sizes {:x}",
debug!("assign_inline_sizes({}): assigning inline_size for flow", "table_row"); self.block_flow.base.debug_id()
);
debug!(
"assign_inline_sizes({}): assigning inline_size for flow",
"table_row"
);
let shared_context = layout_context.shared_context(); let shared_context = layout_context.shared_context();
// The position was set to the containing block by the flow's parent. // The position was set to the containing block by the flow's parent.
@ -447,9 +491,11 @@ impl Flow for TableRowFlow {
let inline_end_content_edge = Au(0); let inline_end_content_edge = Au(0);
let inline_size_computer = InternalTable; let inline_size_computer = InternalTable;
inline_size_computer.compute_used_inline_size(&mut self.block_flow, inline_size_computer.compute_used_inline_size(
&mut self.block_flow,
shared_context, shared_context,
containing_block_inline_size); containing_block_inline_size,
);
// Spread out the completed inline sizes among columns with spans > 1. // Spread out the completed inline sizes among columns with spans > 1.
let num_columns = self.column_computed_inline_sizes.len(); let num_columns = self.column_computed_inline_sizes.len();
@ -461,14 +507,13 @@ impl Flow for TableRowFlow {
while col < self.incoming_rowspan.len() && self.incoming_rowspan[col] != 1 { while col < self.incoming_rowspan.len() && self.incoming_rowspan[col] != 1 {
let size = match self.column_computed_inline_sizes.get(col) { let size = match self.column_computed_inline_sizes.get(col) {
Some(column_computed_inline_size) => *column_computed_inline_size, Some(column_computed_inline_size) => *column_computed_inline_size,
None => ColumnComputedInlineSize { size: Au(0) } // See FIXME below. None => ColumnComputedInlineSize { size: Au(0) }, // See FIXME below.
}; };
computed_inline_size_for_cells.push(size); computed_inline_size_for_cells.push(size);
col += 1; col += 1;
} }
// Start with the computed inline size for the first column in the span. // Start with the computed inline size for the first column in the span.
let mut column_computed_inline_size = let mut column_computed_inline_size = match self.column_computed_inline_sizes.get(col) {
match self.column_computed_inline_sizes.get(col) {
Some(column_computed_inline_size) => *column_computed_inline_size, Some(column_computed_inline_size) => *column_computed_inline_size,
None => { None => {
// We're in fixed layout mode and there are more cells in this row than // We're in fixed layout mode and there are more cells in this row than
@ -476,10 +521,8 @@ impl Flow for TableRowFlow {
// now undefined. So just use zero. // now undefined. So just use zero.
// //
// FIXME(pcwalton): $10 says this isn't Web compatible. // FIXME(pcwalton): $10 says this isn't Web compatible.
ColumnComputedInlineSize { ColumnComputedInlineSize { size: Au(0) }
size: Au(0), },
}
}
}; };
col += 1; col += 1;
@ -491,7 +534,8 @@ impl Flow for TableRowFlow {
None => break, None => break,
}; };
column_computed_inline_size.size = column_computed_inline_size.size + column_computed_inline_size.size = column_computed_inline_size.size +
extra_column_computed_inline_size.size + self.spacing.horizontal(); extra_column_computed_inline_size.size +
self.spacing.horizontal();
col += 1; col += 1;
} }
@ -499,14 +543,17 @@ impl Flow for TableRowFlow {
} }
// Set up border collapse info. // Set up border collapse info.
let border_collapse_info = let border_collapse_info = match self
match self.block_flow.fragment.style().get_inherited_table().border_collapse { .block_flow
BorderCollapse::Collapse => { .fragment
Some(BorderCollapseInfoForChildTableCell { .style()
.get_inherited_table()
.border_collapse
{
BorderCollapse::Collapse => Some(BorderCollapseInfoForChildTableCell {
collapsed_borders_for_row: &self.final_collapsed_borders, collapsed_borders_for_row: &self.final_collapsed_borders,
collapsed_border_spacing_for_row: &self.collapsed_border_spacing, collapsed_border_spacing_for_row: &self.collapsed_border_spacing,
}) }),
}
BorderCollapse::Separate => None, BorderCollapse::Separate => None,
}; };
@ -517,7 +564,8 @@ impl Flow for TableRowFlow {
let incoming_rowspan = &self.incoming_rowspan; let incoming_rowspan = &self.incoming_rowspan;
let mut column_index = 0; let mut column_index = 0;
self.block_flow.propagate_assigned_inline_size_to_children(shared_context, self.block_flow.propagate_assigned_inline_size_to_children(
shared_context,
inline_start_content_edge, inline_start_content_edge,
inline_end_content_edge, inline_end_content_edge,
containing_block_inline_size, containing_block_inline_size,
@ -539,8 +587,10 @@ impl Flow for TableRowFlow {
&border_collapse_info, &border_collapse_info,
content_inline_size, content_inline_size,
inline_start_margin_edge, inline_start_margin_edge,
inline_end_margin_edge); inline_end_margin_edge,
}) );
},
)
} }
fn assign_block_size(&mut self, _: &LayoutContext) { fn assign_block_size(&mut self, _: &LayoutContext) {
@ -548,15 +598,18 @@ impl Flow for TableRowFlow {
} }
fn compute_stacking_relative_position(&mut self, layout_context: &LayoutContext) { fn compute_stacking_relative_position(&mut self, layout_context: &LayoutContext) {
self.block_flow.compute_stacking_relative_position(layout_context) self.block_flow
.compute_stacking_relative_position(layout_context)
} }
fn update_late_computed_inline_position_if_necessary(&mut self, inline_position: Au) { fn update_late_computed_inline_position_if_necessary(&mut self, inline_position: Au) {
self.block_flow.update_late_computed_inline_position_if_necessary(inline_position) self.block_flow
.update_late_computed_inline_position_if_necessary(inline_position)
} }
fn update_late_computed_block_position_if_necessary(&mut self, block_position: Au) { fn update_late_computed_block_position_if_necessary(&mut self, block_position: Au) {
self.block_flow.update_late_computed_block_position_if_necessary(block_position) self.block_flow
.update_late_computed_block_position_if_necessary(block_position)
} }
fn build_display_list(&mut self, _: &mut DisplayListBuildState) { fn build_display_list(&mut self, _: &mut DisplayListBuildState) {
@ -564,12 +617,15 @@ impl Flow for TableRowFlow {
// handled in TableCellStyleInfo::build_display_list // handled in TableCellStyleInfo::build_display_list
// we skip setting the damage in TableCellStyleInfo::build_display_list() // we skip setting the damage in TableCellStyleInfo::build_display_list()
// because we only have immutable access // because we only have immutable access
self.block_flow.fragment.restyle_damage.remove(ServoRestyleDamage::REPAINT); self.block_flow
.fragment
.restyle_damage
.remove(ServoRestyleDamage::REPAINT);
} }
fn collect_stacking_contexts(&mut self, state: &mut StackingContextCollectionState) { fn collect_stacking_contexts(&mut self, state: &mut StackingContextCollectionState) {
self.block_flow.collect_stacking_contexts_for_block(state, self.block_flow
StackingContextCollectionFlags::empty()); .collect_stacking_contexts_for_block(state, StackingContextCollectionFlags::empty());
} }
fn repair_style(&mut self, new_style: &::ServoArc<ComputedValues>) { fn repair_style(&mut self, new_style: &::ServoArc<ComputedValues>) {
@ -592,11 +648,17 @@ impl Flow for TableRowFlow {
self.block_flow.generated_containing_block_size(flow) self.block_flow.generated_containing_block_size(flow)
} }
fn iterate_through_fragment_border_boxes(&self, fn iterate_through_fragment_border_boxes(
&self,
iterator: &mut FragmentBorderBoxIterator, iterator: &mut FragmentBorderBoxIterator,
level: i32, level: i32,
stacking_context_position: &Point2D<Au>) { stacking_context_position: &Point2D<Au>,
self.block_flow.iterate_through_fragment_border_boxes(iterator, level, stacking_context_position) ) {
self.block_flow.iterate_through_fragment_border_boxes(
iterator,
level,
stacking_context_position,
)
} }
fn mutate_fragments(&mut self, mutator: &mut FnMut(&mut Fragment)) { fn mutate_fragments(&mut self, mutator: &mut FnMut(&mut Fragment)) {
@ -711,8 +773,7 @@ impl CollapsedBorder {
/// Creates a collapsed border from the block-start border described in the given CSS style /// Creates a collapsed border from the block-start border described in the given CSS style
/// object. /// object.
fn top(css_style: &ComputedValues, provenance: CollapsedBorderProvenance) fn top(css_style: &ComputedValues, provenance: CollapsedBorderProvenance) -> CollapsedBorder {
-> CollapsedBorder {
CollapsedBorder { CollapsedBorder {
style: css_style.get_border().border_top_style, style: css_style.get_border().border_top_style,
width: Au::from(css_style.get_border().border_top_width), width: Au::from(css_style.get_border().border_top_width),
@ -723,8 +784,7 @@ impl CollapsedBorder {
/// Creates a collapsed border style from the right border described in the given CSS style /// Creates a collapsed border style from the right border described in the given CSS style
/// object. /// object.
fn right(css_style: &ComputedValues, provenance: CollapsedBorderProvenance) fn right(css_style: &ComputedValues, provenance: CollapsedBorderProvenance) -> CollapsedBorder {
-> CollapsedBorder {
CollapsedBorder { CollapsedBorder {
style: css_style.get_border().border_right_style, style: css_style.get_border().border_right_style,
width: Au::from(css_style.get_border().border_right_width), width: Au::from(css_style.get_border().border_right_width),
@ -735,8 +795,10 @@ impl CollapsedBorder {
/// Creates a collapsed border style from the bottom border described in the given CSS style /// Creates a collapsed border style from the bottom border described in the given CSS style
/// object. /// object.
fn bottom(css_style: &ComputedValues, provenance: CollapsedBorderProvenance) fn bottom(
-> CollapsedBorder { css_style: &ComputedValues,
provenance: CollapsedBorderProvenance,
) -> CollapsedBorder {
CollapsedBorder { CollapsedBorder {
style: css_style.get_border().border_bottom_style, style: css_style.get_border().border_bottom_style,
width: Au::from(css_style.get_border().border_bottom_width), width: Au::from(css_style.get_border().border_bottom_width),
@ -747,8 +809,7 @@ impl CollapsedBorder {
/// Creates a collapsed border style from the left border described in the given CSS style /// Creates a collapsed border style from the left border described in the given CSS style
/// object. /// object.
fn left(css_style: &ComputedValues, provenance: CollapsedBorderProvenance) fn left(css_style: &ComputedValues, provenance: CollapsedBorderProvenance) -> CollapsedBorder {
-> CollapsedBorder {
CollapsedBorder { CollapsedBorder {
style: css_style.get_border().border_left_style, style: css_style.get_border().border_left_style,
width: Au::from(css_style.get_border().border_left_width), width: Au::from(css_style.get_border().border_left_width),
@ -758,10 +819,11 @@ impl CollapsedBorder {
} }
/// Creates a collapsed border style from the given physical side. /// Creates a collapsed border style from the given physical side.
fn from_side(side: PhysicalSide, fn from_side(
side: PhysicalSide,
css_style: &ComputedValues, css_style: &ComputedValues,
provenance: CollapsedBorderProvenance) provenance: CollapsedBorderProvenance,
-> CollapsedBorder { ) -> CollapsedBorder {
match side { match side {
PhysicalSide::Top => CollapsedBorder::top(css_style, provenance), PhysicalSide::Top => CollapsedBorder::top(css_style, provenance),
PhysicalSide::Right => CollapsedBorder::right(css_style, provenance), PhysicalSide::Right => CollapsedBorder::right(css_style, provenance),
@ -772,56 +834,72 @@ impl CollapsedBorder {
/// Creates a collapsed border style from the inline-start border described in the given CSS /// Creates a collapsed border style from the inline-start border described in the given CSS
/// style object. /// style object.
pub fn inline_start(css_style: &ComputedValues, provenance: CollapsedBorderProvenance) pub fn inline_start(
-> CollapsedBorder { css_style: &ComputedValues,
CollapsedBorder::from_side(css_style.writing_mode.inline_start_physical_side(), provenance: CollapsedBorderProvenance,
) -> CollapsedBorder {
CollapsedBorder::from_side(
css_style.writing_mode.inline_start_physical_side(),
css_style, css_style,
provenance) provenance,
)
} }
/// Creates a collapsed border style from the inline-start border described in the given CSS /// Creates a collapsed border style from the inline-start border described in the given CSS
/// style object. /// style object.
pub fn inline_end(css_style: &ComputedValues, provenance: CollapsedBorderProvenance) pub fn inline_end(
-> CollapsedBorder { css_style: &ComputedValues,
CollapsedBorder::from_side(css_style.writing_mode.inline_end_physical_side(), provenance: CollapsedBorderProvenance,
) -> CollapsedBorder {
CollapsedBorder::from_side(
css_style.writing_mode.inline_end_physical_side(),
css_style, css_style,
provenance) provenance,
)
} }
/// Creates a collapsed border style from the block-start border described in the given CSS /// Creates a collapsed border style from the block-start border described in the given CSS
/// style object. /// style object.
pub fn block_start(css_style: &ComputedValues, provenance: CollapsedBorderProvenance) pub fn block_start(
-> CollapsedBorder { css_style: &ComputedValues,
CollapsedBorder::from_side(css_style.writing_mode.block_start_physical_side(), provenance: CollapsedBorderProvenance,
) -> CollapsedBorder {
CollapsedBorder::from_side(
css_style.writing_mode.block_start_physical_side(),
css_style, css_style,
provenance) provenance,
)
} }
/// Creates a collapsed border style from the block-end border described in the given CSS style /// Creates a collapsed border style from the block-end border described in the given CSS style
/// object. /// object.
pub fn block_end(css_style: &ComputedValues, provenance: CollapsedBorderProvenance) pub fn block_end(
-> CollapsedBorder { css_style: &ComputedValues,
CollapsedBorder::from_side(css_style.writing_mode.block_end_physical_side(), provenance: CollapsedBorderProvenance,
) -> CollapsedBorder {
CollapsedBorder::from_side(
css_style.writing_mode.block_end_physical_side(),
css_style, css_style,
provenance) provenance,
)
} }
/// If `other` has a higher priority per CSS 2.1 § 17.6.2.1, replaces `self` with it. /// If `other` has a higher priority per CSS 2.1 § 17.6.2.1, replaces `self` with it.
pub fn combine(&mut self, other: &CollapsedBorder) { pub fn combine(&mut self, other: &CollapsedBorder) {
match (self.style, other.style) { match (self.style, other.style) {
// Step 1. // Step 1.
(BorderStyle::Hidden, _) => {} (BorderStyle::Hidden, _) => {},
(_, BorderStyle::Hidden) => *self = *other, (_, BorderStyle::Hidden) => *self = *other,
// Step 2. // Step 2.
(BorderStyle::None, _) => *self = *other, (BorderStyle::None, _) => *self = *other,
(_, BorderStyle::None) => {} (_, BorderStyle::None) => {},
// Step 3. // Step 3.
_ if self.width > other.width => {} _ if self.width > other.width => {},
_ if self.width < other.width => *self = *other, _ if self.width < other.width => *self = *other,
(this_style, other_style) if this_style > other_style => {} (this_style, other_style) if this_style > other_style => {},
(this_style, other_style) if this_style < other_style => *self = *other, (this_style, other_style) if this_style < other_style => *self = *other,
// Step 4. // Step 4.
_ if (self.provenance as i8) >= other.provenance as i8 => {} _ if (self.provenance as i8) >= other.provenance as i8 => {},
_ => *self = *other, _ => *self = *other,
} }
} }
@ -833,7 +911,8 @@ pub fn propagate_column_inline_sizes_to_child(
table_writing_mode: WritingMode, table_writing_mode: WritingMode,
column_computed_inline_sizes: &[ColumnComputedInlineSize], column_computed_inline_sizes: &[ColumnComputedInlineSize],
border_spacing: &BorderSpacing, border_spacing: &BorderSpacing,
incoming_rowspan: &mut Vec<u32>) { incoming_rowspan: &mut Vec<u32>,
) {
// If the child is a row group or a row, the column inline-size and rowspan info should be copied from its // If the child is a row group or a row, the column inline-size and rowspan info should be copied from its
// parent. // parent.
// //
@ -844,13 +923,15 @@ pub fn propagate_column_inline_sizes_to_child(
let child_table_rowgroup_flow = child_flow.as_mut_table_rowgroup(); let child_table_rowgroup_flow = child_flow.as_mut_table_rowgroup();
child_table_rowgroup_flow.spacing = *border_spacing; child_table_rowgroup_flow.spacing = *border_spacing;
for kid in child_table_rowgroup_flow.block_flow.base.child_iter_mut() { for kid in child_table_rowgroup_flow.block_flow.base.child_iter_mut() {
propagate_column_inline_sizes_to_child(kid, propagate_column_inline_sizes_to_child(
kid,
table_writing_mode, table_writing_mode,
column_computed_inline_sizes, column_computed_inline_sizes,
border_spacing, border_spacing,
incoming_rowspan); incoming_rowspan,
} );
} }
},
FlowClass::TableRow => { FlowClass::TableRow => {
let child_table_row_flow = child_flow.as_mut_table_row(); let child_table_row_flow = child_flow.as_mut_table_row();
child_table_row_flow.column_computed_inline_sizes = child_table_row_flow.column_computed_inline_sizes =
@ -887,8 +968,8 @@ pub fn propagate_column_inline_sizes_to_child(
col += 1; col += 1;
} }
} }
} },
c => warn!("unexpected flow in table {:?}", c) c => warn!("unexpected flow in table {:?}", c),
} }
} }
@ -905,9 +986,10 @@ fn set_inline_position_of_child_flow(
border_collapse_info: &Option<BorderCollapseInfoForChildTableCell>, border_collapse_info: &Option<BorderCollapseInfoForChildTableCell>,
parent_content_inline_size: Au, parent_content_inline_size: Au,
inline_start_margin_edge: &mut Au, inline_start_margin_edge: &mut Au,
inline_end_margin_edge: &mut Au) { inline_end_margin_edge: &mut Au,
) {
if !child_flow.is_table_cell() { if !child_flow.is_table_cell() {
return return;
} }
let reverse_column_order = table_writing_mode.is_bidi_ltr() != row_writing_mode.is_bidi_ltr(); let reverse_column_order = table_writing_mode.is_bidi_ltr() != row_writing_mode.is_bidi_ltr();
@ -933,33 +1015,42 @@ fn set_inline_position_of_child_flow(
Some(ref border_collapse_info) => { Some(ref border_collapse_info) => {
// Write in the child's border collapse state. // Write in the child's border collapse state.
child_table_cell.collapsed_borders = CollapsedBordersForCell { child_table_cell.collapsed_borders = CollapsedBordersForCell {
inline_start_border: border_collapse_info.collapsed_borders_for_row inline_start_border: border_collapse_info
.collapsed_borders_for_row
.inline .inline
.get(child_index) .get(child_index)
.map_or(CollapsedBorder::new(), |x| *x), .map_or(CollapsedBorder::new(), |x| *x),
inline_end_border: border_collapse_info.collapsed_borders_for_row inline_end_border: border_collapse_info
.collapsed_borders_for_row
.inline .inline
.get(child_index + 1) .get(child_index + 1)
.map_or(CollapsedBorder::new(), |x| *x), .map_or(CollapsedBorder::new(), |x| *x),
block_start_border: border_collapse_info.collapsed_borders_for_row block_start_border: border_collapse_info
.collapsed_borders_for_row
.block_start .block_start
.get(child_index) .get(child_index)
.map_or(CollapsedBorder::new(), |x| *x), .map_or(CollapsedBorder::new(), |x| *x),
block_end_border: border_collapse_info.collapsed_borders_for_row block_end_border: border_collapse_info
.collapsed_borders_for_row
.block_end .block_end
.get(child_index) .get(child_index)
.map_or(CollapsedBorder::new(), |x| *x), .map_or(CollapsedBorder::new(), |x| *x),
inline_start_width: border_collapse_info.collapsed_border_spacing_for_row inline_start_width: border_collapse_info
.collapsed_border_spacing_for_row
.inline .inline
.get(child_index) .get(child_index)
.map_or(Au(0), |x| *x), .map_or(Au(0), |x| *x),
inline_end_width: border_collapse_info.collapsed_border_spacing_for_row inline_end_width: border_collapse_info
.collapsed_border_spacing_for_row
.inline .inline
.get(child_index + 1) .get(child_index + 1)
.map_or(Au(0), |x| *x), .map_or(Au(0), |x| *x),
block_start_width: border_collapse_info.collapsed_border_spacing_for_row block_start_width: border_collapse_info
.collapsed_border_spacing_for_row
.block_start, .block_start,
block_end_width: border_collapse_info.collapsed_border_spacing_for_row.block_end, block_end_width: border_collapse_info
.collapsed_border_spacing_for_row
.block_end,
}; };
// Move over past the collapsed border. // Move over past the collapsed border.
@ -968,7 +1059,7 @@ fn set_inline_position_of_child_flow(
} else { } else {
*inline_start_margin_edge += child_table_cell.collapsed_borders.inline_start_width; *inline_start_margin_edge += child_table_cell.collapsed_borders.inline_start_width;
} }
} },
None => { None => {
// Take spacing into account. // Take spacing into account.
if reverse_column_order { if reverse_column_order {
@ -976,7 +1067,7 @@ fn set_inline_position_of_child_flow(
} else { } else {
*inline_start_margin_edge += border_spacing.horizontal(); *inline_start_margin_edge += border_spacing.horizontal();
} }
} },
} }
let column_inline_size = column_computed_inline_sizes[*column_index].size; let column_inline_size = column_computed_inline_sizes[*column_index].size;
@ -1013,46 +1104,63 @@ fn perform_inline_direction_border_collapse_for_row(
child_index: usize, child_index: usize,
child_table_cell: &mut TableCellFlow, child_table_cell: &mut TableCellFlow,
iterator: &mut Peekable<Enumerate<MutFlowListIterator>>, iterator: &mut Peekable<Enumerate<MutFlowListIterator>>,
preliminary_collapsed_borders: &mut CollapsedBordersForRow) { preliminary_collapsed_borders: &mut CollapsedBordersForRow,
) {
// In the first cell, combine its border with the one coming from the row. // In the first cell, combine its border with the one coming from the row.
if child_index == 0 { if child_index == 0 {
let first_inline_border = &mut preliminary_collapsed_borders.inline[0]; let first_inline_border = &mut preliminary_collapsed_borders.inline[0];
first_inline_border.combine( first_inline_border.combine(&CollapsedBorder::inline_start(
&CollapsedBorder::inline_start(&*child_table_cell.block_flow.fragment.style, &*child_table_cell.block_flow.fragment.style,
CollapsedBorderProvenance::FromNextTableCell)); CollapsedBorderProvenance::FromNextTableCell,
));
} }
let inline_collapsed_border = preliminary_collapsed_borders.inline.push_or_set( let inline_collapsed_border = preliminary_collapsed_borders.inline.push_or_set(
child_index + 1, child_index + 1,
CollapsedBorder::inline_end(&*child_table_cell.block_flow.fragment.style, CollapsedBorder::inline_end(
CollapsedBorderProvenance::FromPreviousTableCell)); &*child_table_cell.block_flow.fragment.style,
CollapsedBorderProvenance::FromPreviousTableCell,
),
);
if let Some(&(_, ref next_child_flow)) = iterator.peek() { if let Some(&(_, ref next_child_flow)) = iterator.peek() {
let next_child_flow = next_child_flow.as_block(); let next_child_flow = next_child_flow.as_block();
inline_collapsed_border.combine( inline_collapsed_border.combine(&CollapsedBorder::inline_start(
&CollapsedBorder::inline_start(&*next_child_flow.fragment.style, &*next_child_flow.fragment.style,
CollapsedBorderProvenance::FromNextTableCell)) CollapsedBorderProvenance::FromNextTableCell,
))
}; };
// In the last cell, also take into account the border that may // In the last cell, also take into account the border that may
// come from the row. // come from the row.
if child_index + 1 == children_count { if child_index + 1 == children_count {
inline_collapsed_border.combine( inline_collapsed_border.combine(&CollapsedBorder::inline_end(
&CollapsedBorder::inline_end(&row_style, &row_style,
CollapsedBorderProvenance::FromTableRow)); CollapsedBorderProvenance::FromTableRow,
));
} }
let mut block_start_border = let mut block_start_border = CollapsedBorder::block_start(
CollapsedBorder::block_start(&*child_table_cell.block_flow.fragment.style, &*child_table_cell.block_flow.fragment.style,
CollapsedBorderProvenance::FromNextTableCell); CollapsedBorderProvenance::FromNextTableCell,
block_start_border.combine( );
&CollapsedBorder::block_start(row_style, CollapsedBorderProvenance::FromTableRow)); block_start_border.combine(&CollapsedBorder::block_start(
preliminary_collapsed_borders.block_start.push_or_set(child_index, block_start_border); row_style,
let mut block_end_border = CollapsedBorderProvenance::FromTableRow,
CollapsedBorder::block_end(&*child_table_cell.block_flow.fragment.style, ));
CollapsedBorderProvenance::FromPreviousTableCell); preliminary_collapsed_borders
block_end_border.combine( .block_start
&CollapsedBorder::block_end(row_style, CollapsedBorderProvenance::FromTableRow)); .push_or_set(child_index, block_start_border);
let mut block_end_border = CollapsedBorder::block_end(
&*child_table_cell.block_flow.fragment.style,
CollapsedBorderProvenance::FromPreviousTableCell,
);
block_end_border.combine(&CollapsedBorder::block_end(
row_style,
CollapsedBorderProvenance::FromTableRow,
));
preliminary_collapsed_borders.block_end.push_or_set(child_index, block_end_border); preliminary_collapsed_borders
.block_end
.push_or_set(child_index, block_end_border);
} }

View file

@ -68,21 +68,30 @@ impl TableRowGroupFlow {
pub fn populate_collapsed_border_spacing<'a, I>( pub fn populate_collapsed_border_spacing<'a, I>(
&mut self, &mut self,
collapsed_inline_direction_border_widths_for_table: &[Au], collapsed_inline_direction_border_widths_for_table: &[Au],
collapsed_block_direction_border_widths_for_table: &mut Peekable<I>) collapsed_block_direction_border_widths_for_table: &mut Peekable<I>,
where I: Iterator<Item=&'a Au> { ) where
self.collapsed_inline_direction_border_widths_for_table.clear(); I: Iterator<Item = &'a Au>,
{
self.collapsed_inline_direction_border_widths_for_table self.collapsed_inline_direction_border_widths_for_table
.extend(collapsed_inline_direction_border_widths_for_table.into_iter().map(|x| *x)); .clear();
self.collapsed_inline_direction_border_widths_for_table
.extend(
collapsed_inline_direction_border_widths_for_table
.into_iter()
.map(|x| *x),
);
for _ in 0..self.block_flow.base.children.len() { for _ in 0..self.block_flow.base.children.len() {
if let Some(collapsed_block_direction_border_width_for_table) = if let Some(collapsed_block_direction_border_width_for_table) =
collapsed_block_direction_border_widths_for_table.next() { collapsed_block_direction_border_widths_for_table.next()
{
self.collapsed_block_direction_border_widths_for_table self.collapsed_block_direction_border_widths_for_table
.push(*collapsed_block_direction_border_width_for_table) .push(*collapsed_block_direction_border_width_for_table)
} }
} }
if let Some(collapsed_block_direction_border_width_for_table) = if let Some(collapsed_block_direction_border_width_for_table) =
collapsed_block_direction_border_widths_for_table.peek() { collapsed_block_direction_border_widths_for_table.peek()
{
self.collapsed_block_direction_border_widths_for_table self.collapsed_block_direction_border_widths_for_table
.push(**collapsed_block_direction_border_width_for_table) .push(**collapsed_block_direction_border_width_for_table)
} }
@ -111,8 +120,10 @@ impl Flow for TableRowGroupFlow {
} }
fn bubble_inline_sizes(&mut self) { fn bubble_inline_sizes(&mut self) {
let _scope = layout_debug_scope!("table_rowgroup::bubble_inline_sizes {:x}", let _scope = layout_debug_scope!(
self.block_flow.base.debug_id()); "table_rowgroup::bubble_inline_sizes {:x}",
self.block_flow.base.debug_id()
);
// Proper calculation of intrinsic sizes in table layout requires access to the entire // Proper calculation of intrinsic sizes in table layout requires access to the entire
// table, which we don't have yet. Defer to our parent. // table, which we don't have yet. Defer to our parent.
} }
@ -120,9 +131,14 @@ impl Flow for TableRowGroupFlow {
/// Recursively (top-down) determines the actual inline-size of child contexts and fragments. /// Recursively (top-down) determines the actual inline-size of child contexts and fragments.
/// When called on this context, the context has had its inline-size set by the parent context. /// When called on this context, the context has had its inline-size set by the parent context.
fn assign_inline_sizes(&mut self, layout_context: &LayoutContext) { fn assign_inline_sizes(&mut self, layout_context: &LayoutContext) {
let _scope = layout_debug_scope!("table_rowgroup::assign_inline_sizes {:x}", let _scope = layout_debug_scope!(
self.block_flow.base.debug_id()); "table_rowgroup::assign_inline_sizes {:x}",
debug!("assign_inline_sizes({}): assigning inline_size for flow", "table_rowgroup"); self.block_flow.base.debug_id()
);
debug!(
"assign_inline_sizes({}): assigning inline_size for flow",
"table_rowgroup"
);
let shared_context = layout_context.shared_context(); let shared_context = layout_context.shared_context();
// The position was set to the containing block by the flow's parent. // The position was set to the containing block by the flow's parent.
@ -130,17 +146,27 @@ impl Flow for TableRowGroupFlow {
let (inline_start_content_edge, inline_end_content_edge) = (Au(0), Au(0)); let (inline_start_content_edge, inline_end_content_edge) = (Au(0), Au(0));
let content_inline_size = containing_block_inline_size; let content_inline_size = containing_block_inline_size;
let border_collapse = self.block_flow.fragment.style.get_inherited_table().border_collapse; let border_collapse = self
.block_flow
.fragment
.style
.get_inherited_table()
.border_collapse;
let inline_size_computer = InternalTable; let inline_size_computer = InternalTable;
inline_size_computer.compute_used_inline_size(&mut self.block_flow, inline_size_computer.compute_used_inline_size(
&mut self.block_flow,
shared_context, shared_context,
containing_block_inline_size); containing_block_inline_size,
);
let collapsed_inline_direction_border_widths_for_table = let collapsed_inline_direction_border_widths_for_table =
&self.collapsed_inline_direction_border_widths_for_table; &self.collapsed_inline_direction_border_widths_for_table;
let mut collapsed_block_direction_border_widths_for_table = let mut collapsed_block_direction_border_widths_for_table = self
self.collapsed_block_direction_border_widths_for_table.iter().peekable(); .collapsed_block_direction_border_widths_for_table
self.block_flow.propagate_assigned_inline_size_to_children(shared_context, .iter()
.peekable();
self.block_flow.propagate_assigned_inline_size_to_children(
shared_context,
inline_start_content_edge, inline_start_content_edge,
inline_end_content_edge, inline_end_content_edge,
content_inline_size, content_inline_size,
@ -154,26 +180,32 @@ impl Flow for TableRowGroupFlow {
let child_table_row = child_flow.as_mut_table_row(); let child_table_row = child_flow.as_mut_table_row();
child_table_row.populate_collapsed_border_spacing( child_table_row.populate_collapsed_border_spacing(
collapsed_inline_direction_border_widths_for_table, collapsed_inline_direction_border_widths_for_table,
&mut collapsed_block_direction_border_widths_for_table); &mut collapsed_block_direction_border_widths_for_table,
);
} }
}); },
);
} }
fn assign_block_size(&mut self, lc: &LayoutContext) { fn assign_block_size(&mut self, lc: &LayoutContext) {
debug!("assign_block_size: assigning block_size for table_rowgroup"); debug!("assign_block_size: assigning block_size for table_rowgroup");
self.block_flow.assign_block_size_for_table_like_flow(self.spacing.vertical(), lc); self.block_flow
.assign_block_size_for_table_like_flow(self.spacing.vertical(), lc);
} }
fn compute_stacking_relative_position(&mut self, layout_context: &LayoutContext) { fn compute_stacking_relative_position(&mut self, layout_context: &LayoutContext) {
self.block_flow.compute_stacking_relative_position(layout_context) self.block_flow
.compute_stacking_relative_position(layout_context)
} }
fn update_late_computed_inline_position_if_necessary(&mut self, inline_position: Au) { fn update_late_computed_inline_position_if_necessary(&mut self, inline_position: Au) {
self.block_flow.update_late_computed_inline_position_if_necessary(inline_position) self.block_flow
.update_late_computed_inline_position_if_necessary(inline_position)
} }
fn update_late_computed_block_position_if_necessary(&mut self, block_position: Au) { fn update_late_computed_block_position_if_necessary(&mut self, block_position: Au) {
self.block_flow.update_late_computed_block_position_if_necessary(block_position) self.block_flow
.update_late_computed_block_position_if_necessary(block_position)
} }
fn build_display_list(&mut self, _: &mut DisplayListBuildState) { fn build_display_list(&mut self, _: &mut DisplayListBuildState) {
@ -181,12 +213,17 @@ impl Flow for TableRowGroupFlow {
// we skip setting the damage in TableCellStyleInfo::build_display_list() // we skip setting the damage in TableCellStyleInfo::build_display_list()
// because we only have immutable access // because we only have immutable access
self.block_flow.fragment.restyle_damage.remove(ServoRestyleDamage::REPAINT); self.block_flow
.fragment
.restyle_damage
.remove(ServoRestyleDamage::REPAINT);
} }
fn collect_stacking_contexts(&mut self, state: &mut StackingContextCollectionState) { fn collect_stacking_contexts(&mut self, state: &mut StackingContextCollectionState) {
self.block_flow.collect_stacking_contexts_for_block(state, self.block_flow.collect_stacking_contexts_for_block(
StackingContextCollectionFlags::POSITION_NEVER_CREATES_CONTAINING_BLOCK); state,
StackingContextCollectionFlags::POSITION_NEVER_CREATES_CONTAINING_BLOCK,
);
} }
fn repair_style(&mut self, new_style: &::ServoArc<ComputedValues>) { fn repair_style(&mut self, new_style: &::ServoArc<ComputedValues>) {
@ -209,11 +246,17 @@ impl Flow for TableRowGroupFlow {
self.block_flow.generated_containing_block_size(flow) self.block_flow.generated_containing_block_size(flow)
} }
fn iterate_through_fragment_border_boxes(&self, fn iterate_through_fragment_border_boxes(
&self,
iterator: &mut FragmentBorderBoxIterator, iterator: &mut FragmentBorderBoxIterator,
level: i32, level: i32,
stacking_context_position: &Point2D<Au>) { stacking_context_position: &Point2D<Au>,
self.block_flow.iterate_through_fragment_border_boxes(iterator, level, stacking_context_position) ) {
self.block_flow.iterate_through_fragment_border_boxes(
iterator,
level,
stacking_context_position,
)
} }
fn mutate_fragments(&mut self, mutator: &mut FnMut(&mut Fragment)) { fn mutate_fragments(&mut self, mutator: &mut FnMut(&mut Fragment)) {

View file

@ -39,7 +39,7 @@ use table::{ColumnComputedInlineSize, ColumnIntrinsicInlineSize};
#[derive(Clone, Copy, Debug, Serialize)] #[derive(Clone, Copy, Debug, Serialize)]
pub enum TableLayout { pub enum TableLayout {
Fixed, Fixed,
Auto Auto,
} }
#[allow(unsafe_code)] #[allow(unsafe_code)]
@ -63,19 +63,21 @@ impl TableWrapperFlow {
TableWrapperFlow::from_fragment_and_float_kind(fragment, None) TableWrapperFlow::from_fragment_and_float_kind(fragment, None)
} }
pub fn from_fragment_and_float_kind(fragment: Fragment, float_kind: Option<FloatKind>) pub fn from_fragment_and_float_kind(
-> TableWrapperFlow { fragment: Fragment,
float_kind: Option<FloatKind>,
) -> TableWrapperFlow {
let mut block_flow = BlockFlow::from_fragment_and_float_kind(fragment, float_kind); let mut block_flow = BlockFlow::from_fragment_and_float_kind(fragment, float_kind);
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
}; };
TableWrapperFlow { TableWrapperFlow {
block_flow: block_flow, block_flow: block_flow,
column_intrinsic_inline_sizes: vec!(), column_intrinsic_inline_sizes: vec![],
table_layout: table_layout table_layout: table_layout,
} }
} }
@ -85,9 +87,12 @@ impl TableWrapperFlow {
if kid.is_table() { if kid.is_table() {
let kid_table = kid.as_table(); let kid_table = kid.as_table();
spacing = kid_table.total_horizontal_spacing(); spacing = kid_table.total_horizontal_spacing();
table_border_padding = table_border_padding = kid_table
kid_table.block_flow.fragment.border_padding.inline_start_end(); .block_flow
break .fragment
.border_padding
.inline_start_end();
break;
} }
} }
(table_border_padding, spacing) (table_border_padding, spacing)
@ -103,41 +108,53 @@ impl TableWrapperFlow {
let available_inline_size = self.block_flow.base.block_container_inline_size; let available_inline_size = self.block_flow.base.block_container_inline_size;
for kid in self.block_flow.base.child_iter_mut() { for kid in self.block_flow.base.child_iter_mut() {
if !kid.is_table() { if !kid.is_table() {
continue continue;
} }
let kid_table = kid.as_mut_table(); let kid_table = kid.as_mut_table();
let kid_block_flow = &mut kid_table.block_flow; let kid_block_flow = &mut kid_table.block_flow;
kid_block_flow.fragment.compute_border_and_padding(available_inline_size); kid_block_flow
kid_block_flow.fragment.compute_block_direction_margins(available_inline_size); .fragment
kid_block_flow.fragment.compute_inline_direction_margins(available_inline_size); .compute_border_and_padding(available_inline_size);
return kid_block_flow
.fragment
.compute_block_direction_margins(available_inline_size);
kid_block_flow
.fragment
.compute_inline_direction_margins(available_inline_size);
return;
} }
} }
/// Calculates table column sizes for automatic layout per INTRINSIC § 4.3. /// Calculates table column sizes for automatic layout per INTRINSIC § 4.3.
fn calculate_table_column_sizes_for_automatic_layout( fn calculate_table_column_sizes_for_automatic_layout(
&mut self, &mut self,
intermediate_column_inline_sizes: &mut [IntermediateColumnInlineSize]) { intermediate_column_inline_sizes: &mut [IntermediateColumnInlineSize],
) {
let available_inline_size = self.available_inline_size(); let available_inline_size = self.available_inline_size();
// Compute all the guesses for the column sizes, and sum them. // Compute all the guesses for the column sizes, and sum them.
let mut total_guess = AutoLayoutCandidateGuess::new(); let mut total_guess = AutoLayoutCandidateGuess::new();
let guesses: Vec<AutoLayoutCandidateGuess> = let guesses: Vec<AutoLayoutCandidateGuess> = self
self.column_intrinsic_inline_sizes.iter().map(|column_intrinsic_inline_size| { .column_intrinsic_inline_sizes
.iter()
.map(|column_intrinsic_inline_size| {
let guess = AutoLayoutCandidateGuess::from_column_intrinsic_inline_size( let guess = AutoLayoutCandidateGuess::from_column_intrinsic_inline_size(
column_intrinsic_inline_size, column_intrinsic_inline_size,
available_inline_size); available_inline_size,
);
total_guess = &total_guess + &guess; total_guess = &total_guess + &guess;
guess guess
}).collect(); }).collect();
// Assign inline sizes. // Assign inline sizes.
let selection = SelectedAutoLayoutCandidateGuess::select(&total_guess, let selection =
available_inline_size); SelectedAutoLayoutCandidateGuess::select(&total_guess, available_inline_size);
let mut total_used_inline_size = Au(0); let mut total_used_inline_size = Au(0);
for (intermediate_column_inline_size, guess) in for (intermediate_column_inline_size, guess) in intermediate_column_inline_sizes
intermediate_column_inline_sizes.iter_mut().zip(guesses.iter()) { .iter_mut()
.zip(guesses.iter())
{
intermediate_column_inline_size.size = guess.calculate(selection); intermediate_column_inline_size.size = guess.calculate(selection);
intermediate_column_inline_size.percentage = 0.0; intermediate_column_inline_size.percentage = 0.0;
total_used_inline_size = total_used_inline_size + intermediate_column_inline_size.size total_used_inline_size = total_used_inline_size + intermediate_column_inline_size.size
@ -147,8 +164,10 @@ impl TableWrapperFlow {
// //
// FIXME(pcwalton, spec): How do I deal with fractional excess? // FIXME(pcwalton, spec): How do I deal with fractional excess?
let excess_inline_size = available_inline_size - total_used_inline_size; let excess_inline_size = available_inline_size - total_used_inline_size;
if excess_inline_size > Au(0) && selection == if excess_inline_size > Au(0) &&
SelectedAutoLayoutCandidateGuess::UsePreferredGuessAndDistributeExcessInlineSize { selection ==
SelectedAutoLayoutCandidateGuess::UsePreferredGuessAndDistributeExcessInlineSize
{
let mut info = ExcessInlineSizeDistributionInfo::new(); let mut info = ExcessInlineSizeDistributionInfo::new();
for column_intrinsic_inline_size in &self.column_intrinsic_inline_sizes { for column_intrinsic_inline_size in &self.column_intrinsic_inline_sizes {
info.update(column_intrinsic_inline_size) info.update(column_intrinsic_inline_size)
@ -156,13 +175,16 @@ impl TableWrapperFlow {
let mut total_distributed_excess_size = Au(0); let mut total_distributed_excess_size = Au(0);
for (intermediate_column_inline_size, column_intrinsic_inline_size) in for (intermediate_column_inline_size, column_intrinsic_inline_size) in
intermediate_column_inline_sizes.iter_mut() intermediate_column_inline_sizes
.zip(self.column_intrinsic_inline_sizes .iter_mut()
.iter()) { .zip(self.column_intrinsic_inline_sizes.iter())
info.distribute_excess_inline_size_to_column(intermediate_column_inline_size, {
info.distribute_excess_inline_size_to_column(
intermediate_column_inline_size,
column_intrinsic_inline_size, column_intrinsic_inline_size,
excess_inline_size, excess_inline_size,
&mut total_distributed_excess_size) &mut total_distributed_excess_size,
)
} }
total_used_inline_size = available_inline_size total_used_inline_size = available_inline_size
} }
@ -179,9 +201,10 @@ impl TableWrapperFlow {
// just use the shrink-to-fit inline size. // just use the shrink-to-fit inline size.
let available_inline_size = match self.block_flow.fragment.style().content_inline_size() { let available_inline_size = match self.block_flow.fragment.style().content_inline_size() {
LengthOrPercentageOrAuto::Auto => { LengthOrPercentageOrAuto::Auto => {
self.block_flow.get_shrink_to_fit_inline_size(available_inline_size) - self.block_flow
.get_shrink_to_fit_inline_size(available_inline_size) -
table_border_padding table_border_padding
} },
// FIXME(mttr): This fixes #4421 without breaking our current reftests, but I'm not // FIXME(mttr): This fixes #4421 without breaking our current reftests, but I'm not
// completely sure this is "correct". // completely sure this is "correct".
// //
@ -196,10 +219,12 @@ impl TableWrapperFlow {
fn set_inline_size(&mut self, total_used_inline_size: Au) { fn set_inline_size(&mut self, total_used_inline_size: Au) {
let (table_border_padding, spacing) = self.border_padding_and_spacing(); let (table_border_padding, spacing) = self.border_padding_and_spacing();
self.block_flow.fragment.border_box.size.inline = total_used_inline_size + self.block_flow.fragment.border_box.size.inline =
table_border_padding + spacing; total_used_inline_size + table_border_padding + spacing;
self.block_flow.base.position.size.inline = total_used_inline_size + self.block_flow.base.position.size.inline = total_used_inline_size +
table_border_padding + spacing + self.block_flow.fragment.margin.inline_start_end(); table_border_padding +
spacing +
self.block_flow.fragment.margin.inline_start_end();
let writing_mode = self.block_flow.base.writing_mode; let writing_mode = self.block_flow.base.writing_mode;
let container_mode = self.block_flow.base.block_container_writing_mode; let container_mode = self.block_flow.base.block_container_writing_mode;
@ -218,20 +243,21 @@ impl TableWrapperFlow {
&mut self, &mut self,
shared_context: &SharedStyleContext, shared_context: &SharedStyleContext,
parent_flow_inline_size: Au, parent_flow_inline_size: Au,
intermediate_column_inline_sizes: &[IntermediateColumnInlineSize]) { intermediate_column_inline_sizes: &[IntermediateColumnInlineSize],
) {
let (border_padding, spacing) = self.border_padding_and_spacing(); let (border_padding, spacing) = self.border_padding_and_spacing();
let minimum_width_of_all_columns = let minimum_width_of_all_columns = intermediate_column_inline_sizes.iter().fold(
intermediate_column_inline_sizes.iter() border_padding + spacing,
.fold(border_padding + spacing,
|accumulator, intermediate_column_inline_sizes| { |accumulator, intermediate_column_inline_sizes| {
accumulator + intermediate_column_inline_sizes.size accumulator + intermediate_column_inline_sizes.size
}); },
let preferred_width_of_all_columns = );
self.column_intrinsic_inline_sizes.iter() let preferred_width_of_all_columns = self.column_intrinsic_inline_sizes.iter().fold(
.fold(border_padding + spacing, border_padding + spacing,
|accumulator, column_intrinsic_inline_sizes| { |accumulator, column_intrinsic_inline_sizes| {
accumulator + column_intrinsic_inline_sizes.preferred accumulator + column_intrinsic_inline_sizes.preferred
}); },
);
// Delegate to the appropriate inline size computer to find the constraint inputs and write // Delegate to the appropriate inline size computer to find the constraint inputs and write
// the constraint solutions in. // the constraint solutions in.
@ -241,38 +267,45 @@ impl TableWrapperFlow {
preferred_width_of_all_columns: preferred_width_of_all_columns, preferred_width_of_all_columns: preferred_width_of_all_columns,
table_border_padding: border_padding, table_border_padding: border_padding,
}; };
let input = let input = inline_size_computer.compute_inline_size_constraint_inputs(
inline_size_computer.compute_inline_size_constraint_inputs(&mut self.block_flow, &mut self.block_flow,
parent_flow_inline_size, parent_flow_inline_size,
shared_context); shared_context,
);
let solution = inline_size_computer.solve_inline_size_constraints(&mut self.block_flow, let solution =
&input); inline_size_computer.solve_inline_size_constraints(&mut self.block_flow, &input);
inline_size_computer.set_inline_size_constraint_solutions(&mut self.block_flow, inline_size_computer
solution); .set_inline_size_constraint_solutions(&mut self.block_flow, solution);
inline_size_computer.set_inline_position_of_flow_if_necessary(&mut self.block_flow, inline_size_computer
solution); .set_inline_position_of_flow_if_necessary(&mut self.block_flow, solution);
return return;
} }
if !self.block_flow.base.flags.contains(FlowFlags::INLINE_POSITION_IS_STATIC) { if !self
.block_flow
.base
.flags
.contains(FlowFlags::INLINE_POSITION_IS_STATIC)
{
let inline_size_computer = AbsoluteTable { let inline_size_computer = AbsoluteTable {
minimum_width_of_all_columns: minimum_width_of_all_columns, minimum_width_of_all_columns: minimum_width_of_all_columns,
preferred_width_of_all_columns: preferred_width_of_all_columns, preferred_width_of_all_columns: preferred_width_of_all_columns,
table_border_padding: border_padding, table_border_padding: border_padding,
}; };
let input = let input = inline_size_computer.compute_inline_size_constraint_inputs(
inline_size_computer.compute_inline_size_constraint_inputs(&mut self.block_flow, &mut self.block_flow,
parent_flow_inline_size, parent_flow_inline_size,
shared_context); shared_context,
);
let solution = inline_size_computer.solve_inline_size_constraints(&mut self.block_flow, let solution =
&input); inline_size_computer.solve_inline_size_constraints(&mut self.block_flow, &input);
inline_size_computer.set_inline_size_constraint_solutions(&mut self.block_flow, inline_size_computer
solution); .set_inline_size_constraint_solutions(&mut self.block_flow, solution);
inline_size_computer.set_inline_position_of_flow_if_necessary(&mut self.block_flow, inline_size_computer
solution); .set_inline_position_of_flow_if_necessary(&mut self.block_flow, solution);
return return;
} }
let inline_size_computer = Table { let inline_size_computer = Table {
@ -280,16 +313,17 @@ impl TableWrapperFlow {
preferred_width_of_all_columns: preferred_width_of_all_columns, preferred_width_of_all_columns: preferred_width_of_all_columns,
table_border_padding: border_padding, table_border_padding: border_padding,
}; };
let input = let input = inline_size_computer.compute_inline_size_constraint_inputs(
inline_size_computer.compute_inline_size_constraint_inputs(&mut self.block_flow, &mut self.block_flow,
parent_flow_inline_size, parent_flow_inline_size,
shared_context); shared_context,
);
let solution = inline_size_computer.solve_inline_size_constraints(&mut self.block_flow, let solution =
&input); inline_size_computer.solve_inline_size_constraints(&mut self.block_flow, &input);
inline_size_computer.set_inline_size_constraint_solutions(&mut self.block_flow, solution); inline_size_computer.set_inline_size_constraint_solutions(&mut self.block_flow, solution);
inline_size_computer.set_inline_position_of_flow_if_necessary(&mut self.block_flow, inline_size_computer
solution); .set_inline_position_of_flow_if_necessary(&mut self.block_flow, solution);
} }
} }
@ -332,47 +366,55 @@ impl Flow for TableWrapperFlow {
} }
fn assign_inline_sizes(&mut self, layout_context: &LayoutContext) { fn assign_inline_sizes(&mut self, layout_context: &LayoutContext) {
debug!("assign_inline_sizes({}): assigning inline_size for flow", debug!(
"assign_inline_sizes({}): assigning inline_size for flow",
if self.block_flow.base.flags.is_float() { if self.block_flow.base.flags.is_float() {
"floated table_wrapper" "floated table_wrapper"
} else { } else {
"table_wrapper" "table_wrapper"
}); }
);
let shared_context = layout_context.shared_context(); let shared_context = layout_context.shared_context();
self.block_flow.initialize_container_size_for_root(shared_context); self.block_flow
.initialize_container_size_for_root(shared_context);
let mut intermediate_column_inline_sizes = self.column_intrinsic_inline_sizes let mut intermediate_column_inline_sizes = self
.column_intrinsic_inline_sizes
.iter() .iter()
.map(|column_intrinsic_inline_size| { .map(
IntermediateColumnInlineSize { |column_intrinsic_inline_size| IntermediateColumnInlineSize {
size: column_intrinsic_inline_size.minimum_length, size: column_intrinsic_inline_size.minimum_length,
percentage: column_intrinsic_inline_size.percentage, percentage: column_intrinsic_inline_size.percentage,
} },
}).collect::<Vec<_>>(); ).collect::<Vec<_>>();
// Our inline-size was set to the inline-size of the containing block by the flow's parent. // Our inline-size was set to the inline-size of the containing block by the flow's parent.
// Now compute the real value. // Now compute the real value.
let containing_block_inline_size = self.block_flow.base.block_container_inline_size; let containing_block_inline_size = self.block_flow.base.block_container_inline_size;
if self.block_flow.base.flags.is_float() { if self.block_flow.base.flags.is_float() {
self.block_flow.float.as_mut().unwrap().containing_inline_size = self.block_flow
containing_block_inline_size; .float
.as_mut()
.unwrap()
.containing_inline_size = containing_block_inline_size;
} }
// This has to be done before computing our inline size because `compute_used_inline_size` // This has to be done before computing our inline size because `compute_used_inline_size`
// internally consults the border and padding of the table. // internally consults the border and padding of the table.
self.compute_border_and_padding_of_table(); self.compute_border_and_padding_of_table();
self.compute_used_inline_size(shared_context, self.compute_used_inline_size(
shared_context,
containing_block_inline_size, containing_block_inline_size,
&intermediate_column_inline_sizes); &intermediate_column_inline_sizes,
);
match self.table_layout { match self.table_layout {
TableLayout::Auto => { TableLayout::Auto => self.calculate_table_column_sizes_for_automatic_layout(
self.calculate_table_column_sizes_for_automatic_layout( &mut intermediate_column_inline_sizes,
&mut intermediate_column_inline_sizes) ),
} TableLayout::Fixed => {},
TableLayout::Fixed => {}
} }
let inline_start_content_edge = self.block_flow.fragment.border_box.start.i; let inline_start_content_edge = self.block_flow.fragment.border_box.start.i;
@ -383,27 +425,25 @@ impl Flow for TableWrapperFlow {
// In case of fixed layout, column inline-sizes are calculated in table flow. // In case of fixed layout, column inline-sizes are calculated in table flow.
let assigned_column_inline_sizes = match self.table_layout { let assigned_column_inline_sizes = match self.table_layout {
TableLayout::Fixed => None, TableLayout::Fixed => None,
TableLayout::Auto => { TableLayout::Auto => Some(
Some(intermediate_column_inline_sizes.iter().map(|sizes| { intermediate_column_inline_sizes
ColumnComputedInlineSize { .iter()
size: sizes.size, .map(|sizes| ColumnComputedInlineSize { size: sizes.size })
} .collect::<Vec<_>>(),
}).collect::<Vec<_>>()) ),
}
}; };
match assigned_column_inline_sizes { match assigned_column_inline_sizes {
None => { None => self.block_flow.propagate_assigned_inline_size_to_children(
self.block_flow shared_context,
.propagate_assigned_inline_size_to_children(shared_context,
inline_start_content_edge, inline_start_content_edge,
inline_end_content_edge, inline_end_content_edge,
content_inline_size, content_inline_size,
|_, _, _, _, _, _| {}) |_, _, _, _, _, _| {},
} ),
Some(ref assigned_column_inline_sizes) => { Some(ref assigned_column_inline_sizes) => {
self.block_flow self.block_flow.propagate_assigned_inline_size_to_children(
.propagate_assigned_inline_size_to_children(shared_context, shared_context,
inline_start_content_edge, inline_start_content_edge,
inline_end_content_edge, inline_end_content_edge,
content_inline_size, content_inline_size,
@ -412,45 +452,53 @@ impl Flow for TableWrapperFlow {
child_flow.as_mut_table().column_computed_inline_sizes = child_flow.as_mut_table().column_computed_inline_sizes =
assigned_column_inline_sizes.to_vec(); assigned_column_inline_sizes.to_vec();
} }
}) },
)
},
} }
} }
}
fn assign_block_size(&mut self, layout_context: &LayoutContext) { fn assign_block_size(&mut self, layout_context: &LayoutContext) {
debug!("assign_block_size: assigning block_size for table_wrapper"); debug!("assign_block_size: assigning block_size for table_wrapper");
let remaining = self.block_flow.assign_block_size_block_base( let remaining = self.block_flow.assign_block_size_block_base(
layout_context, layout_context,
None, None,
MarginsMayCollapseFlag::MarginsMayNotCollapse); MarginsMayCollapseFlag::MarginsMayNotCollapse,
);
debug_assert!(remaining.is_none()); debug_assert!(remaining.is_none());
} }
fn compute_stacking_relative_position(&mut self, layout_context: &LayoutContext) { fn compute_stacking_relative_position(&mut self, layout_context: &LayoutContext) {
self.block_flow.compute_stacking_relative_position(layout_context) self.block_flow
.compute_stacking_relative_position(layout_context)
} }
fn place_float_if_applicable<'a>(&mut self) { fn place_float_if_applicable<'a>(&mut self) {
self.block_flow.place_float_if_applicable() self.block_flow.place_float_if_applicable()
} }
fn assign_block_size_for_inorder_child_if_necessary(&mut self, fn assign_block_size_for_inorder_child_if_necessary(
&mut self,
layout_context: &LayoutContext, layout_context: &LayoutContext,
parent_thread_id: u8, parent_thread_id: u8,
content_box: LogicalRect<Au>) content_box: LogicalRect<Au>,
-> bool { ) -> bool {
self.block_flow.assign_block_size_for_inorder_child_if_necessary(layout_context, self.block_flow
.assign_block_size_for_inorder_child_if_necessary(
layout_context,
parent_thread_id, parent_thread_id,
content_box) content_box,
)
} }
fn update_late_computed_inline_position_if_necessary(&mut self, inline_position: Au) { fn update_late_computed_inline_position_if_necessary(&mut self, inline_position: Au) {
self.block_flow.update_late_computed_inline_position_if_necessary(inline_position) self.block_flow
.update_late_computed_inline_position_if_necessary(inline_position)
} }
fn update_late_computed_block_position_if_necessary(&mut self, block_position: Au) { fn update_late_computed_block_position_if_necessary(&mut self, block_position: Au) {
self.block_flow.update_late_computed_block_position_if_necessary(block_position) self.block_flow
.update_late_computed_block_position_if_necessary(block_position)
} }
fn generated_containing_block_size(&self, flow: OpaqueFlow) -> LogicalSize<Au> { fn generated_containing_block_size(&self, flow: OpaqueFlow) -> LogicalSize<Au> {
@ -465,7 +513,8 @@ impl Flow for TableWrapperFlow {
self.block_flow.collect_stacking_contexts_for_block( self.block_flow.collect_stacking_contexts_for_block(
state, state,
StackingContextCollectionFlags::POSITION_NEVER_CREATES_CONTAINING_BLOCK | StackingContextCollectionFlags::POSITION_NEVER_CREATES_CONTAINING_BLOCK |
StackingContextCollectionFlags::NEVER_CREATES_CLIP_SCROLL_NODE); StackingContextCollectionFlags::NEVER_CREATES_CLIP_SCROLL_NODE,
);
} }
fn repair_style(&mut self, new_style: &::ServoArc<ComputedValues>) { fn repair_style(&mut self, new_style: &::ServoArc<ComputedValues>) {
@ -476,11 +525,17 @@ impl Flow for TableWrapperFlow {
self.block_flow.compute_overflow() self.block_flow.compute_overflow()
} }
fn iterate_through_fragment_border_boxes(&self, fn iterate_through_fragment_border_boxes(
&self,
iterator: &mut FragmentBorderBoxIterator, iterator: &mut FragmentBorderBoxIterator,
level: i32, level: i32,
stacking_context_position: &Point2D<Au>) { stacking_context_position: &Point2D<Au>,
self.block_flow.iterate_through_fragment_border_boxes(iterator, level, stacking_context_position) ) {
self.block_flow.iterate_through_fragment_border_boxes(
iterator,
level,
stacking_context_position,
)
} }
fn mutate_fragments(&mut self, mutator: &mut FnMut(&mut Fragment)) { fn mutate_fragments(&mut self, mutator: &mut FnMut(&mut Fragment)) {
@ -550,12 +605,14 @@ impl AutoLayoutCandidateGuess {
} }
/// Fills in the inline-size guesses for this column per INTRINSIC § 4.3. /// Fills in the inline-size guesses for this column per INTRINSIC § 4.3.
fn from_column_intrinsic_inline_size(column_intrinsic_inline_size: &ColumnIntrinsicInlineSize, fn from_column_intrinsic_inline_size(
assignable_inline_size: Au) column_intrinsic_inline_size: &ColumnIntrinsicInlineSize,
-> AutoLayoutCandidateGuess { assignable_inline_size: Au,
let minimum_percentage_guess = ) -> AutoLayoutCandidateGuess {
max(assignable_inline_size.scale_by(column_intrinsic_inline_size.percentage), let minimum_percentage_guess = max(
column_intrinsic_inline_size.minimum_length); assignable_inline_size.scale_by(column_intrinsic_inline_size.percentage),
column_intrinsic_inline_size.minimum_length,
);
AutoLayoutCandidateGuess { AutoLayoutCandidateGuess {
minimum_guess: column_intrinsic_inline_size.minimum_length, minimum_guess: column_intrinsic_inline_size.minimum_length,
minimum_percentage_guess: minimum_percentage_guess, minimum_percentage_guess: minimum_percentage_guess,
@ -607,8 +664,8 @@ impl<'a> Add for &'a AutoLayoutCandidateGuess {
fn add(self, other: &AutoLayoutCandidateGuess) -> AutoLayoutCandidateGuess { fn add(self, other: &AutoLayoutCandidateGuess) -> AutoLayoutCandidateGuess {
AutoLayoutCandidateGuess { AutoLayoutCandidateGuess {
minimum_guess: self.minimum_guess + other.minimum_guess, minimum_guess: self.minimum_guess + other.minimum_guess,
minimum_percentage_guess: minimum_percentage_guess: self.minimum_percentage_guess +
self.minimum_percentage_guess + other.minimum_percentage_guess, other.minimum_percentage_guess,
minimum_specified_guess: self.minimum_specified_guess + other.minimum_specified_guess, minimum_specified_guess: self.minimum_specified_guess + other.minimum_specified_guess,
preferred_guess: self.preferred_guess + other.preferred_guess, preferred_guess: self.preferred_guess + other.preferred_guess,
} }
@ -631,24 +688,32 @@ impl SelectedAutoLayoutCandidateGuess {
/// ///
/// FIXME(pcwalton, INTRINSIC spec): INTRINSIC doesn't specify whether these are exclusive or /// FIXME(pcwalton, INTRINSIC spec): INTRINSIC doesn't specify whether these are exclusive or
/// inclusive ranges. /// inclusive ranges.
fn select(guess: &AutoLayoutCandidateGuess, assignable_inline_size: Au) fn select(
-> SelectedAutoLayoutCandidateGuess { guess: &AutoLayoutCandidateGuess,
assignable_inline_size: Au,
) -> SelectedAutoLayoutCandidateGuess {
if assignable_inline_size < guess.minimum_guess { if assignable_inline_size < guess.minimum_guess {
SelectedAutoLayoutCandidateGuess::UseMinimumGuess SelectedAutoLayoutCandidateGuess::UseMinimumGuess
} else if assignable_inline_size < guess.minimum_percentage_guess { } else if assignable_inline_size < guess.minimum_percentage_guess {
let weight = weight(guess.minimum_guess, let weight = weight(
guess.minimum_guess,
assignable_inline_size, assignable_inline_size,
guess.minimum_percentage_guess); guess.minimum_percentage_guess,
);
SelectedAutoLayoutCandidateGuess::InterpolateBetweenMinimumGuessAndMinimumPercentageGuess(weight) SelectedAutoLayoutCandidateGuess::InterpolateBetweenMinimumGuessAndMinimumPercentageGuess(weight)
} else if assignable_inline_size < guess.minimum_specified_guess { } else if assignable_inline_size < guess.minimum_specified_guess {
let weight = weight(guess.minimum_percentage_guess, let weight = weight(
guess.minimum_percentage_guess,
assignable_inline_size, assignable_inline_size,
guess.minimum_specified_guess); guess.minimum_specified_guess,
);
SelectedAutoLayoutCandidateGuess::InterpolateBetweenMinimumPercentageGuessAndMinimumSpecifiedGuess(weight) SelectedAutoLayoutCandidateGuess::InterpolateBetweenMinimumPercentageGuessAndMinimumSpecifiedGuess(weight)
} else if assignable_inline_size < guess.preferred_guess { } else if assignable_inline_size < guess.preferred_guess {
let weight = weight(guess.minimum_specified_guess, let weight = weight(
guess.minimum_specified_guess,
assignable_inline_size, assignable_inline_size,
guess.preferred_guess); guess.preferred_guess,
);
SelectedAutoLayoutCandidateGuess::InterpolateBetweenMinimumSpecifiedGuessAndPreferredGuess(weight) SelectedAutoLayoutCandidateGuess::InterpolateBetweenMinimumSpecifiedGuessAndPreferredGuess(weight)
} else { } else {
SelectedAutoLayoutCandidateGuess::UsePreferredGuessAndDistributeExcessInlineSize SelectedAutoLayoutCandidateGuess::UsePreferredGuessAndDistributeExcessInlineSize
@ -688,14 +753,16 @@ impl ExcessInlineSizeDistributionInfo {
fn update(&mut self, column_intrinsic_inline_size: &ColumnIntrinsicInlineSize) { fn update(&mut self, column_intrinsic_inline_size: &ColumnIntrinsicInlineSize) {
if !column_intrinsic_inline_size.constrained && if !column_intrinsic_inline_size.constrained &&
column_intrinsic_inline_size.percentage == 0.0 { column_intrinsic_inline_size.percentage == 0.0
{
self.preferred_inline_size_of_nonconstrained_columns_with_no_percentage = self.preferred_inline_size_of_nonconstrained_columns_with_no_percentage =
self.preferred_inline_size_of_nonconstrained_columns_with_no_percentage + self.preferred_inline_size_of_nonconstrained_columns_with_no_percentage +
column_intrinsic_inline_size.preferred; column_intrinsic_inline_size.preferred;
self.count_of_nonconstrained_columns_with_no_percentage += 1 self.count_of_nonconstrained_columns_with_no_percentage += 1
} }
if column_intrinsic_inline_size.constrained && if column_intrinsic_inline_size.constrained &&
column_intrinsic_inline_size.percentage == 0.0 { column_intrinsic_inline_size.percentage == 0.0
{
self.preferred_inline_size_of_constrained_columns_with_no_percentage = self.preferred_inline_size_of_constrained_columns_with_no_percentage =
self.preferred_inline_size_of_constrained_columns_with_no_percentage + self.preferred_inline_size_of_constrained_columns_with_no_percentage +
column_intrinsic_inline_size.preferred column_intrinsic_inline_size.preferred
@ -714,26 +781,28 @@ impl ExcessInlineSizeDistributionInfo {
intermediate_column_inline_size: &mut IntermediateColumnInlineSize, intermediate_column_inline_size: &mut IntermediateColumnInlineSize,
column_intrinsic_inline_size: &ColumnIntrinsicInlineSize, column_intrinsic_inline_size: &ColumnIntrinsicInlineSize,
excess_inline_size: Au, excess_inline_size: Au,
total_distributed_excess_size: &mut Au) { total_distributed_excess_size: &mut Au,
) {
let proportion = let proportion =
if self.preferred_inline_size_of_nonconstrained_columns_with_no_percentage > Au(0) { if self.preferred_inline_size_of_nonconstrained_columns_with_no_percentage > Au(0) {
// FIXME(spec, pcwalton): Gecko and WebKit do *something* here when there are // FIXME(spec, pcwalton): Gecko and WebKit do *something* here when there are
// nonconstrained columns with no percentage *and* no preferred width. What do they // nonconstrained columns with no percentage *and* no preferred width. What do they
// do? // do?
if !column_intrinsic_inline_size.constrained && if !column_intrinsic_inline_size.constrained &&
column_intrinsic_inline_size.percentage == 0.0 { column_intrinsic_inline_size.percentage == 0.0
column_intrinsic_inline_size.preferred.to_f32_px() / {
self.preferred_inline_size_of_nonconstrained_columns_with_no_percentage column_intrinsic_inline_size.preferred.to_f32_px() / self
.preferred_inline_size_of_nonconstrained_columns_with_no_percentage
.to_f32_px() .to_f32_px()
} else { } else {
0.0 0.0
} }
} else if self.count_of_nonconstrained_columns_with_no_percentage > 0 { } else if self.count_of_nonconstrained_columns_with_no_percentage > 0 {
1.0 / (self.count_of_nonconstrained_columns_with_no_percentage as CSSFloat) 1.0 / (self.count_of_nonconstrained_columns_with_no_percentage as CSSFloat)
} else if self.preferred_inline_size_of_constrained_columns_with_no_percentage > } else if self.preferred_inline_size_of_constrained_columns_with_no_percentage > Au(0) {
Au(0) { column_intrinsic_inline_size.preferred.to_f32_px() / self
column_intrinsic_inline_size.preferred.to_f32_px() / .preferred_inline_size_of_constrained_columns_with_no_percentage
self.preferred_inline_size_of_constrained_columns_with_no_percentage.to_f32_px() .to_f32_px()
} else if self.total_percentage > 0.0 { } else if self.total_percentage > 0.0 {
column_intrinsic_inline_size.percentage / self.total_percentage column_intrinsic_inline_size.percentage / self.total_percentage
} else { } else {
@ -742,11 +811,13 @@ impl ExcessInlineSizeDistributionInfo {
// The `min` here has the effect of throwing away fractional excess at the end of the // The `min` here has the effect of throwing away fractional excess at the end of the
// table. // table.
let amount_to_distribute = min(excess_inline_size.scale_by(proportion), let amount_to_distribute = min(
excess_inline_size - *total_distributed_excess_size); excess_inline_size.scale_by(proportion),
excess_inline_size - *total_distributed_excess_size,
);
*total_distributed_excess_size = *total_distributed_excess_size + amount_to_distribute; *total_distributed_excess_size = *total_distributed_excess_size + amount_to_distribute;
intermediate_column_inline_size.size = intermediate_column_inline_size.size + intermediate_column_inline_size.size =
amount_to_distribute intermediate_column_inline_size.size + amount_to_distribute
} }
} }
@ -760,28 +831,32 @@ struct IntermediateColumnInlineSize {
/// ///
/// `table_border_padding` is the sum of the sizes of all border and padding in the inline /// `table_border_padding` is the sum of the sizes of all border and padding in the inline
/// direction of the table contained within this table wrapper. /// direction of the table contained within this table wrapper.
fn initial_computed_inline_size(block: &mut BlockFlow, fn initial_computed_inline_size(
block: &mut BlockFlow,
containing_block_inline_size: Au, containing_block_inline_size: Au,
minimum_width_of_all_columns: Au, minimum_width_of_all_columns: Au,
preferred_width_of_all_columns: Au, preferred_width_of_all_columns: Au,
table_border_padding: Au) table_border_padding: Au,
-> MaybeAuto { ) -> MaybeAuto {
let inline_size_from_style = MaybeAuto::from_style(block.fragment.style.content_inline_size(), let inline_size_from_style = MaybeAuto::from_style(
containing_block_inline_size); block.fragment.style.content_inline_size(),
containing_block_inline_size,
);
match inline_size_from_style { match inline_size_from_style {
MaybeAuto::Auto => { MaybeAuto::Auto => {
if preferred_width_of_all_columns + table_border_padding <= containing_block_inline_size { if preferred_width_of_all_columns + table_border_padding <= containing_block_inline_size
{
MaybeAuto::Specified(preferred_width_of_all_columns + table_border_padding) MaybeAuto::Specified(preferred_width_of_all_columns + table_border_padding)
} else if minimum_width_of_all_columns > containing_block_inline_size { } else if minimum_width_of_all_columns > containing_block_inline_size {
MaybeAuto::Specified(minimum_width_of_all_columns) MaybeAuto::Specified(minimum_width_of_all_columns)
} else { } else {
MaybeAuto::Auto MaybeAuto::Auto
} }
} },
MaybeAuto::Specified(inline_size_from_style) => { MaybeAuto::Specified(inline_size_from_style) => MaybeAuto::Specified(max(
MaybeAuto::Specified(max(inline_size_from_style - table_border_padding, inline_size_from_style - table_border_padding,
minimum_width_of_all_columns)) minimum_width_of_all_columns,
} )),
} }
} }
@ -793,27 +868,33 @@ struct Table {
impl ISizeAndMarginsComputer for Table { impl ISizeAndMarginsComputer for Table {
fn compute_border_and_padding(&self, block: &mut BlockFlow, containing_block_inline_size: Au) { fn compute_border_and_padding(&self, block: &mut BlockFlow, containing_block_inline_size: Au) {
block.fragment.compute_border_and_padding(containing_block_inline_size) block
.fragment
.compute_border_and_padding(containing_block_inline_size)
} }
fn initial_computed_inline_size(&self, fn initial_computed_inline_size(
&self,
block: &mut BlockFlow, block: &mut BlockFlow,
parent_flow_inline_size: Au, parent_flow_inline_size: Au,
shared_context: &SharedStyleContext) shared_context: &SharedStyleContext,
-> MaybeAuto { ) -> MaybeAuto {
let containing_block_inline_size = let containing_block_inline_size =
self.containing_block_inline_size(block, parent_flow_inline_size, shared_context); self.containing_block_inline_size(block, parent_flow_inline_size, shared_context);
initial_computed_inline_size(block, initial_computed_inline_size(
block,
containing_block_inline_size, containing_block_inline_size,
self.minimum_width_of_all_columns, self.minimum_width_of_all_columns,
self.preferred_width_of_all_columns, self.preferred_width_of_all_columns,
self.table_border_padding) self.table_border_padding,
)
} }
fn solve_inline_size_constraints(&self, fn solve_inline_size_constraints(
&self,
block: &mut BlockFlow, block: &mut BlockFlow,
input: &ISizeConstraintInput) input: &ISizeConstraintInput,
-> ISizeConstraintSolution { ) -> ISizeConstraintSolution {
self.solve_block_inline_size_constraints(block, input) self.solve_block_inline_size_constraints(block, input)
} }
} }
@ -826,29 +907,33 @@ struct FloatedTable {
impl ISizeAndMarginsComputer for FloatedTable { impl ISizeAndMarginsComputer for FloatedTable {
fn compute_border_and_padding(&self, block: &mut BlockFlow, containing_block_inline_size: Au) { fn compute_border_and_padding(&self, block: &mut BlockFlow, containing_block_inline_size: Au) {
block.fragment.compute_border_and_padding(containing_block_inline_size) block
.fragment
.compute_border_and_padding(containing_block_inline_size)
} }
fn initial_computed_inline_size(&self, fn initial_computed_inline_size(
&self,
block: &mut BlockFlow, block: &mut BlockFlow,
parent_flow_inline_size: Au, parent_flow_inline_size: Au,
shared_context: &SharedStyleContext) shared_context: &SharedStyleContext,
-> MaybeAuto { ) -> MaybeAuto {
let containing_block_inline_size = let containing_block_inline_size =
self.containing_block_inline_size(block, self.containing_block_inline_size(block, parent_flow_inline_size, shared_context);
parent_flow_inline_size, initial_computed_inline_size(
shared_context); block,
initial_computed_inline_size(block,
containing_block_inline_size, containing_block_inline_size,
self.minimum_width_of_all_columns, self.minimum_width_of_all_columns,
self.preferred_width_of_all_columns, self.preferred_width_of_all_columns,
self.table_border_padding) self.table_border_padding,
)
} }
fn solve_inline_size_constraints(&self, fn solve_inline_size_constraints(
&self,
block: &mut BlockFlow, block: &mut BlockFlow,
input: &ISizeConstraintInput) input: &ISizeConstraintInput,
-> ISizeConstraintSolution { ) -> ISizeConstraintSolution {
FloatNonReplaced.solve_inline_size_constraints(block, input) FloatNonReplaced.solve_inline_size_constraints(block, input)
} }
} }
@ -861,46 +946,54 @@ struct AbsoluteTable {
impl ISizeAndMarginsComputer for AbsoluteTable { impl ISizeAndMarginsComputer for AbsoluteTable {
fn compute_border_and_padding(&self, block: &mut BlockFlow, containing_block_inline_size: Au) { fn compute_border_and_padding(&self, block: &mut BlockFlow, containing_block_inline_size: Au) {
block.fragment.compute_border_and_padding(containing_block_inline_size) block
.fragment
.compute_border_and_padding(containing_block_inline_size)
} }
fn initial_computed_inline_size(&self, fn initial_computed_inline_size(
&self,
block: &mut BlockFlow, block: &mut BlockFlow,
parent_flow_inline_size: Au, parent_flow_inline_size: Au,
shared_context: &SharedStyleContext) shared_context: &SharedStyleContext,
-> MaybeAuto { ) -> MaybeAuto {
let containing_block_inline_size = let containing_block_inline_size =
self.containing_block_inline_size(block, self.containing_block_inline_size(block, parent_flow_inline_size, shared_context);
parent_flow_inline_size, initial_computed_inline_size(
shared_context); block,
initial_computed_inline_size(block,
containing_block_inline_size, containing_block_inline_size,
self.minimum_width_of_all_columns, self.minimum_width_of_all_columns,
self.preferred_width_of_all_columns, self.preferred_width_of_all_columns,
self.table_border_padding) self.table_border_padding,
)
} }
fn containing_block_inline_size(&self, fn containing_block_inline_size(
&self,
block: &mut BlockFlow, block: &mut BlockFlow,
parent_flow_inline_size: Au, parent_flow_inline_size: Au,
shared_context: &SharedStyleContext) shared_context: &SharedStyleContext,
-> Au { ) -> Au {
AbsoluteNonReplaced.containing_block_inline_size(block, AbsoluteNonReplaced.containing_block_inline_size(
block,
parent_flow_inline_size, parent_flow_inline_size,
shared_context) shared_context,
)
} }
fn solve_inline_size_constraints(&self, fn solve_inline_size_constraints(
&self,
block: &mut BlockFlow, block: &mut BlockFlow,
input: &ISizeConstraintInput) input: &ISizeConstraintInput,
-> ISizeConstraintSolution { ) -> ISizeConstraintSolution {
AbsoluteNonReplaced.solve_inline_size_constraints(block, input) AbsoluteNonReplaced.solve_inline_size_constraints(block, input)
} }
fn set_inline_position_of_flow_if_necessary(&self, fn set_inline_position_of_flow_if_necessary(
&self,
block: &mut BlockFlow, block: &mut BlockFlow,
solution: ISizeConstraintSolution) { solution: ISizeConstraintSolution,
) {
AbsoluteNonReplaced.set_inline_position_of_flow_if_necessary(block, solution); AbsoluteNonReplaced.set_inline_position_of_flow_if_necessary(block, solution);
} }
} }

View file

@ -5,10 +5,15 @@
#![cfg(target_pointer_width = "64")] #![cfg(target_pointer_width = "64")]
extern crate layout; extern crate layout;
#[macro_use] extern crate size_of_test; #[macro_use]
extern crate size_of_test;
use layout::Fragment; use layout::Fragment;
use layout::SpecificFragmentInfo; use layout::SpecificFragmentInfo;
size_of_test!(test_size_of_fragment, Fragment, 176); size_of_test!(test_size_of_fragment, Fragment, 176);
size_of_test!(test_size_of_specific_fragment_info, SpecificFragmentInfo, 24); size_of_test!(
test_size_of_specific_fragment_info,
SpecificFragmentInfo,
24
);

View file

@ -55,7 +55,6 @@ fn text(fragments: &LinkedList<Fragment>) -> String {
text text
} }
/// A stack-allocated object for scanning an inline flow into `TextRun`-containing `TextFragment`s. /// A stack-allocated object for scanning an inline flow into `TextRun`-containing `TextFragment`s.
pub struct TextRunScanner { pub struct TextRunScanner {
pub clump: LinkedList<Fragment>, pub clump: LinkedList<Fragment>,
@ -68,16 +67,25 @@ impl TextRunScanner {
} }
} }
pub fn scan_for_runs(&mut self, pub fn scan_for_runs(
&mut self,
font_context: &mut LayoutFontContext, font_context: &mut LayoutFontContext,
mut fragments: LinkedList<Fragment>) mut fragments: LinkedList<Fragment>,
-> InlineFragments { ) -> InlineFragments {
debug!("TextRunScanner: scanning {} fragments for text runs...", fragments.len()); debug!(
"TextRunScanner: scanning {} fragments for text runs...",
fragments.len()
);
debug_assert!(!fragments.is_empty()); debug_assert!(!fragments.is_empty());
// Calculate bidi embedding levels, so we can split bidirectional fragments for reordering. // Calculate bidi embedding levels, so we can split bidirectional fragments for reordering.
let text = text(&fragments); let text = text(&fragments);
let para_level = fragments.front().unwrap().style.writing_mode.to_bidi_level(); let para_level = fragments
.front()
.unwrap()
.style
.writing_mode
.to_bidi_level();
let bidi_info = bidi::BidiInfo::new(&text, Some(para_level)); let bidi_info = bidi::BidiInfo::new(&text, Some(para_level));
// Optimization: If all the text is LTR, don't bother splitting on bidi levels. // Optimization: If all the text is LTR, don't bother splitting on bidi levels.
@ -106,22 +114,25 @@ impl TextRunScanner {
// Create a clump. // Create a clump.
split_first_fragment_at_newline_if_necessary(&mut fragments); split_first_fragment_at_newline_if_necessary(&mut fragments);
self.clump.append(&mut split_off_head(&mut fragments)); self.clump.append(&mut split_off_head(&mut fragments));
while !fragments.is_empty() && self.clump while !fragments.is_empty() && self
.clump
.back() .back()
.unwrap() .unwrap()
.can_merge_with_fragment(fragments.front() .can_merge_with_fragment(fragments.front().unwrap())
.unwrap()) { {
split_first_fragment_at_newline_if_necessary(&mut fragments); split_first_fragment_at_newline_if_necessary(&mut fragments);
self.clump.append(&mut split_off_head(&mut fragments)); self.clump.append(&mut split_off_head(&mut fragments));
} }
// Flush that clump to the list of fragments we're building up. // Flush that clump to the list of fragments we're building up.
last_whitespace = self.flush_clump_to_list(font_context, last_whitespace = self.flush_clump_to_list(
font_context,
&mut new_fragments, &mut new_fragments,
&mut paragraph_bytes_processed, &mut paragraph_bytes_processed,
bidi_levels, bidi_levels,
last_whitespace, last_whitespace,
&mut linebreaker); &mut linebreaker,
);
} }
debug!("TextRunScanner: complete."); debug!("TextRunScanner: complete.");
@ -136,25 +147,31 @@ impl TextRunScanner {
/// The flow keeps track of the fragments contained by all non-leaf DOM nodes. This is necessary /// The flow keeps track of the fragments contained by all non-leaf DOM nodes. This is necessary
/// for correct painting order. Since we compress several leaf fragments here, the mapping must /// for correct painting order. Since we compress several leaf fragments here, the mapping must
/// be adjusted. /// be adjusted.
fn flush_clump_to_list(&mut self, fn flush_clump_to_list(
&mut self,
mut font_context: &mut LayoutFontContext, mut font_context: &mut LayoutFontContext,
out_fragments: &mut Vec<Fragment>, out_fragments: &mut Vec<Fragment>,
paragraph_bytes_processed: &mut usize, paragraph_bytes_processed: &mut usize,
bidi_levels: Option<&[bidi::Level]>, bidi_levels: Option<&[bidi::Level]>,
mut last_whitespace: bool, mut last_whitespace: bool,
linebreaker: &mut Option<LineBreakLeafIter>) linebreaker: &mut Option<LineBreakLeafIter>,
-> bool { ) -> bool {
debug!("TextRunScanner: flushing {} fragments in range", self.clump.len()); debug!(
"TextRunScanner: flushing {} fragments in range",
self.clump.len()
);
debug_assert!(!self.clump.is_empty()); debug_assert!(!self.clump.is_empty());
match self.clump.front().unwrap().specific { match self.clump.front().unwrap().specific {
SpecificFragmentInfo::UnscannedText(_) => {} SpecificFragmentInfo::UnscannedText(_) => {},
_ => { _ => {
debug_assert!(self.clump.len() == 1, debug_assert!(
"WAT: can't coalesce non-text nodes in flush_clump_to_list()!"); self.clump.len() == 1,
"WAT: can't coalesce non-text nodes in flush_clump_to_list()!"
);
out_fragments.push(self.clump.pop_front().unwrap()); out_fragments.push(self.clump.pop_front().unwrap());
return false return false;
} },
} }
// Concatenate all of the transformed strings together, saving the new character indices. // Concatenate all of the transformed strings together, saving the new character indices.
@ -173,15 +190,17 @@ impl TextRunScanner {
let inherited_text_style = in_fragment.style().get_inherited_text(); let inherited_text_style = in_fragment.style().get_inherited_text();
font_group = font_context.font_group(font_style); font_group = font_context.font_group(font_style);
compression = match in_fragment.white_space() { compression = match in_fragment.white_space() {
WhiteSpace::Normal | WhiteSpace::Normal | WhiteSpace::Nowrap => {
WhiteSpace::Nowrap => CompressionMode::CompressWhitespaceNewline, CompressionMode::CompressWhitespaceNewline
WhiteSpace::Pre | },
WhiteSpace::PreWrap => CompressionMode::CompressNone, WhiteSpace::Pre | WhiteSpace::PreWrap => CompressionMode::CompressNone,
WhiteSpace::PreLine => CompressionMode::CompressWhitespace, WhiteSpace::PreLine => CompressionMode::CompressWhitespace,
}; };
text_transform = inherited_text_style.text_transform; text_transform = inherited_text_style.text_transform;
letter_spacing = inherited_text_style.letter_spacing; letter_spacing = inherited_text_style.letter_spacing;
word_spacing = inherited_text_style.word_spacing.value() word_spacing = inherited_text_style
.word_spacing
.value()
.map(|lop| lop.to_hash_key()) .map(|lop| lop.to_hash_key())
.unwrap_or((Au(0), NotNan::new(0.0).unwrap())); .unwrap_or((Au(0), NotNan::new(0.0).unwrap()));
text_rendering = inherited_text_style.text_rendering; text_rendering = inherited_text_style.text_rendering;
@ -201,7 +220,7 @@ impl TextRunScanner {
SpecificFragmentInfo::UnscannedText(ref text_fragment_info) => { SpecificFragmentInfo::UnscannedText(ref text_fragment_info) => {
text = &text_fragment_info.text; text = &text_fragment_info.text;
selection = text_fragment_info.selection; selection = text_fragment_info.selection;
} },
_ => panic!("Expected an unscanned text fragment!"), _ => panic!("Expected an unscanned text fragment!"),
}; };
insertion_point = match selection { insertion_point = match selection {
@ -209,14 +228,16 @@ impl TextRunScanner {
// `range` is the range within the current fragment. To get the range // `range` is the range within the current fragment. To get the range
// within the text run, offset it by the length of the preceding fragments. // within the text run, offset it by the length of the preceding fragments.
Some(range.begin() + ByteIndex(run_info.text.len() as isize)) Some(range.begin() + ByteIndex(run_info.text.len() as isize))
} },
_ => None _ => None,
}; };
let (mut start_position, mut end_position) = (0, 0); let (mut start_position, mut end_position) = (0, 0);
for (byte_index, character) in text.char_indices() { for (byte_index, character) in text.char_indices() {
if !character.is_control() { if !character.is_control() {
let font = font_group.borrow_mut().find_by_codepoint(&mut font_context, character); let font = font_group
.borrow_mut()
.find_by_codepoint(&mut font_context, character);
let bidi_level = match bidi_levels { let bidi_level = match bidi_levels {
Some(levels) => levels[*paragraph_bytes_processed], Some(levels) => levels[*paragraph_bytes_processed],
@ -230,13 +251,14 @@ impl TextRunScanner {
// http://www.unicode.org/reports/tr24/#Common // http://www.unicode.org/reports/tr24/#Common
let script = get_script(character); let script = get_script(character);
let compatible_script = is_compatible(script, run_info.script); let compatible_script = is_compatible(script, run_info.script);
if compatible_script && !is_specific(run_info.script) && is_specific(script) { if compatible_script && !is_specific(run_info.script) && is_specific(script)
{
run_info.script = script; run_info.script = script;
} }
let selected = match selection { let selected = match selection {
Some(range) => range.contains(ByteIndex(byte_index as isize)), Some(range) => range.contains(ByteIndex(byte_index as isize)),
None => false None => false,
}; };
// Now, if necessary, flush the mapping we were building up. // Now, if necessary, flush the mapping we were building up.
@ -250,22 +272,23 @@ impl TextRunScanner {
// The run info values are uninitialized at this point so // The run info values are uninitialized at this point so
// flushing an empty mapping is pointless. // flushing an empty mapping is pointless.
if end_position > 0 { if end_position > 0 {
mapping.flush(&mut mappings, mapping.flush(
&mut mappings,
&mut run_info, &mut run_info,
&**text, &**text,
compression, compression,
text_transform, text_transform,
&mut last_whitespace, &mut last_whitespace,
&mut start_position, &mut start_position,
end_position); end_position,
);
} }
if run_info.text.len() > 0 { if run_info.text.len() > 0 {
if flush_run { if flush_run {
run_info.flush(&mut run_info_list, &mut insertion_point); run_info.flush(&mut run_info_list, &mut insertion_point);
run_info = RunInfo::new(); run_info = RunInfo::new();
} }
mapping = RunMapping::new(&run_info_list[..], mapping = RunMapping::new(&run_info_list[..], fragment_index);
fragment_index);
} }
run_info.font = font; run_info.font = font;
run_info.bidi_level = bidi_level; run_info.bidi_level = bidi_level;
@ -280,14 +303,16 @@ impl TextRunScanner {
} }
// Flush the last mapping we created for this fragment to the list. // Flush the last mapping we created for this fragment to the list.
mapping.flush(&mut mappings, mapping.flush(
&mut mappings,
&mut run_info, &mut run_info,
&**text, &**text,
compression, compression,
text_transform, text_transform,
&mut last_whitespace, &mut last_whitespace,
&mut start_position, &mut start_position,
end_position); end_position,
);
} }
// Push the final run info. // Push the final run info.
@ -326,20 +351,25 @@ impl TextRunScanner {
} }
// If no font is found (including fallbacks), there's no way we can render. // If no font is found (including fallbacks), there's no way we can render.
let font = let font = run_info
run_info.font .font
.or_else(|| font_group.borrow_mut().first(&mut font_context)) .or_else(|| font_group.borrow_mut().first(&mut font_context))
.expect("No font found for text run!"); .expect("No font found for text run!");
let (run, break_at_zero) = TextRun::new(&mut *font.borrow_mut(), let (run, break_at_zero) = TextRun::new(
&mut *font.borrow_mut(),
run_info.text, run_info.text,
&options, &options,
run_info.bidi_level, run_info.bidi_level,
linebreaker); linebreaker,
result.push((ScannedTextRun { );
result.push((
ScannedTextRun {
run: Arc::new(run), run: Arc::new(run),
insertion_point: run_info.insertion_point, insertion_point: run_info.insertion_point,
}, break_at_zero)) },
break_at_zero,
))
} }
result result
}; };
@ -349,12 +379,14 @@ impl TextRunScanner {
let mut mappings = mappings.into_iter().peekable(); let mut mappings = mappings.into_iter().peekable();
let mut prev_fragments_to_meld = Vec::new(); let mut prev_fragments_to_meld = Vec::new();
for (logical_offset, old_fragment) in for (logical_offset, old_fragment) in mem::replace(&mut self.clump, LinkedList::new())
mem::replace(&mut self.clump, LinkedList::new()).into_iter().enumerate() { .into_iter()
.enumerate()
{
let mut is_first_mapping_of_this_old_fragment = true; let mut is_first_mapping_of_this_old_fragment = true;
loop { loop {
match mappings.peek() { match mappings.peek() {
Some(mapping) if mapping.old_fragment_index == logical_offset => {} Some(mapping) if mapping.old_fragment_index == logical_offset => {},
Some(_) | None => { Some(_) | None => {
if is_first_mapping_of_this_old_fragment { if is_first_mapping_of_this_old_fragment {
// There were no mappings for this unscanned fragment. Transfer its // There were no mappings for this unscanned fragment. Transfer its
@ -365,13 +397,15 @@ impl TextRunScanner {
prev_fragments_to_meld.push(old_fragment); prev_fragments_to_meld.push(old_fragment);
} }
break; break;
} },
}; };
let mapping = mappings.next().unwrap(); let mapping = mappings.next().unwrap();
let (scanned_run, break_at_zero) = runs[mapping.text_run_index].clone(); let (scanned_run, break_at_zero) = runs[mapping.text_run_index].clone();
let mut byte_range = Range::new(ByteIndex(mapping.byte_range.begin() as isize), let mut byte_range = Range::new(
ByteIndex(mapping.byte_range.length() as isize)); ByteIndex(mapping.byte_range.begin() as isize),
ByteIndex(mapping.byte_range.length() as isize),
);
let mut flags = ScannedTextFlags::empty(); let mut flags = ScannedTextFlags::empty();
if !break_at_zero && mapping.byte_range.begin() == 0 { if !break_at_zero && mapping.byte_range.begin() == 0 {
@ -381,20 +415,23 @@ impl TextRunScanner {
} }
let text_size = old_fragment.border_box.size; let text_size = old_fragment.border_box.size;
let requires_line_break_afterward_if_wrapping_on_newlines = let requires_line_break_afterward_if_wrapping_on_newlines = scanned_run.run.text
scanned_run.run.text[mapping.byte_range.begin()..mapping.byte_range.end()] [mapping.byte_range.begin()..mapping.byte_range.end()]
.ends_with('\n'); .ends_with('\n');
if requires_line_break_afterward_if_wrapping_on_newlines { if requires_line_break_afterward_if_wrapping_on_newlines {
byte_range.extend_by(ByteIndex(-1)); // Trim the '\n' byte_range.extend_by(ByteIndex(-1)); // Trim the '\n'
flags.insert(ScannedTextFlags::REQUIRES_LINE_BREAK_AFTERWARD_IF_WRAPPING_ON_NEWLINES); flags.insert(
ScannedTextFlags::REQUIRES_LINE_BREAK_AFTERWARD_IF_WRAPPING_ON_NEWLINES,
);
} }
if mapping.selected { if mapping.selected {
flags.insert(ScannedTextFlags::SELECTED); flags.insert(ScannedTextFlags::SELECTED);
} }
let insertion_point = if mapping.contains_insertion_point(scanned_run.insertion_point) { let insertion_point =
if mapping.contains_insertion_point(scanned_run.insertion_point) {
scanned_run.insertion_point scanned_run.insertion_point
} else { } else {
None None
@ -405,7 +442,7 @@ impl TextRunScanner {
byte_range, byte_range,
text_size, text_size,
insertion_point, insertion_point,
flags flags,
)); ));
let new_metrics = new_text_fragment_info.run.metrics_for_range(&byte_range); let new_metrics = new_text_fragment_info.run.metrics_for_range(&byte_range);
@ -415,20 +452,23 @@ impl TextRunScanner {
let mut new_fragment = old_fragment.transform( let mut new_fragment = old_fragment.transform(
bounding_box_size, bounding_box_size,
SpecificFragmentInfo::ScannedText(new_text_fragment_info)); SpecificFragmentInfo::ScannedText(new_text_fragment_info),
);
let is_last_mapping_of_this_old_fragment = match mappings.peek() { let is_last_mapping_of_this_old_fragment = match mappings.peek() {
Some(mapping) if mapping.old_fragment_index == logical_offset => false, Some(mapping) if mapping.old_fragment_index == logical_offset => false,
_ => true _ => true,
}; };
if let Some(ref mut context) = new_fragment.inline_context { if let Some(ref mut context) = new_fragment.inline_context {
for node in &mut context.nodes { for node in &mut context.nodes {
if !is_last_mapping_of_this_old_fragment { if !is_last_mapping_of_this_old_fragment {
node.flags.remove(InlineFragmentNodeFlags::LAST_FRAGMENT_OF_ELEMENT); node.flags
.remove(InlineFragmentNodeFlags::LAST_FRAGMENT_OF_ELEMENT);
} }
if !is_first_mapping_of_this_old_fragment { if !is_first_mapping_of_this_old_fragment {
node.flags.remove(InlineFragmentNodeFlags::FIRST_FRAGMENT_OF_ELEMENT); node.flags
.remove(InlineFragmentNodeFlags::FIRST_FRAGMENT_OF_ELEMENT);
} }
} }
} }
@ -447,14 +487,17 @@ impl TextRunScanner {
} }
#[inline] #[inline]
fn bounding_box_for_run_metrics(metrics: &RunMetrics, writing_mode: WritingMode) fn bounding_box_for_run_metrics(
-> LogicalSize<Au> { metrics: &RunMetrics,
writing_mode: WritingMode,
) -> LogicalSize<Au> {
// TODO: When the text-orientation property is supported, the block and inline directions may // TODO: When the text-orientation property is supported, the block and inline directions may
// be swapped for horizontal glyphs in vertical lines. // be swapped for horizontal glyphs in vertical lines.
LogicalSize::new( LogicalSize::new(
writing_mode, writing_mode,
metrics.bounding_box.size.width, metrics.bounding_box.size.width,
metrics.bounding_box.size.height) metrics.bounding_box.size.height,
)
} }
/// Returns the metrics of the font represented by the given `FontStyleStruct`. /// Returns the metrics of the font represented by the given `FontStyleStruct`.
@ -465,8 +508,10 @@ fn bounding_box_for_run_metrics(metrics: &RunMetrics, writing_mode: WritingMode)
/// ///
/// Panics if no font can be found for the given font style. /// Panics if no font can be found for the given font style.
#[inline] #[inline]
pub fn font_metrics_for_style(mut font_context: &mut LayoutFontContext, style: ::ServoArc<FontStyleStruct>) pub fn font_metrics_for_style(
-> FontMetrics { mut font_context: &mut LayoutFontContext,
style: ::ServoArc<FontStyleStruct>,
) -> FontMetrics {
let font_group = font_context.font_group(style); let font_group = font_context.font_group(style);
let font = font_group.borrow_mut().first(&mut font_context); let font = font_group.borrow_mut().first(&mut font_context);
let font = font.as_ref().unwrap().borrow(); let font = font.as_ref().unwrap().borrow();
@ -480,13 +525,13 @@ pub fn line_height_from_style(style: &ComputedValues, metrics: &FontMetrics) ->
match style.get_inherited_text().line_height { match style.get_inherited_text().line_height {
LineHeight::Normal => Au::from(metrics.line_gap), LineHeight::Normal => Au::from(metrics.line_gap),
LineHeight::Number(l) => font_size.scale_by(l.0), LineHeight::Number(l) => font_size.scale_by(l.0),
LineHeight::Length(l) => Au::from(l) LineHeight::Length(l) => Au::from(l),
} }
} }
fn split_first_fragment_at_newline_if_necessary(fragments: &mut LinkedList<Fragment>) { fn split_first_fragment_at_newline_if_necessary(fragments: &mut LinkedList<Fragment>) {
if fragments.is_empty() { if fragments.is_empty() {
return return;
} }
let new_fragment = { let new_fragment = {
@ -501,45 +546,46 @@ fn split_first_fragment_at_newline_if_necessary(fragments: &mut LinkedList<Fragm
let unscanned_text_fragment_info = match first_fragment.specific { let unscanned_text_fragment_info = match first_fragment.specific {
SpecificFragmentInfo::UnscannedText(ref mut unscanned_text_fragment_info) => { SpecificFragmentInfo::UnscannedText(ref mut unscanned_text_fragment_info) => {
unscanned_text_fragment_info unscanned_text_fragment_info
} },
_ => return, _ => return,
}; };
let position = match unscanned_text_fragment_info.text.find('\n') { let position = match unscanned_text_fragment_info.text.find('\n') {
Some(position) if position < unscanned_text_fragment_info.text.len() - 1 => { Some(position) if position < unscanned_text_fragment_info.text.len() - 1 => {
position position
} },
Some(_) | None => return, Some(_) | None => return,
}; };
string_before = string_before = unscanned_text_fragment_info.text[..(position + 1)].to_owned();
unscanned_text_fragment_info.text[..(position + 1)].to_owned(); unscanned_text_fragment_info.text = unscanned_text_fragment_info.text[(position + 1)..]
unscanned_text_fragment_info.text = .to_owned()
unscanned_text_fragment_info.text[(position + 1)..].to_owned().into_boxed_str(); .into_boxed_str();
let offset = ByteIndex(string_before.len() as isize); let offset = ByteIndex(string_before.len() as isize);
match unscanned_text_fragment_info.selection { match unscanned_text_fragment_info.selection {
Some(ref mut selection) if selection.begin() >= offset => { Some(ref mut selection) if selection.begin() >= offset => {
// Selection is entirely in the second fragment. // Selection is entirely in the second fragment.
selection_before = None; selection_before = None;
selection.shift_by(-offset); selection.shift_by(-offset);
} },
Some(ref mut selection) if selection.end() > offset => { Some(ref mut selection) if selection.end() > offset => {
// Selection is split across two fragments. // Selection is split across two fragments.
selection_before = Some(Range::new(selection.begin(), offset)); selection_before = Some(Range::new(selection.begin(), offset));
*selection = Range::new(ByteIndex(0), selection.end() - offset); *selection = Range::new(ByteIndex(0), selection.end() - offset);
} },
_ => { _ => {
// Selection is entirely in the first fragment. // Selection is entirely in the first fragment.
selection_before = unscanned_text_fragment_info.selection; selection_before = unscanned_text_fragment_info.selection;
unscanned_text_fragment_info.selection = None; unscanned_text_fragment_info.selection = None;
} },
}; };
} }
first_fragment.transform( first_fragment.transform(
first_fragment.border_box.size, first_fragment.border_box.size,
SpecificFragmentInfo::UnscannedText(Box::new( SpecificFragmentInfo::UnscannedText(Box::new(UnscannedTextFragmentInfo::new(
UnscannedTextFragmentInfo::new(string_before.into_boxed_str(), selection_before) string_before.into_boxed_str(),
)) selection_before,
))),
) )
}; };
@ -575,9 +621,7 @@ impl RunInfo {
/// ///
/// * `insertion_point`: The position of the insertion point, in characters relative to the start /// * `insertion_point`: The position of the insertion point, in characters relative to the start
/// of this text run. /// of this text run.
fn flush(mut self, fn flush(mut self, list: &mut Vec<RunInfo>, insertion_point: &mut Option<ByteIndex>) {
list: &mut Vec<RunInfo>,
insertion_point: &mut Option<ByteIndex>) {
if let Some(idx) = *insertion_point { if let Some(idx) = *insertion_point {
let char_len = ByteIndex(self.text.len() as isize); let char_len = ByteIndex(self.text.len() as isize);
if idx <= char_len { if idx <= char_len {
@ -617,8 +661,7 @@ struct RunMapping {
impl RunMapping { impl RunMapping {
/// Given the current set of text runs, creates a run mapping for the next fragment. /// Given the current set of text runs, creates a run mapping for the next fragment.
/// `run_info_list` describes the set of runs we've seen already. /// `run_info_list` describes the set of runs we've seen already.
fn new(run_info_list: &[RunInfo], fragment_index: usize) fn new(run_info_list: &[RunInfo], fragment_index: usize) -> RunMapping {
-> RunMapping {
RunMapping { RunMapping {
byte_range: Range::new(0, 0), byte_range: Range::new(0, 0),
old_fragment_index: fragment_index, old_fragment_index: fragment_index,
@ -629,7 +672,8 @@ impl RunMapping {
/// Flushes this run mapping to the list. `run_info` describes the text run that we're /// Flushes this run mapping to the list. `run_info` describes the text run that we're
/// currently working on. `text` refers to the text of this fragment. /// currently working on. `text` refers to the text of this fragment.
fn flush(mut self, fn flush(
mut self,
mappings: &mut Vec<RunMapping>, mappings: &mut Vec<RunMapping>,
run_info: &mut RunInfo, run_info: &mut RunInfo,
text: &str, text: &str,
@ -637,19 +681,27 @@ impl RunMapping {
text_transform: TextTransform, text_transform: TextTransform,
last_whitespace: &mut bool, last_whitespace: &mut bool,
start_position: &mut usize, start_position: &mut usize,
end_position: usize) { end_position: usize,
) {
let was_empty = *start_position == end_position; let was_empty = *start_position == end_position;
let old_byte_length = run_info.text.len(); let old_byte_length = run_info.text.len();
*last_whitespace = util::transform_text(&text[(*start_position)..end_position], *last_whitespace = util::transform_text(
&text[(*start_position)..end_position],
compression, compression,
*last_whitespace, *last_whitespace,
&mut run_info.text); &mut run_info.text,
);
// Account for `text-transform`. (Confusingly, this is not handled in "text // Account for `text-transform`. (Confusingly, this is not handled in "text
// transformation" above, but we follow Gecko in the naming.) // transformation" above, but we follow Gecko in the naming.)
let is_first_run = *start_position == 0; let is_first_run = *start_position == 0;
apply_style_transform_if_necessary(&mut run_info.text, old_byte_length, text_transform, apply_style_transform_if_necessary(
*last_whitespace, is_first_run); &mut run_info.text,
old_byte_length,
text_transform,
*last_whitespace,
is_first_run,
);
*start_position = end_position; *start_position = end_position;
let new_byte_length = run_info.text.len(); let new_byte_length = run_info.text.len();
@ -674,38 +726,39 @@ impl RunMapping {
fn contains_insertion_point(&self, insertion_point: Option<ByteIndex>) -> bool { fn contains_insertion_point(&self, insertion_point: Option<ByteIndex>) -> bool {
match insertion_point.map(ByteIndex::to_usize) { match insertion_point.map(ByteIndex::to_usize) {
None => false, None => false,
Some(idx) => self.byte_range.begin() <= idx && idx <= self.byte_range.end() Some(idx) => self.byte_range.begin() <= idx && idx <= self.byte_range.end(),
} }
} }
} }
/// Accounts for `text-transform`. /// Accounts for `text-transform`.
/// ///
/// FIXME(#4311, pcwalton): Title-case mapping can change length of the string; /// FIXME(#4311, pcwalton): Title-case mapping can change length of the string;
/// case mapping should be language-specific; `full-width`; /// case mapping should be language-specific; `full-width`;
/// use graphemes instead of characters. /// use graphemes instead of characters.
fn apply_style_transform_if_necessary(string: &mut String, fn apply_style_transform_if_necessary(
string: &mut String,
first_character_position: usize, first_character_position: usize,
text_transform: TextTransform, text_transform: TextTransform,
last_whitespace: bool, last_whitespace: bool,
is_first_run: bool) { is_first_run: bool,
) {
match text_transform { match text_transform {
TextTransform::None => {} TextTransform::None => {},
TextTransform::Uppercase => { TextTransform::Uppercase => {
let original = string[first_character_position..].to_owned(); let original = string[first_character_position..].to_owned();
string.truncate(first_character_position); string.truncate(first_character_position);
for ch in original.chars().flat_map(|ch| ch.to_uppercase()) { for ch in original.chars().flat_map(|ch| ch.to_uppercase()) {
string.push(ch); string.push(ch);
} }
} },
TextTransform::Lowercase => { TextTransform::Lowercase => {
let original = string[first_character_position..].to_owned(); let original = string[first_character_position..].to_owned();
string.truncate(first_character_position); string.truncate(first_character_position);
for ch in original.chars().flat_map(|ch| ch.to_lowercase()) { for ch in original.chars().flat_map(|ch| ch.to_lowercase()) {
string.push(ch); string.push(ch);
} }
} },
TextTransform::Capitalize => { TextTransform::Capitalize => {
let original = string[first_character_position..].to_owned(); let original = string[first_character_position..].to_owned();
string.truncate(first_character_position); string.truncate(first_character_position);
@ -719,7 +772,7 @@ fn apply_style_transform_if_necessary(string: &mut String,
if capitalize_next_letter && character.is_alphabetic() { if capitalize_next_letter && character.is_alphabetic() {
string.push(character.to_uppercase().next().unwrap()); string.push(character.to_uppercase().next().unwrap());
capitalize_next_letter = false; capitalize_next_letter = false;
continue continue;
} }
string.push(character); string.push(character);
@ -729,7 +782,7 @@ fn apply_style_transform_if_necessary(string: &mut String,
capitalize_next_letter = true capitalize_next_letter = true
} }
} }
} },
} }
} }

View file

@ -33,9 +33,7 @@ impl<'a> RecalcStyleAndConstructFlows<'a> {
impl<'a> RecalcStyleAndConstructFlows<'a> { impl<'a> RecalcStyleAndConstructFlows<'a> {
/// Creates a traversal context, taking ownership of the shared layout context. /// Creates a traversal context, taking ownership of the shared layout context.
pub fn new(context: LayoutContext<'a>) -> Self { pub fn new(context: LayoutContext<'a>) -> Self {
RecalcStyleAndConstructFlows { RecalcStyleAndConstructFlows { context: context }
context: context,
}
} }
/// Consumes this traversal context, returning ownership of the shared layout /// Consumes this traversal context, returning ownership of the shared layout
@ -55,11 +53,11 @@ where
fn process_preorder<F>( fn process_preorder<F>(
&self, &self,
traversal_data: &PerLevelTraversalData, traversal_data: &PerLevelTraversalData,
context: &mut StyleContext<E>, node: E::ConcreteNode, context: &mut StyleContext<E>,
node: E::ConcreteNode,
note_child: F, note_child: F,
) ) where
where F: FnMut(E::ConcreteNode),
F: FnMut(E::ConcreteNode)
{ {
// FIXME(pcwalton): Stop allocating here. Ideally this should just be // FIXME(pcwalton): Stop allocating here. Ideally this should just be
// done by the HTML parser. // done by the HTML parser.
@ -192,7 +190,8 @@ pub trait PostorderNodeMutTraversal<ConcreteThreadSafeLayoutNode: ThreadSafeLayo
#[inline] #[inline]
#[allow(unsafe_code)] #[allow(unsafe_code)]
fn construct_flows_at<N>(context: &LayoutContext, node: N) fn construct_flows_at<N>(context: &LayoutContext, node: N)
where N: LayoutNode, where
N: LayoutNode,
{ {
debug!("construct_flows_at: {:?}", node); debug!("construct_flows_at: {:?}", node);
@ -202,22 +201,32 @@ fn construct_flows_at<N>(context: &LayoutContext, node: N)
// Always reconstruct if incremental layout is turned off. // Always reconstruct if incremental layout is turned off.
let nonincremental_layout = opts::get().nonincremental_layout; let nonincremental_layout = opts::get().nonincremental_layout;
if nonincremental_layout || tnode.restyle_damage() != RestyleDamage::empty() || if nonincremental_layout || tnode.restyle_damage() != RestyleDamage::empty() || node
node.as_element().map_or(false, |el| el.has_dirty_descendants()) { .as_element()
.map_or(false, |el| el.has_dirty_descendants())
{
let mut flow_constructor = FlowConstructor::new(context); let mut flow_constructor = FlowConstructor::new(context);
if nonincremental_layout || !flow_constructor.repair_if_possible(&tnode) { if nonincremental_layout || !flow_constructor.repair_if_possible(&tnode) {
flow_constructor.process(&tnode); flow_constructor.process(&tnode);
debug!("Constructed flow for {:?}: {:x}", debug!(
"Constructed flow for {:?}: {:x}",
tnode, tnode,
tnode.flow_debug_id()); tnode.flow_debug_id()
);
} }
} }
tnode.mutate_layout_data().unwrap().flags.insert(::data::LayoutDataFlags::HAS_BEEN_TRAVERSED); tnode
.mutate_layout_data()
.unwrap()
.flags
.insert(::data::LayoutDataFlags::HAS_BEEN_TRAVERSED);
} }
if let Some(el) = node.as_element() { if let Some(el) = node.as_element() {
unsafe { el.unset_dirty_descendants(); } unsafe {
el.unset_dirty_descendants();
}
} }
} }
@ -231,12 +240,16 @@ impl<'a> PostorderFlowTraversal for BubbleISizes<'a> {
#[inline] #[inline]
fn process(&self, flow: &mut Flow) { fn process(&self, flow: &mut Flow) {
flow.bubble_inline_sizes(); flow.bubble_inline_sizes();
flow.mut_base().restyle_damage.remove(ServoRestyleDamage::BUBBLE_ISIZES); flow.mut_base()
.restyle_damage
.remove(ServoRestyleDamage::BUBBLE_ISIZES);
} }
#[inline] #[inline]
fn should_process(&self, flow: &mut Flow) -> bool { fn should_process(&self, flow: &mut Flow) -> bool {
flow.base().restyle_damage.contains(ServoRestyleDamage::BUBBLE_ISIZES) flow.base()
.restyle_damage
.contains(ServoRestyleDamage::BUBBLE_ISIZES)
} }
} }
@ -254,7 +267,9 @@ impl<'a> PreorderFlowTraversal for AssignISizes<'a> {
#[inline] #[inline]
fn should_process(&self, flow: &mut Flow) -> bool { fn should_process(&self, flow: &mut Flow) -> bool {
flow.base().restyle_damage.intersects(ServoRestyleDamage::REFLOW_OUT_OF_FLOW | ServoRestyleDamage::REFLOW) flow.base()
.restyle_damage
.intersects(ServoRestyleDamage::REFLOW_OUT_OF_FLOW | ServoRestyleDamage::REFLOW)
} }
} }
@ -275,7 +290,7 @@ impl<'a> PostorderFlowTraversal for AssignBSizes<'a> {
// NB: We must return without resetting the restyle bits for these, as we haven't actually // NB: We must return without resetting the restyle bits for these, as we haven't actually
// reflowed anything! // reflowed anything!
if flow.floats_might_flow_through() { if flow.floats_might_flow_through() {
return return;
} }
flow.assign_block_size(self.layout_context); flow.assign_block_size(self.layout_context);
@ -298,13 +313,17 @@ pub struct ComputeStackingRelativePositions<'a> {
impl<'a> PreorderFlowTraversal for ComputeStackingRelativePositions<'a> { impl<'a> PreorderFlowTraversal for ComputeStackingRelativePositions<'a> {
#[inline] #[inline]
fn should_process_subtree(&self, flow: &mut Flow) -> bool { fn should_process_subtree(&self, flow: &mut Flow) -> bool {
flow.base().restyle_damage.contains(ServoRestyleDamage::REPOSITION) flow.base()
.restyle_damage
.contains(ServoRestyleDamage::REPOSITION)
} }
#[inline] #[inline]
fn process(&self, flow: &mut Flow) { fn process(&self, flow: &mut Flow) {
flow.compute_stacking_relative_position(self.layout_context); flow.compute_stacking_relative_position(self.layout_context);
flow.mut_base().restyle_damage.remove(ServoRestyleDamage::REPOSITION) flow.mut_base()
.restyle_damage
.remove(ServoRestyleDamage::REPOSITION)
} }
} }
@ -322,7 +341,9 @@ impl<'a> BuildDisplayList<'a> {
self.state.current_clipping_and_scrolling = flow.clipping_and_scrolling(); self.state.current_clipping_and_scrolling = flow.clipping_and_scrolling();
flow.build_display_list(&mut self.state); flow.build_display_list(&mut self.state);
flow.mut_base().restyle_damage.remove(ServoRestyleDamage::REPAINT); flow.mut_base()
.restyle_damage
.remove(ServoRestyleDamage::REPAINT);
for kid in flow.mut_base().child_iter_mut() { for kid in flow.mut_base().child_iter_mut() {
self.traverse(kid); self.traverse(kid);

View file

@ -57,7 +57,8 @@ impl<T: GetLayoutData> LayoutNodeLayoutData for T {
} }
fn flow_debug_id(self) -> usize { fn flow_debug_id(self) -> usize {
self.borrow_layout_data().map_or(0, |d| d.flow_construction_result.debug_id()) self.borrow_layout_data()
.map_or(0, |d| d.flow_construction_result.debug_id())
} }
} }
@ -114,12 +115,10 @@ impl<T: ThreadSafeLayoutNode> ThreadSafeLayoutNodeHelpers for T {
if self.get_pseudo_element_type().is_replaced_content() { if self.get_pseudo_element_type().is_replaced_content() {
let style = self.as_element().unwrap().resolved_style(); let style = self.as_element().unwrap().resolved_style();
return TextContent::GeneratedContent( return TextContent::GeneratedContent(match style.as_ref().get_counters().content {
match style.as_ref().get_counters().content {
Content::Items(ref value) => value.to_vec(), Content::Items(ref value) => value.to_vec(),
_ => vec![], _ => vec![],
} });
);
} }
TextContent::Text(self.node_text_content().into_boxed_str()) TextContent::Text(self.node_text_content().into_boxed_str())
@ -141,7 +140,12 @@ impl<T: ThreadSafeLayoutNode> ThreadSafeLayoutNodeHelpers for T {
let damage = { let damage = {
let data = node.get_raw_data().unwrap(); let data = node.get_raw_data().unwrap();
if !data.layout_data.borrow().flags.contains(::data::LayoutDataFlags::HAS_BEEN_TRAVERSED) { if !data
.layout_data
.borrow()
.flags
.contains(::data::LayoutDataFlags::HAS_BEEN_TRAVERSED)
{
// We're reflowing a node that was styled for the first time and // We're reflowing a node that was styled for the first time and
// has never been visited by layout. Return rebuild_and_reflow, // has never been visited by layout. Return rebuild_and_reflow,
// because that's what the code expects. // because that's what the code expects.
@ -153,7 +157,6 @@ impl<T: ThreadSafeLayoutNode> ThreadSafeLayoutNodeHelpers for T {
damage damage
} }
} }
pub enum TextContent { pub enum TextContent {