From abf8ced0bf0f79a2fe45aa07a446a438cb103638 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Fri, 27 May 2016 00:25:40 +0200 Subject: [PATCH] stylo: Support linear-gradients as background-image --- components/style/values.rs | 1 + ports/geckolib/gecko_bindings/bindings.rs | 28 ++++ .../gecko_bindings/tools/regen_bindings.sh | 5 +- ports/geckolib/properties.mako.rs | 133 +++++++++++++++++- ports/geckolib/values.rs | 21 +++ 5 files changed, 183 insertions(+), 5 deletions(-) diff --git a/components/style/values.rs b/components/style/values.rs index 8ec5ca5f2ca..a6c73977d44 100644 --- a/components/style/values.rs +++ b/components/style/values.rs @@ -1179,6 +1179,7 @@ pub mod specified { } impl Angle { + #[inline] pub fn radians(self) -> f32 { let Angle(radians) = self; radians diff --git a/ports/geckolib/gecko_bindings/bindings.rs b/ports/geckolib/gecko_bindings/bindings.rs index b5019e16d03..608d22fc63d 100644 --- a/ports/geckolib/gecko_bindings/bindings.rs +++ b/ports/geckolib/gecko_bindings/bindings.rs @@ -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: diff --git a/ports/geckolib/gecko_bindings/tools/regen_bindings.sh b/ports/geckolib/gecko_bindings/tools/regen_bindings.sh index 13678732f26..6af8acb7370 100755 --- a/ports/geckolib/gecko_bindings/tools/regen_bindings.sh +++ b/ports/geckolib/gecko_bindings/tools/regen_bindings.sh @@ -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;' " diff --git a/ports/geckolib/properties.mako.rs b/ports/geckolib/properties.mako.rs index d1497324474..4f35a52f0e5 100644 --- a/ports/geckolib/properties.mako.rs +++ b/ports/geckolib/properties.mako.rs @@ -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 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 style_struct_name="List" skip_longhands="list-style-type" skip_additionals="*"> diff --git a/ports/geckolib/values.rs b/ports/geckolib/values.rs index 3f0ab125d3b..978453aa707 100644 --- a/ports/geckolib/values.rs +++ b/ports/geckolib/values.rs @@ -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 ToGeckoStyleCoord for Option { + 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) |