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>,
pipeline_id: PipelineId,
timer: &Timer,
)
where
) where
E: TElement,
{
let mut new_running_animations = vec![];
@ -66,7 +65,7 @@ where
if running_animations.is_empty() && new_running_animations.is_empty() {
// Nothing to do. Return early so we don't flood the compositor with
// `ChangeRunningAnimationsState` messages.
return
return;
}
let now = timer.seconds();
@ -82,30 +81,32 @@ where
let still_running = !running_animation.is_expired() && match running_animation {
Animation::Transition(_, started_at, ref frame, _expired) => {
now < started_at + frame.duration
}
},
Animation::Keyframes(_, _, _, ref mut state) => {
// This animation is still running, or we need to keep
// iterating.
now < state.started_at + state.duration || state.tick()
}
},
};
if still_running {
animations_still_running.push(running_animation);
continue
continue;
}
if let Animation::Transition(node, _, ref frame, _) = running_animation {
script_chan.send(ConstellationControlMsg::TransitionEnd(node.to_untrusted_node_address(),
frame.property_animation
.property_name().into(),
frame.duration))
.unwrap();
script_chan
.send(ConstellationControlMsg::TransitionEnd(
node.to_untrusted_node_address(),
frame.property_animation.property_name().into(),
frame.duration,
)).unwrap();
}
expired_animations.entry(*key)
.or_insert_with(Vec::new)
.push(running_animation);
expired_animations
.entry(*key)
.or_insert_with(Vec::new)
.push(running_animation);
}
if animations_still_running.is_empty() {
@ -125,16 +126,17 @@ where
match newly_transitioning_nodes {
Some(ref mut nodes) => {
nodes.push(new_running_animation.node().to_untrusted_node_address());
}
},
None => {
warn!("New transition encountered from compositor-initiated layout.");
}
},
}
}
running_animations.entry(*new_running_animation.node())
.or_insert_with(Vec::new)
.push(new_running_animation)
running_animations
.entry(*new_running_animation.node())
.or_insert_with(Vec::new)
.push(new_running_animation)
}
let animation_state = if running_animations.is_empty() {
@ -143,9 +145,11 @@ where
AnimationState::AnimationsPresent
};
constellation_chan.send(ConstellationMsg::ChangeRunningAnimationsState(pipeline_id,
animation_state))
.unwrap();
constellation_chan
.send(ConstellationMsg::ChangeRunningAnimationsState(
pipeline_id,
animation_state,
)).unwrap();
}
/// 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,
flow: &mut Flow,
animations: &FxHashMap<OpaqueNode, Vec<Animation>>,
)
where
) where
E: TElement,
{
let mut damage = RestyleDamage::empty();
@ -170,10 +173,7 @@ where
&ServoMetricsProvider,
);
let difference =
RestyleDamage::compute_style_difference(
&old_style,
&fragment.style,
);
RestyleDamage::compute_style_difference(&old_style, &fragment.style);
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));
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| {
let mut font_context = k.borrow_mut();
@ -69,9 +70,11 @@ pub struct LayoutContext<'a> {
pub font_cache_thread: Mutex<FontCacheThread>,
/// A cache of WebRender image info.
pub webrender_image_cache: Arc<RwLock<HashMap<(ServoUrl, UsePlaceholder),
WebRenderImageInfo,
BuildHasherDefault<FnvHasher>>>>,
pub webrender_image_cache: Arc<
RwLock<
HashMap<(ServoUrl, UsePlaceholder), WebRenderImageInfo, BuildHasherDefault<FnvHasher>>,
>,
>,
/// Paint worklets
pub registered_painters: &'a RegisteredPainters,
@ -101,11 +104,12 @@ impl<'a> LayoutContext<'a> {
&self.style_context
}
pub fn get_or_request_image_or_meta(&self,
node: OpaqueNode,
url: ServoUrl,
use_placeholder: UsePlaceholder)
-> Option<ImageOrMetadataAvailable> {
pub fn get_or_request_image_or_meta(
&self,
node: OpaqueNode,
url: ServoUrl,
use_placeholder: UsePlaceholder,
) -> Option<ImageOrMetadataAvailable> {
//XXXjdm For cases where we do not request an image, we still need to
// ensure the node gets another script-initiated reflow or it
// won't be requested at all.
@ -116,9 +120,9 @@ impl<'a> LayoutContext<'a> {
};
// See if the image is already available
let result = self.image_cache.find_image_or_metadata(url.clone(),
use_placeholder,
can_request);
let result =
self.image_cache
.find_image_or_metadata(url.clone(), use_placeholder, can_request);
match result {
Ok(image_or_metadata) => Some(image_or_metadata),
// Image failed to load, so just return nothing
@ -130,9 +134,14 @@ impl<'a> LayoutContext<'a> {
node: node.to_untrusted_node_address(),
id: id,
};
self.pending_images.as_ref().unwrap().lock().unwrap().push(image);
self.pending_images
.as_ref()
.unwrap()
.lock()
.unwrap()
.push(image);
None
}
},
// 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.
Err(ImageState::Pending(id)) => {
@ -148,19 +157,22 @@ impl<'a> LayoutContext<'a> {
pending_images.lock().unwrap().push(image);
}
None
}
},
}
}
pub fn get_webrender_image_for_url(&self,
node: OpaqueNode,
url: ServoUrl,
use_placeholder: UsePlaceholder)
-> Option<WebRenderImageInfo> {
if let Some(existing_webrender_image) = self.webrender_image_cache
.read()
.get(&(url.clone(), use_placeholder)) {
return Some((*existing_webrender_image).clone())
pub fn get_webrender_image_for_url(
&self,
node: OpaqueNode,
url: ServoUrl,
use_placeholder: UsePlaceholder,
) -> Option<WebRenderImageInfo> {
if let Some(existing_webrender_image) = self
.webrender_image_cache
.read()
.get(&(url.clone(), use_placeholder))
{
return Some((*existing_webrender_image).clone());
}
match self.get_or_request_image_or_meta(node, url.clone(), use_placeholder) {
@ -170,11 +182,10 @@ impl<'a> LayoutContext<'a> {
Some(image_info)
} else {
let mut webrender_image_cache = self.webrender_image_cache.write();
webrender_image_cache.insert((url, use_placeholder),
image_info);
webrender_image_cache.insert((url, use_placeholder), image_info);
Some(image_info)
}
}
},
None | Some(ImageOrMetadataAvailable::MetadataAvailable(_)) => None,
}
}

View file

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

View file

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

View file

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

View file

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

View file

@ -45,25 +45,25 @@ enum AxisSize {
impl AxisSize {
/// Generate a new available cross or main axis size from the specified size of the container,
/// containing block size, min constraint, and max constraint
pub fn new(size: LengthOrPercentageOrAuto, content_size: Option<Au>, min: LengthOrPercentage,
max: LengthOrPercentageOrNone) -> AxisSize {
pub fn new(
size: LengthOrPercentageOrAuto,
content_size: Option<Au>,
min: LengthOrPercentage,
max: LengthOrPercentageOrNone,
) -> AxisSize {
match size {
LengthOrPercentageOrAuto::Length(length) => AxisSize::Definite(Au::from(length)),
LengthOrPercentageOrAuto::Percentage(percent) => {
match content_size {
Some(size) => AxisSize::Definite(size.scale_by(percent.0)),
None => AxisSize::Infinite
}
}
LengthOrPercentageOrAuto::Calc(calc) => {
match calc.to_used_value(content_size) {
Some(length) => AxisSize::Definite(length),
None => AxisSize::Infinite,
}
}
LengthOrPercentageOrAuto::Percentage(percent) => match content_size {
Some(size) => AxisSize::Definite(size.scale_by(percent.0)),
None => AxisSize::Infinite,
},
LengthOrPercentageOrAuto::Calc(calc) => match calc.to_used_value(content_size) {
Some(length) => AxisSize::Definite(length),
None => AxisSize::Infinite,
},
LengthOrPercentageOrAuto::Auto => {
AxisSize::MinMax(SizeConstraint::new(content_size, min, max, None))
}
},
}
}
}
@ -112,7 +112,7 @@ struct FlexItem {
/// Whether the main size has met its constraint.
pub is_frozen: bool,
/// True if this flow has property 'visibility::collapse'.
pub is_strut: bool
pub is_strut: bool,
}
impl FlexItem {
@ -133,7 +133,7 @@ impl FlexItem {
flex_shrink: flex_shrink.into(),
order: order,
is_frozen: false,
is_strut: false
is_strut: false,
}
}
@ -147,41 +147,61 @@ impl FlexItem {
// should change to LengthOrPercentageOrAuto for automatic implied minimal size.
// https://drafts.csswg.org/css-flexbox-1/#min-size-auto
Direction::Inline => {
let basis = from_flex_basis(block.fragment.style.get_position().flex_basis,
block.fragment.style.content_inline_size(),
containing_length);
let basis = from_flex_basis(
block.fragment.style.get_position().flex_basis,
block.fragment.style.content_inline_size(),
containing_length,
);
// 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_inline_direction_margins(containing_length);
block.fragment.compute_block_direction_margins(containing_length);
block
.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 content_size = block.base.intrinsic_inline_sizes.preferred_inline_size
- border_padding
- margin
+ block.fragment.box_sizing_boundary(direction);
let content_size = block.base.intrinsic_inline_sizes.preferred_inline_size -
border_padding -
margin +
block.fragment.box_sizing_boundary(direction);
self.base_size = basis.specified_or_default(content_size);
self.max_size =
block.fragment.style.max_inline_size()
.to_used_value(containing_length)
.unwrap_or(MAX_AU);
self.min_size = block.fragment.style.min_inline_size().to_used_value(containing_length);
}
self.max_size = block
.fragment
.style
.max_inline_size()
.to_used_value(containing_length)
.unwrap_or(MAX_AU);
self.min_size = block
.fragment
.style
.min_inline_size()
.to_used_value(containing_length);
},
Direction::Block => {
let basis = from_flex_basis(block.fragment.style.get_position().flex_basis,
block.fragment.style.content_block_size(),
containing_length);
let content_size = block.fragment.border_box.size.block
- block.fragment.border_padding.block_start_end()
+ block.fragment.box_sizing_boundary(direction);
let basis = from_flex_basis(
block.fragment.style.get_position().flex_basis,
block.fragment.style.content_block_size(),
containing_length,
);
let content_size = block.fragment.border_box.size.block -
block.fragment.border_padding.block_start_end() +
block.fragment.box_sizing_boundary(direction);
self.base_size = basis.specified_or_default(content_size);
self.max_size =
block.fragment.style.max_block_size()
.to_used_value(containing_length)
.unwrap_or(MAX_AU);
self.min_size = block.fragment.style.min_block_size().to_used_value(containing_length);
}
self.max_size = block
.fragment
.style
.max_block_size()
.to_used_value(containing_length)
.unwrap_or(MAX_AU);
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 {
Direction::Inline => {
fragment.border_padding.inline_start_end() + fragment.margin.inline_start_end()
}
},
Direction::Block => {
fragment.border_padding.block_start_end() + fragment.margin.block_start_end()
}
},
};
max(self.min_size, min(self.base_size, self.max_size))
- fragment.box_sizing_boundary(direction) + outer_width
max(self.min_size, min(self.base_size, self.max_size)) -
fragment.box_sizing_boundary(direction) +
outer_width
}
/// Returns the number of auto margins in given direction.
@ -213,7 +234,7 @@ impl FlexItem {
if margin.inline_end == LengthOrPercentageOrAuto::Auto {
margin_count += 1;
}
}
},
Direction::Block => {
if margin.block_start == LengthOrPercentageOrAuto::Auto {
margin_count += 1;
@ -221,7 +242,7 @@ impl FlexItem {
if margin.block_end == LengthOrPercentageOrAuto::Auto {
margin_count += 1;
}
}
},
}
margin_count
}
@ -247,7 +268,7 @@ impl FlexLine {
range: range,
auto_margin_count: auto_margin_count,
free_space: free_space,
cross_size: Au(0)
cross_size: Au(0),
}
}
@ -265,17 +286,20 @@ impl FlexLine {
// https://drafts.csswg.org/css-flexbox/#resolve-flexible-lengths
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));
if (self.free_space > Au(0) && (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;
} else {
item.is_frozen = false;
total_grow += item.flex_grow;
total_shrink += item.flex_shrink;
// The scaled factor is used to calculate flex shrink
total_scaled += item.flex_shrink * item.base_size.0 as f32;
active_count += 1;
}
if (self.free_space > Au(0) &&
(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;
} else {
item.is_frozen = false;
total_grow += item.flex_grow;
total_shrink += item.flex_shrink;
// The scaled factor is used to calculate flex shrink
total_scaled += item.flex_shrink * item.base_size.0 as f32;
active_count += 1;
}
}
let initial_free_space = self.free_space;
@ -291,12 +315,19 @@ impl FlexLine {
};
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.
let (factor, end_size) = if self.free_space > Au(0) {
(item.flex_grow / total_grow, item.max_size)
} 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);
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.
is_wrappable: bool,
/// True if the cross direction is reversed.
cross_reverse: bool
cross_reverse: bool,
}
impl FlexFlow {
pub fn from_fragment(fragment: Fragment,
flotation: Option<FloatKind>)
-> FlexFlow {
pub fn from_fragment(fragment: Fragment, flotation: Option<FloatKind>) -> FlexFlow {
let main_mode;
let main_reverse;
let is_wrappable;
@ -363,8 +392,7 @@ impl FlexFlow {
FlexDirection::ColumnReverse => (Direction::Block, true),
};
main_mode = mode;
main_reverse =
reverse == style.writing_mode.is_bidi_ltr();
main_reverse = reverse == style.writing_mode.is_bidi_ltr();
let (wrappable, reverse) = match fragment.style.get_position().flex_wrap {
FlexWrap::Nowrap => (false, false),
FlexWrap::Wrap => (true, false),
@ -384,7 +412,7 @@ impl FlexFlow {
items: Vec::new(),
main_reverse: main_reverse,
is_wrappable: is_wrappable,
cross_reverse: cross_reverse
cross_reverse: cross_reverse,
}
}
@ -414,7 +442,10 @@ impl FlexFlow {
let kid = children.get(item.index);
item.init_sizes(kid, container_size, 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;
}
margin_count += item.auto_margin_count(kid, self.main_mode);
@ -439,7 +470,8 @@ impl FlexFlow {
if !fixed_width {
for kid in self.block_flow.base.children.iter_mut() {
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 {
let flex_item_inline_sizes = IntrinsicISizes {
minimum_inline_size: base.intrinsic_inline_sizes.minimum_inline_size,
@ -465,15 +497,18 @@ impl FlexFlow {
if !fixed_width {
for kid in self.block_flow.base.children.iter_mut() {
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 {
computation.content_intrinsic_sizes.minimum_inline_size =
max(computation.content_intrinsic_sizes.minimum_inline_size,
base.intrinsic_inline_sizes.minimum_inline_size);
computation.content_intrinsic_sizes.minimum_inline_size = max(
computation.content_intrinsic_sizes.minimum_inline_size,
base.intrinsic_inline_sizes.minimum_inline_size,
);
computation.content_intrinsic_sizes.preferred_inline_size =
max(computation.content_intrinsic_sizes.preferred_inline_size,
base.intrinsic_inline_sizes.preferred_inline_size);
computation.content_intrinsic_sizes.preferred_inline_size = max(
computation.content_intrinsic_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.
// Currently, this is the core of BlockFlow::propagate_assigned_inline_size_to_children() with
// all float and table logic stripped out.
fn block_mode_assign_inline_sizes(&mut self,
_layout_context: &LayoutContext,
inline_start_content_edge: Au,
inline_end_content_edge: Au,
content_inline_size: Au) {
fn block_mode_assign_inline_sizes(
&mut self,
_layout_context: &LayoutContext,
inline_start_content_edge: Au,
inline_end_content_edge: Au,
content_inline_size: Au,
) {
let _scope = layout_debug_scope!("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 {
AxisSize::Definite(length) => Some(length),
_ => None
_ => None,
};
let container_inline_size = match self.available_cross_size {
AxisSize::Definite(length) => length,
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();
for kid in &mut self.items {
let kid_base = children.get(kid.index).mut_base();
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
// edge, and its inline-size is our content inline-size.
kid_base.position.start.i =
@ -525,11 +565,13 @@ impl FlexFlow {
}
}
fn inline_mode_assign_inline_sizes(&mut self,
layout_context: &LayoutContext,
inline_start_content_edge: Au,
_inline_end_content_edge: Au,
content_inline_size: Au) {
fn inline_mode_assign_inline_sizes(
&mut self,
layout_context: &LayoutContext,
inline_start_content_edge: Au,
_inline_end_content_edge: Au,
content_inline_size: Au,
) {
let _scope = layout_debug_scope!("flex::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;
// 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 =
self.block_flow.explicit_block_containing_size(layout_context.shared_context());
let parent_container_size = self
.block_flow
.explicit_block_containing_size(layout_context.shared_context());
// https://drafts.csswg.org/css-ui-3/#box-sizing
let explicit_content_size = self
.block_flow
.explicit_block_size(parent_container_size)
.map(|x| max(x - box_border, Au(0)));
let containing_block_text_align =
self.block_flow.fragment.style().get_inherited_text().text_align;
.block_flow
.explicit_block_size(parent_container_size)
.map(|x| max(x - box_border, Au(0)));
let containing_block_text_align = self
.block_flow
.fragment
.style()
.get_inherited_text()
.text_align;
while let Some(mut line) = self.get_flex_line(inline_size) {
let items = &mut self.items[line.range.clone()];
@ -572,32 +622,42 @@ impl FlexFlow {
let item_count = items.len() as i32;
let mut cur_i = inline_start_content_edge;
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 => {
if item_count == 1 {
Au(0)
} else {
line.free_space / (item_count - 1)
}
}
JustifyContent::SpaceAround => {
line.free_space / item_count
}
},
JustifyContent::SpaceAround => line.free_space / item_count,
_ => Au(0),
}
} else {
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.
JustifyContent::Center | JustifyContent::SpaceAround => {
cur_i += (line.free_space - item_interval * (item_count - 1)) / 2;
}
},
JustifyContent::FlexEnd => {
cur_i += line.free_space;
}
_ => {}
},
_ => {},
}
let mut children = self.block_flow.base.children.random_access_mut();
@ -613,19 +673,18 @@ impl FlexFlow {
block.base.flags.set_text_align(containing_block_text_align);
let margin = block.fragment.style().logical_margin();
let auto_len =
if line.auto_margin_count == 0 || line.free_space <= Au(0) {
Au(0)
} else {
line.free_space / line.auto_margin_count
};
let auto_len = if line.auto_margin_count == 0 || line.free_space <= Au(0) {
Au(0)
} else {
line.free_space / line.auto_margin_count
};
let margin_inline_start = MaybeAuto::from_style(margin.inline_start, inline_size)
.specified_or_default(auto_len);
let margin_inline_end = MaybeAuto::from_style(margin.inline_end, inline_size)
.specified_or_default(auto_len);
let item_inline_size = item.main_size
- block.fragment.box_sizing_boundary(self.main_mode)
+ block.fragment.border_padding.inline_start_end();
let item_inline_size = item.main_size -
block.fragment.box_sizing_boundary(self.main_mode) +
block.fragment.border_padding.inline_start_end();
let item_outer_size = item_inline_size + block.fragment.margin.inline_start_end();
block.fragment.margin.inline_start = margin_inline_start;
@ -635,7 +694,7 @@ impl FlexFlow {
block.base.position.start.i = if !self.main_reverse {
cur_i
} else {
inline_start_content_edge * 2 + content_inline_size - cur_i - item_outer_size
inline_start_content_edge * 2 + content_inline_size - cur_i - item_outer_size
};
block.base.position.size.inline = item_outer_size;
cur_i += item_outer_size + item_interval;
@ -669,7 +728,12 @@ impl FlexFlow {
let _scope = layout_debug_scope!("flex::inline_mode_assign_block_size");
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 total_cross_size = Au(0);
let mut line_interval = Au(0);
@ -679,22 +743,27 @@ impl FlexFlow {
for line in self.lines.iter_mut() {
for item in &self.items[line.range.clone()] {
let fragment = &children.get(item.index).as_block().fragment;
line.cross_size = max(line.cross_size,
fragment.border_box.size.block +
fragment.margin.block_start_end());
line.cross_size = max(
line.cross_size,
fragment.border_box.size.block + fragment.margin.block_start_end(),
);
}
total_cross_size += line.cross_size;
}
}
let box_border = self.block_flow.fragment.box_sizing_boundary(Direction::Block);
let parent_container_size =
self.block_flow.explicit_block_containing_size(layout_context.shared_context());
let box_border = self
.block_flow
.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
let explicit_content_size = self
.block_flow
.explicit_block_size(parent_container_size)
.map(|x| max(x - box_border, Au(0)));
.block_flow
.explicit_block_size(parent_container_size)
.map(|x| max(x - box_border, Au(0)));
if let Some(container_block_size) = explicit_content_size {
let free_space = container_block_size - total_cross_size;
@ -713,25 +782,25 @@ impl FlexFlow {
} else {
free_space / (line_count - 1)
}
}
},
AlignContent::SpaceAround => {
if line_count == 0 {
Au(0)
} else {
free_space / line_count
}
}
},
_ => Au(0),
};
match line_align {
AlignContent::Center | AlignContent::SpaceAround => {
cur_b += (free_space - line_interval * (line_count - 1)) / 2;
}
},
AlignContent::FlexEnd => {
cur_b += free_space;
}
_ => {}
},
_ => {},
}
}
@ -744,8 +813,9 @@ impl FlexFlow {
let mut margin_block_start = block.fragment.margin.block_start;
let mut margin_block_end = block.fragment.margin.block_end;
let mut free_space = line.cross_size - block.base.position.size.block
- block.fragment.margin.block_start_end();
let mut free_space = line.cross_size -
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
// cross size of item should equal to the line size if any auto margin exists.
@ -758,29 +828,31 @@ impl FlexFlow {
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);
}
let self_align = block.fragment.style().get_position().align_self;
if self_align == AlignSelf::Stretch &&
block.fragment.style().content_block_size() == LengthOrPercentageOrAuto::Auto {
free_space = Au(0);
block.base.block_container_explicit_block_size = Some(line.cross_size);
block.base.position.size.block =
line.cross_size - margin_block_start - margin_block_end;
block.fragment.border_box.size.block = block.base.position.size.block;
// FIXME(stshine): item with 'align-self: stretch' and auto cross size should act
// as if it has a fixed cross size, all child blocks should resolve against it.
// block.assign_block_size(layout_context);
}
block.base.position.start.b = margin_block_start +
if !self.cross_reverse {
cur_b
} else {
self.block_flow.fragment.border_padding.block_start * 2
+ total_cross_size - cur_b - line.cross_size
};
block.fragment.style().content_block_size() == LengthOrPercentageOrAuto::Auto
{
free_space = Au(0);
block.base.block_container_explicit_block_size = Some(line.cross_size);
block.base.position.size.block =
line.cross_size - margin_block_start - margin_block_end;
block.fragment.border_box.size.block = block.base.position.size.block;
// FIXME(stshine): item with 'align-self: stretch' and auto cross size should act
// as if it has a fixed cross size, all child blocks should resolve against it.
// block.assign_block_size(layout_context);
}
block.base.position.start.b = margin_block_start + if !self.cross_reverse {
cur_b
} else {
self.block_flow.fragment.border_padding.block_start * 2 + total_cross_size -
cur_b -
line.cross_size
};
// TODO(stshine): support baseline alignment.
if free_space != Au(0) {
let flex_cross = match self_align {
@ -788,17 +860,17 @@ impl FlexFlow {
AlignSelf::Center => free_space / 2,
_ => Au(0),
};
block.base.position.start.b +=
if !self.cross_reverse {
flex_cross
} else {
free_space - flex_cross
};
block.base.position.start.b += if !self.cross_reverse {
flex_cross
} else {
free_space - flex_cross
};
}
}
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.base.position.size.block = total_block_size;
}
@ -830,72 +902,96 @@ impl Flow for FlexFlow {
}
fn bubble_inline_sizes(&mut self) {
let _scope = layout_debug_scope!("flex::bubble_inline_sizes {:x}",
self.block_flow.base.debug_id());
let _scope = layout_debug_scope!(
"flex::bubble_inline_sizes {:x}",
self.block_flow.base.debug_id()
);
// Flexbox Section 9.0: Generate anonymous flex items:
// This part was handled in the flow constructor.
// Flexbox Section 9.1: Re-order flex items according to their order.
// FIXME(stshine): This should be done during flow construction.
let mut items: Vec<FlexItem> =
self.block_flow
.base
.children
.iter()
.enumerate()
.filter(|&(_, flow)| {
!flow.as_block().base.flags.contains(FlowFlags::IS_ABSOLUTELY_POSITIONED)
})
.map(|(index, flow)| FlexItem::new(index, flow))
.collect();
let mut items: Vec<FlexItem> = self
.block_flow
.base
.children
.iter()
.enumerate()
.filter(|&(_, flow)| {
!flow
.as_block()
.base
.flags
.contains(FlowFlags::IS_ABSOLUTELY_POSITIONED)
}).map(|(index, flow)| FlexItem::new(index, flow))
.collect();
items.sort_by_key(|item| item.order);
self.items = items;
match self.main_mode {
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) {
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");
if !self.block_flow.base.restyle_damage.intersects(ServoRestyleDamage::REFLOW_OUT_OF_FLOW |
ServoRestyleDamage::REFLOW) {
return
if !self
.block_flow
.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.
// Now compute the real value.
let containing_block_inline_size = self.block_flow.base.block_container_inline_size;
self.block_flow.compute_used_inline_size(layout_context.shared_context(),
containing_block_inline_size);
self.block_flow.compute_used_inline_size(
layout_context.shared_context(),
containing_block_inline_size,
);
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 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)
} else {
(style.get_position().height, style.get_position().width)
};
let available_inline_size = AxisSize::new(specified_inline_size,
Some(self.block_flow.base.block_container_inline_size),
style.min_inline_size(),
style.max_inline_size());
let available_inline_size = AxisSize::new(
specified_inline_size,
Some(self.block_flow.base.block_container_inline_size),
style.min_inline_size(),
style.max_inline_size(),
);
let available_block_size = AxisSize::new(specified_block_size,
self.block_flow.base.block_container_explicit_block_size,
style.min_block_size(),
style.max_block_size());
let available_block_size = AxisSize::new(
specified_block_size,
self.block_flow.base.block_container_explicit_block_size,
style.min_block_size(),
style.max_block_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 +
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();
// Distance from the inline-end margin edge to the inline-end content edge.
let inline_end_content_edge =
self.block_flow.fragment.margin.inline_end +
let inline_end_content_edge = self.block_flow.fragment.margin.inline_end +
self.block_flow.fragment.border_padding.inline_end;
debug!("padding_and_borders = {:?}", padding_and_borders);
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;
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;
match self.main_mode {
Direction::Inline => {
self.available_main_size = available_inline_size;
self.available_cross_size = available_block_size;
self.inline_mode_assign_inline_sizes(layout_context,
inline_start_content_edge,
inline_end_content_edge,
content_inline_size)
}
Direction::Block => {
self.inline_mode_assign_inline_sizes(
layout_context,
inline_start_content_edge,
inline_end_content_edge,
content_inline_size,
)
},
Direction::Block => {
self.available_main_size = available_block_size;
self.available_cross_size = available_inline_size;
self.block_mode_assign_inline_sizes(layout_context,
inline_start_content_edge,
inline_end_content_edge,
content_inline_size)
}
self.block_mode_assign_inline_sizes(
layout_context,
inline_start_content_edge,
inline_end_content_edge,
content_inline_size,
)
},
}
}
@ -941,31 +1046,37 @@ impl Flow for FlexFlow {
match self.main_mode {
Direction::Inline => {
self.inline_mode_assign_block_size(layout_context);
let block_start = AdjoiningMargins::from_margin(self.block_flow.fragment.margin.block_start);
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);
let block_start =
AdjoiningMargins::from_margin(self.block_flow.fragment.margin.block_start);
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.
if (&*self as &Flow).contains_roots_of_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
// 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);
}
}
Direction::Block =>{
self.block_flow
.assign_block_size_block_base(layout_context,
None,
MarginsMayCollapseFlag::MarginsMayNotCollapse);
},
Direction::Block => {
self.block_flow.assign_block_size_block_base(
layout_context,
None,
MarginsMayCollapseFlag::MarginsMayNotCollapse,
);
self.block_mode_assign_block_size();
}
},
}
}
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) {
@ -973,11 +1084,13 @@ impl Flow for FlexFlow {
}
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) {
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) {
@ -1008,11 +1121,17 @@ impl Flow for FlexFlow {
self.block_flow.generated_containing_block_size(flow)
}
fn iterate_through_fragment_border_boxes(&self,
iterator: &mut FragmentBorderBoxIterator,
level: i32,
stacking_context_position: &Point2D<Au>) {
self.block_flow.iterate_through_fragment_border_boxes(iterator, level, stacking_context_position);
fn iterate_through_fragment_border_boxes(
&self,
iterator: &mut FragmentBorderBoxIterator,
level: i32,
stacking_context_position: &Point2D<Au>,
) {
self.block_flow.iterate_through_fragment_border_boxes(
iterator,
level,
stacking_context_position,
);
}
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)]
pub enum FloatKind {
Left,
Right
Right,
}
impl FloatKind {
@ -78,7 +78,12 @@ impl FloatList {
impl fmt::Debug for FloatList {
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() {
write!(f, " {:?}", float)?;
}
@ -95,22 +100,29 @@ pub struct PlacementInfo {
/// The maximum inline-end position of the float, generally determined by the containing block.
pub max_inline_size: Au,
/// The kind of float.
pub kind: FloatKind
pub kind: FloatKind,
}
impl fmt::Debug for PlacementInfo {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f,
"size={:?} ceiling={:?} max_inline_size={:?} kind={:?}",
self.size,
self.ceiling,
self.max_inline_size,
self.kind)
write!(
f,
"size={:?} ceiling={:?} max_inline_size={:?} kind={:?}",
self.size, 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) {
(max(block_start_1, block_start_2), min(block_end_1, block_end_2))
fn range_intersect(
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
@ -162,8 +174,12 @@ impl Floats {
/// 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.)
pub fn available_rect(&self, block_start: Au, block_size: Au, max_x: Au)
-> Option<LogicalRect<Au>> {
pub fn available_rect(
&self,
block_start: Au,
block_size: Au,
max_x: Au,
) -> Option<LogicalRect<Au>> {
let list = &self.list;
let block_start = block_start - self.offset.block;
@ -186,30 +202,38 @@ impl Floats {
debug!("float_pos: {:?}, float_size: {:?}", float_pos, float_size);
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 < block_start + block_size => {
float_pos.b < block_start + block_size =>
{
max_inline_start = float_pos.i + float_size.inline;
l_block_start = Some(float_pos.b);
l_block_end = Some(float_pos.b + float_size.block);
debug!("available_rect: collision with inline_start float: new \
max_inline_start is {:?}",
max_inline_start);
debug!(
"available_rect: collision with inline_start float: new \
max_inline_start is {:?}",
max_inline_start
);
}
FloatKind::Right if float_pos.i < min_inline_end &&
float_pos.b + float_size.block > block_start &&
float_pos.b < block_start + block_size => {
FloatKind::Right
if float_pos.i < min_inline_end &&
float_pos.b + float_size.block > block_start &&
float_pos.b < block_start + block_size =>
{
min_inline_end = float_pos.i;
r_block_start = Some(float_pos.b);
r_block_end = Some(float_pos.b + float_size.block);
debug!("available_rect: collision with inline_end float: new min_inline_end \
is {:?}",
min_inline_end);
debug!(
"available_rect: collision with inline_end float: new min_inline_end \
is {:?}",
min_inline_end
);
}
FloatKind::Left | FloatKind::Right => {}
FloatKind::Left | FloatKind::Right => {},
}
}
@ -217,25 +241,28 @@ impl Floats {
// 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
// given upper bound.
let (block_start, block_end) = match (r_block_start,
r_block_end,
l_block_start,
l_block_end) {
(Some(r_block_start), Some(r_block_end), Some(l_block_start), Some(l_block_end)) => {
range_intersect(max(block_start, r_block_start),
r_block_end,
max(block_start, l_block_start),
l_block_end)
}
(None, None, Some(l_block_start), Some(l_block_end)) => {
(max(block_start, l_block_start), l_block_end)
}
(Some(r_block_start), Some(r_block_end), None, None) => {
(max(block_start, r_block_start), r_block_end)
}
(None, None, None, None) => return None,
_ => panic!("Reached unreachable state when computing float area")
};
let (block_start, block_end) =
match (r_block_start, r_block_end, l_block_start, l_block_end) {
(
Some(r_block_start),
Some(r_block_end),
Some(l_block_start),
Some(l_block_end),
) => range_intersect(
max(block_start, r_block_start),
r_block_end,
max(block_start, l_block_start),
l_block_end,
),
(None, None, Some(l_block_start), Some(l_block_end)) => {
(max(block_start, l_block_start), l_block_end)
},
(Some(r_block_start), Some(r_block_end), None, None) => {
(max(block_start, r_block_start), r_block_end)
},
(None, None, None, None) => return None,
_ => panic!("Reached unreachable state when computing float area"),
};
// FIXME(eatkinson): This assertion is too strong and fails in some cases. It is OK to
// return negative inline-sizes since we check against that inline-end away, but we should
@ -244,11 +271,13 @@ impl Floats {
assert!(block_start <= block_end, "Float position error");
Some(LogicalRect::new(self.writing_mode,
max_inline_start + self.offset.inline,
block_start + self.offset.block,
min_inline_end - max_inline_start,
block_end - block_start))
Some(LogicalRect::new(
self.writing_mode,
max_inline_start + self.offset.inline,
block_start + self.offset.block,
min_inline_end - max_inline_start,
block_end - block_start,
))
}
/// 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),
},
max_inline_size: info.max_inline_size,
kind: info.kind
kind: info.kind,
};
debug!("add_float: added float with info {:?}", new_info);
@ -271,7 +300,7 @@ impl Floats {
self.place_between_floats(&new_info).start - self.offset,
info.size,
),
kind: info.kind
kind: info.kind,
};
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
/// largest block-size that will result in the rectangle not colliding with any floats. Returns
/// `None` if that block-size is infinite.
fn max_block_size_for_bounds(&self, inline_start: Au, block_start: Au, inline_size: Au)
-> Option<Au> {
fn max_block_size_for_bounds(
&self,
inline_start: Au,
block_start: Au,
inline_size: Au,
) -> Option<Au> {
let list = &self.list;
let block_start = block_start - self.offset.block;
@ -294,10 +327,11 @@ impl Floats {
for float in list.floats.iter() {
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 < inline_start + inline_size {
let new_y = float.bounds.start.b;
max_block_size = Some(min(max_block_size.unwrap_or(new_y), new_y));
float.bounds.start.i + float.bounds.size.inline > inline_start &&
float.bounds.start.i < inline_start + inline_size
{
let new_y = float.bounds.start.b;
max_block_size = Some(min(max_block_size.unwrap_or(new_y), new_y));
}
}
@ -318,85 +352,88 @@ impl Floats {
Au(0),
info.ceiling,
info.max_inline_size,
MAX_AU)
}
MAX_AU,
)
},
FloatKind::Right => {
return LogicalRect::new(
self.writing_mode,
info.max_inline_size - info.size.inline,
info.ceiling,
info.max_inline_size,
MAX_AU)
}
MAX_AU,
)
},
}
}
// Can't go any higher than previous floats or previous elements in the document.
let mut float_b = info.ceiling;
loop {
let maybe_location = self.available_rect(float_b,
info.size.block,
info.max_inline_size);
debug!("place_float: got available rect: {:?} for block-pos: {:?}",
maybe_location,
float_b);
let maybe_location =
self.available_rect(float_b, info.size.block, info.max_inline_size);
debug!(
"place_float: got available rect: {:?} for block-pos: {:?}",
maybe_location, float_b
);
match maybe_location {
// If there are no floats blocking us, return the current location
// TODO(eatkinson): integrate with overflow
None => {
return match info.kind {
FloatKind::Left => {
LogicalRect::new(
self.writing_mode,
Au(0),
float_b,
info.max_inline_size,
MAX_AU)
}
FloatKind::Right => {
LogicalRect::new(
self.writing_mode,
info.max_inline_size - info.size.inline,
float_b,
info.max_inline_size,
MAX_AU)
}
FloatKind::Left => LogicalRect::new(
self.writing_mode,
Au(0),
float_b,
info.max_inline_size,
MAX_AU,
),
FloatKind::Right => LogicalRect::new(
self.writing_mode,
info.max_inline_size - info.size.inline,
float_b,
info.max_inline_size,
MAX_AU,
),
}
}
},
Some(rect) => {
assert_ne!(rect.start.b + rect.size.block, float_b,
"Non-terminating float placement");
assert_ne!(
rect.start.b + rect.size.block,
float_b,
"Non-terminating float placement"
);
// Place here if there is enough room
if rect.size.inline >= info.size.inline {
let block_size = self.max_block_size_for_bounds(rect.start.i,
rect.start.b,
rect.size.inline);
let block_size = self.max_block_size_for_bounds(
rect.start.i,
rect.start.b,
rect.size.inline,
);
let block_size = block_size.unwrap_or(MAX_AU);
return match info.kind {
FloatKind::Left => {
LogicalRect::new(
self.writing_mode,
rect.start.i,
float_b,
rect.size.inline,
block_size)
}
FloatKind::Right => {
LogicalRect::new(
self.writing_mode,
rect.start.i + rect.size.inline - info.size.inline,
float_b,
rect.size.inline,
block_size)
}
}
FloatKind::Left => LogicalRect::new(
self.writing_mode,
rect.start.i,
float_b,
rect.size.inline,
block_size,
),
FloatKind::Right => LogicalRect::new(
self.writing_mode,
rect.start.i + rect.size.inline - info.size.inline,
float_b,
rect.size.inline,
block_size,
),
};
}
// Try to place at the next-lowest location.
// Need to be careful of fencepost errors.
float_b = rect.start.b + rect.size.block;
}
},
}
}
}
@ -411,8 +448,8 @@ impl Floats {
(ClearType::Both, _) => {
let b = self.offset.block + float.bounds.start.b + float.bounds.size.block;
clearance = max(clearance, b);
}
_ => {}
},
_ => {},
}
}
clearance
@ -486,14 +523,20 @@ impl SpeculatedFloatPlacement {
}
}
self.left = max(self.left, block_flow.base.speculated_float_placement_in.left);
self.right = max(self.right, block_flow.base.speculated_float_placement_in.right);
self.left = max(
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();
if !base_flow.flags.is_float() {
return
return;
}
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
// might flow around this float.
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 {
float_inline_size = Au::from_px(1)
}
@ -513,7 +557,7 @@ impl SpeculatedFloatPlacement {
}
match base_flow.flags.float_kind() {
StyleFloat::None => {}
StyleFloat::None => {},
StyleFloat::Left => self.left = self.left + 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.
pub fn compute_floats_in_for_first_child(parent_flow: &mut Flow) -> SpeculatedFloatPlacement {
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();
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 speculated_inline_content_edge_offsets =
parent_block_flow.fragment.guess_inline_content_edge_offsets();
let speculated_inline_content_edge_offsets = parent_block_flow
.fragment
.guess_inline_content_edge_offsets();
if speculated_inline_content_edge_offsets.start > Au(0) {
placement.left = if placement.left > speculated_inline_content_edge_offsets.start {
@ -552,4 +597,3 @@ impl SpeculatedFloatPlacement {
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.
///
/// The default is to make a flow "atomic": it can not be fragmented.
fn fragment(&mut self,
layout_context: &LayoutContext,
_fragmentation_context: Option<FragmentationContext>)
-> Option<Arc<Flow>> {
fn recursive_assign_block_size<F: ?Sized + Flow + GetBaseFlow>(flow: &mut F, ctx: &LayoutContext) {
fn fragment(
&mut self,
layout_context: &LayoutContext,
_fragmentation_context: Option<FragmentationContext>,
) -> Option<Arc<Flow>> {
fn recursive_assign_block_size<F: ?Sized + Flow + GetBaseFlow>(
flow: &mut F,
ctx: &LayoutContext,
) {
for child in flow.mut_base().child_iter_mut() {
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
/// debug mode; if the block size of this flow was determined by its parent, we should treat
/// it as laid out by its parent.
fn assign_block_size_for_inorder_child_if_necessary(&mut self,
layout_context: &LayoutContext,
parent_thread_id: u8,
_content_box: LogicalRect<Au>)
-> bool {
let might_have_floats_in_or_out = self.base().might_have_floats_in() ||
self.base().might_have_floats_out();
fn assign_block_size_for_inorder_child_if_necessary(
&mut self,
layout_context: &LayoutContext,
parent_thread_id: u8,
_content_box: LogicalRect<Au>,
) -> bool {
let might_have_floats_in_or_out =
self.base().might_have_floats_in() || self.base().might_have_floats_out();
if might_have_floats_in_or_out {
self.mut_base().thread_id = parent_thread_id;
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
}
@ -295,23 +302,32 @@ pub trait Flow: HasBaseFlow + fmt::Debug + Sync + Send + 'static {
fn get_overflow_in_parent_coordinates(&self) -> Overflow {
// FIXME(#2795): Get the real container size.
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;
match self.class() {
FlowClass::Block | FlowClass::TableCaption | FlowClass::TableCell => {}
FlowClass::Block | FlowClass::TableCaption | FlowClass::TableCell => {},
_ => {
overflow.translate(&position.origin.to_vector());
return overflow;
}
},
}
let border_box = self.as_block().fragment.stacking_relative_border_box(
&self.base().stacking_relative_position,
&self.base().early_absolute_position_info.relative_containing_block_size,
self.base().early_absolute_position_info.relative_containing_block_mode,
CoordinateSystem::Own);
&self
.base()
.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 {
overflow.paint.origin.x = Au(0);
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;
}
if !self.as_block().fragment.establishes_stacking_context() ||
self.as_block().fragment.style.get_box().transform.0.is_empty() {
if !self.as_block().fragment.establishes_stacking_context() || self
.as_block()
.fragment
.style
.get_box()
.transform
.0
.is_empty()
{
overflow.translate(&position.origin.to_vector());
return overflow;
}
// TODO: Take into account 3d transforms, even though it's a fairly
// uncommon case.
let transform_2d = self.as_block()
.fragment
.transform_matrix(&position)
.unwrap_or(LayoutTransform::identity())
.to_2d().to_untyped();
let transform_2d = self
.as_block()
.fragment
.transform_matrix(&position)
.unwrap_or(LayoutTransform::identity())
.to_2d()
.to_untyped();
let transformed_overflow = Overflow {
paint: f32_rect_to_au_rect(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))),
paint: f32_rect_to_au_rect(
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)),
),
};
// 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.
let mut overflow = self.compute_overflow();
match self.class() {
FlowClass::Block |
FlowClass::TableCaption |
FlowClass::TableCell => {
FlowClass::Block | FlowClass::TableCaption | FlowClass::TableCell => {
for kid in self.mut_base().children.iter_mut() {
overflow.union(&kid.get_overflow_in_parent_coordinates());
}
}
_ => {}
},
_ => {},
}
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.
/// Level provides a zero based index indicating the current
/// depth of the flow tree during fragment iteration.
fn iterate_through_fragment_border_boxes(&self,
iterator: &mut FragmentBorderBoxIterator,
level: i32,
stacking_context_position: &Point2D<Au>);
fn iterate_through_fragment_border_boxes(
&self,
iterator: &mut FragmentBorderBoxIterator,
level: i32,
stacking_context_position: &Point2D<Au>,
);
/// Mutably iterates through fragments in this flow.
fn mutate_fragments(&mut self, mutator: &mut FnMut(&mut Fragment));
fn compute_collapsible_block_start_margin(&mut self,
_layout_context: &mut LayoutContext,
_margin_collapse_info: &mut MarginCollapseInfo) {
fn compute_collapsible_block_start_margin(
&mut self,
_layout_context: &mut LayoutContext,
_margin_collapse_info: &mut MarginCollapseInfo,
) {
// 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 {
self.contains_relatively_positioned_fragments() ||
self.base().flags.contains(FlowFlags::IS_ABSOLUTELY_POSITIONED)
self.contains_relatively_positioned_fragments() || self
.base()
.flags
.contains(FlowFlags::IS_ABSOLUTELY_POSITIONED)
}
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
/// for debugging purposes. Any items inserted into the tree will become
/// 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 {
match self.base().clipping_and_scrolling {
@ -566,8 +597,10 @@ pub trait MutableOwnedFlowUtils {
/// </span>
/// </div>
/// ```
fn take_applicable_absolute_descendants(&mut self,
absolute_descendants: &mut AbsoluteDescendants);
fn take_applicable_absolute_descendants(
&mut self,
absolute_descendants: &mut AbsoluteDescendants,
);
}
#[derive(Clone, Copy, Debug, PartialEq, Serialize)]
@ -590,9 +623,15 @@ pub enum FlowClass {
impl FlowClass {
fn is_block_like(self) -> bool {
match self {
FlowClass::Block | FlowClass::ListItem | FlowClass::Table | FlowClass::TableRowGroup |
FlowClass::TableRow | FlowClass::TableCaption | FlowClass::TableCell |
FlowClass::TableWrapper | FlowClass::Flex => true,
FlowClass::Block |
FlowClass::ListItem |
FlowClass::Table |
FlowClass::TableRowGroup |
FlowClass::TableRow |
FlowClass::TableCaption |
FlowClass::TableCell |
FlowClass::TableWrapper |
FlowClass::Flex => true,
_ => false,
}
}
@ -663,7 +702,7 @@ impl FlowFlags {
#[inline]
pub fn set_text_align(&mut self, value: TextAlign) {
*self = (*self & !FlowFlags::TEXT_ALIGN) |
FlowFlags::from_bits((value as u32) << TEXT_ALIGN_SHIFT).unwrap();
FlowFlags::from_bits((value as u32) << TEXT_ALIGN_SHIFT).unwrap();
}
#[inline]
@ -776,7 +815,9 @@ pub struct AbsoluteDescendantIter<'a> {
impl<'a> Iterator for AbsoluteDescendantIter<'a> {
type Item = &'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>) {
@ -953,22 +994,32 @@ impl fmt::Debug for BaseFlow {
"".to_owned()
};
write!(f,
"\nsc={:?}\
\npos={:?}{}{}\
\nfloatspec-in={:?}\
\nfloatspec-out={:?}\
\noverflow={:?}{}{}{}",
self.stacking_context_id,
self.position,
if self.flags.contains(FlowFlags::FLOATS_LEFT) { "FL" } else { "" },
if self.flags.contains(FlowFlags::FLOATS_RIGHT) { "FR" } else { "" },
self.speculated_float_placement_in,
self.speculated_float_placement_out,
self.overflow,
child_count_string,
absolute_descendants_string,
damage_string)
write!(
f,
"\nsc={:?}\
\npos={:?}{}{}\
\nfloatspec-in={:?}\
\nfloatspec-out={:?}\
\noverflow={:?}{}{}{}",
self.stacking_context_id,
self.position,
if self.flags.contains(FlowFlags::FLOATS_LEFT) {
"FL"
} else {
""
},
if self.flags.contains(FlowFlags::FLOATS_RIGHT) {
"FR"
} else {
""
},
self.speculated_float_placement_in,
self.speculated_float_placement_out,
self.overflow,
child_count_string,
absolute_descendants_string,
damage_string
)
}
}
@ -976,7 +1027,10 @@ impl Serialize for BaseFlow {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let mut serializer = serializer.serialize_struct("base", 5)?;
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("position", &self.position)?;
serializer.serialize_field("children", &self.children)?;
@ -996,10 +1050,11 @@ pub enum ForceNonfloatedFlag {
impl BaseFlow {
#[inline]
pub fn new(style: Option<&ComputedValues>,
writing_mode: WritingMode,
force_nonfloated: ForceNonfloatedFlag)
-> BaseFlow {
pub fn new(
style: Option<&ComputedValues>,
writing_mode: WritingMode,
force_nonfloated: ForceNonfloatedFlag,
) -> BaseFlow {
let mut flags = FlowFlags::empty();
match style {
Some(style) => {
@ -1013,41 +1068,47 @@ impl BaseFlow {
let logical_position = style.logical_position();
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);
}
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 | FlowFlags::INLINE_POSITION_IS_STATIC),
},
_ => flags.insert(
FlowFlags::BLOCK_POSITION_IS_STATIC | FlowFlags::INLINE_POSITION_IS_STATIC,
),
}
if force_nonfloated == ForceNonfloatedFlag::FloatIfNecessary {
match style.get_box().float {
Float::None => {}
Float::None => {},
Float::Left => flags.insert(FlowFlags::FLOATS_LEFT),
Float::Right => flags.insert(FlowFlags::FLOATS_RIGHT),
}
}
match style.get_box().clear {
Clear::None => {}
Clear::None => {},
Clear::Left => flags.insert(FlowFlags::CLEARS_LEFT),
Clear::Right => flags.insert(FlowFlags::CLEARS_RIGHT),
Clear::Both => {
flags.insert(FlowFlags::CLEARS_LEFT);
flags.insert(FlowFlags::CLEARS_RIGHT);
}
},
}
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)
}
}
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.
@ -1089,17 +1150,24 @@ impl BaseFlow {
pub fn update_flags_if_needed(&mut self, style: &ComputedValues) {
// For absolutely-positioned flows, changes to top/bottom/left/right can cause these flags
// 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
// changes to the 'position' property trigger flow reconstruction.
if self.flags.contains(FlowFlags::IS_ABSOLUTELY_POSITIONED) {
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_end == LengthOrPercentageOrAuto::Auto);
self.flags.set(FlowFlags::BLOCK_POSITION_IS_STATIC,
logical_position.inline_end == LengthOrPercentageOrAuto::Auto,
);
self.flags.set(
FlowFlags::BLOCK_POSITION_IS_STATIC,
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 {
BaseFlow {
children: children,
restyle_damage: self.restyle_damage | ServoRestyleDamage::REPAINT |
ServoRestyleDamage::REFLOW_OUT_OF_FLOW | ServoRestyleDamage::REFLOW,
restyle_damage: self.restyle_damage |
ServoRestyleDamage::REPAINT |
ServoRestyleDamage::REFLOW_OUT_OF_FLOW |
ServoRestyleDamage::REFLOW,
parallel: FlowParallelInfo::new(),
floats: self.floats.clone(),
abs_descendants: self.abs_descendants.clone(),
@ -1138,8 +1208,10 @@ impl BaseFlow {
return self as *const BaseFlow as usize;
}
pub fn collect_stacking_contexts_for_children(&mut self,
state: &mut StackingContextCollectionState) {
pub fn collect_stacking_contexts_for_children(
&mut self,
state: &mut StackingContextCollectionState,
) {
for kid in self.children.iter_mut() {
kid.collect_stacking_contexts(state);
}
@ -1157,15 +1229,17 @@ impl BaseFlow {
self.speculated_float_placement_out.right > Au(0)
}
/// 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)
/// for the purposes of this computation.
pub fn stacking_relative_border_box_for_display_list(&self, fragment: &Fragment) -> Rect<Au> {
fragment.stacking_relative_border_box(
&self.stacking_relative_position,
&self.early_absolute_position_info.relative_containing_block_size,
self.early_absolute_position_info.relative_containing_block_mode,
&self
.early_absolute_position_info
.relative_containing_block_size,
self.early_absolute_position_info
.relative_containing_block_mode,
CoordinateSystem::Own,
)
}
@ -1182,8 +1256,10 @@ impl<'a> ImmutableFlowUtils for &'a Flow {
/// table-column-group flow, or table-caption flow.
fn is_proper_table_child(self) -> bool {
match self.class() {
FlowClass::TableRow | FlowClass::TableRowGroup |
FlowClass::TableColGroup | FlowClass::TableCaption => true,
FlowClass::TableRow |
FlowClass::TableRowGroup |
FlowClass::TableColGroup |
FlowClass::TableCaption => true,
_ => false,
}
}
@ -1239,9 +1315,13 @@ impl<'a> ImmutableFlowUtils for &'a Flow {
/// Returns true if this flow is one of table-related flows.
fn is_table_kind(self) -> bool {
match self.class() {
FlowClass::TableWrapper | FlowClass::Table |
FlowClass::TableColGroup | FlowClass::TableRowGroup |
FlowClass::TableRow | FlowClass::TableCaption | FlowClass::TableCell => true,
FlowClass::TableWrapper |
FlowClass::Table |
FlowClass::TableColGroup |
FlowClass::TableRowGroup |
FlowClass::TableRow |
FlowClass::TableCaption |
FlowClass::TableCell => true,
_ => false,
}
}
@ -1268,7 +1348,7 @@ impl<'a> ImmutableFlowUtils for &'a Flow {
FlowClass::Block | FlowClass::TableCaption | FlowClass::TableCell => {
// FIXME: Actually check the type of the node
self.child_count() != 0
}
},
_ => false,
}
}
@ -1307,13 +1387,13 @@ impl<'a> ImmutableFlowUtils for &'a Flow {
fn floats_might_flow_through(self) -> bool {
if !self.base().might_have_floats_in() && !self.base().might_have_floats_out() {
return false
return false;
}
if self.is_root() {
return false
return false;
}
if !self.is_block_like() {
return true
return true;
}
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() {
if kid.is_inline_flow() {
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() {
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>
/// </div>
/// ```
fn take_applicable_absolute_descendants(&mut self,
absolute_descendants: &mut AbsoluteDescendants) {
fn take_applicable_absolute_descendants(
&mut self,
absolute_descendants: &mut AbsoluteDescendants,
) {
let mut applicable_absolute_descendants = AbsoluteDescendants::new();
for absolute_descendant in absolute_descendants.descendant_links.iter() {
if absolute_descendant.has_reached_containing_block {
applicable_absolute_descendants.push(absolute_descendant.flow.clone());
}
}
absolute_descendants.descendant_links.retain(|descendant| {
!descendant.has_reached_containing_block
});
absolute_descendants
.descendant_links
.retain(|descendant| !descendant.has_reached_containing_block);
let this = self.clone();
let base = FlowRef::deref_mut(self).mut_base();
@ -1412,9 +1498,7 @@ pub struct ContainingBlockLink {
impl ContainingBlockLink {
fn new() -> ContainingBlockLink {
ContainingBlockLink {
link: None,
}
ContainingBlockLink { link: None }
}
fn set(&mut self, link: FlowRef) {
@ -1424,34 +1508,38 @@ impl ContainingBlockLink {
#[inline]
pub fn generated_containing_block_size(&self, for_flow: OpaqueFlow) -> LogicalSize<Au> {
match self.link {
None => {
panic!("Link to containing block not established; perhaps you forgot to call \
`set_absolute_descendants`?")
}
None => panic!(
"Link to containing block not established; perhaps you forgot to call \
`set_absolute_descendants`?"
),
Some(ref link) => {
let flow = link.upgrade().unwrap();
flow.generated_containing_block_size(for_flow)
}
},
}
}
#[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 {
None => {
panic!("Link to containing block not established; perhaps you forgot to call \
`set_absolute_descendants`?")
}
None => panic!(
"Link to containing block not established; perhaps you forgot to call \
`set_absolute_descendants`?"
),
Some(ref link) => {
let flow = link.upgrade().unwrap();
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() {
Some(flow.as_inline().minimum_line_metrics.space_above_baseline)
} else {
None
}
}
},
}
}
}

View file

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

View file

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

File diff suppressed because it is too large Load diff

View file

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

View file

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

View file

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

View file

@ -126,21 +126,22 @@ impl MarginCollapseInfo {
}
}
pub fn finish_and_compute_collapsible_margins(mut self,
fragment: &Fragment,
containing_block_size: Option<Au>,
can_collapse_block_end_margin_with_kids: bool,
mut may_collapse_through: bool)
-> (CollapsibleMargins, Au) {
pub fn finish_and_compute_collapsible_margins(
mut self,
fragment: &Fragment,
containing_block_size: Option<Au>,
can_collapse_block_end_margin_with_kids: bool,
mut may_collapse_through: bool,
) -> (CollapsibleMargins, Au) {
let state = match self.state {
MarginCollapseState::AccumulatingCollapsibleTopMargin => {
may_collapse_through = may_collapse_through &&
match fragment.style().content_block_size() {
may_collapse_through =
may_collapse_through && match fragment.style().content_block_size() {
LengthOrPercentageOrAuto::Auto => true,
LengthOrPercentageOrAuto::Length(l) => l.px() == 0.,
LengthOrPercentageOrAuto::Percentage(v) => {
v.0 == 0. || containing_block_size.is_none()
}
},
LengthOrPercentageOrAuto::Calc(_) => false,
};
@ -156,14 +157,14 @@ impl MarginCollapseInfo {
// If the fragment has non-zero min-block-size, margins may not
// collapse through it.
FinalMarginState::BottomMarginCollapses
}
},
}
} else {
// If the fragment has an explicitly specified block-size, margins may not
// collapse through it.
FinalMarginState::BottomMarginCollapses
}
}
},
MarginCollapseState::AccumulatingMarginIn => FinalMarginState::BottomMarginCollapses,
};
@ -174,27 +175,41 @@ impl MarginCollapseInfo {
match state {
FinalMarginState::MarginsCollapseThrough => {
let advance = self.block_start_margin.collapse();
self.margin_in.union(AdjoiningMargins::from_margin(block_end_margin));
(CollapsibleMargins::Collapse(self.block_start_margin, self.margin_in),
advance)
}
self.margin_in
.union(AdjoiningMargins::from_margin(block_end_margin));
(
CollapsibleMargins::Collapse(self.block_start_margin, self.margin_in),
advance,
)
},
FinalMarginState::BottomMarginCollapses => {
let advance = self.margin_in.collapse();
self.margin_in.union(AdjoiningMargins::from_margin(block_end_margin));
(CollapsibleMargins::Collapse(self.block_start_margin, self.margin_in),
advance)
}
self.margin_in
.union(AdjoiningMargins::from_margin(block_end_margin));
(
CollapsibleMargins::Collapse(self.block_start_margin, self.margin_in),
advance,
)
},
}
} else {
match state {
FinalMarginState::MarginsCollapseThrough => {
self.block_start_margin.union(AdjoiningMargins::from_margin(block_end_margin));
(CollapsibleMargins::CollapseThrough(self.block_start_margin), Au(0))
}
self.block_start_margin
.union(AdjoiningMargins::from_margin(block_end_margin));
(
CollapsibleMargins::CollapseThrough(self.block_start_margin),
Au(0),
)
},
FinalMarginState::BottomMarginCollapses => {
self.margin_in.union(AdjoiningMargins::from_margin(block_end_margin));
(CollapsibleMargins::Collapse(self.block_start_margin, self.margin_in), Au(0))
}
self.margin_in
.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
// `tests/ref/float_under_top_margin_a.html`.
Au(0)
}
},
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
/// 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.
pub fn advance_block_start_margin(&mut self,
child_collapsible_margins: &CollapsibleMargins,
can_collapse_block_start_margin: bool)
-> Au {
pub fn advance_block_start_margin(
&mut self,
child_collapsible_margins: &CollapsibleMargins,
can_collapse_block_start_margin: bool,
) -> Au {
if !can_collapse_block_start_margin {
self.state = MarginCollapseState::AccumulatingMarginIn
}
match (self.state, *child_collapsible_margins) {
(MarginCollapseState::AccumulatingCollapsibleTopMargin,
CollapsibleMargins::None(block_start, _)) => {
(
MarginCollapseState::AccumulatingCollapsibleTopMargin,
CollapsibleMargins::None(block_start, _),
) => {
self.state = MarginCollapseState::AccumulatingMarginIn;
block_start
}
(MarginCollapseState::AccumulatingCollapsibleTopMargin,
CollapsibleMargins::Collapse(block_start, _)) => {
},
(
MarginCollapseState::AccumulatingCollapsibleTopMargin,
CollapsibleMargins::Collapse(block_start, _),
) => {
self.block_start_margin.union(block_start);
self.state = MarginCollapseState::AccumulatingMarginIn;
Au(0)
}
(MarginCollapseState::AccumulatingMarginIn,
CollapsibleMargins::None(block_start, _)) => {
},
(
MarginCollapseState::AccumulatingMarginIn,
CollapsibleMargins::None(block_start, _),
) => {
let previous_margin_value = self.margin_in.collapse();
self.margin_in = AdjoiningMargins::new();
previous_margin_value + block_start
}
(MarginCollapseState::AccumulatingMarginIn,
CollapsibleMargins::Collapse(block_start, _)) => {
},
(
MarginCollapseState::AccumulatingMarginIn,
CollapsibleMargins::Collapse(block_start, _),
) => {
self.margin_in.union(block_start);
let margin_value = self.margin_in.collapse();
self.margin_in = AdjoiningMargins::new();
margin_value
}
},
(_, CollapsibleMargins::CollapseThrough(_)) => {
// For now, we ignore this; this will be handled by `advance_block_end_margin`
// below.
Au(0)
}
},
}
}
/// 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
/// that should be added to the Y offset during block layout.
pub fn advance_block_end_margin(&mut self, child_collapsible_margins: &CollapsibleMargins)
-> Au {
pub fn advance_block_end_margin(
&mut self,
child_collapsible_margins: &CollapsibleMargins,
) -> Au {
match (self.state, *child_collapsible_margins) {
(MarginCollapseState::AccumulatingCollapsibleTopMargin, CollapsibleMargins::None(..)) |
(MarginCollapseState::AccumulatingCollapsibleTopMargin,
CollapsibleMargins::Collapse(..)) => {
(
MarginCollapseState::AccumulatingCollapsibleTopMargin,
CollapsibleMargins::None(..),
) |
(
MarginCollapseState::AccumulatingCollapsibleTopMargin,
CollapsibleMargins::Collapse(..),
) => {
// Can't happen because the state will have been replaced with
// `MarginCollapseState::AccumulatingMarginIn` above.
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);
Au(0)
}
(MarginCollapseState::AccumulatingMarginIn,
CollapsibleMargins::None(_, block_end)) => {
},
(MarginCollapseState::AccumulatingMarginIn, CollapsibleMargins::None(_, block_end)) => {
assert_eq!(self.margin_in.most_positive, Au(0));
assert_eq!(self.margin_in.most_negative, Au(0));
block_end
}
(MarginCollapseState::AccumulatingMarginIn,
CollapsibleMargins::Collapse(_, block_end)) |
(MarginCollapseState::AccumulatingMarginIn,
CollapsibleMargins::CollapseThrough(block_end)) => {
},
(
MarginCollapseState::AccumulatingMarginIn,
CollapsibleMargins::Collapse(_, block_end),
) |
(
MarginCollapseState::AccumulatingMarginIn,
CollapsibleMargins::CollapseThrough(block_end),
) => {
self.margin_in.union(block_end);
Au(0)
}
},
}
}
}
@ -309,7 +345,11 @@ pub struct IntrinsicISizes {
impl fmt::Debug for IntrinsicISizes {
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
)
}
}
@ -345,9 +385,9 @@ impl IntrinsicISizesContribution {
pub fn finish(self) -> IntrinsicISizes {
IntrinsicISizes {
minimum_inline_size: self.content_intrinsic_sizes.minimum_inline_size +
self.surrounding_size,
self.surrounding_size,
preferred_inline_size: self.content_intrinsic_sizes.preferred_inline_size +
self.surrounding_size,
self.surrounding_size,
}
}
@ -358,8 +398,10 @@ impl IntrinsicISizesContribution {
/// FIXME(pcwalton): This is incorrect when the inline fragment contains forced line breaks
/// (e.g. `<br>` or `white-space: pre`).
pub fn union_inline(&mut self, sizes: &IntrinsicISizes) {
self.content_intrinsic_sizes.minimum_inline_size =
max(self.content_intrinsic_sizes.minimum_inline_size, sizes.minimum_inline_size);
self.content_intrinsic_sizes.minimum_inline_size = max(
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 + sizes.preferred_inline_size
}
@ -382,10 +424,14 @@ impl IntrinsicISizesContribution {
///
/// This is used when contributing the intrinsic sizes for individual fragments.
pub fn union_block(&mut self, sizes: &IntrinsicISizes) {
self.content_intrinsic_sizes.minimum_inline_size =
max(self.content_intrinsic_sizes.minimum_inline_size, sizes.minimum_inline_size);
self.content_intrinsic_sizes.preferred_inline_size =
max(self.content_intrinsic_sizes.preferred_inline_size, sizes.preferred_inline_size)
self.content_intrinsic_sizes.minimum_inline_size = max(
self.content_intrinsic_sizes.minimum_inline_size,
sizes.minimum_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 {
#[inline]
pub fn from_style(length: LengthOrPercentageOrAuto, containing_length: Au)
-> MaybeAuto {
pub fn from_style(length: LengthOrPercentageOrAuto, containing_length: Au) -> MaybeAuto {
match length {
LengthOrPercentageOrAuto::Auto => MaybeAuto::Auto,
LengthOrPercentageOrAuto::Percentage(percent) => {
MaybeAuto::Specified(containing_length.scale_by(percent.0))
}
},
LengthOrPercentageOrAuto::Calc(calc) => {
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]
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 {
MaybeAuto::Auto => MaybeAuto::Auto,
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.
///
/// `style_length`: content size as given in the CSS.
pub fn style_length(style_length: LengthOrPercentageOrAuto,
container_size: Option<Au>) -> MaybeAuto {
pub fn style_length(
style_length: LengthOrPercentageOrAuto,
container_size: Option<Au>,
) -> MaybeAuto {
match container_size {
Some(length) => MaybeAuto::from_style(style_length, length),
None => if let LengthOrPercentageOrAuto::Length(length) = style_length {
MaybeAuto::Specified(Au::from(length))
} else {
MaybeAuto::Auto
}
},
}
}
@ -475,25 +525,37 @@ pub fn style_length(style_length: LengthOrPercentageOrAuto,
/// [1]: https://drafts.csswg.org/css-backgrounds-3/#border-radius
pub fn specified_border_radius(
radius: BorderCornerRadius,
containing_size: Size2D<Au>)
-> Size2D<Au>
{
containing_size: Size2D<Au>,
) -> Size2D<Au> {
let w = radius.0.width().to_used_value(containing_size.width);
let h = radius.0.height().to_used_value(containing_size.height);
Size2D::new(w, h)
}
#[inline]
pub fn padding_from_style(style: &ComputedValues,
containing_block_inline_size: Au,
writing_mode: WritingMode)
-> LogicalMargin<Au> {
pub fn padding_from_style(
style: &ComputedValues,
containing_block_inline_size: Au,
writing_mode: WritingMode,
) -> LogicalMargin<Au> {
let padding_style = style.get_padding();
LogicalMargin::from_physical(writing_mode, SideOffsets2D::new(
padding_style.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)))
LogicalMargin::from_physical(
writing_mode,
SideOffsets2D::new(
padding_style
.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
@ -501,14 +563,20 @@ pub fn padding_from_style(style: &ComputedValues,
///
/// This is used when calculating intrinsic inline sizes.
#[inline]
pub fn specified_margin_from_style(style: &ComputedValues,
writing_mode: WritingMode) -> LogicalMargin<Au> {
pub fn specified_margin_from_style(
style: &ComputedValues,
writing_mode: WritingMode,
) -> LogicalMargin<Au> {
let margin_style = style.get_margin();
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_right, 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()))
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_right, 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(),
),
)
}
/// A min-size and max-size constraint. The constructor has a optional `border`
@ -523,17 +591,19 @@ pub struct SizeConstraint {
impl SizeConstraint {
/// Create a `SizeConstraint` for an axis.
pub fn new(container_size: Option<Au>,
min_size: LengthOrPercentage,
max_size: LengthOrPercentageOrNone,
border: Option<Au>) -> SizeConstraint {
pub fn new(
container_size: Option<Au>,
min_size: LengthOrPercentage,
max_size: LengthOrPercentageOrNone,
border: Option<Au>,
) -> SizeConstraint {
let mut min_size = match container_size {
Some(container_size) => min_size.to_used_value(container_size),
None => if let LengthOrPercentage::Length(length) = min_size {
Au::from(length)
} else {
Au(0)
}
},
};
let mut max_size = match container_size {
@ -542,7 +612,7 @@ impl SizeConstraint {
Some(Au::from(length))
} else {
None
}
},
};
// Make sure max size is not smaller than min size.
max_size = max_size.map(|x| max(x, min_size));
@ -554,7 +624,7 @@ impl SizeConstraint {
SizeConstraint {
min_size: min_size,
max_size: max_size
max_size: max_size,
}
}
@ -565,7 +635,7 @@ impl SizeConstraint {
} else {
match self.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) {
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();
self.block_flow.compute_inline_sizes(shared_context);
@ -94,8 +97,7 @@ impl Flow for MulticolFlow {
self.block_flow.fragment.border_padding.inline_start;
// Distance from the inline-end margin edge to the inline-end content edge.
let inline_end_content_edge =
self.block_flow.fragment.margin.inline_end +
let inline_end_content_edge = self.block_flow.fragment.margin.inline_end +
self.block_flow.fragment.border_padding.inline_end;
self.block_flow.assign_inline_sizes(layout_context);
@ -107,15 +109,19 @@ impl Flow for MulticolFlow {
let style = &self.block_flow.fragment.style;
let column_gap = match style.get_position().column_gap {
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 mut column_count;
if let Either::First(column_width) = column_style.column_width {
let column_width = Au::from(column_width);
column_count =
max(1, (content_inline_size + column_gap).0 / (column_width + column_gap).0);
column_count = max(
1,
(content_inline_size + column_gap).0 / (column_width + column_gap).0,
);
if let ColumnCount::Integer(specified_column_count) = column_style.column_count {
column_count = min(column_count, specified_column_count.0 as i32);
}
@ -125,16 +131,22 @@ impl Flow for MulticolFlow {
_ => unreachable!(),
}
}
column_width =
max(Au(0), (content_inline_size + column_gap) / column_count - column_gap);
column_width = max(
Au(0),
(content_inline_size + column_gap) / column_count - 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.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) {
@ -156,7 +168,7 @@ impl Flow for MulticolFlow {
ctx.shared_context().viewport_size(),
).block
}
}
},
});
// Before layout, everything is in a single "column"
@ -167,17 +179,20 @@ impl Flow for MulticolFlow {
self.block_flow.assign_block_size(ctx);
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);
column = match remaining {
Some(remaining) => remaining,
None => break
None => break,
};
}
}
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 = pitch.to_physical(self.block_flow.base.writing_mode);
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) {
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) {
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) {
@ -223,11 +240,17 @@ impl Flow for MulticolFlow {
self.block_flow.generated_containing_block_size(flow)
}
fn iterate_through_fragment_border_boxes(&self,
iterator: &mut FragmentBorderBoxIterator,
level: i32,
stacking_context_position: &Point2D<Au>) {
self.block_flow.iterate_through_fragment_border_boxes(iterator, level, stacking_context_position);
fn iterate_through_fragment_border_boxes(
&self,
iterator: &mut FragmentBorderBoxIterator,
level: i32,
stacking_context_position: &Point2D<Au>,
) {
self.block_flow.iterate_through_fragment_border_boxes(
iterator,
level,
stacking_context_position,
);
}
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) {
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);
}
@ -266,22 +292,27 @@ impl Flow for MulticolColumnFlow {
self.block_flow.assign_block_size(ctx);
}
fn fragment(&mut self, layout_context: &LayoutContext,
fragmentation_context: Option<FragmentationContext>)
-> Option<Arc<Flow>> {
fn fragment(
&mut self,
layout_context: &LayoutContext,
fragmentation_context: Option<FragmentationContext>,
) -> Option<Arc<Flow>> {
Flow::fragment(&mut self.block_flow, layout_context, fragmentation_context)
}
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) {
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) {
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) {
@ -313,11 +344,17 @@ impl Flow for MulticolColumnFlow {
self.block_flow.generated_containing_block_size(flow)
}
fn iterate_through_fragment_border_boxes(&self,
iterator: &mut FragmentBorderBoxIterator,
level: i32,
stacking_context_position: &Point2D<Au>) {
self.block_flow.iterate_through_fragment_border_boxes(iterator, level, stacking_context_position);
fn iterate_through_fragment_border_boxes(
&self,
iterator: &mut FragmentBorderBoxIterator,
level: i32,
stacking_context_position: &Point2D<Au>,
) {
self.block_flow.iterate_through_fragment_border_boxes(
iterator,
level,
stacking_context_position,
);
}
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
/// fetch-and-subtract the parent's children count.
fn bottom_up_flow(mut unsafe_flow: UnsafeFlow,
assign_bsize_traversal: &AssignBSizes) {
fn bottom_up_flow(mut unsafe_flow: UnsafeFlow, assign_bsize_traversal: &AssignBSizes) {
loop {
// Get a real flow.
let flow: &mut Flow = unsafe {
mem::transmute(unsafe_flow)
};
let flow: &mut Flow = unsafe { mem::transmute(unsafe_flow) };
// Perform the appropriate traversal.
if assign_bsize_traversal.should_process(flow) {
assign_bsize_traversal.process(flow);
}
let base = flow.mut_base();
// Reset the count of children for the next layout traversal.
base.parallel.children_count.store(base.children.len() as isize,
Ordering::Relaxed);
base.parallel
.children_count
.store(base.children.len() as isize, Ordering::Relaxed);
// Possibly enqueue the parent.
let unsafe_parent = base.parallel.parent;
if unsafe_parent == null_unsafe_flow() {
// We're done!
break
break;
}
// 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
// on with our parent; otherwise, we've gotta wait.
let parent: &mut Flow = unsafe {
&mut *(unsafe_parent.0 as *mut Flow)
};
let parent: &mut Flow = unsafe { &mut *(unsafe_parent.0 as *mut Flow) };
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.
unsafe_flow = unsafe_parent
} else {
// Stop.
break
break;
}
}
}
fn top_down_flow<'scope>(unsafe_flows: &[UnsafeFlow],
pool: &'scope rayon::ThreadPool,
scope: &rayon::Scope<'scope>,
assign_isize_traversal: &'scope AssignISizes,
assign_bsize_traversal: &'scope AssignBSizes)
{
fn top_down_flow<'scope>(
unsafe_flows: &[UnsafeFlow],
pool: &'scope rayon::ThreadPool,
scope: &rayon::Scope<'scope>,
assign_isize_traversal: &'scope AssignISizes,
assign_bsize_traversal: &'scope AssignBSizes,
) {
let mut discovered_child_flows = FlowList::new();
for unsafe_flow in unsafe_flows {
@ -127,8 +128,7 @@ fn top_down_flow<'scope>(unsafe_flows: &[UnsafeFlow],
unsafe {
// Get a real flow.
let flow: &mut Flow = mem::transmute(*unsafe_flow);
flow.mut_base().thread_id =
pool.current_thread_index().unwrap() as u8;
flow.mut_base().thread_id = pool.current_thread_index().unwrap() as u8;
if assign_isize_traversal.should_process(flow) {
// Perform the appropriate traversal.
@ -149,16 +149,18 @@ fn top_down_flow<'scope>(unsafe_flows: &[UnsafeFlow],
}
if discovered_child_flows.is_empty() {
return
return;
}
if discovered_child_flows.len() <= CHUNK_SIZE {
// We can handle all the children in this work unit.
top_down_flow(&discovered_child_flows,
pool,
scope,
&assign_isize_traversal,
&assign_bsize_traversal);
top_down_flow(
&discovered_child_flows,
pool,
scope,
&assign_isize_traversal,
&assign_bsize_traversal,
);
} else {
// Spawn a new work unit for each chunk after the first.
let mut chunks = discovered_child_flows.chunks(CHUNK_SIZE);
@ -166,37 +168,66 @@ fn top_down_flow<'scope>(unsafe_flows: &[UnsafeFlow],
for chunk in chunks {
let nodes = chunk.iter().cloned().collect::<FlowList>();
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 {
top_down_flow(chunk, pool, scope, &assign_isize_traversal, &assign_bsize_traversal);
top_down_flow(
chunk,
pool,
scope,
&assign_isize_traversal,
&assign_bsize_traversal,
);
}
}
}
/// Run the main layout passes in parallel.
pub fn reflow(
root: &mut Flow,
profiler_metadata: Option<TimerMetadata>,
time_profiler_chan: time::ProfilerChan,
context: &LayoutContext,
queue: &rayon::ThreadPool) {
root: &mut Flow,
profiler_metadata: Option<TimerMetadata>,
time_profiler_chan: time::ProfilerChan,
context: &LayoutContext,
queue: &rayon::ThreadPool,
) {
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);
}
let assign_isize_traversal = &AssignISizes { layout_context: &context };
let assign_bsize_traversal = &AssignBSizes { layout_context: &context };
let assign_isize_traversal = &AssignISizes {
layout_context: &context,
};
let assign_bsize_traversal = &AssignBSizes {
layout_context: &context,
};
let nodes = [UnsafeFlow(root)];
queue.install(move || {
rayon::scope(move |scope| {
profile(time::ProfilerCategory::LayoutParallelWarmup,
profiler_metadata, time_profiler_chan, move || {
top_down_flow(&nodes, queue, scope, assign_isize_traversal, assign_bsize_traversal);
});
profile(
time::ProfilerCategory::LayoutParallelWarmup,
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>>>;
impl<T> PersistentList<T> where T: Send + Sync {
impl<T> PersistentList<T>
where
T: Send + Sync,
{
#[inline]
pub fn new() -> PersistentList<T> {
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> {
// This establishes the persistent nature of this list: we can clone a list by just cloning
// 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>>,
}
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;
#[inline]

View file

@ -94,13 +94,24 @@ pub struct LayoutRPCImpl(pub Arc<Mutex<LayoutThreadData>>);
// https://drafts.csswg.org/cssom-view/#overflow-directions
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::LeftToRight, InlineBaseDirection::LeftToRight) => OverflowDirection::RightAndDown,
(BlockFlowDirection::LeftToRight, InlineBaseDirection::LeftToRight) => {
OverflowDirection::RightAndDown
},
(BlockFlowDirection::TopToBottom, InlineBaseDirection::RightToLeft) |
(BlockFlowDirection::RightToLeft, InlineBaseDirection::LeftToRight) => OverflowDirection::LeftAndDown,
(BlockFlowDirection::RightToLeft, InlineBaseDirection::RightToLeft) => OverflowDirection::LeftAndUp,
(BlockFlowDirection::LeftToRight, InlineBaseDirection::RightToLeft) => OverflowDirection::RightAndUp
(BlockFlowDirection::RightToLeft, InlineBaseDirection::LeftToRight) => {
OverflowDirection::LeftAndDown
},
(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 rw_data = rw_data.lock().unwrap();
NodeGeometryResponse {
client_rect: rw_data.client_rect_response
client_rect: rw_data.client_rect_response,
}
}
fn node_scroll_area(&self) -> 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 {
NodeScrollIdResponse(self.0.lock()
.unwrap().scroll_id_response
.expect("scroll id is not correctly fetched"))
NodeScrollIdResponse(
self.0
.lock()
.unwrap()
.scroll_id_response
.expect("scroll id is not correctly fetched"),
)
}
/// Retrieves the resolved value for a CSS style property.
@ -187,7 +202,7 @@ impl UnioningFragmentBorderBoxIterator {
fn new(node_address: OpaqueNode) -> UnioningFragmentBorderBoxIterator {
UnioningFragmentBorderBoxIterator {
node_address: node_address,
rect: None
rect: None,
}
}
}
@ -195,12 +210,8 @@ impl UnioningFragmentBorderBoxIterator {
impl FragmentBorderBoxIterator for UnioningFragmentBorderBoxIterator {
fn process(&mut self, _: &Fragment, _: i32, border_box: &Rect<Au>) {
self.rect = match self.rect {
Some(rect) => {
Some(rect.union(border_box))
}
None => {
Some(*border_box)
}
Some(rect) => Some(rect.union(border_box)),
None => Some(*border_box),
};
}
@ -237,12 +248,12 @@ enum Side {
Left,
Right,
Bottom,
Top
Top,
}
enum MarginPadding {
Margin,
Padding
Padding,
}
enum PositionProperty {
@ -270,9 +281,11 @@ struct PositionRetrievingFragmentBorderBoxIterator {
}
impl PositionRetrievingFragmentBorderBoxIterator {
fn new(node_address: OpaqueNode,
property: PositionProperty,
position: Point2D<Au>) -> PositionRetrievingFragmentBorderBoxIterator {
fn new(
node_address: OpaqueNode,
property: PositionProperty,
position: Point2D<Au>,
) -> PositionRetrievingFragmentBorderBoxIterator {
PositionRetrievingFragmentBorderBoxIterator {
node_address: node_address,
position: position,
@ -284,18 +297,19 @@ impl PositionRetrievingFragmentBorderBoxIterator {
impl FragmentBorderBoxIterator for PositionRetrievingFragmentBorderBoxIterator {
fn process(&mut self, fragment: &Fragment, _: i32, border_box: &Rect<Au>) {
let border_padding = fragment.border_padding.to_physical(fragment.style.writing_mode);
self.result =
Some(match self.property {
PositionProperty::Left => self.position.x,
PositionProperty::Top => self.position.y,
PositionProperty::Width => border_box.size.width - border_padding.horizontal(),
PositionProperty::Height => border_box.size.height - border_padding.vertical(),
// TODO: the following 2 calculations are completely wrong.
// They should return the difference between the parent's and this
// fragment's border boxes.
PositionProperty::Right => border_box.max_x() + self.position.x,
PositionProperty::Bottom => border_box.max_y() + self.position.y,
let border_padding = fragment
.border_padding
.to_physical(fragment.style.writing_mode);
self.result = Some(match self.property {
PositionProperty::Left => self.position.x,
PositionProperty::Top => self.position.y,
PositionProperty::Width => border_box.size.width - border_padding.horizontal(),
PositionProperty::Height => border_box.size.height - border_padding.vertical(),
// TODO: the following 2 calculations are completely wrong.
// They should return the difference between the parent's and this
// fragment's border boxes.
PositionProperty::Right => border_box.max_x() + self.position.x,
PositionProperty::Bottom => border_box.max_y() + self.position.y,
});
}
@ -313,8 +327,12 @@ struct MarginRetrievingFragmentBorderBoxIterator {
}
impl MarginRetrievingFragmentBorderBoxIterator {
fn new(node_address: OpaqueNode, side: Side, margin_padding:
MarginPadding, writing_mode: WritingMode) -> MarginRetrievingFragmentBorderBoxIterator {
fn new(
node_address: OpaqueNode,
side: Side,
margin_padding: MarginPadding,
writing_mode: WritingMode,
) -> MarginRetrievingFragmentBorderBoxIterator {
MarginRetrievingFragmentBorderBoxIterator {
node_address: node_address,
side: side,
@ -329,13 +347,13 @@ impl FragmentBorderBoxIterator for MarginRetrievingFragmentBorderBoxIterator {
fn process(&mut self, fragment: &Fragment, _: i32, _: &Rect<Au>) {
let rect = match self.margin_padding {
MarginPadding::Margin => &fragment.margin,
MarginPadding::Padding => &fragment.border_padding
MarginPadding::Padding => &fragment.border_padding,
};
self.result = Some(match self.side {
Side::Left => rect.left(self.writing_mode),
Side::Right => rect.right(self.writing_mode),
Side::Bottom => rect.bottom(self.writing_mode),
Side::Top => rect.top(self.writing_mode)
Side::Left => rect.left(self.writing_mode),
Side::Right => rect.right(self.writing_mode),
Side::Bottom => rect.bottom(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>(
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
// stuff. So the position is wrong in most cases.
let mut iterator = UnioningFragmentBorderBoxIterator::new(requested_node.opaque());
@ -353,8 +373,10 @@ pub fn process_content_box_request<N: LayoutNode>(
iterator.rect
}
pub fn process_content_boxes_request<N: LayoutNode>(requested_node: N, layout_root: &mut Flow)
-> Vec<Rect<Au>> {
pub fn process_content_boxes_request<N: LayoutNode>(
requested_node: N,
layout_root: &mut Flow,
) -> Vec<Rect<Au>> {
// FIXME(pcwalton): This has not been updated to handle the stacking context relative
// stuff. So the position is wrong in most cases.
let mut iterator = CollectingFragmentBorderBoxIterator::new(requested_node.opaque());
@ -371,7 +393,7 @@ impl FragmentLocatingFragmentIterator {
fn new(node_address: OpaqueNode) -> FragmentLocatingFragmentIterator {
FragmentLocatingFragmentIterator {
node_address: node_address,
client_rect: Rect::zero()
client_rect: Rect::zero(),
}
}
}
@ -382,7 +404,7 @@ struct UnioningFragmentScrollAreaIterator {
origin_rect: Rect<i32>,
level: Option<i32>,
is_child: bool,
overflow_direction: OverflowDirection
overflow_direction: OverflowDirection,
}
impl UnioningFragmentScrollAreaIterator {
@ -394,7 +416,7 @@ impl UnioningFragmentScrollAreaIterator {
level: None,
is_child: false,
// 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 (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 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 left_padding = left_border as i32;
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(_) => {
let padding = Rect::new(Point2D::new(left_padding, top_padding),
Size2D::new(right_padding, bottom_padding));
let padding = Rect::new(
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 left_margin = fragment.margin.left(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 margin = Rect::new(Point2D::new(left_margin, top_margin),
Size2D::new(right_margin, bottom_margin));
let margin = Rect::new(
Point2D::new(left_margin, top_margin),
Size2D::new(right_margin, bottom_margin),
);
self.union_rect = self.union_rect.union(&margin).union(&padding);
}
},
None => {
self.level = Some(level);
self.is_child = true;
self.overflow_direction = overflow_direction(&fragment.style.writing_mode);
self.origin_rect = Rect::new(Point2D::new(left_padding, top_padding),
Size2D::new(right_padding, bottom_padding));
self.origin_rect = Rect::new(
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
// higher, as they can't be parents of this node.
self.parent_nodes.truncate(level as usize);
assert_eq!(self.parent_nodes.len(), level as usize,
"Skipped at least one level in the flow tree!");
assert_eq!(
self.parent_nodes.len(),
level as usize,
"Skipped at least one level in the flow tree!"
);
}
if !fragment.is_primary_fragment() {
@ -530,8 +564,10 @@ impl FragmentBorderBoxIterator for ParentOffsetBorderBoxIterator {
// Found the fragment in the flow tree that matches the
// DOM node being looked for.
assert!(self.node_offset_box.is_none(),
"Node was being treated as inline, but it has an associated fragment!");
assert!(
self.node_offset_box.is_none(),
"Node was being treated as inline, but it has an associated fragment!"
);
self.has_processed_node = true;
self.node_offset_box = Some(NodeOffsetBoxInfo {
@ -544,7 +580,10 @@ impl FragmentBorderBoxIterator for ParentOffsetBorderBoxIterator {
self.parent_nodes.clear();
}
} 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
// 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
// is inline and contains this fragment.
match self.node_offset_box {
Some(NodeOffsetBoxInfo { ref mut rectangle, .. }) => {
Some(NodeOffsetBoxInfo {
ref mut rectangle, ..
}) => {
*rectangle = rectangle.union(border_box);
},
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;
}
} 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)?
let is_body_element = level == 1;
let is_valid_parent = match (is_body_element,
fragment.style.get_box().position,
&fragment.specific) {
let is_valid_parent = match (
is_body_element,
fragment.style.get_box().position,
&fragment.specific,
) {
// Spec says it's valid if any of these are true:
// 1) Is the body element
// 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 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 {
node_address: fragment.node,
@ -619,9 +667,10 @@ impl FragmentBorderBoxIterator for ParentOffsetBorderBoxIterator {
}
}
pub fn process_node_geometry_request<N: LayoutNode>(requested_node: N, layout_root: &mut Flow)
-> Rect<i32> {
pub fn process_node_geometry_request<N: LayoutNode>(
requested_node: N,
layout_root: &mut Flow,
) -> Rect<i32> {
let mut iterator = FragmentLocatingFragmentIterator::new(requested_node.opaque());
sequential::iterate_through_flow_tree_fragment_border_boxes(layout_root, &mut iterator);
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>(
id: PipelineId,
requested_node: N
requested_node: N,
) -> ExternalScrollId {
let layout_node = requested_node.to_threadsafe();
layout_node.generate_scroll_id(id)
}
/// https://drafts.csswg.org/cssom-view/#scrolling-area
pub fn process_node_scroll_area_request< N: LayoutNode>(requested_node: N, layout_root: &mut Flow)
-> Rect<i32> {
pub fn process_node_scroll_area_request<N: LayoutNode>(
requested_node: N,
layout_root: &mut Flow,
) -> Rect<i32> {
let mut iterator = UnioningFragmentScrollAreaIterator::new(requested_node.opaque());
sequential::iterate_through_flow_tree_fragment_border_boxes(layout_root, &mut iterator);
match iterator.overflow_direction {
OverflowDirection::RightAndDown => {
let right = max(iterator.union_rect.size.width, iterator.origin_rect.size.width);
let bottom = max(iterator.union_rect.size.height, iterator.origin_rect.size.height);
let right = max(
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))
},
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);
Rect::new(Point2D::new(left, iterator.origin_rect.origin.y),
Size2D::new(iterator.origin_rect.size.width, bottom))
Rect::new(
Point2D::new(left, iterator.origin_rect.origin.y),
Size2D::new(iterator.origin_rect.size.width, bottom),
)
},
OverflowDirection::LeftAndUp => {
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 => {
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);
Rect::new(Point2D::new(iterator.origin_rect.origin.x, top),
Size2D::new(right, iterator.origin_rect.size.height))
}
let right = max(
iterator.union_rect.size.width,
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.
/// <https://drafts.csswg.org/cssom/#resolved-value>
pub fn process_resolved_style_request<'a, N>(context: &LayoutContext,
node: N,
pseudo: &Option<PseudoElement>,
property: &PropertyId,
layout_root: &mut Flow) -> String
where N: LayoutNode,
pub fn process_resolved_style_request<'a, N>(
context: &LayoutContext,
node: N,
pseudo: &Option<PseudoElement>,
property: &PropertyId,
layout_root: &mut Flow,
) -> String
where
N: LayoutNode,
{
use style::stylist::RuleInclusion;
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 style = styles.primary();
let longhand_id = match *property {
PropertyId::LonghandAlias(id, _) |
PropertyId::Longhand(id) => id,
PropertyId::LonghandAlias(id, _) | PropertyId::Longhand(id) => id,
// Firefox returns blank strings for the computed value of shorthands,
// so this should be web-compatible.
PropertyId::ShorthandAlias(..) |
PropertyId::Shorthand(_) => return String::new(),
PropertyId::ShorthandAlias(..) | PropertyId::Shorthand(_) => return String::new(),
PropertyId::Custom(ref 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
@ -735,7 +803,7 @@ where
Some(PseudoElement::Selection) => None,
// FIXME(emilio): What about the other pseudos? Probably they shouldn't
// just return the element's style!
_ => Some(layout_el)
_ => Some(layout_el),
};
let layout_el = match layout_el {
@ -744,29 +812,24 @@ where
// the element itself in this case, Firefox uses the resolved value.
// https://www.w3.org/Bugs/Public/show_bug.cgi?id=29006
return String::new();
}
Some(layout_el) => layout_el
},
Some(layout_el) => layout_el,
};
let style = &*layout_el.resolved_style();
let longhand_id = match *property {
PropertyId::LonghandAlias(id, _) |
PropertyId::Longhand(id) => id,
PropertyId::LonghandAlias(id, _) | PropertyId::Longhand(id) => id,
// Firefox returns blank strings for the computed value of shorthands,
// so this should be web-compatible.
PropertyId::ShorthandAlias(..) |
PropertyId::Shorthand(_) => return String::new(),
PropertyId::ShorthandAlias(..) | PropertyId::Shorthand(_) => return String::new(),
PropertyId::Custom(ref name) => {
return style.computed_value_to_string(PropertyDeclarationId::Custom(name))
}
},
};
let positioned = match style.get_box().position {
Position::Relative |
Position::Sticky |
Position::Fixed |
Position::Absolute => true,
_ => false
Position::Relative | Position::Sticky | Position::Fixed | Position::Absolute => true,
_ => false,
};
//TODO: determine whether requested property applies to the element.
@ -780,15 +843,20 @@ where
layout_el: <N::ConcreteThreadSafeLayoutNode as ThreadSafeLayoutNode>::ConcreteThreadSafeLayoutElement,
layout_root: &mut Flow,
requested_node: N,
longhand_id: LonghandId) -> String {
longhand_id: LonghandId,
) -> String
{
let maybe_data = layout_el.borrow_layout_data();
let position = maybe_data.map_or(Point2D::zero(), |data| {
match (*data).flow_construction_result {
ConstructionResult::Flow(ref flow_ref, _) =>
flow_ref.deref().base().stacking_relative_position.to_point(),
ConstructionResult::Flow(ref flow_ref, _) => flow_ref
.deref()
.base()
.stacking_relative_position
.to_point(),
// TODO(dzbarsky) search parents until we find node with a flow ref.
// https://github.com/servo/servo/issues/8307
_ => Point2D::zero()
_ => Point2D::zero(),
}
});
let property = match longhand_id {
@ -798,24 +866,32 @@ where
LonghandId::Right => PositionProperty::Right,
LonghandId::Width => PositionProperty::Width,
LonghandId::Height => PositionProperty::Height,
_ => unreachable!()
_ => unreachable!(),
};
let mut iterator =
PositionRetrievingFragmentBorderBoxIterator::new(requested_node.opaque(),
property,
position);
sequential::iterate_through_flow_tree_fragment_border_boxes(layout_root,
&mut iterator);
iterator.result.map(|r| r.to_css_string()).unwrap_or(String::new())
let mut iterator = PositionRetrievingFragmentBorderBoxIterator::new(
requested_node.opaque(),
property,
position,
);
sequential::iterate_through_flow_tree_fragment_border_boxes(layout_root, &mut iterator);
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.
match longhand_id {
LonghandId::MarginBottom | LonghandId::MarginTop |
LonghandId::MarginLeft | LonghandId::MarginRight |
LonghandId::PaddingBottom | LonghandId::PaddingTop |
LonghandId::PaddingLeft | LonghandId::PaddingRight
if applies && style.get_box().display != Display::None => {
LonghandId::MarginBottom |
LonghandId::MarginTop |
LonghandId::MarginLeft |
LonghandId::MarginRight |
LonghandId::PaddingBottom |
LonghandId::PaddingTop |
LonghandId::PaddingLeft |
LonghandId::PaddingRight
if applies && style.get_box().display != Display::None =>
{
let (margin_padding, side) = match longhand_id {
LonghandId::MarginBottom => (MarginPadding::Margin, Side::Bottom),
LonghandId::MarginTop => (MarginPadding::Margin, Side::Top),
@ -825,40 +901,50 @@ where
LonghandId::PaddingTop => (MarginPadding::Padding, Side::Top),
LonghandId::PaddingLeft => (MarginPadding::Padding, Side::Left),
LonghandId::PaddingRight => (MarginPadding::Padding, Side::Right),
_ => unreachable!()
_ => unreachable!(),
};
let mut iterator =
MarginRetrievingFragmentBorderBoxIterator::new(requested_node.opaque(),
side,
margin_padding,
style.writing_mode);
sequential::iterate_through_flow_tree_fragment_border_boxes(layout_root,
&mut iterator);
iterator.result.map(|r| r.to_css_string()).unwrap_or(String::new())
},
let mut iterator = MarginRetrievingFragmentBorderBoxIterator::new(
requested_node.opaque(),
side,
margin_padding,
style.writing_mode,
);
sequential::iterate_through_flow_tree_fragment_border_boxes(layout_root, &mut iterator);
iterator
.result
.map(|r| r.to_css_string())
.unwrap_or(String::new())
}
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)
}
},
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)
}
},
// 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)
-> OffsetParentResponse {
pub fn process_offset_parent_query<N: LayoutNode>(
requested_node: N,
layout_root: &mut Flow,
) -> OffsetParentResponse {
let mut iterator = ParentOffsetBorderBoxIterator::new(requested_node.opaque());
sequential::iterate_through_flow_tree_fragment_border_boxes(layout_root, &mut iterator);
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) {
(Some(node_offset_box), Some(parent_info)) => {
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()),
rect: Rect::new(origin, size),
}
}
_ => {
OffsetParentResponse::empty()
}
},
_ => OffsetParentResponse::empty(),
}
}
pub fn process_style_query<N: LayoutNode>(requested_node: N)
-> StyleResponse {
pub fn process_style_query<N: LayoutNode>(requested_node: N) -> StyleResponse {
let element = requested_node.as_element().unwrap();
let data = element.borrow_data();
@ -888,8 +971,10 @@ enum InnerTextItem {
}
// https://html.spec.whatwg.org/multipage/#the-innertext-idl-attribute
pub fn process_element_inner_text_query<N: LayoutNode>(node: N,
indexable_text: &IndexableText) -> String {
pub fn process_element_inner_text_query<N: LayoutNode>(
node: N,
indexable_text: &IndexableText,
) -> String {
// Step 1.
let mut results = Vec::new();
// Step 2.
@ -923,7 +1008,7 @@ pub fn process_element_inner_text_query<N: LayoutNode>(node: N,
if count > max_req_line_break_count {
max_req_line_break_count = count;
}
}
},
}
}
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
#[allow(unsafe_code)]
fn inner_text_collection_steps<N: LayoutNode>(node: N,
indexable_text: &IndexableText,
results: &mut Vec<InnerTextItem>) {
fn inner_text_collection_steps<N: LayoutNode>(
node: N,
indexable_text: &IndexableText,
results: &mut Vec<InnerTextItem>,
) {
let mut items = Vec::new();
for child in node.traverse_preorder() {
let node = match child.type_id() {
LayoutNodeType::Text => {
child.parent_node().unwrap()
},
LayoutNodeType::Text => child.parent_node().unwrap(),
_ => child,
};
let element_data = unsafe {
node.get_style_and_layout_data().map(|d| {
&(*(d.ptr.as_ptr() as *mut StyleData)).element_data
})
node.get_style_and_layout_data()
.map(|d| &(*(d.ptr.as_ptr() as *mut StyleData)).element_data)
};
if element_data.is_none() {
@ -980,15 +1064,16 @@ fn inner_text_collection_steps<N: LayoutNode>(node: N,
},
LayoutNodeType::Element(LayoutElementType::HTMLBRElement) => {
// 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) => {
// Step 8.
items.insert(0, InnerTextItem::RequiredLineBreakCount(2));
items.push(InnerTextItem::RequiredLineBreakCount(2));
}
},
_ => {},
}
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.
pub fn reflow(root: &mut Flow, layout_context: &LayoutContext, relayout_mode: RelayoutMode) {
fn doit(flow: &mut Flow,
assign_inline_sizes: AssignISizes,
assign_block_sizes: AssignBSizes,
relayout_mode: RelayoutMode) {
fn doit(
flow: &mut Flow,
assign_inline_sizes: AssignISizes,
assign_block_sizes: AssignBSizes,
relayout_mode: RelayoutMode,
) {
// 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.
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);
}
pub fn build_display_list_for_subtree<'a>(flow_root: &mut Flow,
layout_context: &'a LayoutContext)
-> DisplayListBuildState<'a> {
pub fn build_display_list_for_subtree<'a>(
flow_root: &mut Flow,
layout_context: &'a LayoutContext,
) -> DisplayListBuildState<'a> {
let mut state = StackingContextCollectionState::new(layout_context.id);
flow_root.collect_stacking_contexts(&mut state);
let state = DisplayListBuildState::new(layout_context, state);
let mut build_display_list = BuildDisplayList {
state: state,
};
let mut build_display_list = BuildDisplayList { state: state };
build_display_list.traverse(flow_root);
build_display_list.state
}
pub fn iterate_through_flow_tree_fragment_border_boxes(root: &mut Flow, iterator: &mut FragmentBorderBoxIterator) {
fn doit(flow: &mut Flow,
level: i32,
iterator: &mut FragmentBorderBoxIterator,
stacking_context_position: &Point2D<Au>) {
pub fn iterate_through_flow_tree_fragment_border_boxes(
root: &mut Flow,
iterator: &mut FragmentBorderBoxIterator,
) {
fn doit(
flow: &mut Flow,
level: i32,
iterator: &mut FragmentBorderBoxIterator,
stacking_context_position: &Point2D<Au>,
) {
flow.iterate_through_fragment_border_boxes(iterator, level, stacking_context_position);
for kid in flow.mut_base().child_iter_mut() {
let mut stacking_context_position = *stacking_context_position;
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)) +
kid.base().stacking_relative_position +
stacking_context_position.to_vector();
let relative_position = kid.as_block()
stacking_context_position =
Point2D::new(kid.as_block().fragment.margin.inline_start, Au(0)) +
kid.base().stacking_relative_position +
stacking_context_position.to_vector();
let relative_position = kid
.as_block()
.stacking_relative_border_box(CoordinateSystem::Own);
if let Some(matrix) = kid.as_block()
.fragment
.transform_matrix(&relative_position) {
if let Some(matrix) = kid.as_block().fragment.transform_matrix(&relative_position) {
let transform_matrix = matrix.transform_point2d(&LayoutPoint::zero()).unwrap();
stacking_context_position = stacking_context_position +
Vector2D::new(Au::from_f32_px(transform_matrix.x),
Au::from_f32_px(transform_matrix.y))
stacking_context_position = stacking_context_position + Vector2D::new(
Au::from_f32_px(transform_matrix.x),
Au::from_f32_px(transform_matrix.y),
)
}
}
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) {
if !flow.base().restyle_damage.contains(ServoRestyleDamage::STORE_OVERFLOW) {
if !flow
.base()
.restyle_damage
.contains(ServoRestyleDamage::STORE_OVERFLOW)
{
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
/// 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) {
if !flow.base().restyle_damage.intersects(ServoRestyleDamage::REFLOW) {
if !flow
.base()
.restyle_damage
.intersects(ServoRestyleDamage::REFLOW)
{
return;
}
let mut floats_in = SpeculatedFloatPlacement::compute_floats_in_for_first_child(flow);
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.
guess_float_placement(kid);
} else {

File diff suppressed because it is too large Load diff

View file

@ -58,7 +58,10 @@ impl Flow for TableCaptionFlow {
}
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);
}
@ -68,15 +71,18 @@ impl Flow for TableCaptionFlow {
}
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) {
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) {
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) {
@ -85,8 +91,8 @@ impl Flow for TableCaptionFlow {
}
fn collect_stacking_contexts(&mut self, state: &mut StackingContextCollectionState) {
self.block_flow.collect_stacking_contexts_for_block(state,
StackingContextCollectionFlags::empty());
self.block_flow
.collect_stacking_contexts_for_block(state, StackingContextCollectionFlags::empty());
}
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)
}
fn iterate_through_fragment_border_boxes(&self,
iterator: &mut FragmentBorderBoxIterator,
level: i32,
stacking_context_position: &Point2D<Au>) {
self.block_flow.iterate_through_fragment_border_boxes(iterator, level, stacking_context_position)
fn iterate_through_fragment_border_boxes(
&self,
iterator: &mut FragmentBorderBoxIterator,
level: i32,
stacking_context_position: &Point2D<Au>,
) {
self.block_flow.iterate_through_fragment_border_boxes(
iterator,
level,
stacking_context_position,
)
}
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>(
node: &N, fragment: Fragment, visible: bool) -> TableCellFlow {
node: &N,
fragment: Fragment,
visible: bool,
) -> TableCellFlow {
TableCellFlow {
block_flow: BlockFlow::from_fragment(fragment),
collapsed_borders: CollapsedBordersForCell::new(),
@ -90,7 +93,8 @@ impl TableCellFlow {
let remaining = self.block_flow.assign_block_size_block_base(
layout_context,
None,
MarginsMayCollapseFlag::MarginsMayNotCollapse);
MarginsMayCollapseFlag::MarginsMayNotCollapse,
);
debug_assert!(remaining.is_none());
}
@ -102,12 +106,14 @@ impl TableCellFlow {
for kid in self.base().children.iter() {
let kid_base = kid.base();
if kid_base.flags.contains(FlowFlags::IS_ABSOLUTELY_POSITIONED) {
continue
continue;
}
let start = kid_base.position.start.b -
kid_base.collapsible_margins.block_start_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();
let start = kid_base.position.start.b - kid_base
.collapsible_margins
.block_start_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 {
Some((ref mut first_start, ref mut last_end)) => {
if start < *first_start {
@ -116,7 +122,7 @@ impl TableCellFlow {
if end > *last_end {
*last_end = end
}
}
},
None => extents = Some((start, end)),
}
}
@ -138,7 +144,7 @@ impl TableCellFlow {
_ => Au(0),
};
if offset == Au(0) {
return
return;
}
for kid in self.mut_base().children.iter_mut() {
@ -154,9 +160,8 @@ impl TableCellFlow {
// Call after block size calculation
pub fn total_block_size(&mut self) -> Au {
// TODO: Percentage block-size
let specified = MaybeAuto::from_style(self.fragment().style()
.content_block_size(),
Au(0)).specified_or_zero();
let specified = MaybeAuto::from_style(self.fragment().style().content_block_size(), Au(0))
.specified_or_zero();
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
/// calculation.
fn bubble_inline_sizes(&mut self) {
let _scope = layout_debug_scope!("table_cell::bubble_inline_sizes {:x}",
self.block_flow.base.debug_id());
let _scope = layout_debug_scope!(
"table_cell::bubble_inline_sizes {:x}",
self.block_flow.base.debug_id()
);
self.block_flow.bubble_inline_sizes_for_block(true);
let specified_inline_size = MaybeAuto::from_style(self.block_flow
.fragment
.style()
.content_inline_size(),
Au(0)).specified_or_zero();
if self.block_flow.base.intrinsic_inline_sizes.minimum_inline_size <
specified_inline_size {
self.block_flow.base.intrinsic_inline_sizes.minimum_inline_size = specified_inline_size
let specified_inline_size = MaybeAuto::from_style(
self.block_flow.fragment.style().content_inline_size(),
Au(0),
).specified_or_zero();
if self
.block_flow
.base
.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 <
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;
if self
.block_flow
.base
.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
/// row.
fn assign_inline_sizes(&mut self, layout_context: &LayoutContext) {
let _scope = layout_debug_scope!("table_cell::assign_inline_sizes {:x}",
self.block_flow.base.debug_id());
debug!("assign_inline_sizes({}): assigning inline_size for flow", "table_cell");
let _scope = layout_debug_scope!(
"table_cell::assign_inline_sizes {:x}",
self.block_flow.base.debug_id()
);
debug!(
"assign_inline_sizes({}): assigning inline_size for flow",
"table_cell"
);
let shared_context = layout_context.shared_context();
// 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 inline_size_computer = InternalTable;
inline_size_computer.compute_used_inline_size(&mut self.block_flow,
shared_context,
containing_block_inline_size);
inline_size_computer.compute_used_inline_size(
&mut self.block_flow,
shared_context,
containing_block_inline_size,
);
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;
let inline_end_content_edge =
self.block_flow.base.block_container_inline_size -
let inline_end_content_edge = self.block_flow.base.block_container_inline_size -
self.block_flow.fragment.border_padding.inline_start_end() -
self.block_flow.fragment.border_box.size.inline;
let padding_and_borders = self.block_flow.fragment.border_padding.inline_start_end();
let content_inline_size =
self.block_flow.fragment.border_box.size.inline - padding_and_borders;
self.block_flow.propagate_assigned_inline_size_to_children(shared_context,
inline_start_content_edge,
inline_end_content_edge,
content_inline_size,
|_, _, _, _, _, _| {});
self.block_flow.propagate_assigned_inline_size_to_children(
shared_context,
inline_start_content_edge,
inline_end_content_edge,
content_inline_size,
|_, _, _, _, _, _| {},
);
}
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) {
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) {
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) {
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) {
@ -264,12 +302,15 @@ impl Flow for TableCellFlow {
// we skip setting the damage in TableCellStyleInfo::build_display_list()
// 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) {
self.block_flow.collect_stacking_contexts_for_block(state,
StackingContextCollectionFlags::empty());
self.block_flow
.collect_stacking_contexts_for_block(state, StackingContextCollectionFlags::empty());
}
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)
}
fn iterate_through_fragment_border_boxes(&self,
iterator: &mut FragmentBorderBoxIterator,
level: i32,
stacking_context_position: &Point2D<Au>) {
self.block_flow.iterate_through_fragment_border_boxes(iterator, level, stacking_context_position)
fn iterate_through_fragment_border_boxes(
&self,
iterator: &mut FragmentBorderBoxIterator,
level: i32,
stacking_context_position: &Point2D<Au>,
) {
self.block_flow.iterate_through_fragment_border_boxes(
iterator,
level,
stacking_context_position,
)
}
fn mutate_fragments(&mut self, mutator: &mut FnMut(&mut Fragment)) {
@ -379,67 +426,74 @@ impl CollapsedBordersForCell {
}
}
pub fn adjust_border_bounds_for_painting(&self,
border_bounds: &mut Rect<Au>,
writing_mode: WritingMode) {
pub fn adjust_border_bounds_for_painting(
&self,
border_bounds: &mut Rect<Au>,
writing_mode: WritingMode,
) {
let inline_start_divisor = if self.should_paint_inline_start_border() {
2
} else {
-2
};
let inline_start_offset = self.inline_start_width / 2 + self.inline_start_border.width /
inline_start_divisor;
let inline_start_offset =
self.inline_start_width / 2 + self.inline_start_border.width / inline_start_divisor;
let inline_end_divisor = if self.should_paint_inline_end_border() {
2
} else {
-2
};
let inline_end_offset = self.inline_end_width / 2 + self.inline_end_border.width /
inline_end_divisor;
let inline_end_offset =
self.inline_end_width / 2 + self.inline_end_border.width / inline_end_divisor;
let block_start_divisor = if self.should_paint_block_start_border() {
2
} else {
-2
};
let block_start_offset = self.block_start_width / 2 + self.block_start_border.width /
block_start_divisor;
let block_start_offset =
self.block_start_width / 2 + self.block_start_border.width / block_start_divisor;
let block_end_divisor = if self.should_paint_block_end_border() {
2
} else {
-2
};
let block_end_offset = self.block_end_width / 2 + self.block_end_border.width /
block_end_divisor;
let block_end_offset =
self.block_end_width / 2 + self.block_end_border.width / block_end_divisor;
// FIXME(pcwalton): Get the real container size.
let mut logical_bounds =
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.b = logical_bounds.start.b - block_start_offset;
logical_bounds.size.inline = logical_bounds.size.inline + inline_start_offset +
inline_end_offset;
logical_bounds.size.block = logical_bounds.size.block + block_start_offset +
block_end_offset;
logical_bounds.size.inline =
logical_bounds.size.inline + inline_start_offset + inline_end_offset;
logical_bounds.size.block =
logical_bounds.size.block + block_start_offset + block_end_offset;
*border_bounds = logical_bounds.to_physical(writing_mode, Size2D::new(Au(0), Au(0)))
}
pub fn adjust_border_colors_and_styles_for_painting(
&self,
border_colors: &mut SideOffsets2D<Color>,
border_styles: &mut SideOffsets2D<BorderStyle>,
writing_mode: WritingMode) {
let logical_border_colors = LogicalMargin::new(writing_mode,
self.block_start_border.color,
self.inline_end_border.color,
self.block_end_border.color,
self.inline_start_border.color);
&self,
border_colors: &mut SideOffsets2D<Color>,
border_styles: &mut SideOffsets2D<BorderStyle>,
writing_mode: WritingMode,
) {
let logical_border_colors = LogicalMargin::new(
writing_mode,
self.block_start_border.color,
self.inline_end_border.color,
self.block_end_border.color,
self.inline_start_border.color,
);
*border_colors = logical_border_colors.to_physical(writing_mode);
let logical_border_styles = LogicalMargin::new(writing_mode,
self.block_start_border.style,
self.inline_end_border.style,
self.block_end_border.style,
self.inline_start_border.style);
let logical_border_styles = LogicalMargin::new(
writing_mode,
self.block_start_border.style,
self.inline_end_border.style,
self.block_end_border.style,
self.inline_start_border.style,
);
*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 {
let writing_mode = fragment.style().writing_mode;
TableColGroupFlow {
base: BaseFlow::new(Some(fragment.style()),
writing_mode,
ForceNonfloatedFlag::ForceNonfloated),
base: BaseFlow::new(
Some(fragment.style()),
writing_mode,
ForceNonfloatedFlag::ForceNonfloated,
),
fragment: Some(fragment),
cols: fragments,
inline_sizes: vec!(),
inline_sizes: vec![],
}
}
}
@ -67,8 +69,10 @@ impl Flow for TableColGroupFlow {
}
fn bubble_inline_sizes(&mut self) {
let _scope = layout_debug_scope!("table_colgroup::bubble_inline_sizes {:x}",
self.base.debug_id());
let _scope = layout_debug_scope!(
"table_colgroup::bubble_inline_sizes {:x}",
self.base.debug_id()
);
for fragment in &self.cols {
// 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
/// 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.
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_block_position_if_necessary(&mut self, _: Au) {}
// 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) {
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!")
}
fn iterate_through_fragment_border_boxes(&self,
_: &mut FragmentBorderBoxIterator,
_: i32,
_: &Point2D<Au>) {}
fn iterate_through_fragment_border_boxes(
&self,
_: &mut FragmentBorderBoxIterator,
_: i32,
_: &Point2D<Au>,
) {
}
fn mutate_fragments(&mut self, _: &mut FnMut(&mut Fragment)) {}
}

View file

@ -89,7 +89,6 @@ pub struct CellIntrinsicInlineSize {
pub row_span: u32,
}
impl TableRowFlow {
pub fn from_fragment(fragment: Fragment) -> TableRowFlow {
let writing_mode = fragment.style().writing_mode;
@ -111,14 +110,19 @@ impl TableRowFlow {
/// TODO(pcwalton): This doesn't handle floats and positioned elements right.
///
/// Returns the block size
pub fn compute_block_size_table_row_base<'a>(&'a mut self, layout_context: &LayoutContext,
incoming_rowspan_data: &mut Vec<Au>,
border_info: &[TableRowSizeData],
row_index: usize) -> Au {
fn include_sizes_from_previous_rows(col: &mut usize,
incoming_rowspan: &[u32],
incoming_rowspan_data: &mut Vec<Au>,
max_block_size: &mut Au) {
pub fn compute_block_size_table_row_base<'a>(
&'a mut self,
layout_context: &LayoutContext,
incoming_rowspan_data: &mut Vec<Au>,
border_info: &[TableRowSizeData],
row_index: usize,
) -> Au {
fn include_sizes_from_previous_rows(
col: &mut usize,
incoming_rowspan: &[u32],
incoming_rowspan_data: &mut Vec<Au>,
max_block_size: &mut Au,
) {
while let Some(span) = incoming_rowspan.get(*col) {
if *span == 1 {
break;
@ -141,19 +145,28 @@ impl TableRowFlow {
// all cells).
let mut max_block_size = Au(0);
let thread_id = self.block_flow.base.thread_id;
let content_box = self.block_flow.base.position
- self.block_flow.fragment.border_padding
- self.block_flow.fragment.margin;
let content_box = self.block_flow.base.position -
self.block_flow.fragment.border_padding -
self.block_flow.fragment.margin;
let mut col = 0;
for kid in self.block_flow.base.child_iter_mut() {
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,
);
kid.place_float_if_applicable();
debug_assert!(!kid.base().flags.is_float(), "table cells should never float");
kid.assign_block_size_for_inorder_child_if_necessary(layout_context,
thread_id,
content_box);
debug_assert!(
!kid.base().flags.is_float(),
"table cells should never float"
);
kid.assign_block_size_for_inorder_child_if_necessary(
layout_context,
thread_id,
content_box,
);
let mut row_span;
let column_span;
@ -172,7 +185,8 @@ impl TableRowFlow {
if incoming_rowspan_data.len() <= col {
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;
@ -186,33 +200,41 @@ impl TableRowFlow {
max_block_size = max(max_block_size, cell_block_size_pressure);
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;
// TODO: Percentage block-size
block_size = match MaybeAuto::from_style(self.block_flow
.fragment
.style()
.content_block_size(),
Au(0)) {
block_size = match MaybeAuto::from_style(
self.block_flow.fragment.style().content_block_size(),
Au(0),
) {
MaybeAuto::Auto => block_size,
MaybeAuto::Specified(value) => max(value, 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.
let block_size = sizes[index].size;
for kid in self.block_flow.base.child_iter_mut() {
let child_table_cell = kid.as_mut_table_cell();
let block_size = if child_table_cell.row_span != 1 {
let mut row_span = child_table_cell.row_span;
let border_sizes_spanned =
get_spanned_border_size(sizes, index, &mut row_span);
let row_sizes = sizes[index..].iter()
.take(row_span as usize)
.fold(Au(0), |accum, r| accum + r.size);
let border_sizes_spanned = get_spanned_border_size(sizes, index, &mut row_span);
let row_sizes = sizes[index..]
.iter()
.take(row_span as usize)
.fold(Au(0), |accum, r| accum + r.size);
row_sizes + border_sizes_spanned
} else {
block_size
@ -232,17 +254,13 @@ impl TableRowFlow {
// Write in the size of the relative containing block for children. (This
// information is also needed to handle RTL.)
child_table_cell.block_flow.base.early_absolute_position_info =
EarlyAbsolutePositionInfo {
relative_containing_block_size: self.block_flow
.fragment
.content_box()
.size,
relative_containing_block_mode: self.block_flow
.fragment
.style()
.writing_mode,
};
child_table_cell
.block_flow
.base
.early_absolute_position_info = EarlyAbsolutePositionInfo {
relative_containing_block_size: self.block_flow.fragment.content_box().size,
relative_containing_block_mode: self.block_flow.fragment.style().writing_mode,
};
}
// Assign the block-size of own fragment
@ -253,22 +271,28 @@ impl TableRowFlow {
}
pub fn populate_collapsed_border_spacing<'a, I>(
&mut self,
collapsed_inline_direction_border_widths_for_table: &[Au],
collapsed_block_direction_border_widths_for_table: &mut Peekable<I>)
where I: Iterator<Item=&'a Au> {
&mut self,
collapsed_inline_direction_border_widths_for_table: &[Au],
collapsed_block_direction_border_widths_for_table: &mut Peekable<I>,
) where
I: Iterator<Item = &'a Au>,
{
self.collapsed_border_spacing.inline.clear();
self.collapsed_border_spacing
.inline
.extend(collapsed_inline_direction_border_widths_for_table.into_iter().map(|x| *x));
self.collapsed_border_spacing.inline.extend(
collapsed_inline_direction_border_widths_for_table
.into_iter()
.map(|x| *x),
);
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 =
*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 =
**collapsed_block_direction_border_width_for_table
}
@ -308,9 +332,10 @@ fn get_spanned_border_size(sizes: &[TableRowSizeData], row_index: usize, row_spa
if sizes[last_row_idx].rowgroup_id != sizes[row_index].rowgroup_id {
// XXXManishearth this loop can be avoided by also storing
// a "last_rowgroup_at" index so we can leapfrog back quickly
*row_span = sizes[row_index..last_row_idx + 1].iter()
.position(|s| s.rowgroup_id != sizes[row_index].rowgroup_id)
.unwrap() as u32;
*row_span = sizes[row_index..last_row_idx + 1]
.iter()
.position(|s| s.rowgroup_id != sizes[row_index].rowgroup_id)
.unwrap() as u32;
last_row_idx = row_index + *row_span as usize - 1;
}
sizes[last_row_idx].cumulative_border_spacing - sizes[row_index].cumulative_border_spacing
@ -345,20 +370,26 @@ impl Flow for TableRowFlow {
/// The specified column inline-sizes of children cells are used in fixed table layout
/// calculation.
fn bubble_inline_sizes(&mut self) {
let _scope = layout_debug_scope!("table_row::bubble_inline_sizes {:x}",
self.block_flow.base.debug_id());
let _scope = layout_debug_scope!(
"table_row::bubble_inline_sizes {:x}",
self.block_flow.base.debug_id()
);
// Bubble up the specified inline-sizes from child table cells.
let (mut min_inline_size, mut pref_inline_size) = (Au(0), Au(0));
let collapsing_borders = self.block_flow
.fragment
.style()
.get_inherited_table()
.border_collapse == BorderCollapse::Collapse;
let collapsing_borders = self
.block_flow
.fragment
.style()
.get_inherited_table()
.border_collapse ==
BorderCollapse::Collapse;
let row_style = &*self.block_flow.fragment.style;
self.preliminary_collapsed_borders.reset(
CollapsedBorder::inline_start(&row_style,
CollapsedBorderProvenance::FromTableRow));
self.preliminary_collapsed_borders
.reset(CollapsedBorder::inline_start(
&row_style,
CollapsedBorderProvenance::FromTableRow,
));
{
let children_count = self.block_flow.base.children.len();
@ -373,10 +404,11 @@ impl Flow for TableRowFlow {
let child_row_span;
{
let child_table_cell = kid.as_mut_table_cell();
child_specified_inline_size = child_table_cell.block_flow
.fragment
.style
.content_inline_size();
child_specified_inline_size = child_table_cell
.block_flow
.fragment
.style
.content_inline_size();
child_column_span = child_table_cell.column_span;
child_row_span = child_table_cell.row_span;
@ -388,7 +420,8 @@ impl Flow for TableRowFlow {
i,
child_table_cell,
&mut iterator,
&mut self.preliminary_collapsed_borders)
&mut self.preliminary_collapsed_borders,
)
}
}
@ -401,7 +434,7 @@ impl Flow for TableRowFlow {
LengthOrPercentageOrAuto::Calc(_) |
LengthOrPercentageOrAuto::Percentage(_) => {
child_base.intrinsic_inline_sizes.minimum_inline_size
}
},
LengthOrPercentageOrAuto::Length(length) => Au::from(length),
},
percentage: match child_specified_inline_size {
@ -420,23 +453,34 @@ impl Flow for TableRowFlow {
};
min_inline_size = min_inline_size + child_column_inline_size.minimum_length;
pref_inline_size = pref_inline_size + child_column_inline_size.preferred;
self.cell_intrinsic_inline_sizes.push(CellIntrinsicInlineSize {
column_size: child_column_inline_size,
column_span: child_column_span,
row_span: child_row_span,
});
self.cell_intrinsic_inline_sizes
.push(CellIntrinsicInlineSize {
column_size: child_column_inline_size,
column_span: child_column_span,
row_span: child_row_span,
});
}
}
self.block_flow.base.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);
self.block_flow
.base
.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) {
let _scope = layout_debug_scope!("table_row::assign_inline_sizes {:x}",
self.block_flow.base.debug_id());
debug!("assign_inline_sizes({}): assigning inline_size for flow", "table_row");
let _scope = layout_debug_scope!(
"table_row::assign_inline_sizes {:x}",
self.block_flow.base.debug_id()
);
debug!(
"assign_inline_sizes({}): assigning inline_size for flow",
"table_row"
);
let shared_context = layout_context.shared_context();
// 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_size_computer = InternalTable;
inline_size_computer.compute_used_inline_size(&mut self.block_flow,
shared_context,
containing_block_inline_size);
inline_size_computer.compute_used_inline_size(
&mut self.block_flow,
shared_context,
containing_block_inline_size,
);
// Spread out the completed inline sizes among columns with spans > 1.
let num_columns = self.column_computed_inline_sizes.len();
@ -461,26 +507,23 @@ impl Flow for TableRowFlow {
while col < self.incoming_rowspan.len() && self.incoming_rowspan[col] != 1 {
let size = match self.column_computed_inline_sizes.get(col) {
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);
col += 1;
}
// Start with the computed inline size for the first column in the span.
let mut column_computed_inline_size =
match self.column_computed_inline_sizes.get(col) {
Some(column_computed_inline_size) => *column_computed_inline_size,
None => {
// We're in fixed layout mode and there are more cells in this row than
// columns we know about. According to CSS 2.1 § 17.5.2.1, the behavior is
// now undefined. So just use zero.
//
// FIXME(pcwalton): $10 says this isn't Web compatible.
ColumnComputedInlineSize {
size: Au(0),
}
}
};
let mut column_computed_inline_size = match self.column_computed_inline_sizes.get(col) {
Some(column_computed_inline_size) => *column_computed_inline_size,
None => {
// We're in fixed layout mode and there are more cells in this row than
// columns we know about. According to CSS 2.1 § 17.5.2.1, the behavior is
// now undefined. So just use zero.
//
// FIXME(pcwalton): $10 says this isn't Web compatible.
ColumnComputedInlineSize { size: Au(0) }
},
};
col += 1;
// Add in computed inline sizes for any extra columns in the span.
@ -491,7 +534,8 @@ impl Flow for TableRowFlow {
None => break,
};
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;
}
@ -499,16 +543,19 @@ impl Flow for TableRowFlow {
}
// Set up border collapse info.
let border_collapse_info =
match self.block_flow.fragment.style().get_inherited_table().border_collapse {
BorderCollapse::Collapse => {
Some(BorderCollapseInfoForChildTableCell {
collapsed_borders_for_row: &self.final_collapsed_borders,
collapsed_border_spacing_for_row: &self.collapsed_border_spacing,
})
}
BorderCollapse::Separate => None,
};
let border_collapse_info = match self
.block_flow
.fragment
.style()
.get_inherited_table()
.border_collapse
{
BorderCollapse::Collapse => Some(BorderCollapseInfoForChildTableCell {
collapsed_borders_for_row: &self.final_collapsed_borders,
collapsed_border_spacing_for_row: &self.collapsed_border_spacing,
}),
BorderCollapse::Separate => None,
};
// Push those inline sizes down to the cells.
let spacing = self.spacing;
@ -517,30 +564,33 @@ impl Flow for TableRowFlow {
let incoming_rowspan = &self.incoming_rowspan;
let mut column_index = 0;
self.block_flow.propagate_assigned_inline_size_to_children(shared_context,
inline_start_content_edge,
inline_end_content_edge,
containing_block_inline_size,
|child_flow,
child_index,
content_inline_size,
_writing_mode,
inline_start_margin_edge,
inline_end_margin_edge| {
set_inline_position_of_child_flow(
child_flow,
child_index,
&mut column_index,
incoming_rowspan,
row_writing_mode,
table_writing_mode,
&computed_inline_size_for_cells,
&spacing,
&border_collapse_info,
content_inline_size,
inline_start_margin_edge,
inline_end_margin_edge);
})
self.block_flow.propagate_assigned_inline_size_to_children(
shared_context,
inline_start_content_edge,
inline_end_content_edge,
containing_block_inline_size,
|child_flow,
child_index,
content_inline_size,
_writing_mode,
inline_start_margin_edge,
inline_end_margin_edge| {
set_inline_position_of_child_flow(
child_flow,
child_index,
&mut column_index,
incoming_rowspan,
row_writing_mode,
table_writing_mode,
&computed_inline_size_for_cells,
&spacing,
&border_collapse_info,
content_inline_size,
inline_start_margin_edge,
inline_end_margin_edge,
);
},
)
}
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) {
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) {
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) {
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) {
@ -564,12 +617,15 @@ impl Flow for TableRowFlow {
// handled in TableCellStyleInfo::build_display_list
// we skip setting the damage in TableCellStyleInfo::build_display_list()
// 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) {
self.block_flow.collect_stacking_contexts_for_block(state,
StackingContextCollectionFlags::empty());
self.block_flow
.collect_stacking_contexts_for_block(state, StackingContextCollectionFlags::empty());
}
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)
}
fn iterate_through_fragment_border_boxes(&self,
iterator: &mut FragmentBorderBoxIterator,
level: i32,
stacking_context_position: &Point2D<Au>) {
self.block_flow.iterate_through_fragment_border_boxes(iterator, level, stacking_context_position)
fn iterate_through_fragment_border_boxes(
&self,
iterator: &mut FragmentBorderBoxIterator,
level: i32,
stacking_context_position: &Point2D<Au>,
) {
self.block_flow.iterate_through_fragment_border_boxes(
iterator,
level,
stacking_context_position,
)
}
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
/// object.
fn top(css_style: &ComputedValues, provenance: CollapsedBorderProvenance)
-> CollapsedBorder {
fn top(css_style: &ComputedValues, provenance: CollapsedBorderProvenance) -> CollapsedBorder {
CollapsedBorder {
style: css_style.get_border().border_top_style,
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
/// object.
fn right(css_style: &ComputedValues, provenance: CollapsedBorderProvenance)
-> CollapsedBorder {
fn right(css_style: &ComputedValues, provenance: CollapsedBorderProvenance) -> CollapsedBorder {
CollapsedBorder {
style: css_style.get_border().border_right_style,
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
/// object.
fn bottom(css_style: &ComputedValues, provenance: CollapsedBorderProvenance)
-> CollapsedBorder {
fn bottom(
css_style: &ComputedValues,
provenance: CollapsedBorderProvenance,
) -> CollapsedBorder {
CollapsedBorder {
style: css_style.get_border().border_bottom_style,
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
/// object.
fn left(css_style: &ComputedValues, provenance: CollapsedBorderProvenance)
-> CollapsedBorder {
fn left(css_style: &ComputedValues, provenance: CollapsedBorderProvenance) -> CollapsedBorder {
CollapsedBorder {
style: css_style.get_border().border_left_style,
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.
fn from_side(side: PhysicalSide,
css_style: &ComputedValues,
provenance: CollapsedBorderProvenance)
-> CollapsedBorder {
fn from_side(
side: PhysicalSide,
css_style: &ComputedValues,
provenance: CollapsedBorderProvenance,
) -> CollapsedBorder {
match side {
PhysicalSide::Top => CollapsedBorder::top(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
/// style object.
pub fn inline_start(css_style: &ComputedValues, provenance: CollapsedBorderProvenance)
-> CollapsedBorder {
CollapsedBorder::from_side(css_style.writing_mode.inline_start_physical_side(),
css_style,
provenance)
pub fn inline_start(
css_style: &ComputedValues,
provenance: CollapsedBorderProvenance,
) -> CollapsedBorder {
CollapsedBorder::from_side(
css_style.writing_mode.inline_start_physical_side(),
css_style,
provenance,
)
}
/// Creates a collapsed border style from the inline-start border described in the given CSS
/// style object.
pub fn inline_end(css_style: &ComputedValues, provenance: CollapsedBorderProvenance)
-> CollapsedBorder {
CollapsedBorder::from_side(css_style.writing_mode.inline_end_physical_side(),
css_style,
provenance)
pub fn inline_end(
css_style: &ComputedValues,
provenance: CollapsedBorderProvenance,
) -> CollapsedBorder {
CollapsedBorder::from_side(
css_style.writing_mode.inline_end_physical_side(),
css_style,
provenance,
)
}
/// Creates a collapsed border style from the block-start border described in the given CSS
/// style object.
pub fn block_start(css_style: &ComputedValues, provenance: CollapsedBorderProvenance)
-> CollapsedBorder {
CollapsedBorder::from_side(css_style.writing_mode.block_start_physical_side(),
css_style,
provenance)
pub fn block_start(
css_style: &ComputedValues,
provenance: CollapsedBorderProvenance,
) -> CollapsedBorder {
CollapsedBorder::from_side(
css_style.writing_mode.block_start_physical_side(),
css_style,
provenance,
)
}
/// Creates a collapsed border style from the block-end border described in the given CSS style
/// object.
pub fn block_end(css_style: &ComputedValues, provenance: CollapsedBorderProvenance)
-> CollapsedBorder {
CollapsedBorder::from_side(css_style.writing_mode.block_end_physical_side(),
css_style,
provenance)
pub fn block_end(
css_style: &ComputedValues,
provenance: CollapsedBorderProvenance,
) -> CollapsedBorder {
CollapsedBorder::from_side(
css_style.writing_mode.block_end_physical_side(),
css_style,
provenance,
)
}
/// 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) {
match (self.style, other.style) {
// Step 1.
(BorderStyle::Hidden, _) => {}
(BorderStyle::Hidden, _) => {},
(_, BorderStyle::Hidden) => *self = *other,
// Step 2.
(BorderStyle::None, _) => *self = *other,
(_, BorderStyle::None) => {}
(_, BorderStyle::None) => {},
// Step 3.
_ if self.width > other.width => {}
_ if self.width > other.width => {},
_ 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,
// Step 4.
_ if (self.provenance as i8) >= other.provenance as i8 => {}
_ if (self.provenance as i8) >= other.provenance as i8 => {},
_ => *self = *other,
}
}
@ -829,11 +907,12 @@ impl CollapsedBorder {
/// Pushes column inline size, incoming rowspan, and border collapse info down to a child.
pub fn propagate_column_inline_sizes_to_child(
child_flow: &mut Flow,
table_writing_mode: WritingMode,
column_computed_inline_sizes: &[ColumnComputedInlineSize],
border_spacing: &BorderSpacing,
incoming_rowspan: &mut Vec<u32>) {
child_flow: &mut Flow,
table_writing_mode: WritingMode,
column_computed_inline_sizes: &[ColumnComputedInlineSize],
border_spacing: &BorderSpacing,
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
// parent.
//
@ -844,13 +923,15 @@ pub fn propagate_column_inline_sizes_to_child(
let child_table_rowgroup_flow = child_flow.as_mut_table_rowgroup();
child_table_rowgroup_flow.spacing = *border_spacing;
for kid in child_table_rowgroup_flow.block_flow.base.child_iter_mut() {
propagate_column_inline_sizes_to_child(kid,
table_writing_mode,
column_computed_inline_sizes,
border_spacing,
incoming_rowspan);
propagate_column_inline_sizes_to_child(
kid,
table_writing_mode,
column_computed_inline_sizes,
border_spacing,
incoming_rowspan,
);
}
}
},
FlowClass::TableRow => {
let child_table_row_flow = child_flow.as_mut_table_row();
child_table_row_flow.column_computed_inline_sizes =
@ -887,27 +968,28 @@ pub fn propagate_column_inline_sizes_to_child(
col += 1;
}
}
}
c => warn!("unexpected flow in table {:?}", c)
},
c => warn!("unexpected flow in table {:?}", c),
}
}
/// Lay out table cells inline according to the computer column sizes.
fn set_inline_position_of_child_flow(
child_flow: &mut Flow,
child_index: usize,
column_index: &mut usize,
incoming_rowspan: &[u32],
row_writing_mode: WritingMode,
table_writing_mode: WritingMode,
column_computed_inline_sizes: &[ColumnComputedInlineSize],
border_spacing: &BorderSpacing,
border_collapse_info: &Option<BorderCollapseInfoForChildTableCell>,
parent_content_inline_size: Au,
inline_start_margin_edge: &mut Au,
inline_end_margin_edge: &mut Au) {
child_flow: &mut Flow,
child_index: usize,
column_index: &mut usize,
incoming_rowspan: &[u32],
row_writing_mode: WritingMode,
table_writing_mode: WritingMode,
column_computed_inline_sizes: &[ColumnComputedInlineSize],
border_spacing: &BorderSpacing,
border_collapse_info: &Option<BorderCollapseInfoForChildTableCell>,
parent_content_inline_size: Au,
inline_start_margin_edge: &mut Au,
inline_end_margin_edge: &mut Au,
) {
if !child_flow.is_table_cell() {
return
return;
}
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) => {
// Write in the child's border collapse state.
child_table_cell.collapsed_borders = CollapsedBordersForCell {
inline_start_border: border_collapse_info.collapsed_borders_for_row
.inline
.get(child_index)
.map_or(CollapsedBorder::new(), |x| *x),
inline_end_border: border_collapse_info.collapsed_borders_for_row
.inline
.get(child_index + 1)
.map_or(CollapsedBorder::new(), |x| *x),
block_start_border: border_collapse_info.collapsed_borders_for_row
.block_start
.get(child_index)
.map_or(CollapsedBorder::new(), |x| *x),
block_end_border: border_collapse_info.collapsed_borders_for_row
.block_end
.get(child_index)
.map_or(CollapsedBorder::new(), |x| *x),
inline_start_width: border_collapse_info.collapsed_border_spacing_for_row
.inline
.get(child_index)
.map_or(Au(0), |x| *x),
inline_end_width: border_collapse_info.collapsed_border_spacing_for_row
.inline
.get(child_index + 1)
.map_or(Au(0), |x| *x),
block_start_width: border_collapse_info.collapsed_border_spacing_for_row
.block_start,
block_end_width: border_collapse_info.collapsed_border_spacing_for_row.block_end,
inline_start_border: border_collapse_info
.collapsed_borders_for_row
.inline
.get(child_index)
.map_or(CollapsedBorder::new(), |x| *x),
inline_end_border: border_collapse_info
.collapsed_borders_for_row
.inline
.get(child_index + 1)
.map_or(CollapsedBorder::new(), |x| *x),
block_start_border: border_collapse_info
.collapsed_borders_for_row
.block_start
.get(child_index)
.map_or(CollapsedBorder::new(), |x| *x),
block_end_border: border_collapse_info
.collapsed_borders_for_row
.block_end
.get(child_index)
.map_or(CollapsedBorder::new(), |x| *x),
inline_start_width: border_collapse_info
.collapsed_border_spacing_for_row
.inline
.get(child_index)
.map_or(Au(0), |x| *x),
inline_end_width: border_collapse_info
.collapsed_border_spacing_for_row
.inline
.get(child_index + 1)
.map_or(Au(0), |x| *x),
block_start_width: border_collapse_info
.collapsed_border_spacing_for_row
.block_start,
block_end_width: border_collapse_info
.collapsed_border_spacing_for_row
.block_end,
};
// Move over past the collapsed border.
@ -968,7 +1059,7 @@ fn set_inline_position_of_child_flow(
} else {
*inline_start_margin_edge += child_table_cell.collapsed_borders.inline_start_width;
}
}
},
None => {
// Take spacing into account.
if reverse_column_order {
@ -976,7 +1067,7 @@ fn set_inline_position_of_child_flow(
} else {
*inline_start_margin_edge += border_spacing.horizontal();
}
}
},
}
let column_inline_size = column_computed_inline_sizes[*column_index].size;
@ -1008,51 +1099,68 @@ pub struct BorderCollapseInfoForChildTableCell<'a> {
/// table row. This is done eagerly here so that at least the inline inside border collapse
/// computations can be parallelized across all the rows of the table.
fn perform_inline_direction_border_collapse_for_row(
row_style: &ComputedValues,
children_count: usize,
child_index: usize,
child_table_cell: &mut TableCellFlow,
iterator: &mut Peekable<Enumerate<MutFlowListIterator>>,
preliminary_collapsed_borders: &mut CollapsedBordersForRow) {
row_style: &ComputedValues,
children_count: usize,
child_index: usize,
child_table_cell: &mut TableCellFlow,
iterator: &mut Peekable<Enumerate<MutFlowListIterator>>,
preliminary_collapsed_borders: &mut CollapsedBordersForRow,
) {
// In the first cell, combine its border with the one coming from the row.
if child_index == 0 {
let first_inline_border = &mut preliminary_collapsed_borders.inline[0];
first_inline_border.combine(
&CollapsedBorder::inline_start(&*child_table_cell.block_flow.fragment.style,
CollapsedBorderProvenance::FromNextTableCell));
first_inline_border.combine(&CollapsedBorder::inline_start(
&*child_table_cell.block_flow.fragment.style,
CollapsedBorderProvenance::FromNextTableCell,
));
}
let inline_collapsed_border = preliminary_collapsed_borders.inline.push_or_set(
child_index + 1,
CollapsedBorder::inline_end(&*child_table_cell.block_flow.fragment.style,
CollapsedBorderProvenance::FromPreviousTableCell));
CollapsedBorder::inline_end(
&*child_table_cell.block_flow.fragment.style,
CollapsedBorderProvenance::FromPreviousTableCell,
),
);
if let Some(&(_, ref next_child_flow)) = iterator.peek() {
let next_child_flow = next_child_flow.as_block();
inline_collapsed_border.combine(
&CollapsedBorder::inline_start(&*next_child_flow.fragment.style,
CollapsedBorderProvenance::FromNextTableCell))
inline_collapsed_border.combine(&CollapsedBorder::inline_start(
&*next_child_flow.fragment.style,
CollapsedBorderProvenance::FromNextTableCell,
))
};
// In the last cell, also take into account the border that may
// come from the row.
if child_index + 1 == children_count {
inline_collapsed_border.combine(
&CollapsedBorder::inline_end(&row_style,
CollapsedBorderProvenance::FromTableRow));
inline_collapsed_border.combine(&CollapsedBorder::inline_end(
&row_style,
CollapsedBorderProvenance::FromTableRow,
));
}
let mut block_start_border =
CollapsedBorder::block_start(&*child_table_cell.block_flow.fragment.style,
CollapsedBorderProvenance::FromNextTableCell);
block_start_border.combine(
&CollapsedBorder::block_start(row_style, CollapsedBorderProvenance::FromTableRow));
preliminary_collapsed_borders.block_start.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));
let mut block_start_border = CollapsedBorder::block_start(
&*child_table_cell.block_flow.fragment.style,
CollapsedBorderProvenance::FromNextTableCell,
);
block_start_border.combine(&CollapsedBorder::block_start(
row_style,
CollapsedBorderProvenance::FromTableRow,
));
preliminary_collapsed_borders
.block_start
.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

@ -66,23 +66,32 @@ impl TableRowGroupFlow {
}
pub fn populate_collapsed_border_spacing<'a, I>(
&mut self,
collapsed_inline_direction_border_widths_for_table: &[Au],
collapsed_block_direction_border_widths_for_table: &mut Peekable<I>)
where I: Iterator<Item=&'a Au> {
self.collapsed_inline_direction_border_widths_for_table.clear();
&mut self,
collapsed_inline_direction_border_widths_for_table: &[Au],
collapsed_block_direction_border_widths_for_table: &mut Peekable<I>,
) where
I: Iterator<Item = &'a Au>,
{
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() {
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
.push(*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
.push(**collapsed_block_direction_border_width_for_table)
}
@ -111,8 +120,10 @@ impl Flow for TableRowGroupFlow {
}
fn bubble_inline_sizes(&mut self) {
let _scope = layout_debug_scope!("table_rowgroup::bubble_inline_sizes {:x}",
self.block_flow.base.debug_id());
let _scope = layout_debug_scope!(
"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
// 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.
/// 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) {
let _scope = layout_debug_scope!("table_rowgroup::assign_inline_sizes {:x}",
self.block_flow.base.debug_id());
debug!("assign_inline_sizes({}): assigning inline_size for flow", "table_rowgroup");
let _scope = layout_debug_scope!(
"table_rowgroup::assign_inline_sizes {:x}",
self.block_flow.base.debug_id()
);
debug!(
"assign_inline_sizes({}): assigning inline_size for flow",
"table_rowgroup"
);
let shared_context = layout_context.shared_context();
// The position was set to the containing block by the flow's parent.
@ -130,50 +146,66 @@ impl Flow for TableRowGroupFlow {
let (inline_start_content_edge, inline_end_content_edge) = (Au(0), Au(0));
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;
inline_size_computer.compute_used_inline_size(&mut self.block_flow,
shared_context,
containing_block_inline_size);
inline_size_computer.compute_used_inline_size(
&mut self.block_flow,
shared_context,
containing_block_inline_size,
);
let collapsed_inline_direction_border_widths_for_table =
&self.collapsed_inline_direction_border_widths_for_table;
let mut collapsed_block_direction_border_widths_for_table =
self.collapsed_block_direction_border_widths_for_table.iter().peekable();
self.block_flow.propagate_assigned_inline_size_to_children(shared_context,
inline_start_content_edge,
inline_end_content_edge,
content_inline_size,
|child_flow,
_child_index,
_content_inline_size,
_writing_mode,
_inline_start_margin_edge,
_inline_end_margin_edge| {
if border_collapse == border_collapse::T::Collapse {
let child_table_row = child_flow.as_mut_table_row();
child_table_row.populate_collapsed_border_spacing(
collapsed_inline_direction_border_widths_for_table,
&mut collapsed_block_direction_border_widths_for_table);
}
});
let mut collapsed_block_direction_border_widths_for_table = self
.collapsed_block_direction_border_widths_for_table
.iter()
.peekable();
self.block_flow.propagate_assigned_inline_size_to_children(
shared_context,
inline_start_content_edge,
inline_end_content_edge,
content_inline_size,
|child_flow,
_child_index,
_content_inline_size,
_writing_mode,
_inline_start_margin_edge,
_inline_end_margin_edge| {
if border_collapse == border_collapse::T::Collapse {
let child_table_row = child_flow.as_mut_table_row();
child_table_row.populate_collapsed_border_spacing(
collapsed_inline_direction_border_widths_for_table,
&mut collapsed_block_direction_border_widths_for_table,
);
}
},
);
}
fn assign_block_size(&mut self, lc: &LayoutContext) {
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) {
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) {
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) {
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) {
@ -181,12 +213,17 @@ impl Flow for TableRowGroupFlow {
// we skip setting the damage in TableCellStyleInfo::build_display_list()
// 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) {
self.block_flow.collect_stacking_contexts_for_block(state,
StackingContextCollectionFlags::POSITION_NEVER_CREATES_CONTAINING_BLOCK);
self.block_flow.collect_stacking_contexts_for_block(
state,
StackingContextCollectionFlags::POSITION_NEVER_CREATES_CONTAINING_BLOCK,
);
}
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)
}
fn iterate_through_fragment_border_boxes(&self,
iterator: &mut FragmentBorderBoxIterator,
level: i32,
stacking_context_position: &Point2D<Au>) {
self.block_flow.iterate_through_fragment_border_boxes(iterator, level, stacking_context_position)
fn iterate_through_fragment_border_boxes(
&self,
iterator: &mut FragmentBorderBoxIterator,
level: i32,
stacking_context_position: &Point2D<Au>,
) {
self.block_flow.iterate_through_fragment_border_boxes(
iterator,
level,
stacking_context_position,
)
}
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)]
pub enum TableLayout {
Fixed,
Auto
Auto,
}
#[allow(unsafe_code)]
@ -63,19 +63,21 @@ impl TableWrapperFlow {
TableWrapperFlow::from_fragment_and_float_kind(fragment, None)
}
pub fn from_fragment_and_float_kind(fragment: Fragment, float_kind: Option<FloatKind>)
-> TableWrapperFlow {
pub fn from_fragment_and_float_kind(
fragment: Fragment,
float_kind: Option<FloatKind>,
) -> TableWrapperFlow {
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 ==
table_layout::T::Fixed {
TableLayout::Fixed
} else {
TableLayout::Auto
};
let table_layout =
if block_flow.fragment().style().get_table().table_layout == table_layout::T::Fixed {
TableLayout::Fixed
} else {
TableLayout::Auto
};
TableWrapperFlow {
block_flow: block_flow,
column_intrinsic_inline_sizes: vec!(),
table_layout: table_layout
column_intrinsic_inline_sizes: vec![],
table_layout: table_layout,
}
}
@ -85,9 +87,12 @@ impl TableWrapperFlow {
if kid.is_table() {
let kid_table = kid.as_table();
spacing = kid_table.total_horizontal_spacing();
table_border_padding =
kid_table.block_flow.fragment.border_padding.inline_start_end();
break
table_border_padding = kid_table
.block_flow
.fragment
.border_padding
.inline_start_end();
break;
}
}
(table_border_padding, spacing)
@ -103,41 +108,53 @@ impl TableWrapperFlow {
let available_inline_size = self.block_flow.base.block_container_inline_size;
for kid in self.block_flow.base.child_iter_mut() {
if !kid.is_table() {
continue
continue;
}
let kid_table = kid.as_mut_table();
let kid_block_flow = &mut kid_table.block_flow;
kid_block_flow.fragment.compute_border_and_padding(available_inline_size);
kid_block_flow.fragment.compute_block_direction_margins(available_inline_size);
kid_block_flow.fragment.compute_inline_direction_margins(available_inline_size);
return
kid_block_flow
.fragment
.compute_border_and_padding(available_inline_size);
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.
fn calculate_table_column_sizes_for_automatic_layout(
&mut self,
intermediate_column_inline_sizes: &mut [IntermediateColumnInlineSize]) {
&mut self,
intermediate_column_inline_sizes: &mut [IntermediateColumnInlineSize],
) {
let available_inline_size = self.available_inline_size();
// Compute all the guesses for the column sizes, and sum them.
let mut total_guess = AutoLayoutCandidateGuess::new();
let guesses: Vec<AutoLayoutCandidateGuess> =
self.column_intrinsic_inline_sizes.iter().map(|column_intrinsic_inline_size| {
let guesses: Vec<AutoLayoutCandidateGuess> = self
.column_intrinsic_inline_sizes
.iter()
.map(|column_intrinsic_inline_size| {
let guess = AutoLayoutCandidateGuess::from_column_intrinsic_inline_size(
column_intrinsic_inline_size,
available_inline_size);
available_inline_size,
);
total_guess = &total_guess + &guess;
guess
}).collect();
// Assign inline sizes.
let selection = SelectedAutoLayoutCandidateGuess::select(&total_guess,
available_inline_size);
let selection =
SelectedAutoLayoutCandidateGuess::select(&total_guess, available_inline_size);
let mut total_used_inline_size = Au(0);
for (intermediate_column_inline_size, guess) in
intermediate_column_inline_sizes.iter_mut().zip(guesses.iter()) {
for (intermediate_column_inline_size, guess) in intermediate_column_inline_sizes
.iter_mut()
.zip(guesses.iter())
{
intermediate_column_inline_size.size = guess.calculate(selection);
intermediate_column_inline_size.percentage = 0.0;
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?
let excess_inline_size = available_inline_size - total_used_inline_size;
if excess_inline_size > Au(0) && selection ==
SelectedAutoLayoutCandidateGuess::UsePreferredGuessAndDistributeExcessInlineSize {
if excess_inline_size > Au(0) &&
selection ==
SelectedAutoLayoutCandidateGuess::UsePreferredGuessAndDistributeExcessInlineSize
{
let mut info = ExcessInlineSizeDistributionInfo::new();
for column_intrinsic_inline_size in &self.column_intrinsic_inline_sizes {
info.update(column_intrinsic_inline_size)
@ -156,13 +175,16 @@ impl TableWrapperFlow {
let mut total_distributed_excess_size = Au(0);
for (intermediate_column_inline_size, column_intrinsic_inline_size) in
intermediate_column_inline_sizes.iter_mut()
.zip(self.column_intrinsic_inline_sizes
.iter()) {
info.distribute_excess_inline_size_to_column(intermediate_column_inline_size,
column_intrinsic_inline_size,
excess_inline_size,
&mut total_distributed_excess_size)
intermediate_column_inline_sizes
.iter_mut()
.zip(self.column_intrinsic_inline_sizes.iter())
{
info.distribute_excess_inline_size_to_column(
intermediate_column_inline_size,
column_intrinsic_inline_size,
excess_inline_size,
&mut total_distributed_excess_size,
)
}
total_used_inline_size = available_inline_size
}
@ -179,9 +201,10 @@ impl TableWrapperFlow {
// just use the shrink-to-fit inline size.
let available_inline_size = match self.block_flow.fragment.style().content_inline_size() {
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
}
},
// FIXME(mttr): This fixes #4421 without breaking our current reftests, but I'm not
// completely sure this is "correct".
//
@ -196,10 +219,12 @@ impl TableWrapperFlow {
fn set_inline_size(&mut self, total_used_inline_size: Au) {
let (table_border_padding, spacing) = self.border_padding_and_spacing();
self.block_flow.fragment.border_box.size.inline = total_used_inline_size +
table_border_padding + spacing;
self.block_flow.fragment.border_box.size.inline =
total_used_inline_size + table_border_padding + spacing;
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 container_mode = self.block_flow.base.block_container_writing_mode;
@ -209,29 +234,30 @@ impl TableWrapperFlow {
// depends on `border_box.size.inline`.
self.block_flow.fragment.border_box.start.i =
self.block_flow.base.block_container_inline_size -
self.block_flow.fragment.margin.inline_end -
self.block_flow.fragment.border_box.size.inline;
self.block_flow.fragment.margin.inline_end -
self.block_flow.fragment.border_box.size.inline;
}
}
fn compute_used_inline_size(
&mut self,
shared_context: &SharedStyleContext,
parent_flow_inline_size: Au,
intermediate_column_inline_sizes: &[IntermediateColumnInlineSize]) {
&mut self,
shared_context: &SharedStyleContext,
parent_flow_inline_size: Au,
intermediate_column_inline_sizes: &[IntermediateColumnInlineSize],
) {
let (border_padding, spacing) = self.border_padding_and_spacing();
let minimum_width_of_all_columns =
intermediate_column_inline_sizes.iter()
.fold(border_padding + spacing,
|accumulator, intermediate_column_inline_sizes| {
let minimum_width_of_all_columns = intermediate_column_inline_sizes.iter().fold(
border_padding + spacing,
|accumulator, intermediate_column_inline_sizes| {
accumulator + intermediate_column_inline_sizes.size
});
let preferred_width_of_all_columns =
self.column_intrinsic_inline_sizes.iter()
.fold(border_padding + spacing,
|accumulator, column_intrinsic_inline_sizes| {
},
);
let preferred_width_of_all_columns = self.column_intrinsic_inline_sizes.iter().fold(
border_padding + spacing,
|accumulator, column_intrinsic_inline_sizes| {
accumulator + column_intrinsic_inline_sizes.preferred
});
},
);
// Delegate to the appropriate inline size computer to find the constraint inputs and write
// the constraint solutions in.
@ -241,38 +267,45 @@ impl TableWrapperFlow {
preferred_width_of_all_columns: preferred_width_of_all_columns,
table_border_padding: border_padding,
};
let input =
inline_size_computer.compute_inline_size_constraint_inputs(&mut self.block_flow,
parent_flow_inline_size,
shared_context);
let input = inline_size_computer.compute_inline_size_constraint_inputs(
&mut self.block_flow,
parent_flow_inline_size,
shared_context,
);
let solution = 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_position_of_flow_if_necessary(&mut self.block_flow,
solution);
return
let solution =
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_position_of_flow_if_necessary(&mut self.block_flow, solution);
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 {
minimum_width_of_all_columns: minimum_width_of_all_columns,
preferred_width_of_all_columns: preferred_width_of_all_columns,
table_border_padding: border_padding,
};
let input =
inline_size_computer.compute_inline_size_constraint_inputs(&mut self.block_flow,
parent_flow_inline_size,
shared_context);
let input = inline_size_computer.compute_inline_size_constraint_inputs(
&mut self.block_flow,
parent_flow_inline_size,
shared_context,
);
let solution = 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_position_of_flow_if_necessary(&mut self.block_flow,
solution);
return
let solution =
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_position_of_flow_if_necessary(&mut self.block_flow, solution);
return;
}
let inline_size_computer = Table {
@ -280,16 +313,17 @@ impl TableWrapperFlow {
preferred_width_of_all_columns: preferred_width_of_all_columns,
table_border_padding: border_padding,
};
let input =
inline_size_computer.compute_inline_size_constraint_inputs(&mut self.block_flow,
parent_flow_inline_size,
shared_context);
let input = inline_size_computer.compute_inline_size_constraint_inputs(
&mut self.block_flow,
parent_flow_inline_size,
shared_context,
);
let solution = inline_size_computer.solve_inline_size_constraints(&mut self.block_flow,
&input);
let solution =
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_position_of_flow_if_necessary(&mut self.block_flow,
solution);
inline_size_computer
.set_inline_position_of_flow_if_necessary(&mut self.block_flow, solution);
}
}
@ -332,90 +366,96 @@ impl Flow for TableWrapperFlow {
}
fn assign_inline_sizes(&mut self, layout_context: &LayoutContext) {
debug!("assign_inline_sizes({}): assigning inline_size for flow",
if self.block_flow.base.flags.is_float() {
"floated table_wrapper"
} else {
"table_wrapper"
});
debug!(
"assign_inline_sizes({}): assigning inline_size for flow",
if self.block_flow.base.flags.is_float() {
"floated table_wrapper"
} else {
"table_wrapper"
}
);
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
.iter()
.map(|column_intrinsic_inline_size| {
IntermediateColumnInlineSize {
size: column_intrinsic_inline_size.minimum_length,
percentage: column_intrinsic_inline_size.percentage,
}
}).collect::<Vec<_>>();
let mut intermediate_column_inline_sizes = self
.column_intrinsic_inline_sizes
.iter()
.map(
|column_intrinsic_inline_size| IntermediateColumnInlineSize {
size: column_intrinsic_inline_size.minimum_length,
percentage: column_intrinsic_inline_size.percentage,
},
).collect::<Vec<_>>();
// Our inline-size was set to the inline-size of the containing block by the flow's parent.
// Now compute the real value.
let containing_block_inline_size = self.block_flow.base.block_container_inline_size;
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;
}
// This has to be done before computing our inline size because `compute_used_inline_size`
// internally consults the border and padding of the table.
self.compute_border_and_padding_of_table();
self.compute_used_inline_size(shared_context,
containing_block_inline_size,
&intermediate_column_inline_sizes);
self.compute_used_inline_size(
shared_context,
containing_block_inline_size,
&intermediate_column_inline_sizes,
);
match self.table_layout {
TableLayout::Auto => {
self.calculate_table_column_sizes_for_automatic_layout(
&mut intermediate_column_inline_sizes)
}
TableLayout::Fixed => {}
TableLayout::Auto => self.calculate_table_column_sizes_for_automatic_layout(
&mut intermediate_column_inline_sizes,
),
TableLayout::Fixed => {},
}
let inline_start_content_edge = self.block_flow.fragment.border_box.start.i;
let content_inline_size = self.block_flow.fragment.border_box.size.inline;
let inline_end_content_edge = self.block_flow.fragment.border_padding.inline_end +
self.block_flow.fragment.margin.inline_end;
self.block_flow.fragment.margin.inline_end;
// In case of fixed layout, column inline-sizes are calculated in table flow.
let assigned_column_inline_sizes = match self.table_layout {
TableLayout::Fixed => None,
TableLayout::Auto => {
Some(intermediate_column_inline_sizes.iter().map(|sizes| {
ColumnComputedInlineSize {
size: sizes.size,
}
}).collect::<Vec<_>>())
}
TableLayout::Auto => Some(
intermediate_column_inline_sizes
.iter()
.map(|sizes| ColumnComputedInlineSize { size: sizes.size })
.collect::<Vec<_>>(),
),
};
match assigned_column_inline_sizes {
None => {
self.block_flow
.propagate_assigned_inline_size_to_children(shared_context,
inline_start_content_edge,
inline_end_content_edge,
content_inline_size,
|_, _, _, _, _, _| {})
}
None => self.block_flow.propagate_assigned_inline_size_to_children(
shared_context,
inline_start_content_edge,
inline_end_content_edge,
content_inline_size,
|_, _, _, _, _, _| {},
),
Some(ref assigned_column_inline_sizes) => {
self.block_flow
.propagate_assigned_inline_size_to_children(shared_context,
inline_start_content_edge,
inline_end_content_edge,
content_inline_size,
|child_flow, _, _, _, _, _| {
if child_flow.class() == FlowClass::Table {
child_flow.as_mut_table().column_computed_inline_sizes =
assigned_column_inline_sizes.to_vec();
}
})
}
self.block_flow.propagate_assigned_inline_size_to_children(
shared_context,
inline_start_content_edge,
inline_end_content_edge,
content_inline_size,
|child_flow, _, _, _, _, _| {
if child_flow.class() == FlowClass::Table {
child_flow.as_mut_table().column_computed_inline_sizes =
assigned_column_inline_sizes.to_vec();
}
},
)
},
}
}
fn assign_block_size(&mut self, layout_context: &LayoutContext) {
@ -423,34 +463,42 @@ impl Flow for TableWrapperFlow {
let remaining = self.block_flow.assign_block_size_block_base(
layout_context,
None,
MarginsMayCollapseFlag::MarginsMayNotCollapse);
MarginsMayCollapseFlag::MarginsMayNotCollapse,
);
debug_assert!(remaining.is_none());
}
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) {
self.block_flow.place_float_if_applicable()
}
fn assign_block_size_for_inorder_child_if_necessary(&mut self,
layout_context: &LayoutContext,
parent_thread_id: u8,
content_box: LogicalRect<Au>)
-> bool {
self.block_flow.assign_block_size_for_inorder_child_if_necessary(layout_context,
parent_thread_id,
content_box)
fn assign_block_size_for_inorder_child_if_necessary(
&mut self,
layout_context: &LayoutContext,
parent_thread_id: u8,
content_box: LogicalRect<Au>,
) -> bool {
self.block_flow
.assign_block_size_for_inorder_child_if_necessary(
layout_context,
parent_thread_id,
content_box,
)
}
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) {
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> {
@ -465,7 +513,8 @@ impl Flow for TableWrapperFlow {
self.block_flow.collect_stacking_contexts_for_block(
state,
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>) {
@ -476,11 +525,17 @@ impl Flow for TableWrapperFlow {
self.block_flow.compute_overflow()
}
fn iterate_through_fragment_border_boxes(&self,
iterator: &mut FragmentBorderBoxIterator,
level: i32,
stacking_context_position: &Point2D<Au>) {
self.block_flow.iterate_through_fragment_border_boxes(iterator, level, stacking_context_position)
fn iterate_through_fragment_border_boxes(
&self,
iterator: &mut FragmentBorderBoxIterator,
level: i32,
stacking_context_position: &Point2D<Au>,
) {
self.block_flow.iterate_through_fragment_border_boxes(
iterator,
level,
stacking_context_position,
)
}
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.
fn from_column_intrinsic_inline_size(column_intrinsic_inline_size: &ColumnIntrinsicInlineSize,
assignable_inline_size: Au)
-> AutoLayoutCandidateGuess {
let minimum_percentage_guess =
max(assignable_inline_size.scale_by(column_intrinsic_inline_size.percentage),
column_intrinsic_inline_size.minimum_length);
fn from_column_intrinsic_inline_size(
column_intrinsic_inline_size: &ColumnIntrinsicInlineSize,
assignable_inline_size: Au,
) -> AutoLayoutCandidateGuess {
let minimum_percentage_guess = max(
assignable_inline_size.scale_by(column_intrinsic_inline_size.percentage),
column_intrinsic_inline_size.minimum_length,
);
AutoLayoutCandidateGuess {
minimum_guess: column_intrinsic_inline_size.minimum_length,
minimum_percentage_guess: minimum_percentage_guess,
@ -607,8 +664,8 @@ impl<'a> Add for &'a AutoLayoutCandidateGuess {
fn add(self, other: &AutoLayoutCandidateGuess) -> AutoLayoutCandidateGuess {
AutoLayoutCandidateGuess {
minimum_guess: self.minimum_guess + other.minimum_guess,
minimum_percentage_guess:
self.minimum_percentage_guess + other.minimum_percentage_guess,
minimum_percentage_guess: self.minimum_percentage_guess +
other.minimum_percentage_guess,
minimum_specified_guess: self.minimum_specified_guess + other.minimum_specified_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
/// inclusive ranges.
fn select(guess: &AutoLayoutCandidateGuess, assignable_inline_size: Au)
-> SelectedAutoLayoutCandidateGuess {
fn select(
guess: &AutoLayoutCandidateGuess,
assignable_inline_size: Au,
) -> SelectedAutoLayoutCandidateGuess {
if assignable_inline_size < guess.minimum_guess {
SelectedAutoLayoutCandidateGuess::UseMinimumGuess
} else if assignable_inline_size < guess.minimum_percentage_guess {
let weight = weight(guess.minimum_guess,
assignable_inline_size,
guess.minimum_percentage_guess);
let weight = weight(
guess.minimum_guess,
assignable_inline_size,
guess.minimum_percentage_guess,
);
SelectedAutoLayoutCandidateGuess::InterpolateBetweenMinimumGuessAndMinimumPercentageGuess(weight)
} else if assignable_inline_size < guess.minimum_specified_guess {
let weight = weight(guess.minimum_percentage_guess,
assignable_inline_size,
guess.minimum_specified_guess);
let weight = weight(
guess.minimum_percentage_guess,
assignable_inline_size,
guess.minimum_specified_guess,
);
SelectedAutoLayoutCandidateGuess::InterpolateBetweenMinimumPercentageGuessAndMinimumSpecifiedGuess(weight)
} else if assignable_inline_size < guess.preferred_guess {
let weight = weight(guess.minimum_specified_guess,
assignable_inline_size,
guess.preferred_guess);
let weight = weight(
guess.minimum_specified_guess,
assignable_inline_size,
guess.preferred_guess,
);
SelectedAutoLayoutCandidateGuess::InterpolateBetweenMinimumSpecifiedGuessAndPreferredGuess(weight)
} else {
SelectedAutoLayoutCandidateGuess::UsePreferredGuessAndDistributeExcessInlineSize
@ -688,17 +753,19 @@ impl ExcessInlineSizeDistributionInfo {
fn update(&mut self, column_intrinsic_inline_size: &ColumnIntrinsicInlineSize) {
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 +
column_intrinsic_inline_size.preferred;
column_intrinsic_inline_size.preferred;
self.count_of_nonconstrained_columns_with_no_percentage += 1
}
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 +
column_intrinsic_inline_size.preferred
column_intrinsic_inline_size.preferred
}
self.total_percentage += column_intrinsic_inline_size.percentage;
self.column_count += 1
@ -710,30 +777,32 @@ impl ExcessInlineSizeDistributionInfo {
/// `#[inline]` so the compiler will hoist out the branch, which is loop-invariant.
#[inline]
fn distribute_excess_inline_size_to_column(
&self,
intermediate_column_inline_size: &mut IntermediateColumnInlineSize,
column_intrinsic_inline_size: &ColumnIntrinsicInlineSize,
excess_inline_size: Au,
total_distributed_excess_size: &mut Au) {
&self,
intermediate_column_inline_size: &mut IntermediateColumnInlineSize,
column_intrinsic_inline_size: &ColumnIntrinsicInlineSize,
excess_inline_size: Au,
total_distributed_excess_size: &mut Au,
) {
let proportion =
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
// nonconstrained columns with no percentage *and* no preferred width. What do they
// do?
if !column_intrinsic_inline_size.constrained &&
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
.to_f32_px()
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
.to_f32_px()
} else {
0.0
}
} else if self.count_of_nonconstrained_columns_with_no_percentage > 0 {
1.0 / (self.count_of_nonconstrained_columns_with_no_percentage as CSSFloat)
} else if self.preferred_inline_size_of_constrained_columns_with_no_percentage >
Au(0) {
column_intrinsic_inline_size.preferred.to_f32_px() /
self.preferred_inline_size_of_constrained_columns_with_no_percentage.to_f32_px()
} else if self.preferred_inline_size_of_constrained_columns_with_no_percentage > Au(0) {
column_intrinsic_inline_size.preferred.to_f32_px() / self
.preferred_inline_size_of_constrained_columns_with_no_percentage
.to_f32_px()
} else if self.total_percentage > 0.0 {
column_intrinsic_inline_size.percentage / self.total_percentage
} else {
@ -742,11 +811,13 @@ impl ExcessInlineSizeDistributionInfo {
// The `min` here has the effect of throwing away fractional excess at the end of the
// table.
let amount_to_distribute = min(excess_inline_size.scale_by(proportion),
excess_inline_size - *total_distributed_excess_size);
let amount_to_distribute = min(
excess_inline_size.scale_by(proportion),
excess_inline_size - *total_distributed_excess_size,
);
*total_distributed_excess_size = *total_distributed_excess_size + amount_to_distribute;
intermediate_column_inline_size.size = intermediate_column_inline_size.size +
amount_to_distribute
intermediate_column_inline_size.size =
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
/// direction of the table contained within this table wrapper.
fn initial_computed_inline_size(block: &mut BlockFlow,
containing_block_inline_size: Au,
minimum_width_of_all_columns: Au,
preferred_width_of_all_columns: Au,
table_border_padding: Au)
-> MaybeAuto {
let inline_size_from_style = MaybeAuto::from_style(block.fragment.style.content_inline_size(),
containing_block_inline_size);
fn initial_computed_inline_size(
block: &mut BlockFlow,
containing_block_inline_size: Au,
minimum_width_of_all_columns: Au,
preferred_width_of_all_columns: Au,
table_border_padding: Au,
) -> MaybeAuto {
let inline_size_from_style = MaybeAuto::from_style(
block.fragment.style.content_inline_size(),
containing_block_inline_size,
);
match inline_size_from_style {
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)
} else if minimum_width_of_all_columns > containing_block_inline_size {
MaybeAuto::Specified(minimum_width_of_all_columns)
} else {
MaybeAuto::Auto
}
}
MaybeAuto::Specified(inline_size_from_style) => {
MaybeAuto::Specified(max(inline_size_from_style - table_border_padding,
minimum_width_of_all_columns))
}
},
MaybeAuto::Specified(inline_size_from_style) => MaybeAuto::Specified(max(
inline_size_from_style - table_border_padding,
minimum_width_of_all_columns,
)),
}
}
@ -793,27 +868,33 @@ struct Table {
impl ISizeAndMarginsComputer for Table {
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,
block: &mut BlockFlow,
parent_flow_inline_size: Au,
shared_context: &SharedStyleContext)
-> MaybeAuto {
fn initial_computed_inline_size(
&self,
block: &mut BlockFlow,
parent_flow_inline_size: Au,
shared_context: &SharedStyleContext,
) -> MaybeAuto {
let containing_block_inline_size =
self.containing_block_inline_size(block, parent_flow_inline_size, shared_context);
initial_computed_inline_size(block,
containing_block_inline_size,
self.minimum_width_of_all_columns,
self.preferred_width_of_all_columns,
self.table_border_padding)
initial_computed_inline_size(
block,
containing_block_inline_size,
self.minimum_width_of_all_columns,
self.preferred_width_of_all_columns,
self.table_border_padding,
)
}
fn solve_inline_size_constraints(&self,
block: &mut BlockFlow,
input: &ISizeConstraintInput)
-> ISizeConstraintSolution {
fn solve_inline_size_constraints(
&self,
block: &mut BlockFlow,
input: &ISizeConstraintInput,
) -> ISizeConstraintSolution {
self.solve_block_inline_size_constraints(block, input)
}
}
@ -826,29 +907,33 @@ struct FloatedTable {
impl ISizeAndMarginsComputer for FloatedTable {
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,
block: &mut BlockFlow,
parent_flow_inline_size: Au,
shared_context: &SharedStyleContext)
-> MaybeAuto {
fn initial_computed_inline_size(
&self,
block: &mut BlockFlow,
parent_flow_inline_size: Au,
shared_context: &SharedStyleContext,
) -> MaybeAuto {
let containing_block_inline_size =
self.containing_block_inline_size(block,
parent_flow_inline_size,
shared_context);
initial_computed_inline_size(block,
containing_block_inline_size,
self.minimum_width_of_all_columns,
self.preferred_width_of_all_columns,
self.table_border_padding)
self.containing_block_inline_size(block, parent_flow_inline_size, shared_context);
initial_computed_inline_size(
block,
containing_block_inline_size,
self.minimum_width_of_all_columns,
self.preferred_width_of_all_columns,
self.table_border_padding,
)
}
fn solve_inline_size_constraints(&self,
block: &mut BlockFlow,
input: &ISizeConstraintInput)
-> ISizeConstraintSolution {
fn solve_inline_size_constraints(
&self,
block: &mut BlockFlow,
input: &ISizeConstraintInput,
) -> ISizeConstraintSolution {
FloatNonReplaced.solve_inline_size_constraints(block, input)
}
}
@ -861,46 +946,54 @@ struct AbsoluteTable {
impl ISizeAndMarginsComputer for AbsoluteTable {
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,
block: &mut BlockFlow,
parent_flow_inline_size: Au,
shared_context: &SharedStyleContext)
-> MaybeAuto {
fn initial_computed_inline_size(
&self,
block: &mut BlockFlow,
parent_flow_inline_size: Au,
shared_context: &SharedStyleContext,
) -> MaybeAuto {
let containing_block_inline_size =
self.containing_block_inline_size(block,
parent_flow_inline_size,
shared_context);
initial_computed_inline_size(block,
containing_block_inline_size,
self.minimum_width_of_all_columns,
self.preferred_width_of_all_columns,
self.table_border_padding)
self.containing_block_inline_size(block, parent_flow_inline_size, shared_context);
initial_computed_inline_size(
block,
containing_block_inline_size,
self.minimum_width_of_all_columns,
self.preferred_width_of_all_columns,
self.table_border_padding,
)
}
fn containing_block_inline_size(&self,
block: &mut BlockFlow,
parent_flow_inline_size: Au,
shared_context: &SharedStyleContext)
-> Au {
AbsoluteNonReplaced.containing_block_inline_size(block,
parent_flow_inline_size,
shared_context)
fn containing_block_inline_size(
&self,
block: &mut BlockFlow,
parent_flow_inline_size: Au,
shared_context: &SharedStyleContext,
) -> Au {
AbsoluteNonReplaced.containing_block_inline_size(
block,
parent_flow_inline_size,
shared_context,
)
}
fn solve_inline_size_constraints(&self,
block: &mut BlockFlow,
input: &ISizeConstraintInput)
-> ISizeConstraintSolution {
fn solve_inline_size_constraints(
&self,
block: &mut BlockFlow,
input: &ISizeConstraintInput,
) -> ISizeConstraintSolution {
AbsoluteNonReplaced.solve_inline_size_constraints(block, input)
}
fn set_inline_position_of_flow_if_necessary(&self,
block: &mut BlockFlow,
solution: ISizeConstraintSolution) {
fn set_inline_position_of_flow_if_necessary(
&self,
block: &mut BlockFlow,
solution: ISizeConstraintSolution,
) {
AbsoluteNonReplaced.set_inline_position_of_flow_if_necessary(block, solution);
}
}

View file

@ -5,10 +5,15 @@
#![cfg(target_pointer_width = "64")]
extern crate layout;
#[macro_use] extern crate size_of_test;
#[macro_use]
extern crate size_of_test;
use layout::Fragment;
use layout::SpecificFragmentInfo;
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
}
/// A stack-allocated object for scanning an inline flow into `TextRun`-containing `TextFragment`s.
pub struct TextRunScanner {
pub clump: LinkedList<Fragment>,
@ -68,16 +67,25 @@ impl TextRunScanner {
}
}
pub fn scan_for_runs(&mut self,
font_context: &mut LayoutFontContext,
mut fragments: LinkedList<Fragment>)
-> InlineFragments {
debug!("TextRunScanner: scanning {} fragments for text runs...", fragments.len());
pub fn scan_for_runs(
&mut self,
font_context: &mut LayoutFontContext,
mut fragments: LinkedList<Fragment>,
) -> InlineFragments {
debug!(
"TextRunScanner: scanning {} fragments for text runs...",
fragments.len()
);
debug_assert!(!fragments.is_empty());
// Calculate bidi embedding levels, so we can split bidirectional fragments for reordering.
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));
// Optimization: If all the text is LTR, don't bother splitting on bidi levels.
@ -106,22 +114,25 @@ impl TextRunScanner {
// Create a clump.
split_first_fragment_at_newline_if_necessary(&mut fragments);
self.clump.append(&mut split_off_head(&mut fragments));
while !fragments.is_empty() && self.clump
.back()
.unwrap()
.can_merge_with_fragment(fragments.front()
.unwrap()) {
while !fragments.is_empty() && self
.clump
.back()
.unwrap()
.can_merge_with_fragment(fragments.front().unwrap())
{
split_first_fragment_at_newline_if_necessary(&mut fragments);
self.clump.append(&mut split_off_head(&mut fragments));
}
// Flush that clump to the list of fragments we're building up.
last_whitespace = self.flush_clump_to_list(font_context,
&mut new_fragments,
&mut paragraph_bytes_processed,
bidi_levels,
last_whitespace,
&mut linebreaker);
last_whitespace = self.flush_clump_to_list(
font_context,
&mut new_fragments,
&mut paragraph_bytes_processed,
bidi_levels,
last_whitespace,
&mut linebreaker,
);
}
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
/// for correct painting order. Since we compress several leaf fragments here, the mapping must
/// be adjusted.
fn flush_clump_to_list(&mut self,
mut font_context: &mut LayoutFontContext,
out_fragments: &mut Vec<Fragment>,
paragraph_bytes_processed: &mut usize,
bidi_levels: Option<&[bidi::Level]>,
mut last_whitespace: bool,
linebreaker: &mut Option<LineBreakLeafIter>)
-> bool {
debug!("TextRunScanner: flushing {} fragments in range", self.clump.len());
fn flush_clump_to_list(
&mut self,
mut font_context: &mut LayoutFontContext,
out_fragments: &mut Vec<Fragment>,
paragraph_bytes_processed: &mut usize,
bidi_levels: Option<&[bidi::Level]>,
mut last_whitespace: bool,
linebreaker: &mut Option<LineBreakLeafIter>,
) -> bool {
debug!(
"TextRunScanner: flushing {} fragments in range",
self.clump.len()
);
debug_assert!(!self.clump.is_empty());
match self.clump.front().unwrap().specific {
SpecificFragmentInfo::UnscannedText(_) => {}
SpecificFragmentInfo::UnscannedText(_) => {},
_ => {
debug_assert!(self.clump.len() == 1,
"WAT: can't coalesce non-text nodes in flush_clump_to_list()!");
debug_assert!(
self.clump.len() == 1,
"WAT: can't coalesce non-text nodes in flush_clump_to_list()!"
);
out_fragments.push(self.clump.pop_front().unwrap());
return false
}
return false;
},
}
// Concatenate all of the transformed strings together, saving the new character indices.
@ -173,17 +190,19 @@ impl TextRunScanner {
let inherited_text_style = in_fragment.style().get_inherited_text();
font_group = font_context.font_group(font_style);
compression = match in_fragment.white_space() {
WhiteSpace::Normal |
WhiteSpace::Nowrap => CompressionMode::CompressWhitespaceNewline,
WhiteSpace::Pre |
WhiteSpace::PreWrap => CompressionMode::CompressNone,
WhiteSpace::Normal | WhiteSpace::Nowrap => {
CompressionMode::CompressWhitespaceNewline
},
WhiteSpace::Pre | WhiteSpace::PreWrap => CompressionMode::CompressNone,
WhiteSpace::PreLine => CompressionMode::CompressWhitespace,
};
text_transform = inherited_text_style.text_transform;
letter_spacing = inherited_text_style.letter_spacing;
word_spacing = inherited_text_style.word_spacing.value()
.map(|lop| lop.to_hash_key())
.unwrap_or((Au(0), NotNan::new(0.0).unwrap()));
word_spacing = inherited_text_style
.word_spacing
.value()
.map(|lop| lop.to_hash_key())
.unwrap_or((Au(0), NotNan::new(0.0).unwrap()));
text_rendering = inherited_text_style.text_rendering;
word_break = inherited_text_style.word_break;
}
@ -201,7 +220,7 @@ impl TextRunScanner {
SpecificFragmentInfo::UnscannedText(ref text_fragment_info) => {
text = &text_fragment_info.text;
selection = text_fragment_info.selection;
}
},
_ => panic!("Expected an unscanned text fragment!"),
};
insertion_point = match selection {
@ -209,14 +228,16 @@ impl TextRunScanner {
// `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.
Some(range.begin() + ByteIndex(run_info.text.len() as isize))
}
_ => None
},
_ => None,
};
let (mut start_position, mut end_position) = (0, 0);
for (byte_index, character) in text.char_indices() {
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 {
Some(levels) => levels[*paragraph_bytes_processed],
@ -230,19 +251,20 @@ impl TextRunScanner {
// http://www.unicode.org/reports/tr24/#Common
let script = get_script(character);
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;
}
let selected = match selection {
Some(range) => range.contains(ByteIndex(byte_index as isize)),
None => false
None => false,
};
// Now, if necessary, flush the mapping we were building up.
let flush_run = !run_info.has_font(&font) ||
run_info.bidi_level != bidi_level ||
!compatible_script;
run_info.bidi_level != bidi_level ||
!compatible_script;
let new_mapping_needed = flush_run || mapping.selected != selected;
if new_mapping_needed {
@ -250,22 +272,23 @@ impl TextRunScanner {
// The run info values are uninitialized at this point so
// flushing an empty mapping is pointless.
if end_position > 0 {
mapping.flush(&mut mappings,
&mut run_info,
&**text,
compression,
text_transform,
&mut last_whitespace,
&mut start_position,
end_position);
mapping.flush(
&mut mappings,
&mut run_info,
&**text,
compression,
text_transform,
&mut last_whitespace,
&mut start_position,
end_position,
);
}
if run_info.text.len() > 0 {
if flush_run {
run_info.flush(&mut run_info_list, &mut insertion_point);
run_info = RunInfo::new();
}
mapping = RunMapping::new(&run_info_list[..],
fragment_index);
mapping = RunMapping::new(&run_info_list[..], fragment_index);
}
run_info.font = font;
run_info.bidi_level = bidi_level;
@ -280,14 +303,16 @@ impl TextRunScanner {
}
// Flush the last mapping we created for this fragment to the list.
mapping.flush(&mut mappings,
&mut run_info,
&**text,
compression,
text_transform,
&mut last_whitespace,
&mut start_position,
end_position);
mapping.flush(
&mut mappings,
&mut run_info,
&**text,
compression,
text_transform,
&mut last_whitespace,
&mut start_position,
end_position,
);
}
// 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.
let font =
run_info.font
.or_else(|| font_group.borrow_mut().first(&mut font_context))
.expect("No font found for text run!");
let font = run_info
.font
.or_else(|| font_group.borrow_mut().first(&mut font_context))
.expect("No font found for text run!");
let (run, break_at_zero) = TextRun::new(&mut *font.borrow_mut(),
run_info.text,
&options,
run_info.bidi_level,
linebreaker);
result.push((ScannedTextRun {
run: Arc::new(run),
insertion_point: run_info.insertion_point,
}, break_at_zero))
let (run, break_at_zero) = TextRun::new(
&mut *font.borrow_mut(),
run_info.text,
&options,
run_info.bidi_level,
linebreaker,
);
result.push((
ScannedTextRun {
run: Arc::new(run),
insertion_point: run_info.insertion_point,
},
break_at_zero,
))
}
result
};
@ -349,12 +379,14 @@ impl TextRunScanner {
let mut mappings = mappings.into_iter().peekable();
let mut prev_fragments_to_meld = Vec::new();
for (logical_offset, old_fragment) in
mem::replace(&mut self.clump, LinkedList::new()).into_iter().enumerate() {
for (logical_offset, old_fragment) in mem::replace(&mut self.clump, LinkedList::new())
.into_iter()
.enumerate()
{
let mut is_first_mapping_of_this_old_fragment = true;
loop {
match mappings.peek() {
Some(mapping) if mapping.old_fragment_index == logical_offset => {}
Some(mapping) if mapping.old_fragment_index == logical_offset => {},
Some(_) | None => {
if is_first_mapping_of_this_old_fragment {
// There were no mappings for this unscanned fragment. Transfer its
@ -365,13 +397,15 @@ impl TextRunScanner {
prev_fragments_to_meld.push(old_fragment);
}
break;
}
},
};
let mapping = mappings.next().unwrap();
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),
ByteIndex(mapping.byte_range.length() as isize));
let mut byte_range = Range::new(
ByteIndex(mapping.byte_range.begin() as isize),
ByteIndex(mapping.byte_range.length() as isize),
);
let mut flags = ScannedTextFlags::empty();
if !break_at_zero && mapping.byte_range.begin() == 0 {
@ -381,31 +415,34 @@ impl TextRunScanner {
}
let text_size = old_fragment.border_box.size;
let requires_line_break_afterward_if_wrapping_on_newlines =
scanned_run.run.text[mapping.byte_range.begin()..mapping.byte_range.end()]
let requires_line_break_afterward_if_wrapping_on_newlines = scanned_run.run.text
[mapping.byte_range.begin()..mapping.byte_range.end()]
.ends_with('\n');
if requires_line_break_afterward_if_wrapping_on_newlines {
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 {
flags.insert(ScannedTextFlags::SELECTED);
}
let insertion_point = if mapping.contains_insertion_point(scanned_run.insertion_point) {
scanned_run.insertion_point
} else {
None
};
let insertion_point =
if mapping.contains_insertion_point(scanned_run.insertion_point) {
scanned_run.insertion_point
} else {
None
};
let mut new_text_fragment_info = Box::new(ScannedTextFragmentInfo::new(
scanned_run.run,
byte_range,
text_size,
insertion_point,
flags
flags,
));
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(
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() {
Some(mapping) if mapping.old_fragment_index == logical_offset => false,
_ => true
_ => true,
};
if let Some(ref mut context) = new_fragment.inline_context {
for node in &mut context.nodes {
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 {
node.flags.remove(InlineFragmentNodeFlags::FIRST_FRAGMENT_OF_ELEMENT);
node.flags
.remove(InlineFragmentNodeFlags::FIRST_FRAGMENT_OF_ELEMENT);
}
}
}
@ -447,14 +487,17 @@ impl TextRunScanner {
}
#[inline]
fn bounding_box_for_run_metrics(metrics: &RunMetrics, writing_mode: WritingMode)
-> LogicalSize<Au> {
fn bounding_box_for_run_metrics(
metrics: &RunMetrics,
writing_mode: WritingMode,
) -> LogicalSize<Au> {
// TODO: When the text-orientation property is supported, the block and inline directions may
// be swapped for horizontal glyphs in vertical lines.
LogicalSize::new(
writing_mode,
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`.
@ -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.
#[inline]
pub fn font_metrics_for_style(mut font_context: &mut LayoutFontContext, style: ::ServoArc<FontStyleStruct>)
-> FontMetrics {
pub fn font_metrics_for_style(
mut font_context: &mut LayoutFontContext,
style: ::ServoArc<FontStyleStruct>,
) -> FontMetrics {
let font_group = font_context.font_group(style);
let font = font_group.borrow_mut().first(&mut font_context);
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 {
LineHeight::Normal => Au::from(metrics.line_gap),
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>) {
if fragments.is_empty() {
return
return;
}
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 {
SpecificFragmentInfo::UnscannedText(ref mut unscanned_text_fragment_info) => {
unscanned_text_fragment_info
}
},
_ => return,
};
let position = match unscanned_text_fragment_info.text.find('\n') {
Some(position) if position < unscanned_text_fragment_info.text.len() - 1 => {
position
}
},
Some(_) | None => return,
};
string_before =
unscanned_text_fragment_info.text[..(position + 1)].to_owned();
unscanned_text_fragment_info.text =
unscanned_text_fragment_info.text[(position + 1)..].to_owned().into_boxed_str();
string_before = unscanned_text_fragment_info.text[..(position + 1)].to_owned();
unscanned_text_fragment_info.text = unscanned_text_fragment_info.text[(position + 1)..]
.to_owned()
.into_boxed_str();
let offset = ByteIndex(string_before.len() as isize);
match unscanned_text_fragment_info.selection {
Some(ref mut selection) if selection.begin() >= offset => {
// Selection is entirely in the second fragment.
selection_before = None;
selection.shift_by(-offset);
}
},
Some(ref mut selection) if selection.end() > offset => {
// Selection is split across two fragments.
selection_before = Some(Range::new(selection.begin(), offset));
*selection = Range::new(ByteIndex(0), selection.end() - offset);
}
},
_ => {
// Selection is entirely in the first fragment.
selection_before = unscanned_text_fragment_info.selection;
unscanned_text_fragment_info.selection = None;
}
},
};
}
first_fragment.transform(
first_fragment.border_box.size,
SpecificFragmentInfo::UnscannedText(Box::new(
UnscannedTextFragmentInfo::new(string_before.into_boxed_str(), selection_before)
))
SpecificFragmentInfo::UnscannedText(Box::new(UnscannedTextFragmentInfo::new(
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
/// of this text run.
fn flush(mut self,
list: &mut Vec<RunInfo>,
insertion_point: &mut Option<ByteIndex>) {
fn flush(mut self, list: &mut Vec<RunInfo>, insertion_point: &mut Option<ByteIndex>) {
if let Some(idx) = *insertion_point {
let char_len = ByteIndex(self.text.len() as isize);
if idx <= char_len {
@ -617,8 +661,7 @@ struct RunMapping {
impl RunMapping {
/// 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.
fn new(run_info_list: &[RunInfo], fragment_index: usize)
-> RunMapping {
fn new(run_info_list: &[RunInfo], fragment_index: usize) -> RunMapping {
RunMapping {
byte_range: Range::new(0, 0),
old_fragment_index: fragment_index,
@ -629,27 +672,36 @@ impl RunMapping {
/// 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.
fn flush(mut self,
mappings: &mut Vec<RunMapping>,
run_info: &mut RunInfo,
text: &str,
compression: CompressionMode,
text_transform: TextTransform,
last_whitespace: &mut bool,
start_position: &mut usize,
end_position: usize) {
fn flush(
mut self,
mappings: &mut Vec<RunMapping>,
run_info: &mut RunInfo,
text: &str,
compression: CompressionMode,
text_transform: TextTransform,
last_whitespace: &mut bool,
start_position: &mut usize,
end_position: usize,
) {
let was_empty = *start_position == end_position;
let old_byte_length = run_info.text.len();
*last_whitespace = util::transform_text(&text[(*start_position)..end_position],
compression,
*last_whitespace,
&mut run_info.text);
*last_whitespace = util::transform_text(
&text[(*start_position)..end_position],
compression,
*last_whitespace,
&mut run_info.text,
);
// Account for `text-transform`. (Confusingly, this is not handled in "text
// transformation" above, but we follow Gecko in the naming.)
let is_first_run = *start_position == 0;
apply_style_transform_if_necessary(&mut run_info.text, old_byte_length, text_transform,
*last_whitespace, is_first_run);
apply_style_transform_if_necessary(
&mut run_info.text,
old_byte_length,
text_transform,
*last_whitespace,
is_first_run,
);
*start_position = end_position;
let new_byte_length = run_info.text.len();
@ -674,38 +726,39 @@ impl RunMapping {
fn contains_insertion_point(&self, insertion_point: Option<ByteIndex>) -> bool {
match insertion_point.map(ByteIndex::to_usize) {
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`.
///
/// FIXME(#4311, pcwalton): Title-case mapping can change length of the string;
/// case mapping should be language-specific; `full-width`;
/// use graphemes instead of characters.
fn apply_style_transform_if_necessary(string: &mut String,
first_character_position: usize,
text_transform: TextTransform,
last_whitespace: bool,
is_first_run: bool) {
fn apply_style_transform_if_necessary(
string: &mut String,
first_character_position: usize,
text_transform: TextTransform,
last_whitespace: bool,
is_first_run: bool,
) {
match text_transform {
TextTransform::None => {}
TextTransform::None => {},
TextTransform::Uppercase => {
let original = string[first_character_position..].to_owned();
string.truncate(first_character_position);
for ch in original.chars().flat_map(|ch| ch.to_uppercase()) {
string.push(ch);
}
}
},
TextTransform::Lowercase => {
let original = string[first_character_position..].to_owned();
string.truncate(first_character_position);
for ch in original.chars().flat_map(|ch| ch.to_lowercase()) {
string.push(ch);
}
}
},
TextTransform::Capitalize => {
let original = string[first_character_position..].to_owned();
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() {
string.push(character.to_uppercase().next().unwrap());
capitalize_next_letter = false;
continue
continue;
}
string.push(character);
@ -729,7 +782,7 @@ fn apply_style_transform_if_necessary(string: &mut String,
capitalize_next_letter = true
}
}
}
},
}
}

View file

@ -33,9 +33,7 @@ impl<'a> RecalcStyleAndConstructFlows<'a> {
impl<'a> RecalcStyleAndConstructFlows<'a> {
/// Creates a traversal context, taking ownership of the shared layout context.
pub fn new(context: LayoutContext<'a>) -> Self {
RecalcStyleAndConstructFlows {
context: context,
}
RecalcStyleAndConstructFlows { context: context }
}
/// Consumes this traversal context, returning ownership of the shared layout
@ -55,11 +53,11 @@ where
fn process_preorder<F>(
&self,
traversal_data: &PerLevelTraversalData,
context: &mut StyleContext<E>, node: E::ConcreteNode,
context: &mut StyleContext<E>,
node: E::ConcreteNode,
note_child: F,
)
where
F: FnMut(E::ConcreteNode)
) where
F: FnMut(E::ConcreteNode),
{
// FIXME(pcwalton): Stop allocating here. Ideally this should just be
// done by the HTML parser.
@ -76,7 +74,7 @@ where
construct_flows_at(&self.context, node);
}
fn text_node_needs_traversal(node: E::ConcreteNode, parent_data: &ElementData) -> bool {
fn text_node_needs_traversal(node: E::ConcreteNode, parent_data: &ElementData) -> bool {
// Text nodes never need styling. However, there are two cases they may need
// flow construction:
// (1) They child doesn't yet have layout data (preorder traversal initializes it).
@ -192,7 +190,8 @@ pub trait PostorderNodeMutTraversal<ConcreteThreadSafeLayoutNode: ThreadSafeLayo
#[inline]
#[allow(unsafe_code)]
fn construct_flows_at<N>(context: &LayoutContext, node: N)
where N: LayoutNode,
where
N: LayoutNode,
{
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.
let nonincremental_layout = opts::get().nonincremental_layout;
if nonincremental_layout || tnode.restyle_damage() != RestyleDamage::empty() ||
node.as_element().map_or(false, |el| el.has_dirty_descendants()) {
if nonincremental_layout || tnode.restyle_damage() != RestyleDamage::empty() || node
.as_element()
.map_or(false, |el| el.has_dirty_descendants())
{
let mut flow_constructor = FlowConstructor::new(context);
if nonincremental_layout || !flow_constructor.repair_if_possible(&tnode) {
flow_constructor.process(&tnode);
debug!("Constructed flow for {:?}: {:x}",
tnode,
tnode.flow_debug_id());
debug!(
"Constructed flow for {:?}: {:x}",
tnode,
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() {
unsafe { el.unset_dirty_descendants(); }
unsafe {
el.unset_dirty_descendants();
}
}
}
@ -231,12 +240,16 @@ impl<'a> PostorderFlowTraversal for BubbleISizes<'a> {
#[inline]
fn process(&self, flow: &mut Flow) {
flow.bubble_inline_sizes();
flow.mut_base().restyle_damage.remove(ServoRestyleDamage::BUBBLE_ISIZES);
flow.mut_base()
.restyle_damage
.remove(ServoRestyleDamage::BUBBLE_ISIZES);
}
#[inline]
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]
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
// reflowed anything!
if flow.floats_might_flow_through() {
return
return;
}
flow.assign_block_size(self.layout_context);
@ -298,13 +313,17 @@ pub struct ComputeStackingRelativePositions<'a> {
impl<'a> PreorderFlowTraversal for ComputeStackingRelativePositions<'a> {
#[inline]
fn should_process_subtree(&self, flow: &mut Flow) -> bool {
flow.base().restyle_damage.contains(ServoRestyleDamage::REPOSITION)
flow.base()
.restyle_damage
.contains(ServoRestyleDamage::REPOSITION)
}
#[inline]
fn process(&self, flow: &mut Flow) {
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();
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() {
self.traverse(kid);

View file

@ -57,7 +57,8 @@ impl<T: GetLayoutData> LayoutNodeLayoutData for T {
}
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() {
let style = self.as_element().unwrap().resolved_style();
return TextContent::GeneratedContent(
match style.as_ref().get_counters().content {
Content::Items(ref value) => value.to_vec(),
_ => vec![],
}
);
return TextContent::GeneratedContent(match style.as_ref().get_counters().content {
Content::Items(ref value) => value.to_vec(),
_ => vec![],
});
}
TextContent::Text(self.node_text_content().into_boxed_str())
@ -141,7 +140,12 @@ impl<T: ThreadSafeLayoutNode> ThreadSafeLayoutNodeHelpers for T {
let damage = {
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
// has never been visited by layout. Return rebuild_and_reflow,
// because that's what the code expects.
@ -153,7 +157,6 @@ impl<T: ThreadSafeLayoutNode> ThreadSafeLayoutNodeHelpers for T {
damage
}
}
pub enum TextContent {