mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
Rustfmt layout crate
This commit is contained in:
parent
577830de90
commit
349047b096
37 changed files with 7177 additions and 4832 deletions
|
@ -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
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,7 +24,6 @@ impl StyleAndLayoutData {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/// Data that layout associates with a node.
|
||||
#[repr(C)]
|
||||
pub struct LayoutData {
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
@ -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 {
|
||||
"es.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 {
|
||||
"es.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.
|
||||
|
|
|
@ -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
|
@ -47,7 +47,7 @@ impl ScopeData {
|
|||
name: name,
|
||||
pre: pre,
|
||||
post: Value::Null,
|
||||
children: vec!(),
|
||||
children: vec![],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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,
|
||||
);
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
@ -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)) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)) {}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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
|
||||
);
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue