mirror of
https://github.com/servo/servo.git
synced 2025-08-06 06:00:15 +01:00
Add support for most of the border-image properties, pass to WR.
This adds support for: * border-image (images, not gradients yet) * border-image-source * border-image-slice * border-image-repeat (stretch + repeat only for now) Remaining work: * Connect border-image-outset (WR supports this). * border-image-width
This commit is contained in:
parent
854d720b21
commit
ffcb319324
17 changed files with 231 additions and 107 deletions
|
@ -20,7 +20,8 @@ use flow::{BaseFlow, Flow, IS_ABSOLUTELY_POSITIONED};
|
|||
use flow_ref::FlowRef;
|
||||
use fragment::{CoordinateSystem, Fragment, ImageFragmentInfo, ScannedTextFragmentInfo};
|
||||
use fragment::{SpecificFragmentInfo, TruncatedFragmentInfo};
|
||||
use gfx::display_list::{BLUR_INFLATION_FACTOR, BaseDisplayItem, BorderDisplayItem};
|
||||
use gfx::display_list::{BLUR_INFLATION_FACTOR, BaseDisplayItem, BorderDetails};
|
||||
use gfx::display_list::{BorderDisplayItem, ImageBorder, NormalBorder};
|
||||
use gfx::display_list::{BorderRadii, BoxShadowClipMode, BoxShadowDisplayItem, ClippingRegion};
|
||||
use gfx::display_list::{DisplayItem, DisplayItemMetadata, DisplayList, DisplayListSection};
|
||||
use gfx::display_list::{GradientDisplayItem, IframeDisplayItem, ImageDisplayItem};
|
||||
|
@ -45,13 +46,14 @@ use std::mem;
|
|||
use std::sync::Arc;
|
||||
use style::computed_values::{background_attachment, background_clip, background_origin};
|
||||
use style::computed_values::{background_repeat, background_size, border_style};
|
||||
use style::computed_values::{cursor, image_rendering, overflow_x};
|
||||
use style::computed_values::{cursor, image_rendering, overflow_x, border_image_slice};
|
||||
use style::computed_values::{pointer_events, position, transform_style, visibility};
|
||||
use style::computed_values::_servo_overflow_clip_box as overflow_clip_box;
|
||||
use style::computed_values::filter::Filter;
|
||||
use style::computed_values::text_shadow::TextShadow;
|
||||
use style::logical_geometry::{LogicalPoint, LogicalRect, LogicalSize, WritingMode};
|
||||
use style::properties::{self, ServoComputedValues};
|
||||
use style::properties::longhands::border_image_repeat::computed_value::RepeatKeyword;
|
||||
use style::properties::style_structs;
|
||||
use style::servo::restyle_damage::REPAINT;
|
||||
use style::values::{RGBA, computed};
|
||||
|
@ -60,7 +62,33 @@ use style::values::specified::{HorizontalDirection, VerticalDirection};
|
|||
use style_traits::PagePx;
|
||||
use style_traits::cursor::Cursor;
|
||||
use table_cell::CollapsedBordersForCell;
|
||||
use webrender_traits::{ColorF, GradientStop, ScrollPolicy};
|
||||
use webrender_traits::{ColorF, GradientStop, RepeatMode, ScrollPolicy};
|
||||
|
||||
trait ResolvePercentage {
|
||||
fn resolve(&self, length: u32) -> u32;
|
||||
}
|
||||
|
||||
impl ResolvePercentage for border_image_slice::PercentageOrNumber {
|
||||
fn resolve(&self, length: u32) -> u32 {
|
||||
match *self {
|
||||
border_image_slice::PercentageOrNumber::Percentage(p) => {
|
||||
(p.0 * length as f32).round() as u32
|
||||
}
|
||||
border_image_slice::PercentageOrNumber::Number(n) => {
|
||||
n.round() as u32
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn convert_repeat_mode(from: RepeatKeyword) -> RepeatMode {
|
||||
match from {
|
||||
RepeatKeyword::Stretch => RepeatMode::Stretch,
|
||||
RepeatKeyword::Repeat => RepeatMode::Repeat,
|
||||
RepeatKeyword::Round => RepeatMode::Round,
|
||||
RepeatKeyword::Space => RepeatMode::Space,
|
||||
}
|
||||
}
|
||||
|
||||
trait RgbColor {
|
||||
fn rgb(r: u8, g: u8, b: u8) -> Self;
|
||||
|
@ -1056,16 +1084,55 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
self.node,
|
||||
style.get_cursor(Cursor::Default),
|
||||
display_list_section);
|
||||
state.add_display_item(DisplayItem::Border(box BorderDisplayItem {
|
||||
base: base,
|
||||
border_widths: border.to_physical(style.writing_mode),
|
||||
color: SideOffsets2D::new(colors.top.to_gfx_color(),
|
||||
colors.right.to_gfx_color(),
|
||||
colors.bottom.to_gfx_color(),
|
||||
colors.left.to_gfx_color()),
|
||||
style: border_style,
|
||||
radius: build_border_radius(&bounds, border_style_struct),
|
||||
}));
|
||||
|
||||
match border_style_struct.border_image_source.0 {
|
||||
None => {
|
||||
state.add_display_item(DisplayItem::Border(box BorderDisplayItem {
|
||||
base: base,
|
||||
border_widths: border.to_physical(style.writing_mode),
|
||||
details: BorderDetails::Normal(NormalBorder {
|
||||
color: SideOffsets2D::new(colors.top.to_gfx_color(),
|
||||
colors.right.to_gfx_color(),
|
||||
colors.bottom.to_gfx_color(),
|
||||
colors.left.to_gfx_color()),
|
||||
style: border_style,
|
||||
radius: build_border_radius(&bounds, border_style_struct),
|
||||
}),
|
||||
}));
|
||||
}
|
||||
Some(computed::Image::Gradient(..)) => {
|
||||
// TODO(gw): Handle border-image with gradient.
|
||||
}
|
||||
Some(computed::Image::Url(ref image_url)) => {
|
||||
if let Some(url) = image_url.url() {
|
||||
let webrender_image = state.layout_context
|
||||
.get_webrender_image_for_url(self.node,
|
||||
url.clone(),
|
||||
UsePlaceholder::No);
|
||||
if let Some(webrender_image) = webrender_image {
|
||||
// The corners array is guaranteed to be len=4 by the css parser.
|
||||
let corners = &border_style_struct.border_image_slice.corners;
|
||||
|
||||
state.add_display_item(DisplayItem::Border(box BorderDisplayItem {
|
||||
base: base,
|
||||
border_widths: border.to_physical(style.writing_mode),
|
||||
details: BorderDetails::Image(ImageBorder {
|
||||
image: webrender_image,
|
||||
fill: border_style_struct.border_image_slice.fill,
|
||||
slice: SideOffsets2D::new(corners[0].resolve(webrender_image.height),
|
||||
corners[1].resolve(webrender_image.width),
|
||||
corners[2].resolve(webrender_image.height),
|
||||
corners[3].resolve(webrender_image.width)),
|
||||
// TODO(gw): Support border-image-outset
|
||||
outset: SideOffsets2D::zero(),
|
||||
repeat_horizontal: convert_repeat_mode(border_style_struct.border_image_repeat.0),
|
||||
repeat_vertical: convert_repeat_mode(border_style_struct.border_image_repeat.1),
|
||||
}),
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn build_display_list_for_outline_if_applicable(&self,
|
||||
|
@ -1105,9 +1172,11 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
state.add_display_item(DisplayItem::Border(box BorderDisplayItem {
|
||||
base: base,
|
||||
border_widths: SideOffsets2D::new_all_same(width),
|
||||
color: SideOffsets2D::new_all_same(color),
|
||||
style: SideOffsets2D::new_all_same(outline_style),
|
||||
radius: Default::default(),
|
||||
details: BorderDetails::Normal(NormalBorder {
|
||||
color: SideOffsets2D::new_all_same(color),
|
||||
style: SideOffsets2D::new_all_same(outline_style),
|
||||
radius: Default::default(),
|
||||
}),
|
||||
}));
|
||||
}
|
||||
|
||||
|
@ -1130,9 +1199,11 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
state.add_display_item(DisplayItem::Border(box BorderDisplayItem {
|
||||
base: base,
|
||||
border_widths: SideOffsets2D::new_all_same(Au::from_px(1)),
|
||||
color: SideOffsets2D::new_all_same(ColorF::rgb(0, 0, 200)),
|
||||
style: SideOffsets2D::new_all_same(border_style::T::solid),
|
||||
radius: Default::default(),
|
||||
details: BorderDetails::Normal(NormalBorder {
|
||||
color: SideOffsets2D::new_all_same(ColorF::rgb(0, 0, 200)),
|
||||
style: SideOffsets2D::new_all_same(border_style::T::solid),
|
||||
radius: Default::default(),
|
||||
}),
|
||||
}));
|
||||
|
||||
// Draw a rectangle representing the baselines.
|
||||
|
@ -1168,9 +1239,11 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
state.add_display_item(DisplayItem::Border(box BorderDisplayItem {
|
||||
base: base,
|
||||
border_widths: SideOffsets2D::new_all_same(Au::from_px(1)),
|
||||
color: SideOffsets2D::new_all_same(ColorF::rgb(0, 0, 200)),
|
||||
style: SideOffsets2D::new_all_same(border_style::T::solid),
|
||||
radius: Default::default(),
|
||||
details: BorderDetails::Normal(NormalBorder {
|
||||
color: SideOffsets2D::new_all_same(ColorF::rgb(0, 0, 200)),
|
||||
style: SideOffsets2D::new_all_same(border_style::T::solid),
|
||||
radius: Default::default(),
|
||||
}),
|
||||
}));
|
||||
}
|
||||
|
||||
|
@ -2129,9 +2202,11 @@ impl BaseFlowDisplayListBuilding for BaseFlow {
|
|||
state.add_display_item(DisplayItem::Border(box BorderDisplayItem {
|
||||
base: base,
|
||||
border_widths: SideOffsets2D::new_all_same(Au::from_px(2)),
|
||||
color: SideOffsets2D::new_all_same(color),
|
||||
style: SideOffsets2D::new_all_same(border_style::T::solid),
|
||||
radius: BorderRadii::all_same(Au(0)),
|
||||
details: BorderDetails::Normal(NormalBorder {
|
||||
color: SideOffsets2D::new_all_same(color),
|
||||
style: SideOffsets2D::new_all_same(border_style::T::solid),
|
||||
radius: BorderRadii::all_same(Au(0)),
|
||||
}),
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,8 +8,8 @@
|
|||
// completely converting layout to directly generate WebRender display lists, for example.
|
||||
|
||||
use app_units::Au;
|
||||
use euclid::{Point2D, Rect, Size2D};
|
||||
use gfx::display_list::{BorderRadii, BoxShadowClipMode, ClippingRegion};
|
||||
use euclid::{Point2D, Rect, SideOffsets2D, Size2D};
|
||||
use gfx::display_list::{BorderDetails, BorderRadii, BoxShadowClipMode, ClippingRegion};
|
||||
use gfx::display_list::{DisplayItem, DisplayList, DisplayListTraversal, StackingContextType};
|
||||
use gfx_traits::{FragmentType, ScrollRootId};
|
||||
use msg::constellation_msg::PipelineId;
|
||||
|
@ -46,6 +46,22 @@ impl ToBorderStyle for BorderStyle {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
trait ToBorderWidths {
|
||||
fn to_border_widths(&self) -> webrender_traits::BorderWidths;
|
||||
}
|
||||
|
||||
impl ToBorderWidths for SideOffsets2D<Au> {
|
||||
fn to_border_widths(&self) -> webrender_traits::BorderWidths {
|
||||
webrender_traits::BorderWidths {
|
||||
left: self.left.to_f32_px(),
|
||||
top: self.top.to_f32_px(),
|
||||
right: self.right.to_f32_px(),
|
||||
bottom: self.bottom.to_f32_px(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
trait ToBoxShadowClipMode {
|
||||
fn to_clip_mode(&self) -> webrender_traits::BoxShadowClipMode;
|
||||
}
|
||||
|
@ -270,41 +286,57 @@ impl WebRenderDisplayItemConverter for DisplayItem {
|
|||
}
|
||||
DisplayItem::Border(ref item) => {
|
||||
let rect = item.base.bounds.to_rectf();
|
||||
let widths = webrender_traits::BorderWidths {
|
||||
left: item.border_widths.left.to_f32_px(),
|
||||
top: item.border_widths.top.to_f32_px(),
|
||||
right: item.border_widths.right.to_f32_px(),
|
||||
bottom: item.border_widths.bottom.to_f32_px(),
|
||||
};
|
||||
let left = webrender_traits::BorderSide {
|
||||
color: item.color.left,
|
||||
style: item.style.left.to_border_style(),
|
||||
};
|
||||
let top = webrender_traits::BorderSide {
|
||||
color: item.color.top,
|
||||
style: item.style.top.to_border_style(),
|
||||
};
|
||||
let right = webrender_traits::BorderSide {
|
||||
color: item.color.right,
|
||||
style: item.style.right.to_border_style(),
|
||||
};
|
||||
let bottom = webrender_traits::BorderSide {
|
||||
color: item.color.bottom,
|
||||
style: item.style.bottom.to_border_style(),
|
||||
};
|
||||
let radius = item.radius.to_border_radius();
|
||||
let widths = item.border_widths.to_border_widths();
|
||||
let clip = item.base.clip.to_clip_region(builder);
|
||||
let details = webrender_traits::NormalBorder {
|
||||
left: left,
|
||||
top: top,
|
||||
right: right,
|
||||
bottom: bottom,
|
||||
radius: radius,
|
||||
|
||||
let details = match item.details {
|
||||
BorderDetails::Normal(ref border) => {
|
||||
let left = webrender_traits::BorderSide {
|
||||
color: border.color.left,
|
||||
style: border.style.left.to_border_style(),
|
||||
};
|
||||
let top = webrender_traits::BorderSide {
|
||||
color: border.color.top,
|
||||
style: border.style.top.to_border_style(),
|
||||
};
|
||||
let right = webrender_traits::BorderSide {
|
||||
color: border.color.right,
|
||||
style: border.style.right.to_border_style(),
|
||||
};
|
||||
let bottom = webrender_traits::BorderSide {
|
||||
color: border.color.bottom,
|
||||
style: border.style.bottom.to_border_style(),
|
||||
};
|
||||
let radius = border.radius.to_border_radius();
|
||||
webrender_traits::BorderDetails::Normal(webrender_traits::NormalBorder {
|
||||
left: left,
|
||||
top: top,
|
||||
right: right,
|
||||
bottom: bottom,
|
||||
radius: radius,
|
||||
})
|
||||
}
|
||||
BorderDetails::Image(ref image) => {
|
||||
match image.image.key {
|
||||
None => return,
|
||||
Some(key) => {
|
||||
webrender_traits::BorderDetails::Image(webrender_traits::ImageBorder {
|
||||
image_key: key,
|
||||
patch: webrender_traits::NinePatchDescriptor {
|
||||
width: image.image.width,
|
||||
height: image.image.height,
|
||||
slice: image.slice,
|
||||
},
|
||||
outset: image.outset,
|
||||
repeat_horizontal: image.repeat_horizontal,
|
||||
repeat_vertical: image.repeat_vertical,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
builder.push_border(rect,
|
||||
clip,
|
||||
widths,
|
||||
webrender_traits::BorderDetails::Normal(details));
|
||||
|
||||
builder.push_border(rect, clip, widths, details);
|
||||
}
|
||||
DisplayItem::Gradient(ref item) => {
|
||||
let rect = item.base.bounds.to_rectf();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue