mirror of
https://github.com/servo/servo.git
synced 2025-08-04 21:20:23 +01:00
Auto merge of #24928 - servo:2020-images, r=SimonSapin
Start supporting images in layout 2020
This commit is contained in:
commit
40fd7910a5
13 changed files with 267 additions and 65 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -2723,6 +2723,7 @@ dependencies = [
|
||||||
"ipc-channel",
|
"ipc-channel",
|
||||||
"libc",
|
"libc",
|
||||||
"msg",
|
"msg",
|
||||||
|
"net_traits",
|
||||||
"range",
|
"range",
|
||||||
"rayon",
|
"rayon",
|
||||||
"rayon_croissant",
|
"rayon_croissant",
|
||||||
|
|
|
@ -22,6 +22,7 @@ gfx_traits = {path = "../gfx_traits"}
|
||||||
ipc-channel = "0.12"
|
ipc-channel = "0.12"
|
||||||
libc = "0.2"
|
libc = "0.2"
|
||||||
msg = {path = "../msg"}
|
msg = {path = "../msg"}
|
||||||
|
net_traits = {path = "../net_traits"}
|
||||||
range = {path = "../range"}
|
range = {path = "../range"}
|
||||||
rayon = "1"
|
rayon = "1"
|
||||||
rayon_croissant = "0.1.1"
|
rayon_croissant = "0.1.1"
|
||||||
|
|
|
@ -78,6 +78,34 @@ impl Fragment {
|
||||||
.wr
|
.wr
|
||||||
.push_text(&common, rect.into(), &glyphs, t.font_key, rgba(color), None);
|
.push_text(&common, rect.into(), &glyphs, t.font_key, rgba(color), None);
|
||||||
},
|
},
|
||||||
|
Fragment::Image(i) => {
|
||||||
|
use style::computed_values::image_rendering::T as ImageRendering;
|
||||||
|
is_contentful.0 = true;
|
||||||
|
let rect = i
|
||||||
|
.content_rect
|
||||||
|
.to_physical(i.style.writing_mode(), containing_block)
|
||||||
|
.translate(&containing_block.top_left);
|
||||||
|
let common = CommonItemProperties {
|
||||||
|
clip_rect: rect.clone().into(),
|
||||||
|
clip_id: wr::ClipId::root(builder.pipeline_id),
|
||||||
|
spatial_id: wr::SpatialId::root_scroll_node(builder.pipeline_id),
|
||||||
|
hit_info: None,
|
||||||
|
// TODO(gw): Make use of the WR backface visibility functionality.
|
||||||
|
flags: PrimitiveFlags::default(),
|
||||||
|
};
|
||||||
|
builder.wr.push_image(
|
||||||
|
&common,
|
||||||
|
rect.into(),
|
||||||
|
match i.style.get_inherited_box().image_rendering {
|
||||||
|
ImageRendering::Auto => wr::ImageRendering::Auto,
|
||||||
|
ImageRendering::CrispEdges => wr::ImageRendering::CrispEdges,
|
||||||
|
ImageRendering::Pixelated => wr::ImageRendering::Pixelated,
|
||||||
|
},
|
||||||
|
wr::AlphaType::PremultipliedAlpha,
|
||||||
|
i.image_key,
|
||||||
|
wr::ColorF::WHITE,
|
||||||
|
);
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,18 +3,22 @@
|
||||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use crate::element_data::{LayoutBox, LayoutDataForElement};
|
use crate::element_data::{LayoutBox, LayoutDataForElement};
|
||||||
|
use crate::geom::physical::Vec2;
|
||||||
use crate::replaced::ReplacedContent;
|
use crate::replaced::ReplacedContent;
|
||||||
use crate::style_ext::{Display, DisplayGeneratingBox, DisplayInside, DisplayOutside};
|
use crate::style_ext::{Display, DisplayGeneratingBox, DisplayInside, DisplayOutside};
|
||||||
use crate::wrapper::GetRawData;
|
use crate::wrapper::GetRawData;
|
||||||
use atomic_refcell::{AtomicRefCell, AtomicRefMut};
|
use atomic_refcell::{AtomicRefCell, AtomicRefMut};
|
||||||
|
use net_traits::image::base::{Image as NetImage, ImageMetadata};
|
||||||
use script_layout_interface::wrapper_traits::{LayoutNode, ThreadSafeLayoutNode};
|
use script_layout_interface::wrapper_traits::{LayoutNode, ThreadSafeLayoutNode};
|
||||||
use servo_arc::Arc as ServoArc;
|
use servo_arc::Arc as ServoArc;
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
use std::marker::PhantomData as marker;
|
use std::marker::PhantomData as marker;
|
||||||
|
use std::sync::Arc;
|
||||||
use style::context::SharedStyleContext;
|
use style::context::SharedStyleContext;
|
||||||
use style::dom::TNode;
|
use style::dom::TNode;
|
||||||
use style::properties::ComputedValues;
|
use style::properties::ComputedValues;
|
||||||
use style::selector_parser::PseudoElement;
|
use style::selector_parser::PseudoElement;
|
||||||
|
use style::values::computed::Length;
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub enum WhichPseudoElement {
|
pub enum WhichPseudoElement {
|
||||||
|
@ -90,11 +94,12 @@ fn traverse_element<'dom, Node>(
|
||||||
) where
|
) where
|
||||||
Node: NodeExt<'dom>,
|
Node: NodeExt<'dom>,
|
||||||
{
|
{
|
||||||
|
let replaced = ReplacedContent::for_element(element);
|
||||||
let style = element.style(context);
|
let style = element.style(context);
|
||||||
match Display::from(style.get_box().display) {
|
match Display::from(style.get_box().display) {
|
||||||
Display::None => element.unset_boxes_in_subtree(),
|
Display::None => element.unset_boxes_in_subtree(),
|
||||||
Display::Contents => {
|
Display::Contents => {
|
||||||
if ReplacedContent::for_element(element, context).is_some() {
|
if replaced.is_some() {
|
||||||
// `display: content` on a replaced element computes to `display: none`
|
// `display: content` on a replaced element computes to `display: none`
|
||||||
// <https://drafts.csswg.org/css-display-3/#valdef-display-contents>
|
// <https://drafts.csswg.org/css-display-3/#valdef-display-contents>
|
||||||
element.unset_boxes_in_subtree()
|
element.unset_boxes_in_subtree()
|
||||||
|
@ -107,10 +112,7 @@ fn traverse_element<'dom, Node>(
|
||||||
handler.handle_element(
|
handler.handle_element(
|
||||||
&style,
|
&style,
|
||||||
display,
|
display,
|
||||||
match ReplacedContent::for_element(element, context) {
|
replaced.map_or(Contents::OfElement(element), Contents::Replaced),
|
||||||
Some(replaced) => Contents::Replaced(replaced),
|
|
||||||
None => Contents::OfElement(element),
|
|
||||||
},
|
|
||||||
element.element_box_slot(),
|
element.element_box_slot(),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
@ -287,6 +289,7 @@ impl Drop for BoxSlot<'_> {
|
||||||
pub(crate) trait NodeExt<'dom>: 'dom + Copy + LayoutNode + Send + Sync {
|
pub(crate) trait NodeExt<'dom>: 'dom + Copy + LayoutNode + Send + Sync {
|
||||||
fn is_element(self) -> bool;
|
fn is_element(self) -> bool;
|
||||||
fn as_text(self) -> Option<String>;
|
fn as_text(self) -> Option<String>;
|
||||||
|
fn as_image(self) -> Option<(Option<Arc<NetImage>>, Vec2<Length>)>;
|
||||||
fn first_child(self) -> Option<Self>;
|
fn first_child(self) -> Option<Self>;
|
||||||
fn next_sibling(self) -> Option<Self>;
|
fn next_sibling(self) -> Option<Self>;
|
||||||
fn parent_node(self) -> Option<Self>;
|
fn parent_node(self) -> Option<Self>;
|
||||||
|
@ -315,6 +318,26 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn as_image(self) -> Option<(Option<Arc<NetImage>>, Vec2<Length>)> {
|
||||||
|
let node = self.to_threadsafe();
|
||||||
|
let (resource, metadata) = node.image_data()?;
|
||||||
|
let (width, height) = resource
|
||||||
|
.as_ref()
|
||||||
|
.map(|image| (image.width, image.height))
|
||||||
|
.or_else(|| metadata.map(|metadata| (metadata.width, metadata.height)))
|
||||||
|
.unwrap_or((0, 0));
|
||||||
|
let (mut width, mut height) = (width as f32, height as f32);
|
||||||
|
if let Some(density) = node.image_density().filter(|density| *density != 1.) {
|
||||||
|
width = (width as f64 / density) as f32;
|
||||||
|
height = (height as f64 / density) as f32;
|
||||||
|
}
|
||||||
|
let size = Vec2 {
|
||||||
|
x: Length::new(width),
|
||||||
|
y: Length::new(height),
|
||||||
|
};
|
||||||
|
Some((resource, size))
|
||||||
|
}
|
||||||
|
|
||||||
fn first_child(self) -> Option<Self> {
|
fn first_child(self) -> Option<Self> {
|
||||||
TNode::first_child(&self)
|
TNode::first_child(&self)
|
||||||
}
|
}
|
||||||
|
|
|
@ -325,10 +325,14 @@ where
|
||||||
contents: Contents<Node>,
|
contents: Contents<Node>,
|
||||||
) -> Arc<InlineLevelBox> {
|
) -> Arc<InlineLevelBox> {
|
||||||
let box_ = match contents.try_into() {
|
let box_ = match contents.try_into() {
|
||||||
Err(replaced) => Arc::new(InlineLevelBox::Atomic {
|
Err(replaced) => Arc::new(InlineLevelBox::Atomic(
|
||||||
style: style.clone(),
|
IndependentFormattingContext::construct(
|
||||||
contents: replaced,
|
self.context,
|
||||||
}),
|
style.clone(),
|
||||||
|
display_inside,
|
||||||
|
<Contents<Node>>::Replaced(replaced),
|
||||||
|
),
|
||||||
|
)),
|
||||||
Ok(non_replaced) => match display_inside {
|
Ok(non_replaced) => match display_inside {
|
||||||
DisplayInside::Flow |
|
DisplayInside::Flow |
|
||||||
// TODO: Properly implement display: inline-block.
|
// TODO: Properly implement display: inline-block.
|
||||||
|
@ -449,7 +453,7 @@ where
|
||||||
let box_ = Arc::new(InlineLevelBox::OutOfFlowAbsolutelyPositionedBox(
|
let box_ = Arc::new(InlineLevelBox::OutOfFlowAbsolutelyPositionedBox(
|
||||||
AbsolutelyPositionedBox {
|
AbsolutelyPositionedBox {
|
||||||
contents: IndependentFormattingContext::construct(
|
contents: IndependentFormattingContext::construct(
|
||||||
unimplemented!(),
|
self.context,
|
||||||
style,
|
style,
|
||||||
display_inside,
|
display_inside,
|
||||||
contents,
|
contents,
|
||||||
|
|
|
@ -5,12 +5,12 @@
|
||||||
use crate::context::LayoutContext;
|
use crate::context::LayoutContext;
|
||||||
use crate::flow::float::FloatBox;
|
use crate::flow::float::FloatBox;
|
||||||
use crate::flow::FlowLayout;
|
use crate::flow::FlowLayout;
|
||||||
|
use crate::formatting_contexts::IndependentFormattingContext;
|
||||||
use crate::fragments::{
|
use crate::fragments::{
|
||||||
AnonymousFragment, BoxFragment, CollapsedBlockMargins, Fragment, TextFragment,
|
AnonymousFragment, BoxFragment, CollapsedBlockMargins, Fragment, TextFragment,
|
||||||
};
|
};
|
||||||
use crate::geom::flow_relative::{Rect, Sides, Vec2};
|
use crate::geom::flow_relative::{Rect, Sides, Vec2};
|
||||||
use crate::positioned::{AbsolutelyPositionedBox, AbsolutelyPositionedFragment};
|
use crate::positioned::{AbsolutelyPositionedBox, AbsolutelyPositionedFragment};
|
||||||
use crate::replaced::ReplacedContent;
|
|
||||||
use crate::style_ext::{ComputedValuesExt, Display, DisplayGeneratingBox, DisplayOutside};
|
use crate::style_ext::{ComputedValuesExt, Display, DisplayGeneratingBox, DisplayOutside};
|
||||||
use crate::{relative_adjustement, ContainingBlock};
|
use crate::{relative_adjustement, ContainingBlock};
|
||||||
use servo_arc::Arc;
|
use servo_arc::Arc;
|
||||||
|
@ -29,11 +29,7 @@ pub(crate) enum InlineLevelBox {
|
||||||
TextRun(TextRun),
|
TextRun(TextRun),
|
||||||
OutOfFlowAbsolutelyPositionedBox(AbsolutelyPositionedBox),
|
OutOfFlowAbsolutelyPositionedBox(AbsolutelyPositionedBox),
|
||||||
OutOfFlowFloatBox(FloatBox),
|
OutOfFlowFloatBox(FloatBox),
|
||||||
Atomic {
|
Atomic(IndependentFormattingContext),
|
||||||
style: Arc<ComputedValues>,
|
|
||||||
// FIXME: this should be IndependentFormattingContext:
|
|
||||||
contents: ReplacedContent,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -112,9 +108,9 @@ impl InlineFormattingContext {
|
||||||
ifc.partial_inline_boxes_stack.push(partial)
|
ifc.partial_inline_boxes_stack.push(partial)
|
||||||
},
|
},
|
||||||
InlineLevelBox::TextRun(run) => run.layout(layout_context, &mut ifc),
|
InlineLevelBox::TextRun(run) => run.layout(layout_context, &mut ifc),
|
||||||
InlineLevelBox::Atomic { style: _, contents } => {
|
InlineLevelBox::Atomic(_independent) => {
|
||||||
// FIXME
|
// TODO
|
||||||
match *contents {}
|
continue;
|
||||||
},
|
},
|
||||||
InlineLevelBox::OutOfFlowAbsolutelyPositionedBox(box_) => {
|
InlineLevelBox::OutOfFlowAbsolutelyPositionedBox(box_) => {
|
||||||
let initial_start_corner =
|
let initial_start_corner =
|
||||||
|
|
|
@ -15,6 +15,7 @@ use crate::geom::flow_relative::{Rect, Sides, Vec2};
|
||||||
use crate::positioned::{
|
use crate::positioned::{
|
||||||
adjust_static_positions, AbsolutelyPositionedBox, AbsolutelyPositionedFragment,
|
adjust_static_positions, AbsolutelyPositionedBox, AbsolutelyPositionedFragment,
|
||||||
};
|
};
|
||||||
|
use crate::replaced::ReplacedContent;
|
||||||
use crate::style_ext::{ComputedValuesExt, Position};
|
use crate::style_ext::{ComputedValuesExt, Position};
|
||||||
use crate::{relative_adjustement, ContainingBlock};
|
use crate::{relative_adjustement, ContainingBlock};
|
||||||
use rayon::iter::{IndexedParallelIterator, IntoParallelRefIterator, ParallelIterator};
|
use rayon::iter::{IndexedParallelIterator, IntoParallelRefIterator, ParallelIterator};
|
||||||
|
@ -295,10 +296,12 @@ impl BlockLevelBox {
|
||||||
))
|
))
|
||||||
},
|
},
|
||||||
BlockLevelBox::Independent(contents) => match contents.as_replaced() {
|
BlockLevelBox::Independent(contents) => match contents.as_replaced() {
|
||||||
Ok(replaced) => {
|
Ok(replaced) => Fragment::Box(layout_in_flow_replaced_block_level(
|
||||||
// FIXME
|
layout_context,
|
||||||
match *replaced {}
|
containing_block,
|
||||||
},
|
&contents.style,
|
||||||
|
replaced,
|
||||||
|
)),
|
||||||
Err(non_replaced) => Fragment::Box(layout_in_flow_non_replaced_block_level(
|
Err(non_replaced) => Fragment::Box(layout_in_flow_non_replaced_block_level(
|
||||||
layout_context,
|
layout_context,
|
||||||
containing_block,
|
containing_block,
|
||||||
|
@ -360,27 +363,15 @@ fn layout_in_flow_non_replaced_block_level<'a>(
|
||||||
let box_size = style.box_size();
|
let box_size = style.box_size();
|
||||||
let inline_size = box_size.inline.percentage_relative_to(cbis);
|
let inline_size = box_size.inline.percentage_relative_to(cbis);
|
||||||
if let LengthOrAuto::LengthPercentage(is) = inline_size {
|
if let LengthOrAuto::LengthPercentage(is) = inline_size {
|
||||||
let inline_margins = cbis - is - pb.inline_sum();
|
let (margin_inline_start, margin_inline_end) = solve_inline_margins_for_in_flow_block_level(
|
||||||
match (
|
containing_block,
|
||||||
&mut computed_margin.inline_start,
|
pb.inline_sum(),
|
||||||
&mut computed_margin.inline_end,
|
computed_margin.inline_start,
|
||||||
) {
|
computed_margin.inline_end,
|
||||||
(s @ &mut LengthOrAuto::Auto, e @ &mut LengthOrAuto::Auto) => {
|
is,
|
||||||
*s = LengthOrAuto::LengthPercentage(inline_margins / 2.);
|
);
|
||||||
*e = LengthOrAuto::LengthPercentage(inline_margins / 2.);
|
computed_margin.inline_start = LengthOrAuto::LengthPercentage(margin_inline_start);
|
||||||
},
|
computed_margin.inline_end = LengthOrAuto::LengthPercentage(margin_inline_end);
|
||||||
(s @ &mut LengthOrAuto::Auto, _) => {
|
|
||||||
*s = LengthOrAuto::LengthPercentage(inline_margins);
|
|
||||||
},
|
|
||||||
(_, e @ &mut LengthOrAuto::Auto) => {
|
|
||||||
*e = LengthOrAuto::LengthPercentage(inline_margins);
|
|
||||||
},
|
|
||||||
(_, e @ _) => {
|
|
||||||
// Either the inline-end margin is auto,
|
|
||||||
// or we’re over-constrained and we do as if it were.
|
|
||||||
*e = LengthOrAuto::LengthPercentage(inline_margins);
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
let margin = computed_margin.auto_is(Length::zero);
|
let margin = computed_margin.auto_is(Length::zero);
|
||||||
let mut block_margins_collapsed_with_children = CollapsedBlockMargins::from_margin(&margin);
|
let mut block_margins_collapsed_with_children = CollapsedBlockMargins::from_margin(&margin);
|
||||||
|
@ -479,3 +470,104 @@ fn layout_in_flow_non_replaced_block_level<'a>(
|
||||||
block_margins_collapsed_with_children,
|
block_margins_collapsed_with_children,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// https://drafts.csswg.org/css2/visudet.html#block-replaced-width
|
||||||
|
/// https://drafts.csswg.org/css2/visudet.html#inline-replaced-width
|
||||||
|
/// https://drafts.csswg.org/css2/visudet.html#inline-replaced-height
|
||||||
|
fn layout_in_flow_replaced_block_level<'a>(
|
||||||
|
layout_context: &LayoutContext,
|
||||||
|
containing_block: &ContainingBlock,
|
||||||
|
style: &Arc<ComputedValues>,
|
||||||
|
replaced: &ReplacedContent,
|
||||||
|
) -> BoxFragment {
|
||||||
|
let cbis = containing_block.inline_size;
|
||||||
|
let padding = style.padding().percentages_relative_to(cbis);
|
||||||
|
let border = style.border_width();
|
||||||
|
let computed_margin = style.margin().percentages_relative_to(cbis);
|
||||||
|
let pb = &padding + &border;
|
||||||
|
let mode = style.writing_mode();
|
||||||
|
// FIXME(nox): We shouldn't pretend we always have a fully known intrinsic size.
|
||||||
|
let intrinsic_size = replaced.intrinsic_size.size_to_flow_relative(mode);
|
||||||
|
// FIXME(nox): This can divide by zero.
|
||||||
|
let intrinsic_ratio = intrinsic_size.inline.px() / intrinsic_size.block.px();
|
||||||
|
let box_size = style.box_size();
|
||||||
|
let inline_size = box_size.inline.percentage_relative_to(cbis);
|
||||||
|
let block_size = box_size
|
||||||
|
.block
|
||||||
|
.maybe_percentage_relative_to(containing_block.block_size.non_auto());
|
||||||
|
let (inline_size, block_size) = match (inline_size, block_size) {
|
||||||
|
(LengthOrAuto::LengthPercentage(inline), LengthOrAuto::LengthPercentage(block)) => {
|
||||||
|
(inline, block)
|
||||||
|
},
|
||||||
|
(LengthOrAuto::LengthPercentage(inline), LengthOrAuto::Auto) => {
|
||||||
|
(inline, inline / intrinsic_ratio)
|
||||||
|
},
|
||||||
|
(LengthOrAuto::Auto, LengthOrAuto::LengthPercentage(block)) => {
|
||||||
|
(block * intrinsic_ratio, block)
|
||||||
|
},
|
||||||
|
(LengthOrAuto::Auto, LengthOrAuto::Auto) => (intrinsic_size.inline, intrinsic_size.block),
|
||||||
|
};
|
||||||
|
let (margin_inline_start, margin_inline_end) = solve_inline_margins_for_in_flow_block_level(
|
||||||
|
containing_block,
|
||||||
|
pb.inline_sum(),
|
||||||
|
computed_margin.inline_start,
|
||||||
|
computed_margin.inline_end,
|
||||||
|
inline_size,
|
||||||
|
);
|
||||||
|
let margin = Sides {
|
||||||
|
inline_start: margin_inline_start,
|
||||||
|
inline_end: margin_inline_end,
|
||||||
|
block_start: computed_margin.block_start.auto_is(Length::zero),
|
||||||
|
block_end: computed_margin.block_end.auto_is(Length::zero),
|
||||||
|
};
|
||||||
|
let containing_block_for_children = ContainingBlock {
|
||||||
|
inline_size,
|
||||||
|
block_size: LengthOrAuto::LengthPercentage(block_size),
|
||||||
|
mode,
|
||||||
|
};
|
||||||
|
// https://drafts.csswg.org/css-writing-modes/#orthogonal-flows
|
||||||
|
assert_eq!(
|
||||||
|
containing_block.mode, containing_block_for_children.mode,
|
||||||
|
"Mixed writing modes are not supported yet"
|
||||||
|
);
|
||||||
|
let independent_layout = replaced.layout(layout_context, style, &containing_block_for_children);
|
||||||
|
let relative_adjustement = relative_adjustement(
|
||||||
|
style,
|
||||||
|
inline_size,
|
||||||
|
LengthOrAuto::LengthPercentage(block_size),
|
||||||
|
);
|
||||||
|
let content_rect = Rect {
|
||||||
|
start_corner: Vec2 {
|
||||||
|
block: pb.block_start + relative_adjustement.block,
|
||||||
|
inline: pb.inline_start + relative_adjustement.inline + margin.inline_start,
|
||||||
|
},
|
||||||
|
size: Vec2 {
|
||||||
|
block: block_size,
|
||||||
|
inline: inline_size,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
BoxFragment {
|
||||||
|
style: style.clone(),
|
||||||
|
children: independent_layout.fragments,
|
||||||
|
content_rect,
|
||||||
|
padding,
|
||||||
|
border,
|
||||||
|
block_margins_collapsed_with_children: CollapsedBlockMargins::from_margin(&margin),
|
||||||
|
margin,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn solve_inline_margins_for_in_flow_block_level(
|
||||||
|
containing_block: &ContainingBlock,
|
||||||
|
padding_border_inline_sum: Length,
|
||||||
|
computed_margin_inline_start: LengthOrAuto,
|
||||||
|
computed_margin_inline_end: LengthOrAuto,
|
||||||
|
inline_size: Length,
|
||||||
|
) -> (Length, Length) {
|
||||||
|
let inline_margins = containing_block.inline_size - padding_border_inline_sum - inline_size;
|
||||||
|
match (computed_margin_inline_start, computed_margin_inline_end) {
|
||||||
|
(LengthOrAuto::Auto, LengthOrAuto::Auto) => (inline_margins / 2., inline_margins / 2.),
|
||||||
|
(LengthOrAuto::Auto, LengthOrAuto::LengthPercentage(end)) => (inline_margins - end, end),
|
||||||
|
(LengthOrAuto::LengthPercentage(start), _) => (start, inline_margins - start),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -48,7 +48,7 @@ fn construct_for_root_element<'dom>(
|
||||||
root_element: impl NodeExt<'dom>,
|
root_element: impl NodeExt<'dom>,
|
||||||
) -> (ContainsFloats, Vec<Arc<BlockLevelBox>>) {
|
) -> (ContainsFloats, Vec<Arc<BlockLevelBox>>) {
|
||||||
let style = root_element.style(context);
|
let style = root_element.style(context);
|
||||||
let replaced = ReplacedContent::for_element(root_element, context);
|
let replaced = ReplacedContent::for_element(root_element);
|
||||||
let box_style = style.get_box();
|
let box_style = style.get_box();
|
||||||
|
|
||||||
let display_inside = match Display::from(box_style.display) {
|
let display_inside = match Display::from(box_style.display) {
|
||||||
|
@ -63,21 +63,13 @@ fn construct_for_root_element<'dom>(
|
||||||
Display::GeneratingBox(DisplayGeneratingBox::OutsideInside { inside, .. }) => inside,
|
Display::GeneratingBox(DisplayGeneratingBox::OutsideInside { inside, .. }) => inside,
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(replaced) = replaced {
|
|
||||||
let _box = match replaced {};
|
|
||||||
#[allow(unreachable_code)]
|
|
||||||
{
|
|
||||||
return (ContainsFloats::No, vec![Arc::new(_box)]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let position = box_style.position;
|
let position = box_style.position;
|
||||||
let float = box_style.float;
|
let float = box_style.float;
|
||||||
let contents = IndependentFormattingContext::construct(
|
let contents = IndependentFormattingContext::construct(
|
||||||
context,
|
context,
|
||||||
style,
|
style,
|
||||||
display_inside,
|
display_inside,
|
||||||
Contents::OfElement(root_element),
|
replaced.map_or(Contents::OfElement(root_element), Contents::Replaced),
|
||||||
);
|
);
|
||||||
if position.is_absolutely_positioned() {
|
if position.is_absolutely_positioned() {
|
||||||
(
|
(
|
||||||
|
|
|
@ -83,7 +83,7 @@ impl IndependentFormattingContext {
|
||||||
absolutely_positioned_fragments: &mut Vec<AbsolutelyPositionedFragment<'a>>,
|
absolutely_positioned_fragments: &mut Vec<AbsolutelyPositionedFragment<'a>>,
|
||||||
) -> IndependentLayout {
|
) -> IndependentLayout {
|
||||||
match self.as_replaced() {
|
match self.as_replaced() {
|
||||||
Ok(replaced) => match *replaced {},
|
Ok(replaced) => replaced.layout(layout_context, &self.style, containing_block),
|
||||||
Err(ifc) => ifc.layout(
|
Err(ifc) => ifc.layout(
|
||||||
layout_context,
|
layout_context,
|
||||||
containing_block,
|
containing_block,
|
||||||
|
|
|
@ -10,12 +10,13 @@ use std::sync::Arc;
|
||||||
use style::properties::ComputedValues;
|
use style::properties::ComputedValues;
|
||||||
use style::values::computed::Length;
|
use style::values::computed::Length;
|
||||||
use style::Zero;
|
use style::Zero;
|
||||||
use webrender_api::FontInstanceKey;
|
use webrender_api::{FontInstanceKey, ImageKey};
|
||||||
|
|
||||||
pub(crate) enum Fragment {
|
pub(crate) enum Fragment {
|
||||||
Box(BoxFragment),
|
Box(BoxFragment),
|
||||||
Anonymous(AnonymousFragment),
|
Anonymous(AnonymousFragment),
|
||||||
Text(TextFragment),
|
Text(TextFragment),
|
||||||
|
Image(ImageFragment),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct BoxFragment {
|
pub(crate) struct BoxFragment {
|
||||||
|
@ -61,6 +62,12 @@ pub(crate) struct TextFragment {
|
||||||
pub glyphs: Vec<Arc<GlyphStore>>,
|
pub glyphs: Vec<Arc<GlyphStore>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) struct ImageFragment {
|
||||||
|
pub style: ServoArc<ComputedValues>,
|
||||||
|
pub content_rect: Rect<Length>,
|
||||||
|
pub image_key: ImageKey,
|
||||||
|
}
|
||||||
|
|
||||||
impl AnonymousFragment {
|
impl AnonymousFragment {
|
||||||
pub fn no_op(mode: (WritingMode, Direction)) -> Self {
|
pub fn no_op(mode: (WritingMode, Direction)) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
|
|
@ -2,20 +2,77 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
use crate::context::LayoutContext;
|
||||||
use crate::dom_traversal::NodeExt;
|
use crate::dom_traversal::NodeExt;
|
||||||
|
use crate::formatting_contexts::IndependentLayout;
|
||||||
|
use crate::fragments::{Fragment, ImageFragment};
|
||||||
|
use crate::geom::{flow_relative, physical};
|
||||||
|
use crate::positioned::AbsolutelyPositionedFragment;
|
||||||
|
use crate::ContainingBlock;
|
||||||
|
use net_traits::image::base::Image;
|
||||||
|
use servo_arc::Arc as ServoArc;
|
||||||
|
use std::sync::Arc;
|
||||||
use style::context::SharedStyleContext;
|
use style::context::SharedStyleContext;
|
||||||
|
use style::properties::ComputedValues;
|
||||||
|
use style::values::computed::Length;
|
||||||
|
use style::Zero;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(super) enum ReplacedContent {
|
pub(crate) struct ReplacedContent {
|
||||||
// Not implemented yet
|
pub kind: ReplacedContentKind,
|
||||||
|
pub intrinsic_size: physical::Vec2<Length>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub(crate) enum ReplacedContentKind {
|
||||||
|
Image(Option<Arc<Image>>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ReplacedContent {
|
impl ReplacedContent {
|
||||||
pub fn for_element<'dom, Node>(element: Node, _context: &SharedStyleContext) -> Option<Self>
|
pub fn for_element<'dom>(element: impl NodeExt<'dom>) -> Option<Self> {
|
||||||
where
|
if let Some((image, intrinsic_size)) = element.as_image() {
|
||||||
Node: NodeExt<'dom>,
|
return Some(Self {
|
||||||
{
|
kind: ReplacedContentKind::Image(image),
|
||||||
// FIXME: implement <img> etc.
|
intrinsic_size,
|
||||||
|
});
|
||||||
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn layout<'a>(
|
||||||
|
&'a self,
|
||||||
|
layout_context: &LayoutContext,
|
||||||
|
style: &ServoArc<ComputedValues>,
|
||||||
|
containing_block: &ContainingBlock,
|
||||||
|
) -> IndependentLayout {
|
||||||
|
let (fragments, content_block_size) = match self.kind {
|
||||||
|
ReplacedContentKind::Image(ref image) => {
|
||||||
|
// FIXME(nox): We should not assume block size is known.
|
||||||
|
let block_size = containing_block.block_size.non_auto().unwrap();
|
||||||
|
let fragments = image
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|image| image.id)
|
||||||
|
.map(|image_key| {
|
||||||
|
Fragment::Image(ImageFragment {
|
||||||
|
style: style.clone(),
|
||||||
|
content_rect: flow_relative::Rect {
|
||||||
|
start_corner: flow_relative::Vec2::zero(),
|
||||||
|
size: flow_relative::Vec2 {
|
||||||
|
inline: containing_block.inline_size,
|
||||||
|
block: block_size,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
image_key,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.into_iter()
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
(fragments, block_size)
|
||||||
|
},
|
||||||
|
};
|
||||||
|
IndependentLayout {
|
||||||
|
fragments,
|
||||||
|
content_block_size,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,9 +72,10 @@ ${helpers.single_keyword(
|
||||||
${helpers.single_keyword(
|
${helpers.single_keyword(
|
||||||
"image-rendering",
|
"image-rendering",
|
||||||
"auto crisp-edges",
|
"auto crisp-edges",
|
||||||
engines="gecko servo-2013",
|
engines="gecko servo-2013 servo-2020",
|
||||||
extra_gecko_values="optimizespeed optimizequality",
|
extra_gecko_values="optimizespeed optimizequality",
|
||||||
extra_servo_2013_values="pixelated",
|
extra_servo_2013_values="pixelated",
|
||||||
|
extra_servo_2020_values="pixelated",
|
||||||
gecko_aliases="-moz-crisp-edges=crisp-edges",
|
gecko_aliases="-moz-crisp-edges=crisp-edges",
|
||||||
animation_value_type="discrete",
|
animation_value_type="discrete",
|
||||||
spec="https://drafts.csswg.org/css-images/#propdef-image-rendering",
|
spec="https://drafts.csswg.org/css-images/#propdef-image-rendering",
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
[containing-block-007.xht]
|
[containing-block-007.xht]
|
||||||
expected: CRASH
|
expected: FAIL
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue