Add layout support and tests for inline iframes. Fixes #1697.

This commit is contained in:
Glenn Watson 2015-01-29 14:09:43 +10:00
parent 221a343883
commit 1f37c6eabe
17 changed files with 200 additions and 31 deletions

View file

@ -1306,6 +1306,7 @@ impl<'ln> NodeUtils for ThreadSafeLayoutNode<'ln> {
None | None |
Some(NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLImageElement))) => true, Some(NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLImageElement))) => true,
Some(NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLObjectElement))) => self.has_object_data(), Some(NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLObjectElement))) => self.has_object_data(),
Some(NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLIFrameElement))) => true,
Some(NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLCanvasElement))) => true, Some(NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLCanvasElement))) => true,
Some(NodeTypeId::Element(_)) => false, Some(NodeTypeId::Element(_)) => false,
} }

View file

@ -194,6 +194,18 @@ impl SpecificFragmentInfo {
} }
} }
/// Clamp a value obtained from style_length, based on min / max lengths.
fn clamp_size(size: Au, min_size: LengthOrPercentage, max_size: LengthOrPercentageOrNone,
container_inline_size: Au) -> Au {
let min_size = model::specified(min_size, container_inline_size);
let max_size = model::specified_or_none(max_size, container_inline_size);
Au::max(min_size, match max_size {
None => size,
Some(max_size) => Au::min(size, max_size),
})
}
/// A hypothetical box (see CSS 2.1 § 10.3.7) for an absolutely-positioned block that was declared /// A hypothetical box (see CSS 2.1 § 10.3.7) for an absolutely-positioned block that was declared
/// with `display: inline;`. /// with `display: inline;`.
/// ///
@ -375,18 +387,6 @@ impl ReplacedImageFragmentInfo {
} }
} }
/// Clamp a value obtained from style_length, based on min / max lengths.
pub fn clamp_size(size: Au, min_size: LengthOrPercentage, max_size: LengthOrPercentageOrNone,
container_inline_size: Au) -> Au {
let min_size = model::specified(min_size, container_inline_size);
let max_size = model::specified_or_none(max_size, container_inline_size);
Au::max(min_size, match max_size {
None => size,
Some(max_size) => Au::min(size, max_size),
})
}
pub fn calculate_replaced_inline_size(&mut self, pub fn calculate_replaced_inline_size(&mut self,
style: ComputedValues, style: ComputedValues,
noncontent_inline_size: Au, noncontent_inline_size: Au,
@ -425,21 +425,20 @@ impl ReplacedImageFragmentInfo {
MaybeAuto::Auto => intrinsic_height, MaybeAuto::Auto => intrinsic_height,
MaybeAuto::Specified(h) => h, MaybeAuto::Specified(h) => h,
}; };
let specified_height = ReplacedImageFragmentInfo::clamp_size( let specified_height = clamp_size(specified_height,
specified_height, style_min_block_size,
style_min_block_size, style_max_block_size,
style_max_block_size, Au(0));
Au(0));
Au((specified_height.to_f32().unwrap() * ratio) as i32) Au((specified_height.to_f32().unwrap() * ratio) as i32)
} }
}, },
MaybeAuto::Specified(w) => w, MaybeAuto::Specified(w) => w,
}; };
let inline_size = ReplacedImageFragmentInfo::clamp_size(inline_size, let inline_size = clamp_size(inline_size,
style_min_inline_size, style_min_inline_size,
style_max_inline_size, style_max_inline_size,
container_inline_size); container_inline_size);
self.computed_inline_size = Some(inline_size); self.computed_inline_size = Some(inline_size);
inline_size + noncontent_inline_size inline_size + noncontent_inline_size
@ -475,10 +474,10 @@ impl ReplacedImageFragmentInfo {
} }
}; };
let block_size = ReplacedImageFragmentInfo::clamp_size(block_size, let block_size = clamp_size(block_size,
style_min_block_size, style_min_block_size,
style_max_block_size, style_max_block_size,
Au(0)); Au(0));
self.computed_block_size = Some(block_size); self.computed_block_size = Some(block_size);
block_size + noncontent_block_size block_size + noncontent_block_size
@ -504,6 +503,44 @@ impl IframeFragmentInfo {
subpage_id: subpage_id, subpage_id: subpage_id,
} }
} }
#[inline]
pub fn calculate_replaced_inline_size(style: ComputedValues, containing_size: Au) -> Au {
// Calculate the replaced inline size (or default) as per CSS 2.1 § 10.3.2
IframeFragmentInfo::calculate_replaced_size(style.content_inline_size(),
style.min_inline_size(),
style.max_inline_size(),
containing_size,
Au::from_px(300))
}
#[inline]
pub fn calculate_replaced_block_size(style: ComputedValues, containing_size: Au) -> Au {
// Calculate the replaced block size (or default) as per CSS 2.1 § 10.3.2
IframeFragmentInfo::calculate_replaced_size(style.content_block_size(),
style.min_block_size(),
style.max_block_size(),
containing_size,
Au::from_px(150))
}
fn calculate_replaced_size(content_size: LengthOrPercentageOrAuto,
style_min_size: LengthOrPercentage,
style_max_size: LengthOrPercentageOrNone,
containing_size: Au, default_size: Au) -> Au {
let computed_size = match MaybeAuto::from_style(content_size, containing_size) {
MaybeAuto::Specified(length) => length,
MaybeAuto::Auto => default_size,
};
let size = clamp_size(computed_size,
style_min_size,
style_max_size,
containing_size);
size
}
} }
/// A scanned text fragment represents a single run of text with a distinct style. A `TextFragment` /// A scanned text fragment represents a single run of text with a distinct style. A `TextFragment`
@ -1171,8 +1208,10 @@ impl Fragment {
pub fn compute_intrinsic_inline_sizes(&mut self) -> IntrinsicISizesContribution { pub fn compute_intrinsic_inline_sizes(&mut self) -> IntrinsicISizesContribution {
let mut result = self.style_specified_intrinsic_inline_size(); let mut result = self.style_specified_intrinsic_inline_size();
match self.specific { match self.specific {
SpecificFragmentInfo::Generic | SpecificFragmentInfo::Iframe(_) | SpecificFragmentInfo::Table | SpecificFragmentInfo::TableCell | SpecificFragmentInfo::Generic | SpecificFragmentInfo::Iframe(_) |
SpecificFragmentInfo::TableColumn(_) | SpecificFragmentInfo::TableRow | SpecificFragmentInfo::TableWrapper | SpecificFragmentInfo::Table | SpecificFragmentInfo::TableCell |
SpecificFragmentInfo::TableColumn(_) | SpecificFragmentInfo::TableRow |
SpecificFragmentInfo::TableWrapper |
SpecificFragmentInfo::InlineAbsoluteHypothetical(_) => {} SpecificFragmentInfo::InlineAbsoluteHypothetical(_) => {}
SpecificFragmentInfo::InlineBlock(ref mut info) => { SpecificFragmentInfo::InlineBlock(ref mut info) => {
let block_flow = info.flow_ref.as_block(); let block_flow = info.flow_ref.as_block();
@ -1543,14 +1582,14 @@ impl Fragment {
/// content per CSS 2.1 § 10.3.2. /// content per CSS 2.1 § 10.3.2.
pub fn assign_replaced_inline_size_if_necessary<'a>(&'a mut self, container_inline_size: Au) { pub fn assign_replaced_inline_size_if_necessary<'a>(&'a mut self, container_inline_size: Au) {
match self.specific { match self.specific {
SpecificFragmentInfo::Generic | SpecificFragmentInfo::Iframe(_) | SpecificFragmentInfo::Table | SpecificFragmentInfo::TableCell | SpecificFragmentInfo::Generic | SpecificFragmentInfo::Table | SpecificFragmentInfo::TableCell |
SpecificFragmentInfo::TableRow | SpecificFragmentInfo::TableWrapper => return, SpecificFragmentInfo::TableRow | SpecificFragmentInfo::TableWrapper => return,
SpecificFragmentInfo::TableColumn(_) => panic!("Table column fragments do not have inline_size"), SpecificFragmentInfo::TableColumn(_) => panic!("Table column fragments do not have inline_size"),
SpecificFragmentInfo::UnscannedText(_) => { SpecificFragmentInfo::UnscannedText(_) => {
panic!("Unscanned text fragments should have been scanned by now!") panic!("Unscanned text fragments should have been scanned by now!")
} }
SpecificFragmentInfo::Canvas(_) | SpecificFragmentInfo::Image(_) | SpecificFragmentInfo::ScannedText(_) | SpecificFragmentInfo::InlineBlock(_) | SpecificFragmentInfo::Canvas(_) | SpecificFragmentInfo::Image(_) | SpecificFragmentInfo::ScannedText(_) | SpecificFragmentInfo::InlineBlock(_) |
SpecificFragmentInfo::InlineAbsoluteHypothetical(_) => {} SpecificFragmentInfo::InlineAbsoluteHypothetical(_) | SpecificFragmentInfo::Iframe(_) => {}
}; };
let style = self.style().clone(); let style = self.style().clone();
@ -1596,6 +1635,11 @@ impl Fragment {
fragment_inline_size, fragment_inline_size,
fragment_block_size); fragment_block_size);
} }
SpecificFragmentInfo::Iframe(_) => {
self.border_box.size.inline = IframeFragmentInfo::calculate_replaced_inline_size(
style, container_inline_size) +
noncontent_inline_size;
}
_ => panic!("this case should have been handled above"), _ => panic!("this case should have been handled above"),
} }
} }
@ -1606,14 +1650,14 @@ impl Fragment {
/// Ideally, this should follow CSS 2.1 § 10.6.2. /// Ideally, this should follow CSS 2.1 § 10.6.2.
pub fn assign_replaced_block_size_if_necessary(&mut self, containing_block_block_size: Au) { pub fn assign_replaced_block_size_if_necessary(&mut self, containing_block_block_size: Au) {
match self.specific { match self.specific {
SpecificFragmentInfo::Generic | SpecificFragmentInfo::Iframe(_) | SpecificFragmentInfo::Table | SpecificFragmentInfo::TableCell | SpecificFragmentInfo::Generic | SpecificFragmentInfo::Table | SpecificFragmentInfo::TableCell |
SpecificFragmentInfo::TableRow | SpecificFragmentInfo::TableWrapper => return, SpecificFragmentInfo::TableRow | SpecificFragmentInfo::TableWrapper => return,
SpecificFragmentInfo::TableColumn(_) => panic!("Table column fragments do not have block_size"), SpecificFragmentInfo::TableColumn(_) => panic!("Table column fragments do not have block_size"),
SpecificFragmentInfo::UnscannedText(_) => { SpecificFragmentInfo::UnscannedText(_) => {
panic!("Unscanned text fragments should have been scanned by now!") panic!("Unscanned text fragments should have been scanned by now!")
} }
SpecificFragmentInfo::Canvas(_) | SpecificFragmentInfo::Image(_) | SpecificFragmentInfo::ScannedText(_) | SpecificFragmentInfo::InlineBlock(_) | SpecificFragmentInfo::Canvas(_) | SpecificFragmentInfo::Image(_) | SpecificFragmentInfo::ScannedText(_) | SpecificFragmentInfo::InlineBlock(_) |
SpecificFragmentInfo::InlineAbsoluteHypothetical(_) => {} SpecificFragmentInfo::InlineAbsoluteHypothetical(_) | SpecificFragmentInfo::Iframe(_) => {}
} }
let style = self.style().clone(); let style = self.style().clone();
@ -1656,6 +1700,11 @@ impl Fragment {
let block_flow = info.flow_ref.as_block(); let block_flow = info.flow_ref.as_block();
self.border_box.size.block = block_flow.base.position.size.block; self.border_box.size.block = block_flow.base.position.size.block;
} }
SpecificFragmentInfo::Iframe(_) => {
self.border_box.size.block = IframeFragmentInfo::calculate_replaced_block_size(
style, containing_block_block_size) +
noncontent_block_size;
}
_ => panic!("should have been handled above"), _ => panic!("should have been handled above"),
} }
} }

View file

@ -126,6 +126,13 @@ fragment=top != ../html/acid2.html acid2_ref.html
== multiple_css_class_a.html multiple_css_class_b.html == multiple_css_class_a.html multiple_css_class_b.html
== iframe/simple.html iframe/simple_ref.html == iframe/simple.html iframe/simple_ref.html
== iframe/simple_inline_default.html iframe/simple_inline_default_ref.html
== iframe/simple_inline_width.html iframe/simple_inline_width_ref.html
== iframe/simple_inline_width_height.html iframe/simple_inline_width_height_ref.html
== iframe/simple_inline_height.html iframe/simple_inline_height_ref.html
== iframe/simple_inline_width_percentage.html iframe/simple_inline_width_percentage_ref.html
== iframe/simple_inline_min.html iframe/simple_inline_min_ref.html
== iframe/simple_inline_max.html iframe/simple_inline_max_ref.html
== iframe/multiple_external.html iframe/multiple_external_ref.html == iframe/multiple_external.html iframe/multiple_external_ref.html
== iframe/overflow.html iframe/overflow_ref.html == iframe/overflow.html iframe/overflow_ref.html
== iframe/positioning_margin.html iframe/positioning_margin_ref.html == iframe/positioning_margin.html iframe/positioning_margin_ref.html

