Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions style/custom_properties.rs
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,18 @@ impl CssEnvironment {
return None;
}

#[cfg(feature = "servo")]
if *name == Atom::from("preferred-text-scale") {
return Some(VariableValue::from_token(
Token::Number {
has_sign: false,
value: device.preferred_text_scale(),
int_value: None,
},
url_data,
));
}

if let Some(var) = ENVIRONMENT_VARIABLES.iter().find(|var| var.name == *name) {
return Some((var.evaluator)(device, url_data));
}
Expand Down
82 changes: 82 additions & 0 deletions style/device/servo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@ impl Default for ServoMediaFeaturePreferences {
pub(super) struct ExtraDeviceData {
/// The current media type used by de device.
media_type: MediaType,
/// User preferred text scale exposed through CSS env().
preferred_text_scale: f32,
/// The current viewport size, in CSS pixels.
viewport_size: Size2D<f32, CSSPixel>,
/// The current screen size, in device pixels.
Expand Down Expand Up @@ -148,6 +150,7 @@ impl Device {
body_text_color: AtomicU32::new(AbsoluteColor::BLACK.to_nscolor()),
extra: ExtraDeviceData {
media_type,
preferred_text_scale: 1.0,
viewport_size,
device_size,
device_pixel_ratio,
Expand All @@ -162,6 +165,21 @@ impl Device {
}
}

/// User preferred text scale exposed by `env(preferred-text-scale)`.
pub fn preferred_text_scale(&self) -> f32 {
self.extra.preferred_text_scale
}

/// Set the CSS environment text scale. The embedder must invalidate styles
/// that depend on environment variables when this value changes.
pub fn set_preferred_text_scale(&mut self, scale: f32) {
assert!(
scale.is_finite() && scale > 0.0,
"preferred text scale must be finite and positive"
);
self.extra.preferred_text_scale = scale;
}

/// Returns the computed line-height for the font in a given computed values instance.
///
/// If you pass down an element, then the used line-height is returned.
Expand Down Expand Up @@ -571,6 +589,70 @@ fn used_color_scheme_is_dark(
mod tests {
use super::*;

#[derive(Debug)]
struct TestFontMetrics;

impl FontMetricsProvider for TestFontMetrics {
fn query_font_metrics(
&self,
_vertical: bool,
_font: &Font,
_base_size: CSSPixelLength,
_flags: QueryFontMetricsFlags,
) -> FontMetrics {
FontMetrics::default()
}

fn base_size_for_generic(&self, _generic: GenericFontFamily) -> Length {
Length::new(16.0)
}
}

#[test]
fn preferred_text_scale_environment_tracks_device_and_rejects_invalid_values() {
let mut device = Device::new(
MediaType::screen(),
QuirksMode::NoQuirks,
euclid::size2(100.0, 100.0),
euclid::size2(100.0, 100.0),
Scale::new(1.0),
Box::new(TestFontMetrics),
ComputedValues::initial_values_with_font_override(Font::initial_values()),
PrefersColorScheme::Light,
PointerCapabilities::default(),
PointerCapabilities::default(),
);
let url_data = crate::stylesheets::UrlExtraData::from(
url::Url::parse("https://example.test/").unwrap(),
);
let text_scale = crate::Atom::from("preferred-text-scale");
let value = |device: &Device| {
device
.environment()
.get(&text_scale, device, &url_data)
.unwrap()
.css
.parse::<f32>()
.unwrap()
};
assert_eq!(value(&device), 1.0);
device.set_preferred_text_scale(1.5);
assert_eq!(value(&device), 1.5);
device.set_preferred_text_scale(2.0);
assert_eq!(value(&device), 2.0);
assert!(device
.environment()
.get(&crate::Atom::from("unknown"), &device, &url_data)
.is_none());
for invalid in [0.0, -1.0, f32::NAN, f32::INFINITY, f32::NEG_INFINITY] {
assert!(std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
device.set_preferred_text_scale(invalid);
}))
.is_err());
assert_eq!(value(&device), 2.0);
}
}

#[test]
fn used_color_scheme_honors_supported_schemes_and_user_preference() {
assert!(!used_color_scheme_is_dark(
Expand Down
8 changes: 8 additions & 0 deletions style/servo/selector_parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -540,6 +540,8 @@ pub enum NonTSPseudoClass {
ServoNonZeroBorder,
Seeking,
Target,
ToolFormActive,
ToolSubmitActive,
UserInvalid,
UserValid,
Valid,
Expand Down Expand Up @@ -644,6 +646,8 @@ impl ToCss for NonTSPseudoClass {
Self::ServoNonZeroBorder => ":-servo-nonzero-border",
Self::Seeking => ":seeking",
Self::Target => ":target",
Self::ToolFormActive => ":tool-form-active",
Self::ToolSubmitActive => ":tool-submit-active",
Self::UserInvalid => ":user-invalid",
Self::UserValid => ":user-valid",
Self::Valid => ":valid",
Expand Down Expand Up @@ -693,6 +697,8 @@ impl NonTSPseudoClass {
Self::Required => ElementState::REQUIRED,
Self::Seeking => ElementState::SEEKING,
Self::Target => ElementState::URLTARGET,
Self::ToolFormActive => ElementState::TOOL_FORM_ACTIVE,
Self::ToolSubmitActive => ElementState::TOOL_SUBMIT_ACTIVE,
Self::UserInvalid => ElementState::USER_INVALID,
Self::UserValid => ElementState::USER_VALID,
Self::Valid => ElementState::VALID,
Expand Down Expand Up @@ -816,6 +822,8 @@ impl<'a, 'i> ::selectors::Parser<'i> for SelectorParser<'a> {
"required" => NonTSPseudoClass::Required,
"seeking" => NonTSPseudoClass::Seeking,
"target" => NonTSPseudoClass::Target,
"tool-form-active" => NonTSPseudoClass::ToolFormActive,
"tool-submit-active" => NonTSPseudoClass::ToolSubmitActive,
"user-invalid" => NonTSPseudoClass::UserInvalid,
"user-valid" => NonTSPseudoClass::UserValid,
"valid" => NonTSPseudoClass::Valid,
Expand Down
4 changes: 4 additions & 0 deletions stylo_dom/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,10 @@ bitflags! {
const HEADING_LEVEL_BITS = 0b1111u64 << HEADING_LEVEL_OFFSET;
/// https://w3c.github.io/picture-in-picture/#css-pseudo-class
const PICTURE_IN_PICTURE = 1u64 << 61;
/// A declarative WebMCP form is executing a tool.
const TOOL_FORM_ACTIVE = 1u64 << 62;
/// The submit control selected by an executing WebMCP form.
const TOOL_SUBMIT_ACTIVE = 1u64 << 63;

/// Some convenience unions.
const DIR_STATES = Self::LTR.bits() | Self::RTL.bits();
Expand Down
Loading