stylo: Support linear-gradients as background-image

This commit is contained in:
Emilio Cobos Álvarez 2016-05-27 00:25:40 +02:00
parent 8caa17a466
commit abf8ced0bf
No known key found for this signature in database
GPG key ID: 056B727BB9C1027C
5 changed files with 183 additions and 5 deletions

View file

@ -1179,6 +1179,7 @@ pub mod specified {
}
impl Angle {
#[inline]
pub fn radians(self) -> f32 {
let Angle(radians) = self;
radians

View file

@ -24,9 +24,14 @@ use structs::nsStyleXUL;
use structs::nsStyleSVGReset;
use structs::nsStyleColumn;
use structs::nsStyleEffects;
use structs::nsStyleImage;
use structs::nsStyleGradient;
use structs::nsStyleCoord;
use structs::nsStyleGradientStop;
use structs::SheetParsingMode;
use structs::nsMainThreadPtrHandle;
use structs::nsMainThreadPtrHolder;
use structs::nscolor;
use heapsize::HeapSizeOf;
unsafe impl Send for nsStyleFont {}
unsafe impl Sync for nsStyleFont {}
@ -100,6 +105,18 @@ impl HeapSizeOf for nsStyleColumn { fn heap_size_of_children(&self) -> usize { 0
unsafe impl Send for nsStyleEffects {}
unsafe impl Sync for nsStyleEffects {}
impl HeapSizeOf for nsStyleEffects { fn heap_size_of_children(&self) -> usize { 0 } }
unsafe impl Send for nsStyleImage {}
unsafe impl Sync for nsStyleImage {}
impl HeapSizeOf for nsStyleImage { fn heap_size_of_children(&self) -> usize { 0 } }
unsafe impl Send for nsStyleGradient {}
unsafe impl Sync for nsStyleGradient {}
impl HeapSizeOf for nsStyleGradient { fn heap_size_of_children(&self) -> usize { 0 } }
unsafe impl Send for nsStyleCoord {}
unsafe impl Sync for nsStyleCoord {}
impl HeapSizeOf for nsStyleCoord { fn heap_size_of_children(&self) -> usize { 0 } }
unsafe impl Send for nsStyleGradientStop {}
unsafe impl Sync for nsStyleGradientStop {}
impl HeapSizeOf for nsStyleGradientStop { fn heap_size_of_children(&self) -> usize { 0 } }
pub enum nsIAtom { }
pub enum nsINode { }
@ -171,6 +188,17 @@ extern "C" {
pub fn Gecko_SetListStyleType(style_struct: *mut nsStyleList, type_: u32);
pub fn Gecko_CopyListStyleTypeFrom(dst: *mut nsStyleList,
src: *const nsStyleList);
pub fn Gecko_SetNullImageValue(image: *mut nsStyleImage);
pub fn Gecko_SetGradientImageValue(image: *mut nsStyleImage,
gradient: *mut nsStyleGradient);
pub fn Gecko_CopyImageValueFrom(image: *mut nsStyleImage,
other: *const nsStyleImage);
pub fn Gecko_CreateGradient(shape: u8, size: u8, repeating: bool,
legacy_syntax: bool, stops: u32)
-> *mut nsStyleGradient;
pub fn Gecko_SetGradientStop(gradient: *mut nsStyleGradient, index: u32,
location: *const nsStyleCoord,
color: nscolor, is_interpolation_hint: bool);
pub fn Gecko_AddRefPrincipalArbitraryThread(aPtr:
*mut ThreadSafePrincipalHolder);
pub fn Gecko_ReleasePrincipalArbitraryThread(aPtr:

View file

@ -40,7 +40,8 @@ for STRUCT in nsStyleFont nsStyleColor nsStyleList nsStyleText \
nsStyleSVG nsStyleVariables nsStyleBackground nsStylePosition \
nsStyleTextReset nsStyleDisplay nsStyleContent nsStyleUIReset \
nsStyleTable nsStyleMargin nsStylePadding nsStyleBorder \
nsStyleOutline nsStyleXUL nsStyleSVGReset nsStyleColumn nsStyleEffects
nsStyleOutline nsStyleXUL nsStyleSVGReset nsStyleColumn nsStyleEffects \
nsStyleImage nsStyleGradient nsStyleCoord nsStyleGradientStop
do
MAP_GECKO_TYPES=$MAP_GECKO_TYPES"-blacklist-type $STRUCT "
MAP_GECKO_TYPES=$MAP_GECKO_TYPES"-raw-line 'use structs::$STRUCT;' "
@ -50,7 +51,7 @@ do
done
# Other mapped types.
for TYPE in SheetParsingMode nsMainThreadPtrHandle nsMainThreadPtrHolder
for TYPE in SheetParsingMode nsMainThreadPtrHandle nsMainThreadPtrHolder nscolor
do
MAP_GECKO_TYPES=$MAP_GECKO_TYPES"-blacklist-type $TYPE "
MAP_GECKO_TYPES=$MAP_GECKO_TYPES"-raw-line 'use structs::$TYPE;' "

View file

@ -18,11 +18,15 @@ use gecko_bindings::bindings::Gecko_Destroy_${style_struct.gecko_ffi_name};
% endfor
use gecko_bindings::bindings::{Gecko_CopyMozBindingFrom, Gecko_CopyListStyleTypeFrom};
use gecko_bindings::bindings::{Gecko_SetMozBinding, Gecko_SetListStyleType};
use gecko_bindings::bindings::{Gecko_SetNullImageValue, Gecko_SetGradientImageValue};
use gecko_bindings::bindings::{Gecko_CreateGradient};
use gecko_bindings::bindings::{Gecko_SetGradientStop, Gecko_CopyImageValueFrom};
use gecko_bindings::structs;
use glue::ArcHelpers;
use std::fmt::{self, Debug};
use std::mem::{transmute, zeroed};
use std::mem::{transmute, uninitialized, zeroed};
use std::sync::Arc;
use std::cmp;
use style::custom_properties::ComputedValuesMap;
use style::logical_geometry::WritingMode;
use style::properties::{CascadePropertyFn, ServoComputedValues, ComputedValues};
@ -379,7 +383,7 @@ impl Debug for ${style_struct.gecko_struct_name} {
# These are currently being shuffled to a different style struct on the gecko side.
force_stub += ["backface-visibility", "transform-box", "transform-style"]
# These live in nsStyleImageLayers in gecko. Need to figure out what to do about that.
force_stub += ["background-repeat", "background-attachment", "background-clip", "background-origin"];
force_stub += ["background-attachment", "background-clip", "background-origin"];
# These live in an nsFont member in Gecko. Should be straightforward to do manually.
force_stub += ["font-kerning", "font-stretch", "font-variant"]
# These have unusual representations in gecko.
@ -486,6 +490,7 @@ fn static_assert() {
% endfor
}
<% border_style_keyword = Keyword("border-style",
"none solid double dotted dashed hidden groove ridge inset outset") %>
@ -702,10 +707,132 @@ fn static_assert() {
}
</%self:impl_trait>
<%self:impl_trait style_struct_name="Background" skip_longhands="background-color" skip_additionals="*">
<%self:impl_trait style_struct_name="Background"
skip_longhands="background-color background-repeat background-image"
skip_additionals="*">
<% impl_color("background_color", "mBackgroundColor") %>
fn copy_background_repeat_from(&mut self, other: &Self) {
self.gecko.mImage.mRepeatCount = other.gecko.mImage.mRepeatCount;
self.gecko.mImage.mLayers.mFirstElement.mRepeat =
other.gecko.mImage.mLayers.mFirstElement.mRepeat;
}
fn set_background_repeat(&mut self, v: longhands::background_repeat::computed_value::T) {
use style::properties::longhands::background_repeat::computed_value::T as Computed;
use gecko_bindings::structs::{NS_STYLE_IMAGELAYER_REPEAT_REPEAT, NS_STYLE_IMAGELAYER_REPEAT_NO_REPEAT};
use gecko_bindings::structs::nsStyleImageLayers_Repeat;
let (repeat_x, repeat_y) = match v {
Computed::repeat_x => (NS_STYLE_IMAGELAYER_REPEAT_REPEAT,
NS_STYLE_IMAGELAYER_REPEAT_NO_REPEAT),
Computed::repeat_y => (NS_STYLE_IMAGELAYER_REPEAT_NO_REPEAT,
NS_STYLE_IMAGELAYER_REPEAT_REPEAT),
Computed::repeat => (NS_STYLE_IMAGELAYER_REPEAT_REPEAT,
NS_STYLE_IMAGELAYER_REPEAT_REPEAT),
Computed::no_repeat => (NS_STYLE_IMAGELAYER_REPEAT_NO_REPEAT,
NS_STYLE_IMAGELAYER_REPEAT_NO_REPEAT),
};
self.gecko.mImage.mRepeatCount = 1;
self.gecko.mImage.mLayers.mFirstElement.mRepeat = nsStyleImageLayers_Repeat {
mXRepeat: repeat_x as u8,
mYRepeat: repeat_y as u8,
};
}
fn copy_background_image_from(&mut self, other: &Self) {
unsafe {
Gecko_CopyImageValueFrom(&mut self.gecko.mImage.mLayers.mFirstElement.mImage,
&other.gecko.mImage.mLayers.mFirstElement.mImage);
}
}
fn set_background_image(&mut self, image: longhands::background_image::computed_value::T) {
use gecko_bindings::structs::{NS_STYLE_GRADIENT_SHAPE_LINEAR, NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER};
use gecko_bindings::structs::nsStyleCoord;
use style::values::computed::Image;
use style::values::specified::AngleOrCorner;
use cssparser::Color as CSSColor;
unsafe {
// Prevent leaking of the last element we did set
Gecko_SetNullImageValue(&mut self.gecko.mImage.mLayers.mFirstElement.mImage);
}
self.gecko.mImage.mImageCount = cmp::max(1, self.gecko.mImage.mImageCount);
if let Some(image) = image.0 {
match image {
Image::LinearGradient(ref gradient) => {
let stop_count = gradient.stops.len();
if stop_count >= ::std::u32::MAX as usize {
warn!("stylo: Prevented overflow due to too many gradient stops");
return;
}
let gecko_gradient = unsafe {
Gecko_CreateGradient(NS_STYLE_GRADIENT_SHAPE_LINEAR as u8,
NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER as u8,
/* repeating = */ false,
/* legacy_syntax = */ false,
stop_count as u32)
};
if gecko_gradient.is_null() {
warn!("stylo: Couldn't allocate gradient");
return;
}
if let AngleOrCorner::Angle(angle) = gradient.angle_or_corner {
unsafe {
(*gecko_gradient).mAngle.set(angle);
}
}
let mut coord: nsStyleCoord = unsafe { uninitialized() };
for (index, stop) in gradient.stops.iter().enumerate() {
// NB: stops are guaranteed to be none in the gecko side by
// default.
coord.set(stop.position);
let color = match stop.color {
CSSColor::CurrentColor => {
// TODO(emilio): gecko just stores an nscolor,
// and it doesn't seem to support currentColor
// as value in a gradient.
//
// Double-check it and either remove
// currentColor for servo or see how gecko
// handles this.
0
},
CSSColor::RGBA(ref rgba) => convert_rgba_to_nscolor(rgba),
};
unsafe {
Gecko_SetGradientStop(gecko_gradient,
index as u32,
&coord,
color,
/* interpolation_hint = */ false);
}
}
unsafe {
Gecko_SetGradientImageValue(&mut self.gecko.mImage.mLayers.mFirstElement.mImage,
gecko_gradient);
}
},
Image::Url(_) => {
// let utf8_bytes = url.as_bytes();
// Gecko_SetUrlImageValue(&mut self.gecko.mImage.mLayers.mFirstElement,
// utf8_bytes.as_ptr() as *const _,
// utf8_bytes.len());
warn!("stylo: imgRequestProxies are not threadsafe in gecko, \
background-image: url() not yet implemented");
}
}
}
}
</%self:impl_trait>
<%self:impl_trait style_struct_name="List" skip_longhands="list-style-type" skip_additionals="*">

View file

@ -6,6 +6,7 @@ use app_units::Au;
use cssparser::RGBA;
use gecko_bindings::structs::{nsStyleCoord, nsStyleUnion, nsStyleUnit};
use std::cmp::max;
use style::values::computed::Angle;
use style::values::computed::{LengthOrPercentage, LengthOrPercentageOrAuto, LengthOrPercentageOrNone};
pub trait StyleCoordHelpers {
@ -128,6 +129,26 @@ impl ToGeckoStyleCoord for LengthOrPercentageOrNone {
}
}
impl<T: ToGeckoStyleCoord> ToGeckoStyleCoord for Option<T> {
fn to_gecko_style_coord(&self, unit: &mut nsStyleUnit, union: &mut nsStyleUnion) {
if let Some(ref me) = *self {
me.to_gecko_style_coord(unit, union);
} else {
*unit = nsStyleUnit::eStyleUnit_None;
unsafe { *union.mInt.as_mut() = 0; }
}
}
}
impl ToGeckoStyleCoord for Angle {
fn to_gecko_style_coord(&self,
unit: &mut nsStyleUnit,
union: &mut nsStyleUnion) {
*unit = nsStyleUnit::eStyleUnit_Radian;
unsafe { *union.mFloat.as_mut() = self.radians() };
}
}
pub fn convert_rgba_to_nscolor(rgba: &RGBA) -> u32 {
(((rgba.alpha * 255.0).round() as u32) << 24) |
(((rgba.blue * 255.0).round() as u32) << 16) |