From 26a029d407be480d791972afb5975cf62c9360a6 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 02:47:55 +0200 Subject: Adding upstream version 124.0.1. Signed-off-by: Daniel Baumann --- servo/components/style/values/computed/image.rs | 205 ++++++++++++++++++++++++ 1 file changed, 205 insertions(+) create mode 100644 servo/components/style/values/computed/image.rs (limited to 'servo/components/style/values/computed/image.rs') diff --git a/servo/components/style/values/computed/image.rs b/servo/components/style/values/computed/image.rs new file mode 100644 index 0000000000..8a91d95313 --- /dev/null +++ b/servo/components/style/values/computed/image.rs @@ -0,0 +1,205 @@ +/* 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 https://mozilla.org/MPL/2.0/. */ + +//! CSS handling for the computed value of +//! [`image`][image]s +//! +//! [image]: https://drafts.csswg.org/css-images/#image-values + +use crate::values::computed::percentage::Percentage; +use crate::values::computed::position::Position; +use crate::values::computed::url::ComputedImageUrl; +use crate::values::computed::{Angle, Color, Context}; +use crate::values::computed::{ + AngleOrPercentage, LengthPercentage, NonNegativeLength, NonNegativeLengthPercentage, + Resolution, ToComputedValue, +}; +use crate::values::generics::image::{self as generic, GradientCompatMode}; +use crate::values::specified::image as specified; +use crate::values::specified::position::{HorizontalPositionKeyword, VerticalPositionKeyword}; +use std::f32::consts::PI; +use std::fmt::{self, Write}; +use style_traits::{CssWriter, ToCss}; + +pub use specified::ImageRendering; + +/// Computed values for an image according to CSS-IMAGES. +/// +pub type Image = generic::GenericImage; + +// Images should remain small, see https://github.com/servo/servo/pull/18430 +size_of_test!(Image, 16); + +/// Computed values for a CSS gradient. +/// +pub type Gradient = generic::GenericGradient< + LineDirection, + LengthPercentage, + NonNegativeLength, + NonNegativeLengthPercentage, + Position, + Angle, + AngleOrPercentage, + Color, +>; + +/// Computed values for CSS cross-fade +/// +pub type CrossFade = generic::CrossFade; + +/// A computed radial gradient ending shape. +pub type EndingShape = generic::GenericEndingShape; + +/// A computed gradient line direction. +#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToResolvedValue)] +#[repr(C, u8)] +pub enum LineDirection { + /// An angle. + Angle(Angle), + /// A horizontal direction. + Horizontal(HorizontalPositionKeyword), + /// A vertical direction. + Vertical(VerticalPositionKeyword), + /// A corner. + Corner(HorizontalPositionKeyword, VerticalPositionKeyword), +} + +/// The computed value for an `image-set()` image. +pub type ImageSet = generic::GenericImageSet; + +impl ToComputedValue for specified::ImageSet { + type ComputedValue = ImageSet; + + fn to_computed_value(&self, context: &Context) -> Self::ComputedValue { + let items = self.items.to_computed_value(context); + let dpr = context.device().device_pixel_ratio().get(); + + let mut supported_image = false; + let mut selected_index = std::usize::MAX; + let mut selected_resolution = 0.0; + + for (i, item) in items.iter().enumerate() { + if item.has_mime_type && !context.device().is_supported_mime_type(&item.mime_type) { + // If the MIME type is not supported, we discard the ImageSetItem. + continue; + } + + let candidate_resolution = item.resolution.dppx(); + debug_assert!( + candidate_resolution >= 0.0, + "Resolutions should be non-negative" + ); + if candidate_resolution == 0.0 { + // If the resolution is 0, we also treat it as an invalid image. + continue; + } + + // https://drafts.csswg.org/css-images-4/#image-set-notation: + // + // Make a UA-specific choice of which to load, based on whatever criteria deemed + // relevant (such as the resolution of the display, connection speed, etc). + // + // For now, select the lowest resolution greater than display density, otherwise the + // greatest resolution available. + let better_candidate = || { + if selected_resolution < dpr && candidate_resolution > selected_resolution { + return true; + } + if candidate_resolution < selected_resolution && candidate_resolution >= dpr { + return true; + } + false + }; + + // The first item with a supported MIME type is obviously the current best candidate + if !supported_image || better_candidate() { + supported_image = true; + selected_index = i; + selected_resolution = candidate_resolution; + } + } + + ImageSet { + selected_index, + items, + } + } + + fn from_computed_value(computed: &Self::ComputedValue) -> Self { + Self { + selected_index: std::usize::MAX, + items: ToComputedValue::from_computed_value(&computed.items), + } + } +} + +impl generic::LineDirection for LineDirection { + fn points_downwards(&self, compat_mode: GradientCompatMode) -> bool { + match *self { + LineDirection::Angle(angle) => angle.radians() == PI, + LineDirection::Vertical(VerticalPositionKeyword::Bottom) => { + compat_mode == GradientCompatMode::Modern + }, + LineDirection::Vertical(VerticalPositionKeyword::Top) => { + compat_mode != GradientCompatMode::Modern + }, + _ => false, + } + } + + fn to_css(&self, dest: &mut CssWriter, compat_mode: GradientCompatMode) -> fmt::Result + where + W: Write, + { + match *self { + LineDirection::Angle(ref angle) => angle.to_css(dest), + LineDirection::Horizontal(x) => { + if compat_mode == GradientCompatMode::Modern { + dest.write_str("to ")?; + } + x.to_css(dest) + }, + LineDirection::Vertical(y) => { + if compat_mode == GradientCompatMode::Modern { + dest.write_str("to ")?; + } + y.to_css(dest) + }, + LineDirection::Corner(x, y) => { + if compat_mode == GradientCompatMode::Modern { + dest.write_str("to ")?; + } + x.to_css(dest)?; + dest.write_char(' ')?; + y.to_css(dest) + }, + } + } +} + +impl ToComputedValue for specified::LineDirection { + type ComputedValue = LineDirection; + + fn to_computed_value(&self, context: &Context) -> Self::ComputedValue { + match *self { + specified::LineDirection::Angle(ref angle) => { + LineDirection::Angle(angle.to_computed_value(context)) + }, + specified::LineDirection::Horizontal(x) => LineDirection::Horizontal(x), + specified::LineDirection::Vertical(y) => LineDirection::Vertical(y), + specified::LineDirection::Corner(x, y) => LineDirection::Corner(x, y), + } + } + + fn from_computed_value(computed: &Self::ComputedValue) -> Self { + match *computed { + LineDirection::Angle(ref angle) => { + specified::LineDirection::Angle(ToComputedValue::from_computed_value(angle)) + }, + LineDirection::Horizontal(x) => specified::LineDirection::Horizontal(x), + LineDirection::Vertical(y) => specified::LineDirection::Vertical(y), + LineDirection::Corner(x, y) => specified::LineDirection::Corner(x, y), + } + } +} -- cgit v1.2.3