View file

@ -0,0 +1,9 @@
<html>
<body>
<div style="margin-top: 20px;">
<iframe src="data:text/html,%3Cspan%3EJust%20a%20simple%20little%20iframe.%3C%2Fspan%3E"
style="display: inline; border: 1px solid black;">
</iframe>
</div>
</body>
</html>

View file

@ -0,0 +1,7 @@
<html>
<body>
<div style="border: 1px solid black; width: 300px; height: 150px; margin-top: 20px;">
<div style="margin: 8px; /* matches user-agent body */">Just a simple little iframe.</div>
</div>
</body>
</html>

View file

@ -0,0 +1,9 @@
<html>
<body>
<div style="margin-top: 20px;">
<iframe src="data:text/html,%3Cspan%3EJust%20a%20simple%20little%20iframe.%3C%2Fspan%3E"
style="display: inline; border: 1px solid black; height: 300px;">
</iframe>
</div>
</body>
</html>

View file

@ -0,0 +1,7 @@
<html>
<body>
<div style="border: 1px solid black; width: 300px; height: 300px; margin-top: 20px;">
<div style="margin: 8px; /* matches user-agent body */">Just a simple little iframe.</div>
</div>
</body>
</html>

View file

@ -0,0 +1,9 @@
<html>
<body>
<div style="margin-top: 20px;">
<iframe src="data:text/html,%3Cspan%3EJust%20a%20simple%20little%20iframe.%3C%2Fspan%3E"
style="display: inline; border: 1px solid black; max-width: 250px; max-height: 50px;">
</iframe>
</div>
</body>
</html>

View file

@ -0,0 +1,7 @@
<html>
<body>
<div style="border: 1px solid black; width: 250px; height: 50px; margin-top: 20px;">
<div style="margin: 8px; /* matches user-agent body */">Just a simple little iframe.</div>
</div>
</body>
</html>

View file

@ -0,0 +1,9 @@
<html>
<body>
<div style="margin-top: 20px;">
<iframe src="data:text/html,%3Cspan%3EJust%20a%20simple%20little%20iframe.%3C%2Fspan%3E"
style="display: inline; border: 1px solid black; min-width: 400px; min-height: 250px;">
</iframe>
</div>
</body>
</html>

View file

@ -0,0 +1,7 @@
<html>
<body>
<div style="border: 1px solid black; width: 400px; height: 250px; margin-top: 20px;">
<div style="margin: 8px; /* matches user-agent body */">Just a simple little iframe.</div>
</div>
</body>
</html>

View file

@ -0,0 +1,9 @@
<html>
<body>
<div style="margin-top: 20px;">
<iframe src="data:text/html,%3Cspan%3EJust%20a%20simple%20little%20iframe.%3C%2Fspan%3E"
style="display: inline; border: 1px solid black; width: 500px;">
</iframe>
</div>
</body>
</html>

View file

@ -0,0 +1,9 @@
<html>
<body>
<div style="margin-top: 20px;">
<iframe src="data:text/html,%3Cspan%3EJust%20a%20simple%20little%20iframe.%3C%2Fspan%3E"
style="display: inline; border: 1px solid black; width: 500px; height: 300px;">
</iframe>
</div>
</body>
</html>

View file

@ -0,0 +1,7 @@
<html>
<body>
<div style="border: 1px solid black; width: 500px; height: 300px; margin-top: 20px;">
<div style="margin: 8px; /* matches user-agent body */">Just a simple little iframe.</div>
</div>
</body>
</html>

View file

@ -0,0 +1,9 @@
<html>
<body>
<div style="margin-top: 20px; width: 400px;">
<iframe src="data:text/html,%3Cspan%3EJust%20a%20simple%20little%20iframe.%3C%2Fspan%3E"
style="display: inline; border: 1px solid black; width: 50%;">
</iframe>
</div>
</body>
</html>

View file

@ -0,0 +1,7 @@
<html>
<body>
<div style="border: 1px solid black; width: 200px; height: 150px; margin-top: 20px;">
<div style="margin: 8px; /* matches user-agent body */">Just a simple little iframe.</div>
</div>
</body>
</html>

View file

@ -0,0 +1,7 @@
<html>
<body>
<div style="border: 1px solid black; width: 500px; height: 150px; margin-top: 20px;">
<div style="margin: 8px; /* matches user-agent body */">Just a simple little iframe.</div>
</div>
</body>
</html>