layout: Implement overflow-x and overflow-y per CSS-OVERFLOW § 3.

Fragmentation is not yet supported.
This commit is contained in:
Patrick Walton 2015-01-07 16:05:10 -08:00 committed by Simon Sapin
parent 417a932e30
commit a82fc00806
9 changed files with 199 additions and 17 deletions

View file

@ -57,9 +57,10 @@ use servo_util::logical_geometry::{LogicalPoint, LogicalRect, LogicalSize};
use servo_util::opts;
use std::cmp::{max, min};
use std::fmt;
use style::computed_values::{overflow_x, overflow_y, position, box_sizing, display, float};
use style::properties::ComputedValues;
use style::values::computed::{LengthOrPercentage, LengthOrPercentageOrAuto, LengthOrPercentageOrNone};
use style::computed_values::{overflow, position, box_sizing, display, float};
use style::values::computed::{LengthOrPercentage, LengthOrPercentageOrAuto};
use style::values::computed::{LengthOrPercentageOrNone};
use std::sync::Arc;
/// Information specific to floated blocks.
@ -1431,7 +1432,10 @@ impl BlockFlow {
display::T::inline_block => {
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,
}
}

View file

@ -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::logical_geometry::{LogicalPoint, LogicalRect, LogicalSize};
use servo_util::opts;
use std::cmp;
use std::default::Default;
use std::iter::repeat;
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::RGBA;
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::properties::style_structs::Border;
use style::properties::ComputedValues;
@ -990,17 +991,37 @@ impl FragmentDisplayListBuilding for Fragment {
}
// Account for style-specified `clip`.
let current_clip = self.calculate_style_specified_clip(current_clip,
stacking_relative_border_box);
let mut current_clip = self.calculate_style_specified_clip(current_clip,
stacking_relative_border_box);
// Only clip if `overflow` tells us to.
match self.style.get_box().overflow {
overflow::T::hidden | overflow::T::auto | overflow::T::scroll => {
// Create a new clip rect.
current_clip.intersect_rect(stacking_relative_border_box)
// Clip according to the values of `overflow-x` and `overflow-y`.
//
// TODO(pcwalton): Support scrolling.
// FIXME(pcwalton): This may be more complex than it needs to be, since it seems to be
// 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,

View file

@ -34,7 +34,7 @@ use std::mem;
use std::num::ToPrimitive;
use std::ops::{Add, Sub, Mul, Div, Rem, Neg, Shl, Shr, Not, BitOr, BitAnd, BitXor};
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::properties::ComputedValues;
use std::sync::Arc;
@ -653,8 +653,8 @@ impl LineBreaker {
let available_inline_size = self.pending_line.green_zone.inline -
self.pending_line.bounds.size.inline - indentation;
match (fragment.style().get_inheritedtext().text_overflow,
fragment.style().get_box().overflow) {
(text_overflow::T::clip, _) | (_, overflow::T::visible) => {}
fragment.style().get_box().overflow_x) {
(text_overflow::T::clip, _) | (_, overflow_x::T::visible) => {}
(text_overflow::T::ellipsis, _) => {
need_ellipsis = fragment.border_box.size.inline > available_inline_size;
}

View file

@ -103,6 +103,8 @@ partial interface CSSStyleDeclaration {
[TreatNullAs=EmptyString] attribute DOMString listStyleImage;
[TreatNullAs=EmptyString] attribute DOMString overflow;
[TreatNullAs=EmptyString] attribute DOMString overflowX;
[TreatNullAs=EmptyString] attribute DOMString overflowY;
[TreatNullAs=EmptyString] attribute DOMString overflowWrap;
[TreatNullAs=EmptyString] attribute DOMString tableLayout;

View file

@ -676,8 +676,77 @@ pub mod longhands {
// 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")}
@ -2830,6 +2899,16 @@ pub mod shorthands {
_ => Err(()),
}
</%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(),
color: inherited_style.get_color().color,
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,
floated: false,
border_top_present: false,
@ -3528,6 +3609,12 @@ pub fn cascade(applicable_declarations: &[DeclarationBlock<Vec<PropertyDeclarati
_ => 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) => {
context.floated = get_specified!(get_box, float, value)
!= longhands::float::SpecifiedValue::none;

View file

@ -690,6 +690,8 @@ pub mod computed {
pub 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 overflow_x: longhands::overflow_x::computed_value::T,
pub overflow_y: longhands::overflow_y::computed_value::T,
pub positioned: bool,
pub floated: bool,
pub border_top_present: bool,

View file

@ -255,6 +255,7 @@ fragment=top != ../html/acid2.html acid2_ref.html
== canvas_lineto_a.html canvas_lineto_ref.html
!= text_decoration_smoke_a.html text_decoration_smoke_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_decorations_a.html text_shadow_decorations_ref.html
== text_shadow_blur_a.html text_shadow_blur_ref.html

View 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>

View 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>