mirror of
https://github.com/servo/servo.git
synced 2025-08-04 21:20:23 +01:00
layout: Implement overflow-x
and overflow-y
per CSS-OVERFLOW § 3.
Fragmentation is not yet supported.
This commit is contained in:
parent
417a932e30
commit
a82fc00806
9 changed files with 199 additions and 17 deletions
|
@ -57,9 +57,10 @@ use servo_util::logical_geometry::{LogicalPoint, LogicalRect, LogicalSize};
|
||||||
use servo_util::opts;
|
use servo_util::opts;
|
||||||
use std::cmp::{max, min};
|
use std::cmp::{max, min};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
use style::computed_values::{overflow_x, overflow_y, position, box_sizing, display, float};
|
||||||
use style::properties::ComputedValues;
|
use style::properties::ComputedValues;
|
||||||
use style::values::computed::{LengthOrPercentage, LengthOrPercentageOrAuto, LengthOrPercentageOrNone};
|
use style::values::computed::{LengthOrPercentage, LengthOrPercentageOrAuto};
|
||||||
use style::computed_values::{overflow, position, box_sizing, display, float};
|
use style::values::computed::{LengthOrPercentageOrNone};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// Information specific to floated blocks.
|
/// Information specific to floated blocks.
|
||||||
|
@ -1431,7 +1432,10 @@ impl BlockFlow {
|
||||||
display::T::inline_block => {
|
display::T::inline_block => {
|
||||||
FormattingContextType::Other
|
FormattingContextType::Other
|
||||||
}
|
}
|
||||||
_ if style.get_box().overflow != overflow::T::visible => FormattingContextType::Block,
|
_ if style.get_box().overflow_x != overflow_x::T::visible ||
|
||||||
|
style.get_box().overflow_y != overflow_y::T(overflow_x::T::visible) => {
|
||||||
|
FormattingContextType::Block
|
||||||
|
}
|
||||||
_ => FormattingContextType::None,
|
_ => FormattingContextType::None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,6 +41,7 @@ use servo_util::cursor::Cursor;
|
||||||
use servo_util::geometry::{self, Au, ZERO_POINT, to_px, to_frac_px};
|
use servo_util::geometry::{self, Au, ZERO_POINT, to_px, to_frac_px};
|
||||||
use servo_util::logical_geometry::{LogicalPoint, LogicalRect, LogicalSize};
|
use servo_util::logical_geometry::{LogicalPoint, LogicalRect, LogicalSize};
|
||||||
use servo_util::opts;
|
use servo_util::opts;
|
||||||
|
use std::cmp;
|
||||||
use std::default::Default;
|
use std::default::Default;
|
||||||
use std::iter::repeat;
|
use std::iter::repeat;
|
||||||
use std::num::Float;
|
use std::num::Float;
|
||||||
|
@ -48,7 +49,7 @@ use style::values::specified::{AngleOrCorner, HorizontalDirection, VerticalDirec
|
||||||
use style::values::computed::{Image, LinearGradient, LengthOrPercentage};
|
use style::values::computed::{Image, LinearGradient, LengthOrPercentage};
|
||||||
use style::values::RGBA;
|
use style::values::RGBA;
|
||||||
use style::computed_values::filter::Filter;
|
use style::computed_values::filter::Filter;
|
||||||
use style::computed_values::{background_attachment, background_repeat, border_style, overflow};
|
use style::computed_values::{background_attachment, background_repeat, border_style, overflow_x};
|
||||||
use style::computed_values::{position, visibility};
|
use style::computed_values::{position, visibility};
|
||||||
use style::properties::style_structs::Border;
|
use style::properties::style_structs::Border;
|
||||||
use style::properties::ComputedValues;
|
use style::properties::ComputedValues;
|
||||||
|
@ -990,17 +991,37 @@ impl FragmentDisplayListBuilding for Fragment {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Account for style-specified `clip`.
|
// Account for style-specified `clip`.
|
||||||
let current_clip = self.calculate_style_specified_clip(current_clip,
|
let mut current_clip = self.calculate_style_specified_clip(current_clip,
|
||||||
stacking_relative_border_box);
|
stacking_relative_border_box);
|
||||||
|
|
||||||
// Only clip if `overflow` tells us to.
|
// Clip according to the values of `overflow-x` and `overflow-y`.
|
||||||
match self.style.get_box().overflow {
|
//
|
||||||
overflow::T::hidden | overflow::T::auto | overflow::T::scroll => {
|
// TODO(pcwalton): Support scrolling.
|
||||||
// Create a new clip rect.
|
// FIXME(pcwalton): This may be more complex than it needs to be, since it seems to be
|
||||||
current_clip.intersect_rect(stacking_relative_border_box)
|
// impossible with the computed value rules as they are to have `overflow-x: visible` with
|
||||||
|
// `overflow-y: <scrolling>` or vice versa!
|
||||||
|
match self.style.get_box().overflow_x {
|
||||||
|
overflow_x::T::hidden | overflow_x::T::auto | overflow_x::T::scroll => {
|
||||||
|
let mut bounds = current_clip.bounding_rect();
|
||||||
|
let max_x = cmp::min(bounds.max_x(), stacking_relative_border_box.max_x());
|
||||||
|
bounds.origin.x = cmp::max(bounds.origin.x, stacking_relative_border_box.origin.x);
|
||||||
|
bounds.size.width = max_x - bounds.origin.x;
|
||||||
|
current_clip = current_clip.intersect_rect(&bounds)
|
||||||
}
|
}
|
||||||
_ => current_clip,
|
_ => {}
|
||||||
}
|
}
|
||||||
|
match self.style.get_box().overflow_y.0 {
|
||||||
|
overflow_x::T::hidden | overflow_x::T::auto | overflow_x::T::scroll => {
|
||||||
|
let mut bounds = current_clip.bounding_rect();
|
||||||
|
let max_y = cmp::min(bounds.max_y(), stacking_relative_border_box.max_y());
|
||||||
|
bounds.origin.y = cmp::max(bounds.origin.y, stacking_relative_border_box.origin.y);
|
||||||
|
bounds.size.height = max_y - bounds.origin.y;
|
||||||
|
current_clip = current_clip.intersect_rect(&bounds)
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
current_clip
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_display_list_for_text_fragment(&self,
|
fn build_display_list_for_text_fragment(&self,
|
||||||
|
|
|
@ -34,7 +34,7 @@ use std::mem;
|
||||||
use std::num::ToPrimitive;
|
use std::num::ToPrimitive;
|
||||||
use std::ops::{Add, Sub, Mul, Div, Rem, Neg, Shl, Shr, Not, BitOr, BitAnd, BitXor};
|
use std::ops::{Add, Sub, Mul, Div, Rem, Neg, Shl, Shr, Not, BitOr, BitAnd, BitXor};
|
||||||
use std::u16;
|
use std::u16;
|
||||||
use style::computed_values::{overflow, text_align, text_justify, text_overflow, vertical_align};
|
use style::computed_values::{overflow_x, text_align, text_justify, text_overflow, vertical_align};
|
||||||
use style::computed_values::{white_space};
|
use style::computed_values::{white_space};
|
||||||
use style::properties::ComputedValues;
|
use style::properties::ComputedValues;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
@ -653,8 +653,8 @@ impl LineBreaker {
|
||||||
let available_inline_size = self.pending_line.green_zone.inline -
|
let available_inline_size = self.pending_line.green_zone.inline -
|
||||||
self.pending_line.bounds.size.inline - indentation;
|
self.pending_line.bounds.size.inline - indentation;
|
||||||
match (fragment.style().get_inheritedtext().text_overflow,
|
match (fragment.style().get_inheritedtext().text_overflow,
|
||||||
fragment.style().get_box().overflow) {
|
fragment.style().get_box().overflow_x) {
|
||||||
(text_overflow::T::clip, _) | (_, overflow::T::visible) => {}
|
(text_overflow::T::clip, _) | (_, overflow_x::T::visible) => {}
|
||||||
(text_overflow::T::ellipsis, _) => {
|
(text_overflow::T::ellipsis, _) => {
|
||||||
need_ellipsis = fragment.border_box.size.inline > available_inline_size;
|
need_ellipsis = fragment.border_box.size.inline > available_inline_size;
|
||||||
}
|
}
|
||||||
|
|
|
@ -103,6 +103,8 @@ partial interface CSSStyleDeclaration {
|
||||||
[TreatNullAs=EmptyString] attribute DOMString listStyleImage;
|
[TreatNullAs=EmptyString] attribute DOMString listStyleImage;
|
||||||
|
|
||||||
[TreatNullAs=EmptyString] attribute DOMString overflow;
|
[TreatNullAs=EmptyString] attribute DOMString overflow;
|
||||||
|
[TreatNullAs=EmptyString] attribute DOMString overflowX;
|
||||||
|
[TreatNullAs=EmptyString] attribute DOMString overflowY;
|
||||||
[TreatNullAs=EmptyString] attribute DOMString overflowWrap;
|
[TreatNullAs=EmptyString] attribute DOMString overflowWrap;
|
||||||
|
|
||||||
[TreatNullAs=EmptyString] attribute DOMString tableLayout;
|
[TreatNullAs=EmptyString] attribute DOMString tableLayout;
|
||||||
|
|
|
@ -676,8 +676,77 @@ pub mod longhands {
|
||||||
|
|
||||||
|
|
||||||
// CSS 2.1, Section 11 - Visual effects
|
// CSS 2.1, Section 11 - Visual effects
|
||||||
// FIXME: Implement scrolling for `scroll` and `auto` (#2742).
|
|
||||||
${single_keyword("overflow", "visible hidden scroll auto")}
|
// FIXME(pcwalton, #2742): Implement scrolling for `scroll` and `auto`.
|
||||||
|
<%self:single_keyword_computed name="overflow-x" values="visible hidden scroll auto">
|
||||||
|
use values::computed::{Context, ToComputedValue};
|
||||||
|
|
||||||
|
pub fn compute_with_other_overflow_direction(value: SpecifiedValue,
|
||||||
|
other_direction: SpecifiedValue)
|
||||||
|
-> computed_value::T {
|
||||||
|
// CSS-OVERFLOW 3 states "Otherwise, if one cascaded values is one of the scrolling
|
||||||
|
// values and the other is `visible`, then computed values are the cascaded values with
|
||||||
|
// `visible` changed to `auto`."
|
||||||
|
match (value, other_direction) {
|
||||||
|
(SpecifiedValue::visible, SpecifiedValue::hidden) |
|
||||||
|
(SpecifiedValue::visible, SpecifiedValue::scroll) |
|
||||||
|
(SpecifiedValue::visible, SpecifiedValue::auto) => computed_value::T::auto,
|
||||||
|
_ => value,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToComputedValue for SpecifiedValue {
|
||||||
|
type ComputedValue = computed_value::T;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn to_computed_value(&self, context: &Context) -> computed_value::T {
|
||||||
|
compute_with_other_overflow_direction(*self, context.overflow_y.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</%self:single_keyword_computed>
|
||||||
|
|
||||||
|
// FIXME(pcwalton, #2742): Implement scrolling for `scroll` and `auto`.
|
||||||
|
<%self:longhand name="overflow-y">
|
||||||
|
use super::overflow_x;
|
||||||
|
use values::computed::{Context, ToComputedValue};
|
||||||
|
|
||||||
|
use cssparser::ToCss;
|
||||||
|
use text_writer::{self, TextWriter};
|
||||||
|
|
||||||
|
pub use self::computed_value::T as SpecifiedValue;
|
||||||
|
|
||||||
|
impl ToCss for SpecifiedValue {
|
||||||
|
fn to_css<W>(&self, dest: &mut W) -> text_writer::Result where W: TextWriter {
|
||||||
|
self.0.to_css(dest)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod computed_value {
|
||||||
|
#[derive(Clone, Copy, PartialEq)]
|
||||||
|
pub struct T(pub super::super::overflow_x::computed_value::T);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToComputedValue for SpecifiedValue {
|
||||||
|
type ComputedValue = computed_value::T;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn to_computed_value(&self, context: &Context) -> computed_value::T {
|
||||||
|
let computed_value::T(this) = *self;
|
||||||
|
computed_value::T(overflow_x::compute_with_other_overflow_direction(
|
||||||
|
this,
|
||||||
|
context.overflow_x))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_initial_value() -> computed_value::T {
|
||||||
|
computed_value::T(overflow_x::get_initial_value())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue,()> {
|
||||||
|
overflow_x::parse(context, input).map(|value| SpecifiedValue(value))
|
||||||
|
}
|
||||||
|
</%self:longhand>
|
||||||
|
|
||||||
|
|
||||||
${switch_to_style_struct("InheritedBox")}
|
${switch_to_style_struct("InheritedBox")}
|
||||||
|
|
||||||
|
@ -2830,6 +2899,16 @@ pub mod shorthands {
|
||||||
_ => Err(()),
|
_ => Err(()),
|
||||||
}
|
}
|
||||||
</%self:shorthand>
|
</%self:shorthand>
|
||||||
|
|
||||||
|
<%self:shorthand name="overflow" sub_properties="overflow-x overflow-y">
|
||||||
|
use properties::longhands::{overflow_x, overflow_y};
|
||||||
|
|
||||||
|
let overflow = try!(overflow_x::parse(context, input));
|
||||||
|
Ok(Longhands {
|
||||||
|
overflow_x: Some(overflow),
|
||||||
|
overflow_y: Some(overflow_y::SpecifiedValue(overflow)),
|
||||||
|
})
|
||||||
|
</%self:shorthand>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -3474,6 +3553,8 @@ pub fn cascade(applicable_declarations: &[DeclarationBlock<Vec<PropertyDeclarati
|
||||||
display: longhands::display::get_initial_value(),
|
display: longhands::display::get_initial_value(),
|
||||||
color: inherited_style.get_color().color,
|
color: inherited_style.get_color().color,
|
||||||
text_decoration: longhands::text_decoration::get_initial_value(),
|
text_decoration: longhands::text_decoration::get_initial_value(),
|
||||||
|
overflow_x: longhands::overflow_x::get_initial_value(),
|
||||||
|
overflow_y: longhands::overflow_y::get_initial_value(),
|
||||||
positioned: false,
|
positioned: false,
|
||||||
floated: false,
|
floated: false,
|
||||||
border_top_present: false,
|
border_top_present: false,
|
||||||
|
@ -3528,6 +3609,12 @@ pub fn cascade(applicable_declarations: &[DeclarationBlock<Vec<PropertyDeclarati
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
PropertyDeclaration::OverflowX(ref value) => {
|
||||||
|
context.overflow_x = get_specified!(get_box, overflow_x, value);
|
||||||
|
}
|
||||||
|
PropertyDeclaration::OverflowY(ref value) => {
|
||||||
|
context.overflow_y = get_specified!(get_box, overflow_y, value);
|
||||||
|
}
|
||||||
PropertyDeclaration::Float(ref value) => {
|
PropertyDeclaration::Float(ref value) => {
|
||||||
context.floated = get_specified!(get_box, float, value)
|
context.floated = get_specified!(get_box, float, value)
|
||||||
!= longhands::float::SpecifiedValue::none;
|
!= longhands::float::SpecifiedValue::none;
|
||||||
|
|
|
@ -690,6 +690,8 @@ pub mod computed {
|
||||||
pub font_size: longhands::font_size::computed_value::T,
|
pub font_size: longhands::font_size::computed_value::T,
|
||||||
pub root_font_size: longhands::font_size::computed_value::T,
|
pub root_font_size: longhands::font_size::computed_value::T,
|
||||||
pub display: longhands::display::computed_value::T,
|
pub display: longhands::display::computed_value::T,
|
||||||
|
pub overflow_x: longhands::overflow_x::computed_value::T,
|
||||||
|
pub overflow_y: longhands::overflow_y::computed_value::T,
|
||||||
pub positioned: bool,
|
pub positioned: bool,
|
||||||
pub floated: bool,
|
pub floated: bool,
|
||||||
pub border_top_present: bool,
|
pub border_top_present: bool,
|
||||||
|
|
|
@ -255,6 +255,7 @@ fragment=top != ../html/acid2.html acid2_ref.html
|
||||||
== canvas_lineto_a.html canvas_lineto_ref.html
|
== canvas_lineto_a.html canvas_lineto_ref.html
|
||||||
!= text_decoration_smoke_a.html text_decoration_smoke_ref.html
|
!= text_decoration_smoke_a.html text_decoration_smoke_ref.html
|
||||||
== hide_after_create.html hide_after_create_ref.html
|
== hide_after_create.html hide_after_create_ref.html
|
||||||
|
== overflow_xy_a.html overflow_xy_ref.html
|
||||||
== text_shadow_simple_a.html text_shadow_simple_ref.html
|
== text_shadow_simple_a.html text_shadow_simple_ref.html
|
||||||
== text_shadow_decorations_a.html text_shadow_decorations_ref.html
|
== text_shadow_decorations_a.html text_shadow_decorations_ref.html
|
||||||
== text_shadow_blur_a.html text_shadow_blur_ref.html
|
== text_shadow_blur_a.html text_shadow_blur_ref.html
|
||||||
|
|
36
tests/ref/overflow_xy_a.html
Normal file
36
tests/ref/overflow_xy_a.html
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<!-- Tests that `overflow-x` and `overflow-y` work. -->
|
||||||
|
<style>
|
||||||
|
section {
|
||||||
|
position: absolute;
|
||||||
|
width: 100px;
|
||||||
|
height: 100px;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
#x {
|
||||||
|
overflow-x: hidden;
|
||||||
|
overflow-y: visible; /* computes to `auto` */
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
#y {
|
||||||
|
overflow: hidden;
|
||||||
|
top: 200px;
|
||||||
|
}
|
||||||
|
div {
|
||||||
|
position: absolute;
|
||||||
|
width: 200px;
|
||||||
|
height: 200px;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
background: green;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<section id=x><div></div></section>
|
||||||
|
<section id=y><div></div></section>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
29
tests/ref/overflow_xy_ref.html
Normal file
29
tests/ref/overflow_xy_ref.html
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<!-- Tests that `overflow-x` and `overflow-y` work. -->
|
||||||
|
<style>
|
||||||
|
section {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
background: green;
|
||||||
|
}
|
||||||
|
#x {
|
||||||
|
top: 0;
|
||||||
|
width: 100px;
|
||||||
|
height: 100px;
|
||||||
|
}
|
||||||
|
#y {
|
||||||
|
top: 200px;
|
||||||
|
width: 100px;
|
||||||
|
height: 100px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<section id=x></section>
|
||||||
|
<section id=y></section>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue