mirror of
https://github.com/servo/servo.git
synced 2025-08-03 04:30:10 +01:00
Merge in servo/master
This commit is contained in:
commit
19686acdec
78 changed files with 2000 additions and 989 deletions
|
@ -19,7 +19,7 @@ use fragment::{CoordinateSystem, Fragment, IframeFragmentInfo, ImageFragmentInfo
|
|||
use fragment::{ScannedTextFragmentInfo, SpecificFragmentInfo};
|
||||
use inline::InlineFlow;
|
||||
use list_item::ListItemFlow;
|
||||
use model;
|
||||
use model::{self, MaybeAuto};
|
||||
use opaque_node::OpaqueNodeMethods;
|
||||
|
||||
use geom::{Point2D, Rect, Size2D, SideOffsets2D};
|
||||
|
@ -32,8 +32,7 @@ use gfx::display_list::{GradientStop, ImageDisplayItem, LineDisplayItem};
|
|||
use gfx::display_list::{OpaqueNode, SolidColorDisplayItem};
|
||||
use gfx::display_list::{StackingContext, TextDisplayItem, TextOrientation};
|
||||
use gfx::paint_task::{PaintLayer, THREAD_TINT_COLORS};
|
||||
use png;
|
||||
use png::PixelsByColorType;
|
||||
use png::{self, PixelsByColorType};
|
||||
use msg::compositor_msg::ScrollPolicy;
|
||||
use msg::constellation_msg::Msg as ConstellationMsg;
|
||||
use msg::constellation_msg::ConstellationChan;
|
||||
|
@ -42,15 +41,16 @@ 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;
|
||||
use style::values::specified::{AngleOrCorner, HorizontalDirection, VerticalDirection};
|
||||
use style::values::computed::{Image, LinearGradient, LengthOrPercentage};
|
||||
use style::values::computed::{Image, LinearGradient, LengthOrPercentage, LengthOrPercentageOrAuto};
|
||||
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::{position, visibility};
|
||||
use style::computed_values::{background_attachment, background_repeat, background_size};
|
||||
use style::computed_values::{border_style, image_rendering, overflow_x, position, visibility};
|
||||
use style::properties::style_structs::Border;
|
||||
use style::properties::ComputedValues;
|
||||
use std::num::ToPrimitive;
|
||||
|
@ -93,6 +93,14 @@ pub trait FragmentDisplayListBuilding {
|
|||
absolute_bounds: &Rect<Au>,
|
||||
clip: &ClippingRegion);
|
||||
|
||||
/// Computes the background size for an image with the given background area according to the
|
||||
/// rules in CSS-BACKGROUNDS § 3.9.
|
||||
fn compute_background_image_size(&self,
|
||||
style: &ComputedValues,
|
||||
bounds: &Rect<Au>,
|
||||
image: &png::Image)
|
||||
-> Size2D<Au>;
|
||||
|
||||
/// Adds the display items necessary to paint the background image of this fragment to the
|
||||
/// display list at the appropriate stacking level.
|
||||
fn build_display_list_for_background_image(&self,
|
||||
|
@ -326,6 +334,59 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
}
|
||||
}
|
||||
|
||||
fn compute_background_image_size(&self,
|
||||
style: &ComputedValues,
|
||||
bounds: &Rect<Au>,
|
||||
image: &png::Image)
|
||||
-> Size2D<Au> {
|
||||
// If `image_aspect_ratio` < `bounds_aspect_ratio`, the image is tall; otherwise, it is
|
||||
// wide.
|
||||
let image_aspect_ratio = (image.width as f64) / (image.height as f64);
|
||||
let bounds_aspect_ratio = bounds.size.width.to_subpx() / bounds.size.height.to_subpx();
|
||||
let intrinsic_size = Size2D(Au::from_px(image.width as int),
|
||||
Au::from_px(image.height as int));
|
||||
match (style.get_background().background_size.clone(),
|
||||
image_aspect_ratio < bounds_aspect_ratio) {
|
||||
(background_size::T::Contain, false) | (background_size::T::Cover, true) => {
|
||||
Size2D(bounds.size.width,
|
||||
Au::from_frac_px(bounds.size.width.to_subpx() / image_aspect_ratio))
|
||||
}
|
||||
|
||||
(background_size::T::Contain, true) | (background_size::T::Cover, false) => {
|
||||
Size2D(Au::from_frac_px(bounds.size.height.to_subpx() * image_aspect_ratio),
|
||||
bounds.size.height)
|
||||
}
|
||||
|
||||
(background_size::T::Explicit(background_size::ExplicitSize {
|
||||
width,
|
||||
height: LengthOrPercentageOrAuto::Auto,
|
||||
}), _) => {
|
||||
let width = MaybeAuto::from_style(width, bounds.size.width)
|
||||
.specified_or_default(intrinsic_size.width);
|
||||
Size2D(width, Au::from_frac_px(width.to_subpx() / image_aspect_ratio))
|
||||
}
|
||||
|
||||
(background_size::T::Explicit(background_size::ExplicitSize {
|
||||
width: LengthOrPercentageOrAuto::Auto,
|
||||
height
|
||||
}), _) => {
|
||||
let height = MaybeAuto::from_style(height, bounds.size.height)
|
||||
.specified_or_default(intrinsic_size.height);
|
||||
Size2D(Au::from_frac_px(height.to_subpx() * image_aspect_ratio), height)
|
||||
}
|
||||
|
||||
(background_size::T::Explicit(background_size::ExplicitSize {
|
||||
width,
|
||||
height
|
||||
}), _) => {
|
||||
Size2D(MaybeAuto::from_style(width, bounds.size.width)
|
||||
.specified_or_default(intrinsic_size.width),
|
||||
MaybeAuto::from_style(height, bounds.size.height)
|
||||
.specified_or_default(intrinsic_size.height))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn build_display_list_for_background_image(&self,
|
||||
style: &ComputedValues,
|
||||
display_list: &mut DisplayList,
|
||||
|
@ -349,16 +410,16 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
};
|
||||
debug!("(building display list) building background image");
|
||||
|
||||
let image_width = Au::from_px(image.width as int);
|
||||
let image_height = Au::from_px(image.height as int);
|
||||
// Use `background-size` to get the size.
|
||||
let mut bounds = *absolute_bounds;
|
||||
let image_size = self.compute_background_image_size(style, &bounds, &**image);
|
||||
|
||||
// Clip.
|
||||
//
|
||||
// TODO: Check the bounds to see if a clip item is actually required.
|
||||
let clip = clip.clone().intersect_rect(&bounds);
|
||||
|
||||
// Use background-attachment to get the initial virtual origin
|
||||
// Use `background-attachment` to get the initial virtual origin
|
||||
let (virtual_origin_x, virtual_origin_y) = match background.background_attachment {
|
||||
background_attachment::T::scroll => {
|
||||
(absolute_bounds.origin.x, absolute_bounds.origin.y)
|
||||
|
@ -368,11 +429,11 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
}
|
||||
};
|
||||
|
||||
// Use background-position to get the offset
|
||||
// Use `background-position` to get the offset.
|
||||
let horizontal_position = model::specified(background.background_position.horizontal,
|
||||
bounds.size.width - image_width);
|
||||
bounds.size.width - image_size.width);
|
||||
let vertical_position = model::specified(background.background_position.vertical,
|
||||
bounds.size.height - image_height);
|
||||
bounds.size.height - image_size.height);
|
||||
|
||||
let abs_x = virtual_origin_x + horizontal_position;
|
||||
let abs_y = virtual_origin_y + vertical_position;
|
||||
|
@ -382,26 +443,34 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
background_repeat::T::no_repeat => {
|
||||
bounds.origin.x = abs_x;
|
||||
bounds.origin.y = abs_y;
|
||||
bounds.size.width = image_width;
|
||||
bounds.size.height = image_height;
|
||||
bounds.size.width = image_size.width;
|
||||
bounds.size.height = image_size.height;
|
||||
}
|
||||
background_repeat::T::repeat_x => {
|
||||
bounds.origin.y = abs_y;
|
||||
bounds.size.height = image_height;
|
||||
ImageFragmentInfo::tile_image(&mut bounds.origin.x, &mut bounds.size.width,
|
||||
abs_x, image.width);
|
||||
bounds.size.height = image_size.height;
|
||||
ImageFragmentInfo::tile_image(&mut bounds.origin.x,
|
||||
&mut bounds.size.width,
|
||||
abs_x,
|
||||
image_size.width.to_nearest_px() as u32);
|
||||
}
|
||||
background_repeat::T::repeat_y => {
|
||||
bounds.origin.x = abs_x;
|
||||
bounds.size.width = image_width;
|
||||
ImageFragmentInfo::tile_image(&mut bounds.origin.y, &mut bounds.size.height,
|
||||
abs_y, image.height);
|
||||
bounds.size.width = image_size.width;
|
||||
ImageFragmentInfo::tile_image(&mut bounds.origin.y,
|
||||
&mut bounds.size.height,
|
||||
abs_y,
|
||||
image_size.height.to_nearest_px() as u32);
|
||||
}
|
||||
background_repeat::T::repeat => {
|
||||
ImageFragmentInfo::tile_image(&mut bounds.origin.x, &mut bounds.size.width,
|
||||
abs_x, image.width);
|
||||
ImageFragmentInfo::tile_image(&mut bounds.origin.y, &mut bounds.size.height,
|
||||
abs_y, image.height);
|
||||
ImageFragmentInfo::tile_image(&mut bounds.origin.x,
|
||||
&mut bounds.size.width,
|
||||
abs_x,
|
||||
image_size.width.to_nearest_px() as u32);
|
||||
ImageFragmentInfo::tile_image(&mut bounds.origin.y,
|
||||
&mut bounds.size.height,
|
||||
abs_y,
|
||||
image_size.height.to_nearest_px() as u32);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -413,8 +482,8 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
Cursor::DefaultCursor),
|
||||
clip),
|
||||
image: image.clone(),
|
||||
stretch_size: Size2D(Au::from_px(image.width as int),
|
||||
Au::from_px(image.height as int)),
|
||||
stretch_size: Size2D(image_size.width, image_size.height),
|
||||
image_rendering: style.get_effects().image_rendering.clone(),
|
||||
}), level);
|
||||
}
|
||||
|
||||
|
@ -912,6 +981,7 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
(*clip).clone()),
|
||||
image: image.clone(),
|
||||
stretch_size: stacking_relative_content_box.size,
|
||||
image_rendering: self.style.get_effects().image_rendering.clone(),
|
||||
}));
|
||||
} else {
|
||||
// No image data at all? Do nothing.
|
||||
|
@ -947,6 +1017,7 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
pixels: PixelsByColorType::RGBA8(canvas_data),
|
||||
}),
|
||||
stretch_size: stacking_relative_content_box.size,
|
||||
image_rendering: image_rendering::T::Auto,
|
||||
};
|
||||
|
||||
display_list.content.push_back(DisplayItem::ImageClass(canvas_display_item));
|
||||
|
@ -991,17 +1062,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,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue