mirror of
https://github.com/servo/servo.git
synced 2025-08-03 04:30:10 +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 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,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
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