mirror of
https://github.com/servo/servo.git
synced 2025-08-05 21:50:18 +01:00
style: Experiment with implementing zoom as a transform + transform-origin shorthand.
This is a gross hack, of course, but has the advantage of not breaking sites that use both zoom and -moz-transform / -moz-transform-origin. There should be no behavior change when the pref is off, of course, and the webcompat team wanted to experiment with this. Differential Revision: https://phabricator.services.mozilla.com/D49792
This commit is contained in:
parent
ca05003ef6
commit
854c480177
7 changed files with 136 additions and 24 deletions
|
@ -13,7 +13,6 @@
|
||||||
# "offset"
|
# "offset"
|
||||||
COUNTED_UNKNOWN_PROPERTIES = [
|
COUNTED_UNKNOWN_PROPERTIES = [
|
||||||
"-webkit-font-smoothing",
|
"-webkit-font-smoothing",
|
||||||
"zoom",
|
|
||||||
"-webkit-tap-highlight-color",
|
"-webkit-tap-highlight-color",
|
||||||
"speak",
|
"speak",
|
||||||
"text-size-adjust",
|
"text-size-adjust",
|
||||||
|
|
|
@ -1876,7 +1876,16 @@ impl PropertyId {
|
||||||
if let Some(id) = static_id(property_name) {
|
if let Some(id) = static_id(property_name) {
|
||||||
return Ok(match *id {
|
return Ok(match *id {
|
||||||
StaticId::Longhand(id) => PropertyId::Longhand(id),
|
StaticId::Longhand(id) => PropertyId::Longhand(id),
|
||||||
StaticId::Shorthand(id) => PropertyId::Shorthand(id),
|
StaticId::Shorthand(id) => {
|
||||||
|
// We want to count `zoom` even if disabled.
|
||||||
|
if matches!(id, ShorthandId::Zoom) {
|
||||||
|
if let Some(counters) = use_counters {
|
||||||
|
counters.non_custom_properties.record(id.into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyId::Shorthand(id)
|
||||||
|
},
|
||||||
StaticId::LonghandAlias(id, alias) => PropertyId::LonghandAlias(id, alias),
|
StaticId::LonghandAlias(id, alias) => PropertyId::LonghandAlias(id, alias),
|
||||||
StaticId::ShorthandAlias(id, alias) => PropertyId::ShorthandAlias(id, alias),
|
StaticId::ShorthandAlias(id, alias) => PropertyId::ShorthandAlias(id, alias),
|
||||||
StaticId::CountedUnknown(unknown_prop) => {
|
StaticId::CountedUnknown(unknown_prop) => {
|
||||||
|
|
|
@ -441,3 +441,58 @@ ${helpers.two_properties_shorthand(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</%helpers:shorthand>
|
</%helpers:shorthand>
|
||||||
|
|
||||||
|
<%helpers:shorthand name="zoom" engines="gecko"
|
||||||
|
sub_properties="transform transform-origin"
|
||||||
|
gecko_pref="layout.css.zoom-transform-hack.enabled"
|
||||||
|
flags="SHORTHAND_IN_GETCS IS_LEGACY_SHORTHAND"
|
||||||
|
spec="Not a standard, only a compat hack">
|
||||||
|
use crate::parser::Parse;
|
||||||
|
use crate::values::specified::{Number, NumberOrPercentage, TransformOrigin};
|
||||||
|
use crate::values::generics::transform::{Transform, TransformOperation};
|
||||||
|
|
||||||
|
pub fn parse_value<'i, 't>(
|
||||||
|
context: &ParserContext,
|
||||||
|
input: &mut Parser<'i, 't>,
|
||||||
|
) -> Result<Longhands, ParseError<'i>> {
|
||||||
|
let zoom = match input.try(|input| NumberOrPercentage::parse(context, input)) {
|
||||||
|
Ok(number_or_percent) => number_or_percent.to_number(),
|
||||||
|
Err(..) => {
|
||||||
|
input.expect_ident_matching("normal")?;
|
||||||
|
Number::new(1.0)
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Make sure that the initial value matches the values for the
|
||||||
|
// longhands, just for general sanity.
|
||||||
|
//
|
||||||
|
// FIXME: Should we just do this for the "normal" case? Seems weird
|
||||||
|
// either way, so maybe not?
|
||||||
|
Ok(if zoom.get() == 1.0 {
|
||||||
|
expanded! {
|
||||||
|
transform: Transform::none(),
|
||||||
|
transform_origin: TransformOrigin::initial_value(),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
expanded! {
|
||||||
|
transform: Transform(vec![TransformOperation::Scale(zoom, zoom)].into()),
|
||||||
|
transform_origin: TransformOrigin::zero_zero(),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> ToCss for LonghandsToSerialize<'a> {
|
||||||
|
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result where W: fmt::Write {
|
||||||
|
if self.transform.0.is_empty() && *self.transform_origin == TransformOrigin::initial_value() {
|
||||||
|
return 1.0f32.to_css(dest);
|
||||||
|
}
|
||||||
|
if *self.transform_origin != TransformOrigin::zero_zero() {
|
||||||
|
return Ok(())
|
||||||
|
}
|
||||||
|
match &*self.transform.0 {
|
||||||
|
[TransformOperation::Scale(x, y)] if x == y => x.to_css(dest),
|
||||||
|
_ => Ok(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</%helpers:shorthand>
|
||||||
|
|
|
@ -435,10 +435,7 @@ impl Gradient {
|
||||||
let (color, mut p) = i.parse_nested_block(|i| {
|
let (color, mut p) = i.parse_nested_block(|i| {
|
||||||
let p = match_ignore_ascii_case! { &function,
|
let p = match_ignore_ascii_case! { &function,
|
||||||
"color-stop" => {
|
"color-stop" => {
|
||||||
let p = match NumberOrPercentage::parse(context, i)? {
|
let p = NumberOrPercentage::parse(context, i)?.to_percentage();
|
||||||
NumberOrPercentage::Number(number) => Percentage::new(number.value),
|
|
||||||
NumberOrPercentage::Percentage(p) => p,
|
|
||||||
};
|
|
||||||
i.expect_comma()?;
|
i.expect_comma()?;
|
||||||
p
|
p
|
||||||
},
|
},
|
||||||
|
|
|
@ -178,12 +178,22 @@ impl Parse for Number {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Number {
|
impl Number {
|
||||||
|
/// Returns a new number with the value `val`.
|
||||||
|
fn new_with_clamping_mode(
|
||||||
|
value: CSSFloat,
|
||||||
|
calc_clamping_mode: Option<AllowedNumericType>,
|
||||||
|
) -> Self {
|
||||||
|
Self { value, calc_clamping_mode }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns this percentage as a number.
|
||||||
|
pub fn to_percentage(&self) -> Percentage {
|
||||||
|
Percentage::new_with_clamping_mode(self.value, self.calc_clamping_mode)
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns a new number with the value `val`.
|
/// Returns a new number with the value `val`.
|
||||||
pub fn new(val: CSSFloat) -> Self {
|
pub fn new(val: CSSFloat) -> Self {
|
||||||
Number {
|
Self::new_with_clamping_mode(val, None)
|
||||||
value: val,
|
|
||||||
calc_clamping_mode: None,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns whether this number came from a `calc()` expression.
|
/// Returns whether this number came from a `calc()` expression.
|
||||||
|
@ -370,6 +380,22 @@ impl NumberOrPercentage {
|
||||||
) -> Result<Self, ParseError<'i>> {
|
) -> Result<Self, ParseError<'i>> {
|
||||||
Self::parse_with_clamping_mode(context, input, AllowedNumericType::NonNegative)
|
Self::parse_with_clamping_mode(context, input, AllowedNumericType::NonNegative)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Convert the number or the percentage to a number.
|
||||||
|
pub fn to_percentage(self) -> Percentage {
|
||||||
|
match self {
|
||||||
|
Self::Percentage(p) => p,
|
||||||
|
Self::Number(n) => n.to_percentage(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convert the number or the percentage to a number.
|
||||||
|
pub fn to_number(self) -> Number {
|
||||||
|
match self {
|
||||||
|
Self::Percentage(p) => p.to_number(),
|
||||||
|
Self::Number(n) => n,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parse for NumberOrPercentage {
|
impl Parse for NumberOrPercentage {
|
||||||
|
@ -419,17 +445,7 @@ impl Parse for Opacity {
|
||||||
context: &ParserContext,
|
context: &ParserContext,
|
||||||
input: &mut Parser<'i, 't>,
|
input: &mut Parser<'i, 't>,
|
||||||
) -> Result<Self, ParseError<'i>> {
|
) -> Result<Self, ParseError<'i>> {
|
||||||
let number = match NumberOrPercentage::parse(context, input)? {
|
let number = NumberOrPercentage::parse(context, input)?.to_number();
|
||||||
NumberOrPercentage::Percentage(p) => Number {
|
|
||||||
value: p.get(),
|
|
||||||
calc_clamping_mode: if p.is_calc() {
|
|
||||||
Some(AllowedNumericType::All)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
},
|
|
||||||
},
|
|
||||||
NumberOrPercentage::Number(n) => n,
|
|
||||||
};
|
|
||||||
Ok(Opacity(number))
|
Ok(Opacity(number))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ use crate::parser::{Parse, ParserContext};
|
||||||
use crate::values::computed::percentage::Percentage as ComputedPercentage;
|
use crate::values::computed::percentage::Percentage as ComputedPercentage;
|
||||||
use crate::values::computed::{Context, ToComputedValue};
|
use crate::values::computed::{Context, ToComputedValue};
|
||||||
use crate::values::specified::calc::CalcNode;
|
use crate::values::specified::calc::CalcNode;
|
||||||
|
use crate::values::specified::Number;
|
||||||
use crate::values::{serialize_percentage, CSSFloat};
|
use crate::values::{serialize_percentage, CSSFloat};
|
||||||
use cssparser::{Parser, Token};
|
use cssparser::{Parser, Token};
|
||||||
use std::fmt::{self, Write};
|
use std::fmt::{self, Write};
|
||||||
|
@ -46,13 +47,21 @@ impl ToCss for Percentage {
|
||||||
|
|
||||||
impl Percentage {
|
impl Percentage {
|
||||||
/// Creates a percentage from a numeric value.
|
/// Creates a percentage from a numeric value.
|
||||||
pub fn new(value: CSSFloat) -> Self {
|
pub(super) fn new_with_clamping_mode(
|
||||||
|
value: CSSFloat,
|
||||||
|
calc_clamping_mode: Option<AllowedNumericType>,
|
||||||
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
value,
|
value,
|
||||||
calc_clamping_mode: None,
|
calc_clamping_mode,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates a percentage from a numeric value.
|
||||||
|
pub fn new(value: CSSFloat) -> Self {
|
||||||
|
Self::new_with_clamping_mode(value, None)
|
||||||
|
}
|
||||||
|
|
||||||
/// `0%`
|
/// `0%`
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn zero() -> Self {
|
pub fn zero() -> Self {
|
||||||
|
@ -70,12 +79,18 @@ impl Percentage {
|
||||||
calc_clamping_mode: None,
|
calc_clamping_mode: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the underlying value for this float.
|
/// Gets the underlying value for this float.
|
||||||
pub fn get(&self) -> CSSFloat {
|
pub fn get(&self) -> CSSFloat {
|
||||||
self.calc_clamping_mode
|
self.calc_clamping_mode
|
||||||
.map_or(self.value, |mode| mode.clamp(self.value))
|
.map_or(self.value, |mode| mode.clamp(self.value))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns this percentage as a number.
|
||||||
|
pub fn to_number(&self) -> Number {
|
||||||
|
Number::new_with_clamping_mode(self.value, self.calc_clamping_mode)
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns whether this percentage is a `calc()` value.
|
/// Returns whether this percentage is a `calc()` value.
|
||||||
pub fn is_calc(&self) -> bool {
|
pub fn is_calc(&self) -> bool {
|
||||||
self.calc_clamping_mode.is_some()
|
self.calc_clamping_mode.is_some()
|
||||||
|
|
|
@ -33,6 +33,27 @@ pub type TransformOrigin = generic::TransformOrigin<
|
||||||
Length,
|
Length,
|
||||||
>;
|
>;
|
||||||
|
|
||||||
|
impl TransformOrigin {
|
||||||
|
/// Returns the initial specified value for `transform-origin`.
|
||||||
|
#[inline]
|
||||||
|
pub fn initial_value() -> Self {
|
||||||
|
Self::new(
|
||||||
|
OriginComponent::Length(LengthPercentage::Percentage(ComputedPercentage(0.5))),
|
||||||
|
OriginComponent::Length(LengthPercentage::Percentage(ComputedPercentage(0.5))),
|
||||||
|
Length::zero(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the `0 0` value.
|
||||||
|
pub fn zero_zero() -> Self {
|
||||||
|
Self::new(
|
||||||
|
OriginComponent::Length(LengthPercentage::zero()),
|
||||||
|
OriginComponent::Length(LengthPercentage::zero()),
|
||||||
|
Length::zero(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Transform {
|
impl Transform {
|
||||||
/// Internal parse function for deciding if we wish to accept prefixed values or not
|
/// Internal parse function for deciding if we wish to accept prefixed values or not
|
||||||
///
|
///
|
||||||
|
@ -260,7 +281,7 @@ impl Parse for TransformOrigin {
|
||||||
let parse_depth = |input: &mut Parser| {
|
let parse_depth = |input: &mut Parser| {
|
||||||
input
|
input
|
||||||
.try(|i| Length::parse(context, i))
|
.try(|i| Length::parse(context, i))
|
||||||
.unwrap_or(Length::from_px(0.))
|
.unwrap_or(Length::zero())
|
||||||
};
|
};
|
||||||
match input.try(|i| OriginComponent::parse(context, i)) {
|
match input.try(|i| OriginComponent::parse(context, i)) {
|
||||||
Ok(x_origin @ OriginComponent::Center) => {
|
Ok(x_origin @ OriginComponent::Center) => {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue