Skip to content
Permalink
Browse files

Box gradients and rects in Image. r=xidorn

Gradients and rects are rare, and large.  Image is much smaller with them boxed.

This is part of of the fix for Gecko bug 1397614
<https://bugzilla.mozilla.org/show_bug.cgi?id=1397614>
  • Loading branch information
bzbarsky committed Sep 9, 2017
1 parent 91b748e commit 26b39241f9f5d6c6756b33be3cea9ac9bc0204ae
@@ -151,8 +151,8 @@ impl nsStyleImage {
/// Set a given Servo `Image` value into this `nsStyleImage`.
pub fn set(&mut self, image: Image) {
match image {
GenericImage::Gradient(gradient) => {
self.set_gradient(gradient)
GenericImage::Gradient(boxed_gradient) => {
self.set_gradient(*boxed_gradient)
},
GenericImage::Url(ref url) => {
unsafe {
@@ -399,7 +399,7 @@ impl nsStyleImage {
NumberOrPercentage::from_gecko_style_coord(&rect.data_at(2)),
NumberOrPercentage::from_gecko_style_coord(&rect.data_at(3))) {
(Some(top), Some(right), Some(bottom), Some(left)) =>
Some(GenericImage::Rect(MozImageRect { url, top, right, bottom, left } )),
Some(GenericImage::Rect(Box::new(MozImageRect { url, top, right, bottom, left } ))),
_ => {
debug_assert!(false, "mCropRect could not convert to NumberOrPercentage");
None
@@ -428,7 +428,7 @@ impl nsStyleImage {
url
}

unsafe fn get_gradient(self: &nsStyleImage) -> Gradient {
unsafe fn get_gradient(self: &nsStyleImage) -> Box<Gradient> {
use gecko::values::convert_nscolor_to_rgba;
use gecko_bindings::bindings::Gecko_GetGradientImageValue;
use gecko_bindings::structs::{NS_STYLE_GRADIENT_SHAPE_CIRCULAR, NS_STYLE_GRADIENT_SHAPE_ELLIPTICAL};
@@ -581,7 +581,7 @@ impl nsStyleImage {
CompatMode::Modern
};

Gradient { items, repeating: gecko_gradient.mRepeating, kind, compat_mode }
Box::new(Gradient { items, repeating: gecko_gradient.mRepeating, kind, compat_mode })
}
}

@@ -11,20 +11,21 @@ use cssparser::serialize_identifier;
use custom_properties::SpecifiedValue;
use std::fmt;
use style_traits::ToCss;
use values::computed::ComputedValueAsSpecified;
use values::computed::{ComputedValueAsSpecified, Context, ToComputedValue};

/// An [image].
///
/// [image]: https://drafts.csswg.org/css-images/#image-values
#[derive(Clone, PartialEq, ToComputedValue)]
#[derive(Clone, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub enum Image<Gradient, MozImageRect, ImageUrl> {
/// A `<url()>` image.
Url(ImageUrl),
/// A `<gradient>` image.
Gradient(Gradient),
/// A `-moz-image-rect` image
Rect(MozImageRect),
/// A `<gradient>` image. Gradients are rather large, and not nearly as
/// common as urls, so we box them here to keep the size of this enum sane.
Gradient(Box<Gradient>),
/// A `-moz-image-rect` image. Also fairly large and rare.
Rect(Box<MozImageRect>),
/// A `-moz-element(# <element-id>)`
Element(Atom),
/// A paint worklet image.
@@ -33,6 +34,47 @@ pub enum Image<Gradient, MozImageRect, ImageUrl> {
PaintWorklet(PaintWorklet),
}

// Can't just use derive(ToComputedValue) on Image, because when trying to do
// "impl<T> ToComputedValue for Box<T>" the Rust compiler complains that
// "impl<T> ToComputedValue for T where T: ComputedValueAsSpecified + Clone"
// aleady implements ToComputedValue for std::boxed::Box<_> and hence we have
// conflicting implementations.
impl<Gradient: ToComputedValue,
MozImageRect: ToComputedValue,
ImageUrl: ToComputedValue> ToComputedValue for Image<Gradient, MozImageRect, ImageUrl> {
type ComputedValue = Image<<Gradient as ToComputedValue>::ComputedValue,
<MozImageRect as ToComputedValue>::ComputedValue,
<ImageUrl as ToComputedValue>::ComputedValue>;

#[inline]
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
match *self {
Image::Url(ref url) => Image::Url(url.to_computed_value(context)),
Image::Gradient(ref gradient) =>
Image::Gradient(Box::new(gradient.to_computed_value(context))),
Image::Rect(ref rect) => Image::Rect(Box::new(rect.to_computed_value(context))),
Image::Element(ref atom) => Image::Element(atom.to_computed_value(context)),
#[cfg(feature = "servo")]
Image::PaintWorklet(ref worklet) => Image::PaintWorklet(worklet.to_computed_value(context)),
}
}

#[inline]
fn from_computed_value(computed: &Self::ComputedValue) -> Self {
match *computed {
Image::Url(ref url) => Image::Url(ImageUrl::from_computed_value(url)),
Image::Gradient(ref boxed_gradient) =>
Image::Gradient(Box::new(Gradient::from_computed_value(&*boxed_gradient))),
Image::Rect(ref boxed_rect) =>
Image::Rect(Box::new(MozImageRect::from_computed_value(&*boxed_rect))),
Image::Element(ref atom) => Image::Element(Atom::from_computed_value(atom)),
#[cfg(feature = "servo")]
Image::PaintWorklet(ref worklet) =>
Image::PaintWorklet(PaintWorklet::from_computed_value(worklet)),
}
}
}

/// A CSS gradient.
/// https://drafts.csswg.org/css-images/#gradients
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
@@ -138,7 +138,7 @@ impl Parse for Image {
return Ok(GenericImage::Url(url));
}
if let Ok(gradient) = input.try(|i| Gradient::parse(context, i)) {
return Ok(GenericImage::Gradient(gradient));
return Ok(GenericImage::Gradient(Box::new(gradient)));
}
#[cfg(feature = "servo")]
{
@@ -151,7 +151,7 @@ impl Parse for Image {
{
image_rect.url.build_image_value();
}
return Ok(GenericImage::Rect(image_rect));
return Ok(GenericImage::Rect(Box::new(image_rect)));
}
Ok(GenericImage::Element(Image::parse_element(input)?))
}
@@ -11,6 +11,8 @@ use style::data::{ElementData, ElementStyles, RestyleData};
use style::gecko::selector_parser as real;
use style::properties::ComputedValues;
use style::rule_tree::{RuleNode, StrongRuleNode};
use style::values::computed;
use style::values::specified;

#[test]
fn size_of_selectors_dummy_types() {
@@ -47,3 +49,11 @@ size_of_test!(test_size_of_rule_node, RuleNode, 80);
// This is huge, but we allocate it on the stack and then never move it,
// we only pass `&mut SourcePropertyDeclaration` references around.
size_of_test!(test_size_of_parsed_declaration, style::properties::SourcePropertyDeclaration, 704);

size_of_test!(test_size_of_computed_image, computed::image::Image, 40);
size_of_test!(test_size_of_specified_image, specified::image::Image, 40);

// FIXME(bz): These can shrink if we move the None_ value inside the
// enum instead of paying an extra word for the Either discriminant.
size_of_test!(test_size_of_computed_image_layer, computed::image::ImageLayer, 48);
size_of_test!(test_size_of_specified_image_layer, specified::image::ImageLayer, 48);

0 comments on commit 26b3924

Please sign in to comment.
You can’t perform that action at this time.