mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-16 14:55:47 +00:00
servo: Merge #17199 - Make shadow values share more code (from upsuper:shadow); r=Manishearth
<!-- Please describe your changes on the following line: --> Make `text-shadow` reuse `Shadow` type directly. --- <!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: --> - [x] `./mach build -d` does not report any errors - [x] `./mach test-tidy` does not report any errors - [ ] These changes fix #__ (github issue number if applicable). <!-- Either: --> - [ ] There are tests for these changes OR - [x] These changes do not require tests because refactor <!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.--> <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> Source-Repo: https://github.com/servo/servo Source-Revision: 2df8f69bcf8917a8300c24f920f7677f1f40ae11 --HG-- extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear extra : subtree_revision : 21e0ed70168cc66ca125486a2adaa956f529fe57
This commit is contained in:
parent
24a19f81e0
commit
a5d4fe0775
@ -51,7 +51,6 @@ use style::computed_values::{background_attachment, background_clip, background_
|
||||
use style::computed_values::{background_repeat, border_style, cursor};
|
||||
use style::computed_values::{image_rendering, overflow_x, pointer_events, position, visibility};
|
||||
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;
|
||||
@ -59,7 +58,7 @@ use style::properties::style_structs;
|
||||
use style::servo::restyle_damage::REPAINT;
|
||||
use style::values::{Either, RGBA};
|
||||
use style::values::computed::{Gradient, GradientItem, LengthOrPercentage};
|
||||
use style::values::computed::{LengthOrPercentageOrAuto, NumberOrPercentage, Position};
|
||||
use style::values::computed::{LengthOrPercentageOrAuto, NumberOrPercentage, Position, Shadow};
|
||||
use style::values::computed::image::{EndingShape, LineDirection};
|
||||
use style::values::generics::background::BackgroundSize;
|
||||
use style::values::generics::image::{Circle, Ellipse, EndingShape as GenericEndingShape};
|
||||
@ -504,7 +503,7 @@ pub trait FragmentDisplayListBuilding {
|
||||
state: &mut DisplayListBuildState,
|
||||
text_fragment: &ScannedTextFragmentInfo,
|
||||
stacking_relative_content_box: &Rect<Au>,
|
||||
text_shadow: Option<&TextShadow>,
|
||||
text_shadow: Option<&Shadow>,
|
||||
clip: &Rect<Au>);
|
||||
|
||||
/// Creates the display item for a text decoration: underline, overline, or line-through.
|
||||
@ -1949,7 +1948,7 @@ impl FragmentDisplayListBuilding for Fragment {
|
||||
state: &mut DisplayListBuildState,
|
||||
text_fragment: &ScannedTextFragmentInfo,
|
||||
stacking_relative_content_box: &Rect<Au>,
|
||||
text_shadow: Option<&TextShadow>,
|
||||
text_shadow: Option<&Shadow>,
|
||||
clip: &Rect<Au>) {
|
||||
// TODO(emilio): Allow changing more properties by ::selection
|
||||
let text_color = if let Some(shadow) = text_shadow {
|
||||
|
@ -7,6 +7,7 @@
|
||||
mod ns_com_ptr;
|
||||
mod ns_compatibility;
|
||||
mod ns_css_shadow_array;
|
||||
mod ns_css_shadow_item;
|
||||
pub mod ns_css_value;
|
||||
mod ns_style_auto_array;
|
||||
pub mod ns_style_coord;
|
||||
|
@ -0,0 +1,43 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
//! Rust helpers for Gecko's `nsCSSShadowItem`.
|
||||
|
||||
use app_units::Au;
|
||||
use cssparser::Color;
|
||||
use gecko::values::{convert_rgba_to_nscolor, convert_nscolor_to_rgba};
|
||||
use gecko_bindings::structs::nsCSSShadowItem;
|
||||
use values::computed::Shadow;
|
||||
|
||||
impl nsCSSShadowItem {
|
||||
/// Set this item to the given shadow value.
|
||||
pub fn set_from_shadow(&mut self, other: Shadow) {
|
||||
self.mXOffset = other.offset_x.0;
|
||||
self.mYOffset = other.offset_y.0;
|
||||
self.mRadius = other.blur_radius.0;
|
||||
self.mSpread = other.spread_radius.0;
|
||||
self.mInset = other.inset;
|
||||
self.mColor = match other.color {
|
||||
Color::RGBA(rgba) => {
|
||||
self.mHasColor = true;
|
||||
convert_rgba_to_nscolor(&rgba)
|
||||
},
|
||||
// TODO handle currentColor
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=760345
|
||||
Color::CurrentColor => 0,
|
||||
}
|
||||
}
|
||||
|
||||
/// Generate shadow value from this shadow item.
|
||||
pub fn to_shadow(&self) -> Shadow {
|
||||
Shadow {
|
||||
offset_x: Au(self.mXOffset),
|
||||
offset_y: Au(self.mYOffset),
|
||||
blur_radius: Au(self.mRadius),
|
||||
spread_radius: Au(self.mSpread),
|
||||
inset: self.mInset,
|
||||
color: Color::RGBA(convert_nscolor_to_rgba(self.mColor)),
|
||||
}
|
||||
}
|
||||
}
|
@ -64,7 +64,7 @@ use std::mem::{forget, transmute, zeroed};
|
||||
use std::ptr;
|
||||
use stylearc::Arc;
|
||||
use std::cmp;
|
||||
use values::computed::ToComputedValue;
|
||||
use values::computed::{Shadow, ToComputedValue};
|
||||
use values::{Either, Auto, KeyframesName};
|
||||
use computed_values::border_style;
|
||||
|
||||
@ -3310,31 +3310,13 @@ fn static_assert() {
|
||||
<%self:impl_trait style_struct_name="Effects"
|
||||
skip_longhands="box-shadow clip filter">
|
||||
pub fn set_box_shadow<I>(&mut self, v: I)
|
||||
where I: IntoIterator<Item = longhands::box_shadow::computed_value::single_value::T>,
|
||||
where I: IntoIterator<Item = Shadow>,
|
||||
I::IntoIter: ExactSizeIterator
|
||||
{
|
||||
let v = v.into_iter();
|
||||
|
||||
self.gecko.mBoxShadow.replace_with_new(v.len() as u32);
|
||||
|
||||
for (servo, gecko_shadow) in v.zip(self.gecko.mBoxShadow.iter_mut()) {
|
||||
|
||||
gecko_shadow.mXOffset = servo.offset_x.0;
|
||||
gecko_shadow.mYOffset = servo.offset_y.0;
|
||||
gecko_shadow.mRadius = servo.blur_radius.0;
|
||||
gecko_shadow.mSpread = servo.spread_radius.0;
|
||||
gecko_shadow.mSpread = servo.spread_radius.0;
|
||||
gecko_shadow.mInset = servo.inset;
|
||||
gecko_shadow.mColor = match servo.color {
|
||||
Color::RGBA(rgba) => {
|
||||
gecko_shadow.mHasColor = true;
|
||||
convert_rgba_to_nscolor(&rgba)
|
||||
},
|
||||
// TODO handle currentColor
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=760345
|
||||
Color::CurrentColor => 0,
|
||||
}
|
||||
|
||||
gecko_shadow.set_from_shadow(servo);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3343,16 +3325,7 @@ fn static_assert() {
|
||||
}
|
||||
|
||||
pub fn clone_box_shadow(&self) -> longhands::box_shadow::computed_value::T {
|
||||
let buf = self.gecko.mBoxShadow.iter().map(|shadow| {
|
||||
longhands::box_shadow::single_value::computed_value::T {
|
||||
offset_x: Au(shadow.mXOffset),
|
||||
offset_y: Au(shadow.mYOffset),
|
||||
blur_radius: Au(shadow.mRadius),
|
||||
spread_radius: Au(shadow.mSpread),
|
||||
inset: shadow.mInset,
|
||||
color: Color::RGBA(convert_nscolor_to_rgba(shadow.mColor)),
|
||||
}
|
||||
}).collect();
|
||||
let buf = self.gecko.mBoxShadow.iter().map(|v| v.to_shadow()).collect();
|
||||
longhands::box_shadow::computed_value::T(buf)
|
||||
}
|
||||
|
||||
@ -3524,21 +3497,7 @@ fn static_assert() {
|
||||
}
|
||||
|
||||
let mut gecko_shadow = init_shadow(gecko_filter);
|
||||
gecko_shadow.mArray[0].mXOffset = shadow.offset_x.0;
|
||||
gecko_shadow.mArray[0].mYOffset = shadow.offset_y.0;
|
||||
gecko_shadow.mArray[0].mRadius = shadow.blur_radius.0;
|
||||
// mSpread is not supported in the spec, so we leave it as 0
|
||||
gecko_shadow.mArray[0].mInset = false; // Not supported in spec level 1
|
||||
|
||||
gecko_shadow.mArray[0].mColor = match shadow.color {
|
||||
Color::RGBA(rgba) => {
|
||||
gecko_shadow.mArray[0].mHasColor = true;
|
||||
convert_rgba_to_nscolor(&rgba)
|
||||
},
|
||||
// TODO handle currentColor
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=760345
|
||||
Color::CurrentColor => 0,
|
||||
};
|
||||
gecko_shadow.mArray[0].set_from_shadow(shadow);
|
||||
}
|
||||
Url(ref url) => {
|
||||
unsafe {
|
||||
@ -3617,26 +3576,14 @@ fn static_assert() {
|
||||
${impl_keyword('text_align', 'mTextAlign', text_align_keyword, need_clone=False)}
|
||||
${impl_keyword_clone('text_align', 'mTextAlign', text_align_keyword)}
|
||||
|
||||
pub fn set_text_shadow(&mut self, v: longhands::text_shadow::computed_value::T) {
|
||||
self.gecko.mTextShadow.replace_with_new(v.0.len() as u32);
|
||||
|
||||
for (servo, gecko_shadow) in v.0.into_iter()
|
||||
.zip(self.gecko.mTextShadow.iter_mut()) {
|
||||
|
||||
gecko_shadow.mXOffset = servo.offset_x.0;
|
||||
gecko_shadow.mYOffset = servo.offset_y.0;
|
||||
gecko_shadow.mRadius = servo.blur_radius.0;
|
||||
gecko_shadow.mHasColor = false;
|
||||
gecko_shadow.mColor = match servo.color {
|
||||
Color::RGBA(rgba) => {
|
||||
gecko_shadow.mHasColor = true;
|
||||
convert_rgba_to_nscolor(&rgba)
|
||||
},
|
||||
// TODO handle currentColor
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=760345
|
||||
Color::CurrentColor => 0,
|
||||
}
|
||||
|
||||
pub fn set_text_shadow<I>(&mut self, v: I)
|
||||
where I: IntoIterator<Item = Shadow>,
|
||||
I::IntoIter: ExactSizeIterator
|
||||
{
|
||||
let v = v.into_iter();
|
||||
self.gecko.mTextShadow.replace_with_new(v.len() as u32);
|
||||
for (servo, gecko_shadow) in v.zip(self.gecko.mTextShadow.iter_mut()) {
|
||||
gecko_shadow.set_from_shadow(servo);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3645,16 +3592,7 @@ fn static_assert() {
|
||||
}
|
||||
|
||||
pub fn clone_text_shadow(&self) -> longhands::text_shadow::computed_value::T {
|
||||
|
||||
let buf = self.gecko.mTextShadow.iter().map(|shadow| {
|
||||
longhands::text_shadow::computed_value::TextShadow {
|
||||
offset_x: Au(shadow.mXOffset),
|
||||
offset_y: Au(shadow.mYOffset),
|
||||
blur_radius: Au(shadow.mRadius),
|
||||
color: Color::RGBA(convert_nscolor_to_rgba(shadow.mColor)),
|
||||
}
|
||||
|
||||
}).collect();
|
||||
let buf = self.gecko.mTextShadow.iter().map(|v| v.to_shadow()).collect();
|
||||
longhands::text_shadow::computed_value::T(buf)
|
||||
}
|
||||
|
||||
|
@ -19,9 +19,7 @@ use properties::longhands::background_size::computed_value::T as BackgroundSizeL
|
||||
use properties::longhands::font_weight::computed_value::T as FontWeight;
|
||||
use properties::longhands::font_stretch::computed_value::T as FontStretch;
|
||||
use properties::longhands::text_shadow::computed_value::T as TextShadowList;
|
||||
use properties::longhands::text_shadow::computed_value::TextShadow;
|
||||
use properties::longhands::box_shadow::computed_value::T as BoxShadowList;
|
||||
use properties::longhands::box_shadow::single_value::computed_value::T as BoxShadow;
|
||||
use properties::longhands::transform::computed_value::ComputedMatrix;
|
||||
use properties::longhands::transform::computed_value::ComputedOperation as TransformOperation;
|
||||
use properties::longhands::transform::computed_value::T as TransformList;
|
||||
@ -40,7 +38,7 @@ use values::{Auto, Either};
|
||||
use values::computed::{Angle, LengthOrPercentageOrAuto, LengthOrPercentageOrNone};
|
||||
use values::computed::{BorderCornerRadius, ClipRect};
|
||||
use values::computed::{CalcLengthOrPercentage, Context, ComputedValueAsSpecified};
|
||||
use values::computed::{LengthOrPercentage, MaxLength, MozLength, ToComputedValue};
|
||||
use values::computed::{LengthOrPercentage, MaxLength, MozLength, Shadow, ToComputedValue};
|
||||
use values::generics::{SVGPaint, SVGPaintKind};
|
||||
use values::generics::border::BorderCornerRadius as GenericBorderCornerRadius;
|
||||
use values::generics::position as generic_position;
|
||||
@ -1457,132 +1455,6 @@ impl Animatable for ClipRect {
|
||||
}
|
||||
}
|
||||
|
||||
<%def name="impl_animatable_for_shadow(item, transparent_color)">
|
||||
impl Animatable for ${item} {
|
||||
#[inline]
|
||||
fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
|
||||
% if "Box" in item:
|
||||
// It can't be interpolated if inset does not match.
|
||||
if self.inset != other.inset {
|
||||
return Err(());
|
||||
}
|
||||
% endif
|
||||
|
||||
let x = try!(self.offset_x.add_weighted(&other.offset_x, self_portion, other_portion));
|
||||
let y = try!(self.offset_y.add_weighted(&other.offset_y, self_portion, other_portion));
|
||||
let color = try!(self.color.add_weighted(&other.color, self_portion, other_portion));
|
||||
let blur = try!(self.blur_radius.add_weighted(&other.blur_radius,
|
||||
self_portion, other_portion));
|
||||
% if "Box" in item:
|
||||
let spread = try!(self.spread_radius.add_weighted(&other.spread_radius,
|
||||
self_portion, other_portion));
|
||||
% endif
|
||||
|
||||
Ok(${item} {
|
||||
offset_x: x,
|
||||
offset_y: y,
|
||||
blur_radius: blur,
|
||||
color: color,
|
||||
% if "Box" in item:
|
||||
spread_radius: spread,
|
||||
inset: self.inset,
|
||||
% endif
|
||||
})
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
|
||||
self.compute_squared_distance(other).map(|sd| sd.sqrt())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn compute_squared_distance(&self, other: &Self) -> Result<f64, ()> {
|
||||
% if "Box" in item:
|
||||
if self.inset != other.inset {
|
||||
return Err(());
|
||||
}
|
||||
% endif
|
||||
let list = [ try!(self.offset_x.compute_distance(&other.offset_x)),
|
||||
try!(self.offset_y.compute_distance(&other.offset_y)),
|
||||
try!(self.blur_radius.compute_distance(&other.blur_radius)),
|
||||
try!(self.color.compute_distance(&other.color)),
|
||||
% if "Box" in item:
|
||||
try!(self.spread_radius.compute_distance(&other.spread_radius)),
|
||||
% endif
|
||||
];
|
||||
Ok(list.iter().fold(0.0f64, |sum, diff| sum + diff * diff))
|
||||
}
|
||||
}
|
||||
|
||||
/// https://drafts.csswg.org/css-transitions/#animtype-shadow-list
|
||||
impl Animatable for ${item}List {
|
||||
#[inline]
|
||||
fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
|
||||
// The inset value must change
|
||||
% if "Box" in item:
|
||||
let mut zero = ${item} {
|
||||
% else:
|
||||
let zero = ${item} {
|
||||
% endif
|
||||
offset_x: Au(0),
|
||||
offset_y: Au(0),
|
||||
blur_radius: Au(0),
|
||||
color: ${transparent_color},
|
||||
% if "Box" in item:
|
||||
spread_radius: Au(0),
|
||||
inset: false,
|
||||
% endif
|
||||
};
|
||||
|
||||
let max_len = cmp::max(self.0.len(), other.0.len());
|
||||
|
||||
let mut result = if max_len > 1 {
|
||||
SmallVec::from_vec(Vec::with_capacity(max_len))
|
||||
} else {
|
||||
SmallVec::new()
|
||||
};
|
||||
|
||||
for i in 0..max_len {
|
||||
let shadow = match (self.0.get(i), other.0.get(i)) {
|
||||
(Some(shadow), Some(other))
|
||||
=> try!(shadow.add_weighted(other, self_portion, other_portion)),
|
||||
(Some(shadow), None) => {
|
||||
% if "Box" in item:
|
||||
zero.inset = shadow.inset;
|
||||
% endif
|
||||
shadow.add_weighted(&zero, self_portion, other_portion).unwrap()
|
||||
}
|
||||
(None, Some(shadow)) => {
|
||||
% if "Box" in item:
|
||||
zero.inset = shadow.inset;
|
||||
% endif
|
||||
zero.add_weighted(&shadow, self_portion, other_portion).unwrap()
|
||||
}
|
||||
(None, None) => unreachable!(),
|
||||
};
|
||||
result.push(shadow);
|
||||
}
|
||||
|
||||
Ok(${item}List(result))
|
||||
}
|
||||
|
||||
fn add(&self, other: &Self) -> Result<Self, ()> {
|
||||
let len = self.0.len() + other.0.len();
|
||||
|
||||
let mut result = if len > 1 {
|
||||
SmallVec::from_vec(Vec::with_capacity(len))
|
||||
} else {
|
||||
SmallVec::new()
|
||||
};
|
||||
|
||||
result.extend(self.0.iter().cloned());
|
||||
result.extend(other.0.iter().cloned());
|
||||
|
||||
Ok(${item}List(result))
|
||||
}
|
||||
}
|
||||
</%def>
|
||||
|
||||
/// Check if it's possible to do a direct numerical interpolation
|
||||
/// between these two transform lists.
|
||||
/// http://dev.w3.org/csswg/css-transforms/#transform-transform-animation
|
||||
@ -2922,74 +2794,183 @@ impl Animatable for IntermediateSVGPaintKind {
|
||||
}
|
||||
}
|
||||
|
||||
<%def name="impl_intermediate_type_for_shadow(type)">
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
#[allow(missing_docs)]
|
||||
/// Intermediate type for box-shadow and text-shadow.
|
||||
/// The difference between normal shadow type is that this type uses
|
||||
/// IntermediateColor instead of ParserColor.
|
||||
pub struct Intermediate${type}Shadow {
|
||||
pub offset_x: Au,
|
||||
pub offset_y: Au,
|
||||
pub blur_radius: Au,
|
||||
pub color: IntermediateColor,
|
||||
% if type == "Box":
|
||||
pub spread_radius: Au,
|
||||
pub inset: bool,
|
||||
% endif
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
#[allow(missing_docs)]
|
||||
/// Intermediate type for box-shadow and text-shadow.
|
||||
/// The difference between normal shadow type is that this type uses
|
||||
/// IntermediateColor instead of ParserColor.
|
||||
pub struct IntermediateShadow {
|
||||
pub offset_x: Au,
|
||||
pub offset_y: Au,
|
||||
pub blur_radius: Au,
|
||||
pub spread_radius: Au,
|
||||
pub color: IntermediateColor,
|
||||
pub inset: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
#[allow(missing_docs)]
|
||||
/// Intermediate type for box-shadow list and text-shadow list.
|
||||
pub struct IntermediateShadowList(pub SmallVec<[IntermediateShadow; 1]>);
|
||||
|
||||
type ShadowList = SmallVec<[Shadow; 1]>;
|
||||
|
||||
impl From<IntermediateShadowList> for ShadowList {
|
||||
fn from(shadow_list: IntermediateShadowList) -> Self {
|
||||
shadow_list.0.into_iter().map(|s| s.into()).collect()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
#[allow(missing_docs)]
|
||||
/// Intermediate type for box-shadow list and text-shadow list.
|
||||
pub struct Intermediate${type}ShadowList(pub SmallVec<[Intermediate${type}Shadow; 1]>);
|
||||
impl From<ShadowList> for IntermediateShadowList {
|
||||
fn from(shadow_list: ShadowList) -> IntermediateShadowList {
|
||||
IntermediateShadowList(shadow_list.into_iter().map(|s| s.into()).collect())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Intermediate${type}ShadowList> for ${type}ShadowList {
|
||||
fn from(shadow_list: Intermediate${type}ShadowList) -> ${type}ShadowList {
|
||||
${type}ShadowList(shadow_list.0.into_iter().map(|s| s.into()).collect())
|
||||
% for ty in "Box Text".split():
|
||||
impl From<IntermediateShadowList> for ${ty}ShadowList {
|
||||
#[inline]
|
||||
fn from(shadow_list: IntermediateShadowList) -> Self {
|
||||
${ty}ShadowList(shadow_list.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<${ty}ShadowList> for IntermediateShadowList {
|
||||
#[inline]
|
||||
fn from(shadow_list: ${ty}ShadowList) -> IntermediateShadowList {
|
||||
shadow_list.0.into()
|
||||
}
|
||||
}
|
||||
% endfor
|
||||
|
||||
impl From<IntermediateShadow> for Shadow {
|
||||
fn from(shadow: IntermediateShadow) -> Shadow {
|
||||
Shadow {
|
||||
offset_x: shadow.offset_x,
|
||||
offset_y: shadow.offset_y,
|
||||
blur_radius: shadow.blur_radius,
|
||||
spread_radius: shadow.spread_radius,
|
||||
color: shadow.color.into(),
|
||||
inset: shadow.inset,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<${type}ShadowList> for Intermediate${type}ShadowList {
|
||||
fn from(shadow_list: ${type}ShadowList) -> Intermediate${type}ShadowList {
|
||||
Intermediate${type}ShadowList(shadow_list.0.into_iter().map(|s| s.into()).collect())
|
||||
impl From<Shadow> for IntermediateShadow {
|
||||
fn from(shadow: Shadow) -> IntermediateShadow {
|
||||
IntermediateShadow {
|
||||
offset_x: shadow.offset_x,
|
||||
offset_y: shadow.offset_y,
|
||||
blur_radius: shadow.blur_radius,
|
||||
spread_radius: shadow.spread_radius,
|
||||
color: shadow.color.into(),
|
||||
inset: shadow.inset,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Intermediate${type}Shadow> for ${type}Shadow {
|
||||
fn from(shadow: Intermediate${type}Shadow) -> ${type}Shadow {
|
||||
${type}Shadow {
|
||||
offset_x: shadow.offset_x,
|
||||
offset_y: shadow.offset_y,
|
||||
blur_radius: shadow.blur_radius,
|
||||
color: shadow.color.into(),
|
||||
% if type == "Box":
|
||||
spread_radius: shadow.spread_radius,
|
||||
inset: shadow.inset,
|
||||
% endif
|
||||
}
|
||||
impl Animatable for IntermediateShadow {
|
||||
#[inline]
|
||||
fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
|
||||
// It can't be interpolated if inset does not match.
|
||||
if self.inset != other.inset {
|
||||
return Err(());
|
||||
}
|
||||
|
||||
let x = try!(self.offset_x.add_weighted(&other.offset_x, self_portion, other_portion));
|
||||
let y = try!(self.offset_y.add_weighted(&other.offset_y, self_portion, other_portion));
|
||||
let color = try!(self.color.add_weighted(&other.color, self_portion, other_portion));
|
||||
let blur = try!(self.blur_radius.add_weighted(&other.blur_radius,
|
||||
self_portion, other_portion));
|
||||
let spread = try!(self.spread_radius.add_weighted(&other.spread_radius,
|
||||
self_portion, other_portion));
|
||||
|
||||
Ok(IntermediateShadow {
|
||||
offset_x: x,
|
||||
offset_y: y,
|
||||
blur_radius: blur,
|
||||
spread_radius: spread,
|
||||
color: color,
|
||||
inset: self.inset,
|
||||
})
|
||||
}
|
||||
|
||||
impl From<${type}Shadow> for Intermediate${type}Shadow {
|
||||
fn from(shadow: ${type}Shadow) -> Intermediate${type}Shadow {
|
||||
Intermediate${type}Shadow {
|
||||
offset_x: shadow.offset_x,
|
||||
offset_y: shadow.offset_y,
|
||||
blur_radius: shadow.blur_radius,
|
||||
color: shadow.color.into(),
|
||||
% if type == "Box":
|
||||
spread_radius: shadow.spread_radius,
|
||||
inset: shadow.inset,
|
||||
% endif
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
|
||||
self.compute_squared_distance(other).map(|sd| sd.sqrt())
|
||||
}
|
||||
${impl_animatable_for_shadow('Intermediate%sShadow' % type,
|
||||
'IntermediateColor::IntermediateRGBA(IntermediateRGBA::transparent())')}
|
||||
</%def>
|
||||
|
||||
${impl_intermediate_type_for_shadow('Box')}
|
||||
${impl_intermediate_type_for_shadow('Text')}
|
||||
#[inline]
|
||||
fn compute_squared_distance(&self, other: &Self) -> Result<f64, ()> {
|
||||
if self.inset != other.inset {
|
||||
return Err(());
|
||||
}
|
||||
let list = [ try!(self.offset_x.compute_distance(&other.offset_x)),
|
||||
try!(self.offset_y.compute_distance(&other.offset_y)),
|
||||
try!(self.blur_radius.compute_distance(&other.blur_radius)),
|
||||
try!(self.color.compute_distance(&other.color)),
|
||||
try!(self.spread_radius.compute_distance(&other.spread_radius)),
|
||||
];
|
||||
Ok(list.iter().fold(0.0f64, |sum, diff| sum + diff * diff))
|
||||
}
|
||||
}
|
||||
|
||||
/// https://drafts.csswg.org/css-transitions/#animtype-shadow-list
|
||||
impl Animatable for IntermediateShadowList {
|
||||
#[inline]
|
||||
fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
|
||||
// The inset value must change
|
||||
let mut zero = IntermediateShadow {
|
||||
offset_x: Au(0),
|
||||
offset_y: Au(0),
|
||||
blur_radius: Au(0),
|
||||
spread_radius: Au(0),
|
||||
color: IntermediateColor::IntermediateRGBA(IntermediateRGBA::transparent()),
|
||||
inset: false,
|
||||
};
|
||||
|
||||
let max_len = cmp::max(self.0.len(), other.0.len());
|
||||
|
||||
let mut result = if max_len > 1 {
|
||||
SmallVec::from_vec(Vec::with_capacity(max_len))
|
||||
} else {
|
||||
SmallVec::new()
|
||||
};
|
||||
|
||||
for i in 0..max_len {
|
||||
let shadow = match (self.0.get(i), other.0.get(i)) {
|
||||
(Some(shadow), Some(other)) =>
|
||||
try!(shadow.add_weighted(other, self_portion, other_portion)),
|
||||
(Some(shadow), None) => {
|
||||
zero.inset = shadow.inset;
|
||||
shadow.add_weighted(&zero, self_portion, other_portion).unwrap()
|
||||
}
|
||||
(None, Some(shadow)) => {
|
||||
zero.inset = shadow.inset;
|
||||
zero.add_weighted(&shadow, self_portion, other_portion).unwrap()
|
||||
}
|
||||
(None, None) => unreachable!(),
|
||||
};
|
||||
result.push(shadow);
|
||||
}
|
||||
|
||||
Ok(IntermediateShadowList(result))
|
||||
}
|
||||
|
||||
fn add(&self, other: &Self) -> Result<Self, ()> {
|
||||
let len = self.0.len() + other.0.len();
|
||||
|
||||
let mut result = if len > 1 {
|
||||
SmallVec::from_vec(Vec::with_capacity(len))
|
||||
} else {
|
||||
SmallVec::new()
|
||||
};
|
||||
|
||||
result.extend(self.0.iter().cloned());
|
||||
result.extend(other.0.iter().cloned());
|
||||
|
||||
Ok(IntermediateShadowList(result))
|
||||
}
|
||||
}
|
||||
|
@ -15,60 +15,18 @@ ${helpers.predefined_type("opacity",
|
||||
spec="https://drafts.csswg.org/css-color/#opacity")}
|
||||
|
||||
<%helpers:vector_longhand name="box-shadow" allow_empty="True"
|
||||
animation_value_type="IntermediateBoxShadowList"
|
||||
animation_value_type="IntermediateShadowList"
|
||||
extra_prefixes="webkit"
|
||||
ignored_when_colors_disabled="True"
|
||||
spec="https://drafts.csswg.org/css-backgrounds/#box-shadow">
|
||||
use std::fmt;
|
||||
use style_traits::ToCss;
|
||||
|
||||
pub type SpecifiedValue = specified::Shadow;
|
||||
|
||||
impl ToCss for SpecifiedValue {
|
||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||
if self.inset {
|
||||
try!(dest.write_str("inset "));
|
||||
}
|
||||
try!(self.offset_x.to_css(dest));
|
||||
try!(dest.write_str(" "));
|
||||
try!(self.offset_y.to_css(dest));
|
||||
try!(dest.write_str(" "));
|
||||
try!(self.blur_radius.to_css(dest));
|
||||
try!(dest.write_str(" "));
|
||||
try!(self.spread_radius.to_css(dest));
|
||||
|
||||
if let Some(ref color) = self.color {
|
||||
try!(dest.write_str(" "));
|
||||
try!(color.to_css(dest));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub mod computed_value {
|
||||
use values::computed::Shadow;
|
||||
|
||||
pub type T = Shadow;
|
||||
}
|
||||
|
||||
impl ToCss for computed_value::T {
|
||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||
if self.inset {
|
||||
try!(dest.write_str("inset "));
|
||||
}
|
||||
try!(self.blur_radius.to_css(dest));
|
||||
try!(dest.write_str(" "));
|
||||
try!(self.spread_radius.to_css(dest));
|
||||
try!(dest.write_str(" "));
|
||||
try!(self.offset_x.to_css(dest));
|
||||
try!(dest.write_str(" "));
|
||||
try!(self.offset_y.to_css(dest));
|
||||
try!(dest.write_str(" "));
|
||||
try!(self.color.to_css(dest));
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<specified::Shadow, ()> {
|
||||
specified::Shadow::parse(context, input, false)
|
||||
}
|
||||
@ -252,15 +210,9 @@ ${helpers.predefined_type("clip",
|
||||
computed_value::Filter::Sepia(value) => try!(write!(dest, "sepia({})", value)),
|
||||
% if product == "gecko":
|
||||
computed_value::Filter::DropShadow(shadow) => {
|
||||
try!(dest.write_str("drop-shadow("));
|
||||
try!(shadow.offset_x.to_css(dest));
|
||||
try!(dest.write_str(" "));
|
||||
try!(shadow.offset_y.to_css(dest));
|
||||
try!(dest.write_str(" "));
|
||||
try!(shadow.blur_radius.to_css(dest));
|
||||
try!(dest.write_str(" "));
|
||||
try!(shadow.color.to_css(dest));
|
||||
try!(dest.write_str(")"));
|
||||
dest.write_str("drop-shadow(")?;
|
||||
shadow.to_css(dest)?;
|
||||
dest.write_str(")")?;
|
||||
}
|
||||
computed_value::Filter::Url(ref url) => {
|
||||
url.to_css(dest)?;
|
||||
@ -293,17 +245,9 @@ ${helpers.predefined_type("clip",
|
||||
SpecifiedFilter::Sepia(value) => try!(write!(dest, "sepia({})", value)),
|
||||
% if product == "gecko":
|
||||
SpecifiedFilter::DropShadow(ref shadow) => {
|
||||
try!(dest.write_str("drop-shadow("));
|
||||
try!(shadow.offset_x.to_css(dest));
|
||||
try!(dest.write_str(" "));
|
||||
try!(shadow.offset_y.to_css(dest));
|
||||
try!(dest.write_str(" "));
|
||||
try!(shadow.blur_radius.to_css(dest));
|
||||
if let Some(ref color) = shadow.color {
|
||||
try!(dest.write_str(" "));
|
||||
try!(color.to_css(dest));
|
||||
}
|
||||
try!(dest.write_str(")"));
|
||||
dest.write_str("drop-shadow(")?;
|
||||
shadow.to_css(dest)?;
|
||||
dest.write_str(")")?;
|
||||
}
|
||||
SpecifiedFilter::Url(ref url) => {
|
||||
url.to_css(dest)?;
|
||||
|
@ -401,149 +401,20 @@ ${helpers.predefined_type("word-spacing",
|
||||
% endif
|
||||
</%helpers:single_keyword_computed>
|
||||
|
||||
<%helpers:longhand name="text-shadow"
|
||||
animation_value_type="IntermediateTextShadowList",
|
||||
ignored_when_colors_disabled="True",
|
||||
spec="https://drafts.csswg.org/css-text-decor/#propdef-text-shadow">
|
||||
use cssparser;
|
||||
use std::fmt;
|
||||
use style_traits::ToCss;
|
||||
use values::specified::Shadow;
|
||||
|
||||
#[derive(Clone, Debug, HasViewportPercentage, PartialEq)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
pub struct SpecifiedValue(Vec<SpecifiedTextShadow>);
|
||||
|
||||
#[derive(Clone, Debug, HasViewportPercentage, PartialEq)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
pub struct SpecifiedTextShadow {
|
||||
pub offset_x: specified::Length,
|
||||
pub offset_y: specified::Length,
|
||||
pub blur_radius: specified::Length,
|
||||
pub color: Option<specified::CSSColor>,
|
||||
}
|
||||
|
||||
impl From<Shadow> for SpecifiedTextShadow {
|
||||
fn from(shadow: Shadow) -> SpecifiedTextShadow {
|
||||
SpecifiedTextShadow {
|
||||
offset_x: shadow.offset_x,
|
||||
offset_y: shadow.offset_y,
|
||||
blur_radius: shadow.blur_radius,
|
||||
color: shadow.color,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
<%helpers:vector_longhand name="text-shadow" allow_empty="True"
|
||||
animation_value_type="IntermediateShadowList"
|
||||
ignored_when_colors_disabled="True"
|
||||
spec="https://drafts.csswg.org/css-backgrounds/#box-shadow">
|
||||
pub type SpecifiedValue = specified::Shadow;
|
||||
pub mod computed_value {
|
||||
use app_units::Au;
|
||||
use cssparser::Color;
|
||||
use smallvec::SmallVec;
|
||||
|
||||
#[derive(Clone, PartialEq, Debug)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
pub struct T(pub SmallVec<[TextShadow; 1]>);
|
||||
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
#[derive(Clone, PartialEq, Debug, ToCss)]
|
||||
pub struct TextShadow {
|
||||
pub offset_x: Au,
|
||||
pub offset_y: Au,
|
||||
pub blur_radius: Au,
|
||||
pub color: Color,
|
||||
}
|
||||
use values::computed::Shadow;
|
||||
pub type T = Shadow;
|
||||
}
|
||||
|
||||
impl ToCss for computed_value::T {
|
||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||
let mut iter = self.0.iter();
|
||||
match iter.next() {
|
||||
Some(shadow) => shadow.to_css(dest)?,
|
||||
None => return dest.write_str("none"),
|
||||
}
|
||||
for shadow in iter {
|
||||
dest.write_str(", ")?;
|
||||
shadow.to_css(dest)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<specified::Shadow, ()> {
|
||||
specified::Shadow::parse(context, input, true)
|
||||
}
|
||||
|
||||
impl ToCss for SpecifiedValue {
|
||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||
let mut iter = self.0.iter();
|
||||
match iter.next() {
|
||||
Some(shadow) => shadow.to_css(dest)?,
|
||||
None => return dest.write_str("none"),
|
||||
}
|
||||
for shadow in iter {
|
||||
dest.write_str(", ")?;
|
||||
shadow.to_css(dest)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl ToCss for SpecifiedTextShadow {
|
||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||
self.offset_x.to_css(dest)?;
|
||||
dest.write_str(" ")?;
|
||||
self.offset_y.to_css(dest)?;
|
||||
dest.write_str(" ")?;
|
||||
self.blur_radius.to_css(dest)?;
|
||||
|
||||
if let Some(ref color) = self.color {
|
||||
dest.write_str(" ")?;
|
||||
color.to_css(dest)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_initial_value() -> computed_value::T {
|
||||
use smallvec::SmallVec;
|
||||
computed_value::T(SmallVec::new())
|
||||
}
|
||||
|
||||
pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue,()> {
|
||||
if input.try(|input| input.expect_ident_matching("none")).is_ok() {
|
||||
Ok(SpecifiedValue(Vec::new()))
|
||||
} else {
|
||||
input.parse_comma_separated(|i| {
|
||||
Ok(SpecifiedTextShadow::from(Shadow::parse(context, i, true)?))
|
||||
}).map(SpecifiedValue)
|
||||
}
|
||||
}
|
||||
|
||||
impl ToComputedValue for SpecifiedValue {
|
||||
type ComputedValue = computed_value::T;
|
||||
|
||||
fn to_computed_value(&self, context: &Context) -> computed_value::T {
|
||||
computed_value::T(self.0.iter().map(|value| {
|
||||
computed_value::TextShadow {
|
||||
offset_x: value.offset_x.to_computed_value(context),
|
||||
offset_y: value.offset_y.to_computed_value(context),
|
||||
blur_radius: value.blur_radius.to_computed_value(context),
|
||||
color: value.color
|
||||
.as_ref()
|
||||
.map(|color| color.to_computed_value(context))
|
||||
.unwrap_or(cssparser::Color::CurrentColor),
|
||||
}
|
||||
}).collect())
|
||||
}
|
||||
|
||||
fn from_computed_value(computed: &computed_value::T) -> Self {
|
||||
SpecifiedValue(computed.0.iter().map(|value| {
|
||||
SpecifiedTextShadow {
|
||||
offset_x: ToComputedValue::from_computed_value(&value.offset_x),
|
||||
offset_y: ToComputedValue::from_computed_value(&value.offset_y),
|
||||
blur_radius: ToComputedValue::from_computed_value(&value.blur_radius),
|
||||
color: Some(ToComputedValue::from_computed_value(&value.color)),
|
||||
}
|
||||
}).collect())
|
||||
}
|
||||
}
|
||||
</%helpers:longhand>
|
||||
</%helpers:vector_longhand>
|
||||
|
||||
<%helpers:longhand name="text-emphasis-style" products="gecko" need_clone="True" boxed="True"
|
||||
animation_value_type="none"
|
||||
|
@ -9,6 +9,7 @@ use context::QuirksMode;
|
||||
use euclid::size::Size2D;
|
||||
use font_metrics::FontMetricsProvider;
|
||||
use media_queries::Device;
|
||||
use num_traits::Zero;
|
||||
#[cfg(feature = "gecko")]
|
||||
use properties;
|
||||
use properties::{ComputedValues, StyleBuilder};
|
||||
@ -483,6 +484,26 @@ pub struct Shadow {
|
||||
pub inset: bool,
|
||||
}
|
||||
|
||||
impl ToCss for Shadow {
|
||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||
if self.inset {
|
||||
dest.write_str("inset ")?;
|
||||
}
|
||||
self.offset_x.to_css(dest)?;
|
||||
dest.write_str(" ")?;
|
||||
self.offset_y.to_css(dest)?;
|
||||
dest.write_str(" ")?;
|
||||
self.blur_radius.to_css(dest)?;
|
||||
dest.write_str(" ")?;
|
||||
if self.spread_radius != Au::zero() {
|
||||
self.spread_radius.to_css(dest)?;
|
||||
dest.write_str(" ")?;
|
||||
}
|
||||
self.color.to_css(dest)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// A `<number>` value.
|
||||
pub type Number = CSSFloat;
|
||||
|
||||
|
@ -878,6 +878,28 @@ impl ToComputedValue for Shadow {
|
||||
}
|
||||
}
|
||||
|
||||
impl ToCss for Shadow {
|
||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||
if self.inset {
|
||||
dest.write_str("inset ")?;
|
||||
}
|
||||
self.offset_x.to_css(dest)?;
|
||||
dest.write_str(" ")?;
|
||||
self.offset_y.to_css(dest)?;
|
||||
dest.write_str(" ")?;
|
||||
self.blur_radius.to_css(dest)?;
|
||||
if self.spread_radius != Length::zero() {
|
||||
dest.write_str(" ")?;
|
||||
self.spread_radius.to_css(dest)?;
|
||||
}
|
||||
if let Some(ref color) = self.color {
|
||||
dest.write_str(" ")?;
|
||||
color.to_css(dest)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Shadow {
|
||||
// disable_spread_and_inset is for filter: drop-shadow(...)
|
||||
#[allow(missing_docs)]
|
||||
|
Loading…
Reference in New Issue
Block a user