mirror of
https://github.com/servo/servo.git
synced 2025-07-24 07:40:27 +01:00
Add gradient border support.
This commit is contained in:
parent
cc9fb0ba59
commit
02c675204a
3 changed files with 98 additions and 31 deletions
|
@ -885,10 +885,7 @@ pub struct IframeDisplayItem {
|
||||||
|
|
||||||
/// Paints a gradient.
|
/// Paints a gradient.
|
||||||
#[derive(Clone, Deserialize, HeapSizeOf, Serialize)]
|
#[derive(Clone, Deserialize, HeapSizeOf, Serialize)]
|
||||||
pub struct GradientDisplayItem {
|
pub struct Gradient {
|
||||||
/// Fields common to all display items.
|
|
||||||
pub base: BaseDisplayItem,
|
|
||||||
|
|
||||||
/// The start point of the gradient (computed during display list construction).
|
/// The start point of the gradient (computed during display list construction).
|
||||||
pub start_point: Point2D<Au>,
|
pub start_point: Point2D<Au>,
|
||||||
|
|
||||||
|
@ -899,6 +896,15 @@ pub struct GradientDisplayItem {
|
||||||
pub stops: Vec<GradientStop>,
|
pub stops: Vec<GradientStop>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Deserialize, HeapSizeOf, Serialize)]
|
||||||
|
pub struct GradientDisplayItem {
|
||||||
|
/// Fields common to all display item.
|
||||||
|
pub base: BaseDisplayItem,
|
||||||
|
|
||||||
|
/// Contains all gradient data. Included start, end point and color stops.
|
||||||
|
pub gradient: Gradient,
|
||||||
|
}
|
||||||
|
|
||||||
/// A normal border, supporting CSS border styles.
|
/// A normal border, supporting CSS border styles.
|
||||||
#[derive(Clone, HeapSizeOf, Deserialize, Serialize)]
|
#[derive(Clone, HeapSizeOf, Deserialize, Serialize)]
|
||||||
pub struct NormalBorder {
|
pub struct NormalBorder {
|
||||||
|
@ -938,11 +944,22 @@ pub struct ImageBorder {
|
||||||
pub repeat_vertical: webrender_traits::RepeatMode,
|
pub repeat_vertical: webrender_traits::RepeatMode,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A border that is made of linear gradient
|
||||||
|
#[derive(Clone, HeapSizeOf, Deserialize, Serialize)]
|
||||||
|
pub struct GradientBorder {
|
||||||
|
/// The gradient info that this border uses, border-image-source.
|
||||||
|
pub gradient: Gradient,
|
||||||
|
|
||||||
|
/// Outsets for the border, as per border-image-outset.
|
||||||
|
pub outset: SideOffsets2D<f32>,
|
||||||
|
}
|
||||||
|
|
||||||
/// Specifies the type of border
|
/// Specifies the type of border
|
||||||
#[derive(Clone, HeapSizeOf, Deserialize, Serialize)]
|
#[derive(Clone, HeapSizeOf, Deserialize, Serialize)]
|
||||||
pub enum BorderDetails {
|
pub enum BorderDetails {
|
||||||
Normal(NormalBorder),
|
Normal(NormalBorder),
|
||||||
Image(ImageBorder),
|
Image(ImageBorder),
|
||||||
|
Gradient(GradientBorder),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Paints a border.
|
/// Paints a border.
|
||||||
|
|
|
@ -20,6 +20,7 @@ use flow::{BaseFlow, Flow, IS_ABSOLUTELY_POSITIONED};
|
||||||
use flow_ref::FlowRef;
|
use flow_ref::FlowRef;
|
||||||
use fragment::{CoordinateSystem, Fragment, ImageFragmentInfo, ScannedTextFragmentInfo};
|
use fragment::{CoordinateSystem, Fragment, ImageFragmentInfo, ScannedTextFragmentInfo};
|
||||||
use fragment::{SpecificFragmentInfo, TruncatedFragmentInfo};
|
use fragment::{SpecificFragmentInfo, TruncatedFragmentInfo};
|
||||||
|
use gfx::display_list;
|
||||||
use gfx::display_list::{BLUR_INFLATION_FACTOR, BaseDisplayItem, BorderDetails};
|
use gfx::display_list::{BLUR_INFLATION_FACTOR, BaseDisplayItem, BorderDetails};
|
||||||
use gfx::display_list::{BorderDisplayItem, ImageBorder, NormalBorder};
|
use gfx::display_list::{BorderDisplayItem, ImageBorder, NormalBorder};
|
||||||
use gfx::display_list::{BorderRadii, BoxShadowClipMode, BoxShadowDisplayItem, ClippingRegion};
|
use gfx::display_list::{BorderRadii, BoxShadowClipMode, BoxShadowDisplayItem, ClippingRegion};
|
||||||
|
@ -381,6 +382,12 @@ pub trait FragmentDisplayListBuilding {
|
||||||
image_url: &ServoUrl,
|
image_url: &ServoUrl,
|
||||||
background_index: usize);
|
background_index: usize);
|
||||||
|
|
||||||
|
fn convert_gradient(&self,
|
||||||
|
absolute_bounds: &Rect<Au>,
|
||||||
|
gradient: &Gradient,
|
||||||
|
style: &ServoComputedValues)
|
||||||
|
-> Option<display_list::Gradient>;
|
||||||
|
|
||||||
/// Adds the display items necessary to paint the background linear gradient of this fragment
|
/// Adds the display items necessary to paint the background linear gradient of this fragment
|
||||||
/// to the appropriate section of the display list.
|
/// to the appropriate section of the display list.
|
||||||
fn build_display_list_for_background_gradient(&self,
|
fn build_display_list_for_background_gradient(&self,
|
||||||
|
@ -855,20 +862,13 @@ impl FragmentDisplayListBuilding for Fragment {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_display_list_for_background_gradient(&self,
|
fn convert_gradient(&self,
|
||||||
state: &mut DisplayListBuildState,
|
absolute_bounds: &Rect<Au>,
|
||||||
display_list_section: DisplayListSection,
|
gradient: &Gradient,
|
||||||
absolute_bounds: &Rect<Au>,
|
style: &ServoComputedValues) -> Option<display_list::Gradient> {
|
||||||
clip: &ClippingRegion,
|
|
||||||
gradient: &Gradient,
|
|
||||||
style: &ServoComputedValues) {
|
|
||||||
let mut clip = clip.clone();
|
|
||||||
clip.intersect_rect(absolute_bounds);
|
|
||||||
|
|
||||||
|
|
||||||
// FIXME: Repeating gradients aren't implemented yet.
|
// FIXME: Repeating gradients aren't implemented yet.
|
||||||
if gradient.repeating {
|
if gradient.repeating {
|
||||||
return;
|
return None;
|
||||||
}
|
}
|
||||||
let angle = if let GradientKind::Linear(angle_or_corner) = gradient.gradient_kind {
|
let angle = if let GradientKind::Linear(angle_or_corner) = gradient.gradient_kind {
|
||||||
match angle_or_corner {
|
match angle_or_corner {
|
||||||
|
@ -893,7 +893,7 @@ impl FragmentDisplayListBuilding for Fragment {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// FIXME: Radial gradients aren't implemented yet.
|
// FIXME: Radial gradients aren't implemented yet.
|
||||||
return;
|
return None;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Get correct gradient line length, based on:
|
// Get correct gradient line length, based on:
|
||||||
|
@ -977,19 +977,39 @@ impl FragmentDisplayListBuilding for Fragment {
|
||||||
let center = Point2D::new(absolute_bounds.origin.x + absolute_bounds.size.width / 2,
|
let center = Point2D::new(absolute_bounds.origin.x + absolute_bounds.size.width / 2,
|
||||||
absolute_bounds.origin.y + absolute_bounds.size.height / 2);
|
absolute_bounds.origin.y + absolute_bounds.size.height / 2);
|
||||||
|
|
||||||
let base = state.create_base_display_item(absolute_bounds,
|
Some(display_list::Gradient {
|
||||||
&clip,
|
|
||||||
self.node,
|
|
||||||
style.get_cursor(Cursor::Default),
|
|
||||||
display_list_section);
|
|
||||||
let gradient_display_item = DisplayItem::Gradient(box GradientDisplayItem {
|
|
||||||
base: base,
|
|
||||||
start_point: center - delta,
|
start_point: center - delta,
|
||||||
end_point: center + delta,
|
end_point: center + delta,
|
||||||
stops: stops,
|
stops: stops,
|
||||||
});
|
})
|
||||||
|
}
|
||||||
|
|
||||||
state.add_display_item(gradient_display_item);
|
fn build_display_list_for_background_gradient(&self,
|
||||||
|
state: &mut DisplayListBuildState,
|
||||||
|
display_list_section: DisplayListSection,
|
||||||
|
absolute_bounds: &Rect<Au>,
|
||||||
|
clip: &ClippingRegion,
|
||||||
|
gradient: &Gradient,
|
||||||
|
style: &ServoComputedValues) {
|
||||||
|
let mut clip = clip.clone();
|
||||||
|
clip.intersect_rect(absolute_bounds);
|
||||||
|
|
||||||
|
let grad = self.convert_gradient(absolute_bounds, gradient, style);
|
||||||
|
|
||||||
|
if let Some(x) = grad {
|
||||||
|
let base = state.create_base_display_item(absolute_bounds,
|
||||||
|
&clip,
|
||||||
|
self.node,
|
||||||
|
style.get_cursor(Cursor::Default),
|
||||||
|
display_list_section);
|
||||||
|
|
||||||
|
let gradient_display_item = DisplayItem::Gradient(box GradientDisplayItem {
|
||||||
|
base: base,
|
||||||
|
gradient: x,
|
||||||
|
});
|
||||||
|
|
||||||
|
state.add_display_item(gradient_display_item);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_display_list_for_box_shadow_if_applicable(&self,
|
fn build_display_list_for_box_shadow_if_applicable(&self,
|
||||||
|
@ -1100,8 +1120,28 @@ impl FragmentDisplayListBuilding for Fragment {
|
||||||
}),
|
}),
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
Some(computed::Image::Gradient(..)) => {
|
Some(computed::Image::Gradient(ref gradient)) => {
|
||||||
// TODO(gw): Handle border-image with gradient.
|
match gradient.gradient_kind {
|
||||||
|
GradientKind::Linear(_) => {
|
||||||
|
let grad = self.convert_gradient(&bounds, gradient, style);
|
||||||
|
|
||||||
|
if let Some(x) = grad {
|
||||||
|
state.add_display_item(DisplayItem::Border(box BorderDisplayItem {
|
||||||
|
base: base,
|
||||||
|
border_widths: border.to_physical(style.writing_mode),
|
||||||
|
details: BorderDetails::Gradient(display_list::GradientBorder {
|
||||||
|
gradient: x,
|
||||||
|
|
||||||
|
// TODO(gw): Support border-image-outset
|
||||||
|
outset: SideOffsets2D::zero(),
|
||||||
|
}),
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
GradientKind::Radial(_, _) => {
|
||||||
|
// TODO(gw): Handle border-image with radial gradient.
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Some(computed::Image::Url(ref image_url)) => {
|
Some(computed::Image::Url(ref image_url)) => {
|
||||||
if let Some(url) = image_url.url() {
|
if let Some(url) = image_url.url() {
|
||||||
|
|
|
@ -334,20 +334,30 @@ impl WebRenderDisplayItemConverter for DisplayItem {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
BorderDetails::Gradient(ref gradient) => {
|
||||||
|
webrender_traits::BorderDetails::Gradient(webrender_traits::GradientBorder {
|
||||||
|
gradient: builder.create_gradient(
|
||||||
|
gradient.gradient.start_point.to_pointf(),
|
||||||
|
gradient.gradient.end_point.to_pointf(),
|
||||||
|
gradient.gradient.stops.clone(),
|
||||||
|
ExtendMode::Clamp),
|
||||||
|
outset: gradient.outset,
|
||||||
|
})
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
builder.push_border(rect, clip, widths, details);
|
builder.push_border(rect, clip, widths, details);
|
||||||
}
|
}
|
||||||
DisplayItem::Gradient(ref item) => {
|
DisplayItem::Gradient(ref item) => {
|
||||||
let rect = item.base.bounds.to_rectf();
|
let rect = item.base.bounds.to_rectf();
|
||||||
let start_point = item.start_point.to_pointf();
|
let start_point = item.gradient.start_point.to_pointf();
|
||||||
let end_point = item.end_point.to_pointf();
|
let end_point = item.gradient.end_point.to_pointf();
|
||||||
let clip = item.base.clip.to_clip_region(builder);
|
let clip = item.base.clip.to_clip_region(builder);
|
||||||
builder.push_gradient(rect,
|
builder.push_gradient(rect,
|
||||||
clip,
|
clip,
|
||||||
start_point,
|
start_point,
|
||||||
end_point,
|
end_point,
|
||||||
item.stops.clone(),
|
item.gradient.stops.clone(),
|
||||||
ExtendMode::Clamp);
|
ExtendMode::Clamp);
|
||||||
}
|
}
|
||||||
DisplayItem::Line(..) => {
|
DisplayItem::Line(..) => {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue