mirror of
https://github.com/servo/servo.git
synced 2025-08-05 21:50:18 +01:00
Auto merge of #23108 - emilio:gecko-sync, r=emilio
style: Sync changes from mozilla-central. See each individual commit for details. <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/23108) <!-- Reviewable:end -->
This commit is contained in:
commit
864f855850
53 changed files with 961 additions and 1338 deletions
|
@ -367,7 +367,7 @@ impl FontGroup {
|
|||
|
||||
let families = style
|
||||
.font_family
|
||||
.0
|
||||
.families
|
||||
.iter()
|
||||
.map(|family| FontGroupFamily::new(descriptor.clone(), &family))
|
||||
.collect();
|
||||
|
|
|
@ -119,7 +119,10 @@ fn font_family(names: Vec<&str>) -> FontFamily {
|
|||
})
|
||||
.collect();
|
||||
|
||||
FontFamily(FontFamilyList::new(names.into_boxed_slice()))
|
||||
FontFamily {
|
||||
families: FontFamilyList::new(names.into_boxed_slice()),
|
||||
is_system_font: false,
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -77,7 +77,7 @@ where
|
|||
|
||||
#[cfg(feature = "gecko")]
|
||||
unsafe impl HasFFI for AuthorStyles<crate::gecko::data::GeckoStyleSheet> {
|
||||
type FFIType = crate::gecko_bindings::bindings::RawServoAuthorStyles;
|
||||
type FFIType = crate::gecko_bindings::structs::RawServoAuthorStyles;
|
||||
}
|
||||
#[cfg(feature = "gecko")]
|
||||
unsafe impl HasSimpleFFI for AuthorStyles<crate::gecko::data::GeckoStyleSheet> {}
|
||||
|
|
|
@ -32,7 +32,6 @@ mod bindings {
|
|||
use toml::value::Table;
|
||||
|
||||
const STRUCTS_FILE: &'static str = "structs.rs";
|
||||
const BINDINGS_FILE: &'static str = "bindings.rs";
|
||||
|
||||
fn read_config(path: &PathBuf) -> Table {
|
||||
println!("cargo:rerun-if-changed={}", path.to_str().unwrap());
|
||||
|
@ -128,9 +127,6 @@ mod bindings {
|
|||
trait BuilderExt {
|
||||
fn get_initial_builder() -> Builder;
|
||||
fn include<T: Into<String>>(self, file: T) -> Builder;
|
||||
fn zero_size_type(self, ty: &str, structs_list: &HashSet<&str>) -> Builder;
|
||||
fn borrowed_type(self, ty: &str) -> Builder;
|
||||
fn mutable_borrowed_type(self, ty: &str) -> Builder;
|
||||
}
|
||||
|
||||
impl BuilderExt for Builder {
|
||||
|
@ -181,42 +177,6 @@ mod bindings {
|
|||
fn include<T: Into<String>>(self, file: T) -> Builder {
|
||||
self.clang_arg("-include").clang_arg(file)
|
||||
}
|
||||
// This makes an FFI-safe void type that can't be matched on
|
||||
// &VoidType is UB to have, because you can match on it
|
||||
// to produce a reachable unreachable. If it's wrapped in
|
||||
// a struct as a private field it becomes okay again
|
||||
//
|
||||
// Not 100% sure of how safe this is, but it's what we're using
|
||||
// in the XPCOM ffi too
|
||||
// https://github.com/nikomatsakis/rust-memory-model/issues/2
|
||||
fn zero_size_type(self, ty: &str, structs_list: &HashSet<&str>) -> Builder {
|
||||
if !structs_list.contains(ty) {
|
||||
self.blacklist_type(ty)
|
||||
.raw_line(format!("enum {}Void {{ }}", ty))
|
||||
.raw_line(format!("pub struct {0}({0}Void);", ty))
|
||||
} else {
|
||||
self
|
||||
}
|
||||
}
|
||||
fn borrowed_type(self, ty: &str) -> Builder {
|
||||
self.blacklist_type(format!("{}Borrowed", ty))
|
||||
.raw_line(format!("pub type {0}Borrowed<'a> = &'a {0};", ty))
|
||||
.blacklist_type(format!("{}BorrowedOrNull", ty))
|
||||
.raw_line(format!(
|
||||
"pub type {0}BorrowedOrNull<'a> = Option<&'a {0}>;",
|
||||
ty
|
||||
))
|
||||
}
|
||||
fn mutable_borrowed_type(self, ty: &str) -> Builder {
|
||||
self.borrowed_type(ty)
|
||||
.blacklist_type(format!("{}BorrowedMut", ty))
|
||||
.raw_line(format!("pub type {0}BorrowedMut<'a> = &'a mut {0};", ty))
|
||||
.blacklist_type(format!("{}BorrowedMutOrNull", ty))
|
||||
.raw_line(format!(
|
||||
"pub type {0}BorrowedMutOrNull<'a> = Option<&'a mut {0}>;",
|
||||
ty
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
struct Fixup {
|
||||
|
@ -259,58 +219,6 @@ mod bindings {
|
|||
.expect("Unable to write output");
|
||||
}
|
||||
|
||||
fn get_types(filename: &str, macro_pat: &str) -> Vec<(String, String)> {
|
||||
// Read the file
|
||||
let path = DISTDIR_PATH.join("include/mozilla/").join(filename);
|
||||
let mut list_file = File::open(path).expect(&format!("Unable to open {}", filename));
|
||||
let mut content = String::new();
|
||||
list_file
|
||||
.read_to_string(&mut content)
|
||||
.expect(&format!("Failed to read {}", filename));
|
||||
// Remove comments
|
||||
let block_comment_re = Regex::new(r#"(?s)/\*.*?\*/"#).unwrap();
|
||||
let line_comment_re = Regex::new(r#"//.*"#).unwrap();
|
||||
let content = block_comment_re.replace_all(&content, "");
|
||||
let content = line_comment_re.replace_all(&content, "");
|
||||
// Extract the list
|
||||
let re_string = format!(r#"^({})\(.+,\s*(\w+)\)$"#, macro_pat);
|
||||
let re = Regex::new(&re_string).unwrap();
|
||||
content
|
||||
.lines()
|
||||
.map(|line| line.trim())
|
||||
.filter(|line| !line.is_empty())
|
||||
.map(|line| {
|
||||
let captures = re
|
||||
.captures(&line)
|
||||
.expect(&format!("Unrecognized line in {}: '{}'", filename, line));
|
||||
let macro_name = captures.get(1).unwrap().as_str().to_string();
|
||||
let type_name = captures.get(2).unwrap().as_str().to_string();
|
||||
(macro_name, type_name)
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn get_borrowed_types() -> Vec<(bool, String)> {
|
||||
get_types("BorrowedTypeList.h", "GECKO_BORROWED_TYPE(?:_MUT)?")
|
||||
.into_iter()
|
||||
.map(|(macro_name, type_name)| (macro_name.ends_with("MUT"), type_name))
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn get_arc_types() -> Vec<String> {
|
||||
get_types("ServoArcTypeList.h", "SERVO_ARC_TYPE")
|
||||
.into_iter()
|
||||
.map(|(_, type_name)| type_name)
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn get_boxed_types() -> Vec<String> {
|
||||
get_types("ServoBoxedTypeList.h", "SERVO_BOXED_TYPE")
|
||||
.into_iter()
|
||||
.map(|(_, type_name)| type_name)
|
||||
.collect()
|
||||
}
|
||||
|
||||
struct BuilderWithConfig<'a> {
|
||||
builder: Builder,
|
||||
config: &'a Table,
|
||||
|
@ -386,10 +294,13 @@ mod bindings {
|
|||
fn generate_structs() {
|
||||
let builder = Builder::get_initial_builder()
|
||||
.enable_cxx_namespaces()
|
||||
.with_codegen_config(CodegenConfig::TYPES | CodegenConfig::VARS);
|
||||
.with_codegen_config(
|
||||
CodegenConfig::TYPES | CodegenConfig::VARS | CodegenConfig::FUNCTIONS,
|
||||
);
|
||||
let mut fixups = vec![];
|
||||
let builder = BuilderWithConfig::new(builder, CONFIG["structs"].as_table().unwrap())
|
||||
.handle_common(&mut fixups)
|
||||
.handle_str_items("whitelist-functions", |b, item| b.whitelist_function(item))
|
||||
.handle_str_items("bitfield-enums", |b, item| b.bitfield_enum(item))
|
||||
.handle_str_items("rusty-enums", |b, item| b.rustified_enum(item))
|
||||
.handle_str_items("whitelist-vars", |b, item| b.whitelist_var(item))
|
||||
|
@ -480,89 +391,6 @@ mod bindings {
|
|||
}
|
||||
}
|
||||
|
||||
fn generate_bindings() {
|
||||
let builder = Builder::get_initial_builder()
|
||||
.disable_name_namespacing()
|
||||
.with_codegen_config(CodegenConfig::FUNCTIONS);
|
||||
let config = CONFIG["bindings"].as_table().unwrap();
|
||||
let mut structs_types = HashSet::new();
|
||||
let mut fixups = vec![];
|
||||
let mut builder = BuilderWithConfig::new(builder, config)
|
||||
.handle_common(&mut fixups)
|
||||
.handle_str_items("whitelist-functions", |b, item| b.whitelist_function(item))
|
||||
.handle_str_items("structs-types", |mut builder, ty| {
|
||||
builder = builder
|
||||
.blacklist_type(ty)
|
||||
.raw_line(format!("use gecko_bindings::structs::{};", ty));
|
||||
structs_types.insert(ty);
|
||||
// TODO this is hacky, figure out a better way to do it without
|
||||
// hardcoding everything...
|
||||
if ty.starts_with("nsStyle") {
|
||||
builder = builder
|
||||
.raw_line(format!("unsafe impl Send for {} {{}}", ty))
|
||||
.raw_line(format!("unsafe impl Sync for {} {{}}", ty));
|
||||
}
|
||||
builder
|
||||
})
|
||||
// TODO This was added due to servo/rust-bindgen#75, but
|
||||
// that has been fixed in clang 4.0+. When we switch people
|
||||
// to libclang 4.0, we can remove this.
|
||||
.handle_table_items("array-types", |builder, item| {
|
||||
let cpp_type = item["cpp-type"].as_str().unwrap();
|
||||
let rust_type = item["rust-type"].as_str().unwrap();
|
||||
builder.raw_line(format!(
|
||||
concat!(
|
||||
"pub type nsTArrayBorrowed_{}<'a> = ",
|
||||
"&'a mut ::gecko_bindings::structs::nsTArray<{}>;"
|
||||
),
|
||||
cpp_type, rust_type
|
||||
))
|
||||
})
|
||||
.handle_str_items("servo-immutable-borrow-types", |b, ty| b.borrowed_type(ty))
|
||||
// Right now the only immutable borrow types are ones which we import
|
||||
// from the |structs| module. As such, we don't need to create an opaque
|
||||
// type with zero_size_type. If we ever introduce immutable borrow types
|
||||
// which _do_ need to be opaque, we'll need a separate mode.
|
||||
.handle_str_items("servo-borrow-types", |b, ty| b.mutable_borrowed_type(ty))
|
||||
.get_builder();
|
||||
for (is_mut, ty) in get_borrowed_types().iter() {
|
||||
if *is_mut {
|
||||
builder = builder.mutable_borrowed_type(ty);
|
||||
} else {
|
||||
builder = builder.borrowed_type(ty);
|
||||
}
|
||||
}
|
||||
for ty in get_arc_types().iter() {
|
||||
builder = builder
|
||||
.blacklist_type(format!("{}Strong", ty))
|
||||
.raw_line(format!(
|
||||
"pub type {0}Strong = ::gecko_bindings::sugar::ownership::Strong<{0}>;",
|
||||
ty
|
||||
))
|
||||
.borrowed_type(ty)
|
||||
.zero_size_type(ty, &structs_types);
|
||||
}
|
||||
for ty in get_boxed_types().iter() {
|
||||
builder = builder
|
||||
.blacklist_type(format!("{}Owned", ty))
|
||||
.raw_line(format!(
|
||||
"pub type {0}Owned = ::gecko_bindings::sugar::ownership::Owned<{0}>;",
|
||||
ty
|
||||
))
|
||||
.blacklist_type(format!("{}OwnedOrNull", ty))
|
||||
.raw_line(format!(
|
||||
concat!(
|
||||
"pub type {0}OwnedOrNull = ",
|
||||
"::gecko_bindings::sugar::ownership::OwnedOrNull<{0}>;"
|
||||
),
|
||||
ty
|
||||
))
|
||||
.mutable_borrowed_type(ty)
|
||||
.zero_size_type(ty, &structs_types);
|
||||
}
|
||||
write_binding_file(builder, BINDINGS_FILE, &fixups);
|
||||
}
|
||||
|
||||
fn generate_atoms() {
|
||||
let script = PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").unwrap())
|
||||
.join("gecko")
|
||||
|
@ -580,24 +408,9 @@ mod bindings {
|
|||
}
|
||||
|
||||
pub fn generate() {
|
||||
use std::thread;
|
||||
macro_rules! run_tasks {
|
||||
($($task:expr,)+) => {
|
||||
if setup_logging() {
|
||||
$($task;)+
|
||||
} else {
|
||||
let threads = vec![$( thread::spawn(|| $task) ),+];
|
||||
for thread in threads.into_iter() {
|
||||
thread.join().unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
run_tasks! {
|
||||
generate_structs(),
|
||||
generate_bindings(),
|
||||
generate_atoms(),
|
||||
}
|
||||
setup_logging();
|
||||
generate_structs();
|
||||
generate_atoms();
|
||||
|
||||
for path in ADDED_PATHS.lock().unwrap().iter() {
|
||||
println!("cargo:rerun-if-changed={}", path.to_str().unwrap());
|
||||
|
|
|
@ -103,6 +103,15 @@ include = [
|
|||
"ZIndex",
|
||||
"TransformOrigin",
|
||||
"WordBreak",
|
||||
"Contain",
|
||||
"RestyleHint",
|
||||
"TouchAction",
|
||||
"WillChangeBits",
|
||||
"TextDecorationLine",
|
||||
"MozListReversed",
|
||||
"Owned",
|
||||
"OwnedOrNull",
|
||||
"Strong",
|
||||
]
|
||||
item_types = ["enums", "structs", "typedefs"]
|
||||
|
||||
|
@ -196,3 +205,35 @@ item_types = ["enums", "structs", "typedefs"]
|
|||
"GenericBorderRadius" = """
|
||||
inline const StyleLengthPercentage& Get(mozilla::HalfCorner) const;
|
||||
"""
|
||||
|
||||
"RestyleHint" = """
|
||||
static inline StyleRestyleHint RestyleSubtree();
|
||||
static inline StyleRestyleHint RecascadeSubtree();
|
||||
static inline StyleRestyleHint ForAnimations();
|
||||
"""
|
||||
|
||||
# TODO(emilio): Add hooks to cbindgen to be able to generate MOZ_MUST_USE_TYPE
|
||||
# or MOZ_MUST_USE on the functions.
|
||||
"Owned" = """
|
||||
UniquePtr<GeckoType> Consume() {
|
||||
UniquePtr<GeckoType> ret(ptr);
|
||||
ptr = nullptr;
|
||||
return ret;
|
||||
}
|
||||
"""
|
||||
|
||||
"OwnedOrNull" = """
|
||||
UniquePtr<GeckoType> Consume() {
|
||||
UniquePtr<GeckoType> ret(ptr);
|
||||
ptr = nullptr;
|
||||
return ret;
|
||||
}
|
||||
"""
|
||||
|
||||
"Strong" = """
|
||||
already_AddRefed<GeckoType> Consume() {
|
||||
already_AddRefed<GeckoType> ret(const_cast<GeckoType*>(ptr));
|
||||
ptr = nullptr;
|
||||
return ret;
|
||||
}
|
||||
"""
|
||||
|
|
|
@ -441,6 +441,11 @@ pub trait TElement:
|
|||
None
|
||||
}
|
||||
|
||||
/// The ::marker pseudo-element of this element, if it exists.
|
||||
fn marker_pseudo_element(&self) -> Option<Self> {
|
||||
None
|
||||
}
|
||||
|
||||
/// Execute `f` for each anonymous content child (apart from ::before and
|
||||
/// ::after) whose originating element is `self`.
|
||||
fn each_anonymous_content_child<F>(&self, _f: F)
|
||||
|
|
|
@ -545,7 +545,6 @@ macro_rules! font_face_descriptors {
|
|||
}
|
||||
}
|
||||
|
||||
// css-name rust_identifier: Type,
|
||||
#[cfg(feature = "gecko")]
|
||||
font_face_descriptors! {
|
||||
mandatory descriptors = [
|
||||
|
|
|
@ -7,51 +7,42 @@
|
|||
#![deny(missing_docs)]
|
||||
|
||||
use crate::context::SharedStyleContext;
|
||||
use crate::logical_geometry::WritingMode;
|
||||
use crate::media_queries::Device;
|
||||
use crate::properties::style_structs::Font;
|
||||
use crate::Atom;
|
||||
use app_units::Au;
|
||||
|
||||
/// Represents the font metrics that style needs from a font to compute the
|
||||
/// value of certain CSS units like `ex`.
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
#[derive(Clone, Debug, Default, PartialEq)]
|
||||
pub struct FontMetrics {
|
||||
/// The x-height of the font.
|
||||
pub x_height: Au,
|
||||
pub x_height: Option<Au>,
|
||||
/// The zero advance. This is usually writing mode dependent
|
||||
pub zero_advance_measure: Au,
|
||||
pub zero_advance_measure: Option<Au>,
|
||||
}
|
||||
|
||||
/// The result for querying font metrics for a given font family.
|
||||
/// Type of font metrics to retrieve.
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum FontMetricsQueryResult {
|
||||
/// The font is available, but we may or may not have found any font metrics
|
||||
/// for it.
|
||||
Available(FontMetrics),
|
||||
/// The font is not available.
|
||||
NotAvailable,
|
||||
pub enum FontMetricsOrientation {
|
||||
/// Get metrics for horizontal or vertical according to the Context's
|
||||
/// writing mode.
|
||||
MatchContext,
|
||||
/// Force getting horizontal metrics.
|
||||
Horizontal,
|
||||
}
|
||||
|
||||
/// A trait used to represent something capable of providing us font metrics.
|
||||
pub trait FontMetricsProvider {
|
||||
/// Obtain the metrics for given font family.
|
||||
///
|
||||
/// TODO: We could make this take the full list, I guess, and save a few
|
||||
/// virtual calls in the case we are repeatedly unable to find font metrics?
|
||||
/// That is not too common in practice though.
|
||||
fn query(
|
||||
&self,
|
||||
_font: &Font,
|
||||
_font_size: Au,
|
||||
_wm: WritingMode,
|
||||
_in_media_query: bool,
|
||||
_device: &Device,
|
||||
) -> FontMetricsQueryResult {
|
||||
FontMetricsQueryResult::NotAvailable
|
||||
_context: &crate::values::computed::Context,
|
||||
_base_size: crate::values::specified::length::FontBaseSize,
|
||||
_orientation: FontMetricsOrientation,
|
||||
) -> FontMetrics {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
/// Get default size of a given language and generic family
|
||||
/// Get default size of a given language and generic family.
|
||||
fn get_size(&self, font_name: &Atom, font_family: u8) -> Au;
|
||||
|
||||
/// Construct from a shared style context
|
||||
|
|
|
@ -9,32 +9,29 @@
|
|||
#![allow(non_snake_case, missing_docs)]
|
||||
|
||||
use crate::gecko::url::CssUrlData;
|
||||
use crate::gecko_bindings::bindings::RawServoCounterStyleRule;
|
||||
use crate::gecko_bindings::bindings::RawServoFontFeatureValuesRule;
|
||||
use crate::gecko_bindings::bindings::RawServoImportRule;
|
||||
use crate::gecko_bindings::bindings::RawServoKeyframe;
|
||||
use crate::gecko_bindings::bindings::RawServoKeyframesRule;
|
||||
use crate::gecko_bindings::bindings::RawServoMediaRule;
|
||||
use crate::gecko_bindings::bindings::RawServoMozDocumentRule;
|
||||
use crate::gecko_bindings::bindings::RawServoNamespaceRule;
|
||||
use crate::gecko_bindings::bindings::RawServoPageRule;
|
||||
use crate::gecko_bindings::bindings::RawServoRuleNode;
|
||||
use crate::gecko_bindings::bindings::RawServoRuleNodeStrong;
|
||||
use crate::gecko_bindings::bindings::RawServoSupportsRule;
|
||||
use crate::gecko_bindings::bindings::ServoCssRules;
|
||||
use crate::gecko_bindings::structs::RawServoAnimationValue;
|
||||
use crate::gecko_bindings::structs::RawServoCounterStyleRule;
|
||||
use crate::gecko_bindings::structs::RawServoCssUrlData;
|
||||
use crate::gecko_bindings::structs::RawServoDeclarationBlock;
|
||||
use crate::gecko_bindings::structs::RawServoFontFaceRule;
|
||||
use crate::gecko_bindings::structs::RawServoFontFeatureValuesRule;
|
||||
use crate::gecko_bindings::structs::RawServoImportRule;
|
||||
use crate::gecko_bindings::structs::RawServoKeyframe;
|
||||
use crate::gecko_bindings::structs::RawServoKeyframesRule;
|
||||
use crate::gecko_bindings::structs::RawServoMediaList;
|
||||
use crate::gecko_bindings::structs::RawServoMediaRule;
|
||||
use crate::gecko_bindings::structs::RawServoMozDocumentRule;
|
||||
use crate::gecko_bindings::structs::RawServoNamespaceRule;
|
||||
use crate::gecko_bindings::structs::RawServoPageRule;
|
||||
use crate::gecko_bindings::structs::RawServoQuotes;
|
||||
use crate::gecko_bindings::structs::RawServoStyleRule;
|
||||
use crate::gecko_bindings::structs::RawServoStyleSheetContents;
|
||||
use crate::gecko_bindings::structs::RawServoSupportsRule;
|
||||
use crate::gecko_bindings::structs::ServoCssRules;
|
||||
use crate::gecko_bindings::sugar::ownership::{HasArcFFI, HasFFI, Strong};
|
||||
use crate::media_queries::MediaList;
|
||||
use crate::properties::animated_properties::AnimationValue;
|
||||
use crate::properties::{ComputedValues, PropertyDeclarationBlock};
|
||||
use crate::rule_tree::StrongRuleNode;
|
||||
use crate::shared_lock::Locked;
|
||||
use crate::stylesheets::keyframes_rule::Keyframe;
|
||||
use crate::stylesheets::{CounterStyleRule, CssRules, FontFaceRule, FontFeatureValuesRule};
|
||||
|
@ -121,31 +118,6 @@ impl_arc_ffi!(CssUrlData => RawServoCssUrlData
|
|||
impl_arc_ffi!(Box<[QuotePair]> => RawServoQuotes
|
||||
[Servo_Quotes_AddRef, Servo_Quotes_Release]);
|
||||
|
||||
// RuleNode is a Arc-like type but it does not use Arc.
|
||||
|
||||
impl StrongRuleNode {
|
||||
pub fn into_strong(self) -> RawServoRuleNodeStrong {
|
||||
let ptr = self.ptr();
|
||||
mem::forget(self);
|
||||
unsafe { mem::transmute(ptr) }
|
||||
}
|
||||
|
||||
pub fn from_ffi<'a>(ffi: &'a &RawServoRuleNode) -> &'a Self {
|
||||
unsafe { &*(ffi as *const &RawServoRuleNode as *const StrongRuleNode) }
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Servo_RuleNode_AddRef(obj: &RawServoRuleNode) {
|
||||
mem::forget(StrongRuleNode::from_ffi(&obj).clone());
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Servo_RuleNode_Release(obj: &RawServoRuleNode) {
|
||||
let ptr = StrongRuleNode::from_ffi(&obj);
|
||||
ptr::read(ptr as *const StrongRuleNode);
|
||||
}
|
||||
|
||||
// ComputedStyle is not an opaque type on any side of FFI.
|
||||
// This means that doing the HasArcFFI type trick is actually unsound,
|
||||
// since it gives us a way to construct an Arc<ComputedStyle> from
|
||||
|
|
|
@ -12,8 +12,7 @@
|
|||
|
||||
use crate::gecko::values::GeckoStyleCoordConvertible;
|
||||
use crate::gecko_bindings::bindings;
|
||||
use crate::gecko_bindings::structs::RawGeckoGfxMatrix4x4;
|
||||
use crate::gecko_bindings::structs::{self, nsStyleCoord_CalcValue};
|
||||
use crate::gecko_bindings::structs::{self, nsStyleCoord_CalcValue, Matrix4x4Components};
|
||||
use crate::gecko_bindings::structs::{nsStyleImage, nsresult, SheetType};
|
||||
use crate::gecko_bindings::sugar::ns_style_coord::{CoordData, CoordDataMut, CoordDataValue};
|
||||
use crate::stylesheets::{Origin, RulesMutateError};
|
||||
|
@ -986,8 +985,8 @@ pub unsafe fn string_from_chars_pointer(p: *const u16) -> String {
|
|||
String::from_utf16_lossy(char_vec)
|
||||
}
|
||||
|
||||
impl<'a> From<&'a RawGeckoGfxMatrix4x4> for Matrix3D {
|
||||
fn from(m: &'a RawGeckoGfxMatrix4x4) -> Matrix3D {
|
||||
impl<'a> From<&'a Matrix4x4Components> for Matrix3D {
|
||||
fn from(m: &'a Matrix4x4Components) -> Matrix3D {
|
||||
Matrix3D {
|
||||
m11: m[0],
|
||||
m12: m[1],
|
||||
|
@ -1009,8 +1008,8 @@ impl<'a> From<&'a RawGeckoGfxMatrix4x4> for Matrix3D {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<Matrix3D> for RawGeckoGfxMatrix4x4 {
|
||||
fn from(matrix: Matrix3D) -> RawGeckoGfxMatrix4x4 {
|
||||
impl From<Matrix3D> for Matrix4x4Components {
|
||||
fn from(matrix: Matrix3D) -> Self {
|
||||
[
|
||||
matrix.m11, matrix.m12, matrix.m13, matrix.m14, matrix.m21, matrix.m22, matrix.m23,
|
||||
matrix.m24, matrix.m31, matrix.m32, matrix.m33, matrix.m34, matrix.m41, matrix.m42,
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
|
||||
use crate::context::QuirksMode;
|
||||
use crate::dom::TElement;
|
||||
use crate::gecko_bindings::bindings::{self, RawServoStyleSet};
|
||||
use crate::gecko_bindings::structs::{self, ServoStyleSetSizes};
|
||||
use crate::gecko_bindings::bindings;
|
||||
use crate::gecko_bindings::structs::{self, RawServoStyleSet, ServoStyleSetSizes};
|
||||
use crate::gecko_bindings::structs::{StyleSheet as DomStyleSheet, StyleSheetInfo};
|
||||
use crate::gecko_bindings::sugar::ownership::{HasArcFFI, HasBoxFFI, HasFFI, HasSimpleFFI};
|
||||
use crate::invalidation::media_queries::{MediaListKey, ToMediaListKey};
|
||||
|
|
|
@ -369,8 +369,8 @@ fn eval_prefers_color_scheme(device: &Device, query_value: Option<PrefersColorSc
|
|||
}
|
||||
}
|
||||
|
||||
/// https://drafts.csswg.org/mediaqueries-4/#mf-interaction
|
||||
bitflags! {
|
||||
/// https://drafts.csswg.org/mediaqueries-4/#mf-interaction
|
||||
struct PointerCapabilities: u8 {
|
||||
const COARSE = structs::PointerCapabilities_Coarse;
|
||||
const FINE = structs::PointerCapabilities_Fine;
|
||||
|
|
|
@ -33,7 +33,10 @@ impl ::selectors::parser::PseudoElement for PseudoElement {
|
|||
fn valid_after_slotted(&self) -> bool {
|
||||
matches!(
|
||||
*self,
|
||||
PseudoElement::Before | PseudoElement::After | PseudoElement::Placeholder
|
||||
PseudoElement::Before |
|
||||
PseudoElement::After |
|
||||
PseudoElement::Marker |
|
||||
PseudoElement::Placeholder
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -109,6 +112,12 @@ impl PseudoElement {
|
|||
*self == PseudoElement::After
|
||||
}
|
||||
|
||||
/// Whether this pseudo-element is the ::marker pseudo.
|
||||
#[inline]
|
||||
pub fn is_marker(&self) -> bool {
|
||||
*self == PseudoElement::Marker
|
||||
}
|
||||
|
||||
/// Whether this pseudo-element is ::first-letter.
|
||||
#[inline]
|
||||
pub fn is_first_letter(&self) -> bool {
|
||||
|
@ -180,6 +189,8 @@ impl PseudoElement {
|
|||
/// Whether this pseudo-element should actually exist if it has
|
||||
/// the given styles.
|
||||
pub fn should_exist(&self, style: &ComputedValues) -> bool {
|
||||
debug_assert!(self.is_eager());
|
||||
|
||||
if style.get_box().clone_display() == Display::None {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -195,13 +195,16 @@ impl PseudoElement {
|
|||
return Some(${pseudo_element_variant(pseudo)})
|
||||
}
|
||||
% endfor
|
||||
// Alias "-moz-selection" to "selection" at parse time.
|
||||
// Alias some legacy prefixed pseudos to their standardized name at parse time:
|
||||
"-moz-selection" => {
|
||||
return Some(PseudoElement::Selection);
|
||||
}
|
||||
"-moz-placeholder" => {
|
||||
return Some(PseudoElement::Placeholder);
|
||||
}
|
||||
"-moz-list-bullet" | "-moz-list-number" => {
|
||||
return Some(PseudoElement::Marker);
|
||||
}
|
||||
_ => {
|
||||
if starts_with_ignore_ascii_case(name, "-moz-tree-") {
|
||||
return PseudoElement::tree_pseudo_element(name, Box::new([]))
|
||||
|
|
|
@ -51,8 +51,8 @@ impl GeckoRestyleDamage {
|
|||
let mut reset_only = false;
|
||||
let hint = unsafe {
|
||||
bindings::Gecko_CalcStyleDifference(
|
||||
old_style,
|
||||
new_style,
|
||||
old_style.as_gecko_computed_style(),
|
||||
new_style.as_gecko_computed_style(),
|
||||
&mut any_style_changed,
|
||||
&mut reset_only,
|
||||
)
|
||||
|
|
|
@ -20,7 +20,7 @@ use crate::context::{PostAnimationTasks, QuirksMode, SharedStyleContext, UpdateA
|
|||
use crate::data::ElementData;
|
||||
use crate::dom::{LayoutIterator, NodeInfo, OpaqueNode, TDocument, TElement, TNode, TShadowRoot};
|
||||
use crate::element_state::{DocumentState, ElementState};
|
||||
use crate::font_metrics::{FontMetrics, FontMetricsProvider, FontMetricsQueryResult};
|
||||
use crate::font_metrics::{FontMetrics, FontMetricsOrientation, FontMetricsProvider};
|
||||
use crate::gecko::data::GeckoStyleSheet;
|
||||
use crate::gecko::selector_parser::{NonTSPseudoClass, PseudoElement, SelectorImpl};
|
||||
use crate::gecko::snapshot_helpers;
|
||||
|
@ -44,7 +44,6 @@ use crate::gecko_bindings::bindings::{Gecko_ElementState, Gecko_GetDocumentLWThe
|
|||
use crate::gecko_bindings::bindings::{Gecko_SetNodeFlags, Gecko_UnsetNodeFlags};
|
||||
use crate::gecko_bindings::structs;
|
||||
use crate::gecko_bindings::structs::nsChangeHint;
|
||||
use crate::gecko_bindings::structs::nsRestyleHint;
|
||||
use crate::gecko_bindings::structs::Document_DocumentTheme as DocumentTheme;
|
||||
use crate::gecko_bindings::structs::EffectCompositor_CascadeLevel as CascadeLevel;
|
||||
use crate::gecko_bindings::structs::ELEMENT_HANDLED_SNAPSHOT;
|
||||
|
@ -54,14 +53,15 @@ use crate::gecko_bindings::structs::ELEMENT_HAS_SNAPSHOT;
|
|||
use crate::gecko_bindings::structs::NODE_DESCENDANTS_NEED_FRAMES;
|
||||
use crate::gecko_bindings::structs::NODE_NEEDS_FRAME;
|
||||
use crate::gecko_bindings::structs::{nsAtom, nsIContent, nsINode_BooleanFlag};
|
||||
use crate::gecko_bindings::structs::{RawGeckoElement, RawGeckoNode, RawGeckoXBLBinding};
|
||||
use crate::gecko_bindings::structs::{
|
||||
nsINode as RawGeckoNode, nsXBLBinding as RawGeckoXBLBinding, Element as RawGeckoElement,
|
||||
};
|
||||
use crate::gecko_bindings::sugar::ownership::{HasArcFFI, HasSimpleFFI};
|
||||
use crate::global_style_data::GLOBAL_STYLE_DATA;
|
||||
use crate::hash::FxHashMap;
|
||||
use crate::logical_geometry::WritingMode;
|
||||
use crate::invalidation::element::restyle_hints::RestyleHint;
|
||||
use crate::media_queries::Device;
|
||||
use crate::properties::animated_properties::{AnimationValue, AnimationValueMap};
|
||||
use crate::properties::style_structs::Font;
|
||||
use crate::properties::{ComputedValues, LonghandId};
|
||||
use crate::properties::{Importance, PropertyDeclaration, PropertyDeclarationBlock};
|
||||
use crate::rule_tree::CascadeLevel as ServoCascadeLevel;
|
||||
|
@ -69,6 +69,7 @@ use crate::selector_parser::{AttrValue, HorizontalDirection, Lang};
|
|||
use crate::shared_lock::Locked;
|
||||
use crate::string_cache::{Atom, Namespace, WeakAtom, WeakNamespace};
|
||||
use crate::stylist::CascadeData;
|
||||
use crate::values::specified::length::FontBaseSize;
|
||||
use crate::CaseSensitivityExt;
|
||||
use app_units::Au;
|
||||
use atomic_refcell::{AtomicRefCell, AtomicRefMut};
|
||||
|
@ -169,11 +170,7 @@ impl<'lr> TShadowRoot for GeckoShadowRoot<'lr> {
|
|||
where
|
||||
Self: 'a,
|
||||
{
|
||||
let author_styles = unsafe {
|
||||
(self.0.mServoStyles.mPtr as *const structs::RawServoAuthorStyles
|
||||
as *const bindings::RawServoAuthorStyles)
|
||||
.as_ref()?
|
||||
};
|
||||
let author_styles = unsafe { self.0.mServoStyles.mPtr.as_ref()? };
|
||||
|
||||
let author_styles = AuthorStyles::<GeckoStyleSheet>::from_ffi(author_styles);
|
||||
|
||||
|
@ -326,7 +323,11 @@ impl<'ln> GeckoNode<'ln> {
|
|||
// `flattened_tree_parent`.
|
||||
if self.flattened_tree_parent_is_parent() {
|
||||
debug_assert_eq!(
|
||||
unsafe { bindings::Gecko_GetFlattenedTreeParentNode(self.0).map(GeckoNode) },
|
||||
unsafe {
|
||||
bindings::Gecko_GetFlattenedTreeParentNode(self.0)
|
||||
.as_ref()
|
||||
.map(GeckoNode)
|
||||
},
|
||||
self.parent_node(),
|
||||
"Fast path stopped holding!"
|
||||
);
|
||||
|
@ -336,7 +337,11 @@ impl<'ln> GeckoNode<'ln> {
|
|||
|
||||
// NOTE(emilio): If this call is too expensive, we could manually
|
||||
// inline more aggressively.
|
||||
unsafe { bindings::Gecko_GetFlattenedTreeParentNode(self.0).map(GeckoNode) }
|
||||
unsafe {
|
||||
bindings::Gecko_GetFlattenedTreeParentNode(self.0)
|
||||
.as_ref()
|
||||
.map(GeckoNode)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -381,12 +386,16 @@ impl<'ln> TNode for GeckoNode<'ln> {
|
|||
|
||||
#[inline]
|
||||
fn last_child(&self) -> Option<Self> {
|
||||
unsafe { bindings::Gecko_GetLastChild(self.0).map(GeckoNode) }
|
||||
unsafe { bindings::Gecko_GetLastChild(self.0).as_ref().map(GeckoNode) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn prev_sibling(&self) -> Option<Self> {
|
||||
unsafe { bindings::Gecko_GetPreviousSibling(self.0).map(GeckoNode) }
|
||||
unsafe {
|
||||
bindings::Gecko_GetPreviousSibling(self.0)
|
||||
.as_ref()
|
||||
.map(GeckoNode)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -503,7 +512,9 @@ impl<'a> Iterator for GeckoChildrenIterator<'a> {
|
|||
// however we can't express this easily with bindgen, and it would
|
||||
// introduce functions with two input lifetimes into bindgen,
|
||||
// which would be out of scope for elision.
|
||||
bindings::Gecko_GetNextStyleChild(&mut *(it as *mut _)).map(GeckoNode)
|
||||
bindings::Gecko_GetNextStyleChild(&mut *(it as *mut _))
|
||||
.as_ref()
|
||||
.map(GeckoNode)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -549,7 +560,7 @@ impl<'lb> GeckoXBLBinding<'lb> {
|
|||
base.each_xbl_cascade_data(f);
|
||||
}
|
||||
|
||||
let data = unsafe { bindings::Gecko_XBLBinding_GetRawServoStyles(self.0) };
|
||||
let data = unsafe { bindings::Gecko_XBLBinding_GetRawServoStyles(self.0).as_ref() };
|
||||
|
||||
if let Some(data) = data {
|
||||
let data: &'lb _ = AuthorStyles::<GeckoStyleSheet>::from_ffi(data);
|
||||
|
@ -710,7 +721,11 @@ impl<'le> GeckoElement<'le> {
|
|||
// FIXME(heycam): Having trouble with bindgen on nsXULElement,
|
||||
// where the binding parent is stored in a member variable
|
||||
// rather than in slots. So just get it through FFI for now.
|
||||
unsafe { bindings::Gecko_GetBindingParent(self.0).map(GeckoElement) }
|
||||
unsafe {
|
||||
bindings::Gecko_GetBindingParent(self.0)
|
||||
.as_ref()
|
||||
.map(GeckoElement)
|
||||
}
|
||||
} else {
|
||||
let binding_parent = unsafe { self.non_xul_xbl_binding_parent_raw_content().as_ref() }
|
||||
.map(GeckoNode::from_content)
|
||||
|
@ -718,7 +733,11 @@ impl<'le> GeckoElement<'le> {
|
|||
|
||||
debug_assert!(
|
||||
binding_parent ==
|
||||
unsafe { bindings::Gecko_GetBindingParent(self.0).map(GeckoElement) }
|
||||
unsafe {
|
||||
bindings::Gecko_GetBindingParent(self.0)
|
||||
.as_ref()
|
||||
.map(GeckoElement)
|
||||
}
|
||||
);
|
||||
binding_parent
|
||||
}
|
||||
|
@ -778,7 +797,11 @@ impl<'le> GeckoElement<'le> {
|
|||
return None;
|
||||
}
|
||||
|
||||
unsafe { bindings::Gecko_GetBeforeOrAfterPseudo(self.0, is_before).map(GeckoElement) }
|
||||
unsafe {
|
||||
bindings::Gecko_GetBeforeOrAfterPseudo(self.0, is_before)
|
||||
.as_ref()
|
||||
.map(GeckoElement)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -800,13 +823,8 @@ impl<'le> GeckoElement<'le> {
|
|||
/// animation.
|
||||
///
|
||||
/// Also this function schedules style flush.
|
||||
pub unsafe fn note_explicit_hints(
|
||||
&self,
|
||||
restyle_hint: nsRestyleHint,
|
||||
change_hint: nsChangeHint,
|
||||
) {
|
||||
pub unsafe fn note_explicit_hints(&self, restyle_hint: RestyleHint, change_hint: nsChangeHint) {
|
||||
use crate::gecko::restyle_damage::GeckoRestyleDamage;
|
||||
use crate::invalidation::element::restyle_hints::RestyleHint;
|
||||
|
||||
let damage = GeckoRestyleDamage::new(change_hint);
|
||||
debug!(
|
||||
|
@ -814,7 +832,6 @@ impl<'le> GeckoElement<'le> {
|
|||
self, restyle_hint, change_hint
|
||||
);
|
||||
|
||||
let restyle_hint: RestyleHint = restyle_hint.into();
|
||||
debug_assert!(
|
||||
!(restyle_hint.has_animation_hint() && restyle_hint.has_non_animation_hint()),
|
||||
"Animation restyle hints should not appear with non-animation restyle hints"
|
||||
|
@ -890,7 +907,7 @@ impl<'le> GeckoElement<'le> {
|
|||
let mut map = FxHashMap::with_capacity_and_hasher(collection_length, Default::default());
|
||||
|
||||
for i in 0..collection_length {
|
||||
let raw_end_value = unsafe { Gecko_ElementTransitions_EndValueAt(self.0, i) };
|
||||
let raw_end_value = unsafe { Gecko_ElementTransitions_EndValueAt(self.0, i).as_ref() };
|
||||
|
||||
let end_value = AnimationValue::arc_from_borrowed(&raw_end_value)
|
||||
.expect("AnimationValue not found in ElementTransitions");
|
||||
|
@ -1025,44 +1042,60 @@ impl FontMetricsProvider for GeckoFontMetricsProvider {
|
|||
}
|
||||
|
||||
fn get_size(&self, font_name: &Atom, font_family: u8) -> Au {
|
||||
use crate::gecko_bindings::bindings::Gecko_GetBaseSize;
|
||||
let mut cache = self.font_size_cache.borrow_mut();
|
||||
if let Some(sizes) = cache.iter().find(|el| el.0 == *font_name) {
|
||||
return sizes.1.size_for_generic(font_family);
|
||||
}
|
||||
let sizes = unsafe { Gecko_GetBaseSize(font_name.as_ptr()) };
|
||||
let sizes = unsafe { bindings::Gecko_GetBaseSize(font_name.as_ptr()) };
|
||||
cache.push((font_name.clone(), sizes));
|
||||
sizes.size_for_generic(font_family)
|
||||
}
|
||||
|
||||
fn query(
|
||||
&self,
|
||||
font: &Font,
|
||||
font_size: Au,
|
||||
wm: WritingMode,
|
||||
in_media_query: bool,
|
||||
device: &Device,
|
||||
) -> FontMetricsQueryResult {
|
||||
use crate::gecko_bindings::bindings::Gecko_GetFontMetrics;
|
||||
let pc = match device.pres_context() {
|
||||
context: &crate::values::computed::Context,
|
||||
base_size: FontBaseSize,
|
||||
orientation: FontMetricsOrientation,
|
||||
) -> FontMetrics {
|
||||
let pc = match context.device().pres_context() {
|
||||
Some(pc) => pc,
|
||||
None => return FontMetricsQueryResult::NotAvailable,
|
||||
None => return Default::default(),
|
||||
};
|
||||
|
||||
let size = base_size.resolve(context);
|
||||
let style = context.style();
|
||||
|
||||
let (wm, font) = match base_size {
|
||||
FontBaseSize::CurrentStyle => (style.writing_mode, style.get_font()),
|
||||
// These are only used for font-size computation, and the first is
|
||||
// really dubious...
|
||||
FontBaseSize::InheritedStyleButStripEmUnits | FontBaseSize::InheritedStyle => {
|
||||
(*style.inherited_writing_mode(), style.get_parent_font())
|
||||
},
|
||||
};
|
||||
|
||||
let vertical_metrics = match orientation {
|
||||
FontMetricsOrientation::MatchContext => wm.is_vertical() && wm.is_upright(),
|
||||
FontMetricsOrientation::Horizontal => false,
|
||||
};
|
||||
let gecko_metrics = unsafe {
|
||||
Gecko_GetFontMetrics(
|
||||
bindings::Gecko_GetFontMetrics(
|
||||
pc,
|
||||
wm.is_vertical() && !wm.is_sideways(),
|
||||
vertical_metrics,
|
||||
font.gecko(),
|
||||
font_size.0,
|
||||
size.0,
|
||||
// we don't use the user font set in a media query
|
||||
!in_media_query,
|
||||
!context.in_media_query,
|
||||
)
|
||||
};
|
||||
let metrics = FontMetrics {
|
||||
x_height: Au(gecko_metrics.mXSize),
|
||||
zero_advance_measure: Au(gecko_metrics.mChSize),
|
||||
};
|
||||
FontMetricsQueryResult::Available(metrics)
|
||||
FontMetrics {
|
||||
x_height: Some(Au(gecko_metrics.mXSize)),
|
||||
zero_advance_measure: if gecko_metrics.mChSize >= 0 {
|
||||
Some(Au(gecko_metrics.mChSize))
|
||||
} else {
|
||||
None
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1125,6 +1158,18 @@ impl<'le> TElement for GeckoElement<'le> {
|
|||
self.before_or_after_pseudo(/* is_before = */ false)
|
||||
}
|
||||
|
||||
fn marker_pseudo_element(&self) -> Option<Self> {
|
||||
if !self.has_properties() {
|
||||
return None;
|
||||
}
|
||||
|
||||
unsafe {
|
||||
bindings::Gecko_GetMarkerPseudo(self.0)
|
||||
.as_ref()
|
||||
.map(GeckoElement)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_html_element(&self) -> bool {
|
||||
self.namespace_id() == structs::kNameSpaceID_XHTML as i32
|
||||
|
@ -1254,7 +1299,7 @@ impl<'le> TElement for GeckoElement<'le> {
|
|||
return None;
|
||||
}
|
||||
|
||||
let declarations = unsafe { Gecko_GetStyleAttrDeclarationBlock(self.0) };
|
||||
let declarations = unsafe { Gecko_GetStyleAttrDeclarationBlock(self.0).as_ref() };
|
||||
let declarations: Option<&RawOffsetArc<Locked<PropertyDeclarationBlock>>> =
|
||||
declarations.and_then(|s| s.as_arc_opt());
|
||||
declarations.map(|s| s.borrow_arc())
|
||||
|
@ -1516,7 +1561,7 @@ impl<'le> TElement for GeckoElement<'le> {
|
|||
);
|
||||
unsafe {
|
||||
self.note_explicit_hints(
|
||||
nsRestyleHint::eRestyle_Subtree,
|
||||
RestyleHint::restyle_subtree(),
|
||||
nsChangeHint::nsChangeHint_Empty,
|
||||
);
|
||||
}
|
||||
|
@ -1535,8 +1580,12 @@ impl<'le> TElement for GeckoElement<'le> {
|
|||
// should destroy all CSS animations in display:none subtree.
|
||||
let computed_data = self.borrow_data();
|
||||
let computed_values = computed_data.as_ref().map(|d| d.styles.primary());
|
||||
let before_change_values = before_change_style.as_ref().map(|x| &**x);
|
||||
let computed_values_opt = computed_values.as_ref().map(|x| &***x);
|
||||
let before_change_values = before_change_style
|
||||
.as_ref()
|
||||
.map_or(ptr::null(), |x| x.as_gecko_computed_style());
|
||||
let computed_values_opt = computed_values
|
||||
.as_ref()
|
||||
.map_or(ptr::null(), |x| x.as_gecko_computed_style());
|
||||
unsafe {
|
||||
Gecko_UpdateAnimations(
|
||||
self.0,
|
||||
|
@ -1812,7 +1861,8 @@ impl<'le> TElement for GeckoElement<'le> {
|
|||
hints.push(SVG_TEXT_DISABLE_ZOOM_RULE.clone());
|
||||
}
|
||||
}
|
||||
let declarations = unsafe { Gecko_GetHTMLPresentationAttrDeclarationBlock(self.0) };
|
||||
let declarations =
|
||||
unsafe { Gecko_GetHTMLPresentationAttrDeclarationBlock(self.0).as_ref() };
|
||||
let declarations: Option<&RawOffsetArc<Locked<PropertyDeclarationBlock>>> =
|
||||
declarations.and_then(|s| s.as_arc_opt());
|
||||
if let Some(decl) = declarations {
|
||||
|
@ -1821,7 +1871,7 @@ impl<'le> TElement for GeckoElement<'le> {
|
|||
ServoCascadeLevel::PresHints,
|
||||
));
|
||||
}
|
||||
let declarations = unsafe { Gecko_GetExtraContentStyleDeclarations(self.0) };
|
||||
let declarations = unsafe { Gecko_GetExtraContentStyleDeclarations(self.0).as_ref() };
|
||||
let declarations: Option<&RawOffsetArc<Locked<PropertyDeclarationBlock>>> =
|
||||
declarations.and_then(|s| s.as_arc_opt());
|
||||
if let Some(decl) = declarations {
|
||||
|
@ -1843,10 +1893,10 @@ impl<'le> TElement for GeckoElement<'le> {
|
|||
);
|
||||
},
|
||||
VisitedHandlingMode::AllLinksUnvisited => unsafe {
|
||||
Gecko_GetUnvisitedLinkAttrDeclarationBlock(self.0)
|
||||
Gecko_GetUnvisitedLinkAttrDeclarationBlock(self.0).as_ref()
|
||||
},
|
||||
VisitedHandlingMode::RelevantLinkVisited => unsafe {
|
||||
Gecko_GetVisitedLinkAttrDeclarationBlock(self.0)
|
||||
Gecko_GetVisitedLinkAttrDeclarationBlock(self.0).as_ref()
|
||||
},
|
||||
};
|
||||
let declarations: Option<&RawOffsetArc<Locked<PropertyDeclarationBlock>>> =
|
||||
|
@ -1862,7 +1912,8 @@ impl<'le> TElement for GeckoElement<'le> {
|
|||
.state()
|
||||
.intersects(NonTSPseudoClass::Active.state_flag());
|
||||
if active {
|
||||
let declarations = unsafe { Gecko_GetActiveLinkAttrDeclarationBlock(self.0) };
|
||||
let declarations =
|
||||
unsafe { Gecko_GetActiveLinkAttrDeclarationBlock(self.0).as_ref() };
|
||||
let declarations: Option<&RawOffsetArc<Locked<PropertyDeclarationBlock>>> =
|
||||
declarations.and_then(|s| s.as_arc_opt());
|
||||
if let Some(decl) = declarations {
|
||||
|
|
|
@ -4,11 +4,6 @@
|
|||
|
||||
//! Gecko's C++ bindings, along with some rust helpers to ease its use.
|
||||
|
||||
#[allow(dead_code, improper_ctypes, non_camel_case_types, missing_docs)]
|
||||
pub mod bindings {
|
||||
include!(concat!(env!("OUT_DIR"), "/gecko/bindings.rs"));
|
||||
}
|
||||
|
||||
// FIXME: We allow `improper_ctypes` (for now), because the lint doesn't allow
|
||||
// foreign structs to have `PhantomData`. We should remove this once the lint
|
||||
// ignores this case.
|
||||
|
@ -25,4 +20,6 @@ pub mod structs {
|
|||
include!(concat!(env!("OUT_DIR"), "/gecko/structs.rs"));
|
||||
}
|
||||
|
||||
pub use self::structs as bindings;
|
||||
|
||||
pub mod sugar;
|
||||
|
|
|
@ -135,12 +135,12 @@ pub unsafe trait HasArcFFI: HasFFI {
|
|||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
/// Gecko-FFI-safe Arc (T is an ArcInner).
|
||||
///
|
||||
/// This can be null.
|
||||
///
|
||||
/// Leaks on drop. Please don't drop this.
|
||||
#[repr(C)]
|
||||
pub struct Strong<GeckoType> {
|
||||
ptr: *const GeckoType,
|
||||
_marker: PhantomData<GeckoType>,
|
||||
|
@ -320,27 +320,6 @@ impl<GeckoType> OwnedOrNull<GeckoType> {
|
|||
self.ptr.is_null()
|
||||
}
|
||||
|
||||
/// Returns an owned pointer if this is non-null, and `None` otherwise.
|
||||
pub fn into_box_opt<ServoType>(self) -> Option<Box<ServoType>>
|
||||
where
|
||||
ServoType: HasBoxFFI<FFIType = GeckoType>,
|
||||
{
|
||||
if self.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(unsafe { transmute(self) })
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns an `Owned<GeckoType>` if non-null, `None` otherwise.
|
||||
pub fn into_owned_opt(self) -> Option<Owned<GeckoType>> {
|
||||
if self.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(unsafe { transmute(self) })
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets a immutable reference to the underlying Gecko type, or `None` if
|
||||
/// null.
|
||||
pub fn borrow(&self) -> Option<&GeckoType> {
|
||||
|
|
|
@ -285,7 +285,7 @@ macro_rules! impl_threadsafe_refcount {
|
|||
}
|
||||
|
||||
impl_threadsafe_refcount!(
|
||||
structs::RawGeckoURLExtraData,
|
||||
structs::mozilla::URLExtraData,
|
||||
bindings::Gecko_AddRefURLExtraDataArbitraryThread,
|
||||
bindings::Gecko_ReleaseURLExtraDataArbitraryThread
|
||||
);
|
||||
|
|
|
@ -11,7 +11,6 @@ use crate::parallel::STYLE_THREAD_STACK_SIZE_KB;
|
|||
use crate::shared_lock::SharedRwLock;
|
||||
use crate::thread_state;
|
||||
use rayon;
|
||||
use servo_config::pref;
|
||||
use std::env;
|
||||
|
||||
/// Global style data
|
||||
|
@ -67,6 +66,7 @@ lazy_static! {
|
|||
Ok(num) => num,
|
||||
#[cfg(feature = "servo")]
|
||||
_ => {
|
||||
use servo_config::pref;
|
||||
// We always set this pref on startup, before layout or script
|
||||
// have had a chance of accessing (and thus creating) the
|
||||
// thread-pool.
|
||||
|
|
|
@ -542,6 +542,10 @@ where
|
|||
any_descendant |= self.invalidate_dom_descendants_of(anon_content, invalidations);
|
||||
}
|
||||
|
||||
if let Some(marker) = self.element.marker_pseudo_element() {
|
||||
any_descendant |= self.invalidate_pseudo_element_or_nac(marker, invalidations);
|
||||
}
|
||||
|
||||
if let Some(before) = self.element.before_pseudo_element() {
|
||||
any_descendant |= self.invalidate_pseudo_element_or_nac(before, invalidations);
|
||||
}
|
||||
|
|
|
@ -4,12 +4,11 @@
|
|||
|
||||
//! Restyle hints: an optimization to avoid unnecessarily matching selectors.
|
||||
|
||||
#[cfg(feature = "gecko")]
|
||||
use crate::gecko_bindings::structs::nsRestyleHint;
|
||||
use crate::traversal_flags::TraversalFlags;
|
||||
|
||||
bitflags! {
|
||||
/// The kind of restyle we need to do for a given element.
|
||||
#[repr(C)]
|
||||
pub struct RestyleHint: u8 {
|
||||
/// Do a selector match of the element.
|
||||
const RESTYLE_SELF = 1 << 0;
|
||||
|
@ -190,75 +189,5 @@ impl Default for RestyleHint {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "gecko")]
|
||||
impl From<nsRestyleHint> for RestyleHint {
|
||||
fn from(mut raw: nsRestyleHint) -> Self {
|
||||
let mut hint = RestyleHint::empty();
|
||||
|
||||
debug_assert!(
|
||||
raw.0 & nsRestyleHint::eRestyle_LaterSiblings.0 == 0,
|
||||
"Handle later siblings manually if necessary plz."
|
||||
);
|
||||
|
||||
if (raw.0 & (nsRestyleHint::eRestyle_Self.0 | nsRestyleHint::eRestyle_Subtree.0)) != 0 {
|
||||
raw.0 &= !nsRestyleHint::eRestyle_Self.0;
|
||||
hint.insert(RestyleHint::RESTYLE_SELF);
|
||||
}
|
||||
|
||||
if (raw.0 & (nsRestyleHint::eRestyle_Subtree.0 | nsRestyleHint::eRestyle_SomeDescendants.0)) !=
|
||||
0
|
||||
{
|
||||
raw.0 &= !nsRestyleHint::eRestyle_Subtree.0;
|
||||
raw.0 &= !nsRestyleHint::eRestyle_SomeDescendants.0;
|
||||
hint.insert(RestyleHint::RESTYLE_DESCENDANTS);
|
||||
}
|
||||
|
||||
if (raw.0 & (nsRestyleHint::eRestyle_ForceDescendants.0 | nsRestyleHint::eRestyle_Force.0)) !=
|
||||
0
|
||||
{
|
||||
raw.0 &= !nsRestyleHint::eRestyle_Force.0;
|
||||
hint.insert(RestyleHint::RECASCADE_SELF);
|
||||
}
|
||||
|
||||
if (raw.0 & nsRestyleHint::eRestyle_ForceDescendants.0) != 0 {
|
||||
raw.0 &= !nsRestyleHint::eRestyle_ForceDescendants.0;
|
||||
hint.insert(RestyleHint::RECASCADE_DESCENDANTS);
|
||||
}
|
||||
|
||||
hint.insert(RestyleHint::from_bits_truncate(raw.0 as u8));
|
||||
|
||||
hint
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "servo")]
|
||||
malloc_size_of_is_0!(RestyleHint);
|
||||
|
||||
/// Asserts that all replacement hints have a matching nsRestyleHint value.
|
||||
#[cfg(feature = "gecko")]
|
||||
#[inline]
|
||||
pub fn assert_restyle_hints_match() {
|
||||
use crate::gecko_bindings::structs;
|
||||
|
||||
macro_rules! check_restyle_hints {
|
||||
( $( $a:ident => $b:path),*, ) => {
|
||||
if cfg!(debug_assertions) {
|
||||
let mut replacements = RestyleHint::replacements();
|
||||
$(
|
||||
assert_eq!(structs::nsRestyleHint::$a.0 as usize, $b.bits() as usize, stringify!($b));
|
||||
replacements.remove($b);
|
||||
)*
|
||||
assert_eq!(replacements, RestyleHint::empty(),
|
||||
"all RestyleHint replacement bits should have an \
|
||||
assertion");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
check_restyle_hints! {
|
||||
eRestyle_CSSTransitions => RestyleHint::RESTYLE_CSS_TRANSITIONS,
|
||||
eRestyle_CSSAnimations => RestyleHint::RESTYLE_CSS_ANIMATIONS,
|
||||
eRestyle_StyleAttribute => RestyleHint::RESTYLE_STYLE_ATTRIBUTE,
|
||||
eRestyle_StyleAttribute_Animations => RestyleHint::RESTYLE_SMIL,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -102,20 +102,3 @@ macro_rules! define_keyword_type {
|
|||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(feature = "gecko")]
|
||||
macro_rules! impl_bitflags_conversions {
|
||||
($name:ident) => {
|
||||
impl From<u8> for $name {
|
||||
fn from(bits: u8) -> $name {
|
||||
$name::from_bits(bits).expect("bits contain valid flag")
|
||||
}
|
||||
}
|
||||
|
||||
impl From<$name> for u8 {
|
||||
fn from(v: $name) -> u8 {
|
||||
v.bits()
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -384,8 +384,6 @@ struct Cascade<'a, 'b: 'a> {
|
|||
cascade_mode: CascadeMode<'a>,
|
||||
seen: LonghandIdSet,
|
||||
reverted: PerOrigin<LonghandIdSet>,
|
||||
saved_font_size: Option<PropertyDeclaration>,
|
||||
saved_font_family: Option<PropertyDeclaration>,
|
||||
}
|
||||
|
||||
impl<'a, 'b: 'a> Cascade<'a, 'b> {
|
||||
|
@ -395,8 +393,6 @@ impl<'a, 'b: 'a> Cascade<'a, 'b> {
|
|||
cascade_mode,
|
||||
seen: LonghandIdSet::default(),
|
||||
reverted: Default::default(),
|
||||
saved_font_size: None,
|
||||
saved_font_family: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -424,33 +420,8 @@ impl<'a, 'b: 'a> Cascade<'a, 'b> {
|
|||
))
|
||||
}
|
||||
|
||||
fn apply_declaration<Phase: CascadePhase>(
|
||||
&mut self,
|
||||
longhand_id: LonghandId,
|
||||
declaration: &PropertyDeclaration,
|
||||
) {
|
||||
// FIXME(emilio): Find a cleaner abstraction for this.
|
||||
//
|
||||
// font-size and font-family are special because in Gecko they're
|
||||
// they're dependent on other early props, like lang and
|
||||
// -moz-min-font-size-ratio. This sucks a bit, we should ideally
|
||||
// move the font-size computation code somewhere else...
|
||||
if Phase::is_early() {
|
||||
if longhand_id == LonghandId::FontSize {
|
||||
self.saved_font_size = Some(declaration.clone());
|
||||
return;
|
||||
}
|
||||
if longhand_id == LonghandId::FontFamily {
|
||||
self.saved_font_family = Some(declaration.clone());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
self.apply_declaration_ignoring_phase(longhand_id, declaration);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn apply_declaration_ignoring_phase(
|
||||
fn apply_declaration<Phase: CascadePhase>(
|
||||
&mut self,
|
||||
longhand_id: LonghandId,
|
||||
declaration: &PropertyDeclaration,
|
||||
|
@ -577,7 +548,7 @@ impl<'a, 'b: 'a> Cascade<'a, 'b> {
|
|||
}
|
||||
|
||||
if Phase::is_early() {
|
||||
self.fixup_font_and_apply_saved_font_properties();
|
||||
self.fixup_font_stuff();
|
||||
self.compute_writing_mode();
|
||||
} else {
|
||||
self.finished_applying_properties();
|
||||
|
@ -702,30 +673,156 @@ impl<'a, 'b: 'a> Cascade<'a, 'b> {
|
|||
true
|
||||
}
|
||||
|
||||
// FIXME(emilio): It'd be really nice to simplify all this, somehow. This is
|
||||
// very annoying code in lots of ways, and there are various bits about it
|
||||
// which I think are broken or could be improved, see the various FIXMEs
|
||||
// below.
|
||||
fn fixup_font_and_apply_saved_font_properties(&mut self) {
|
||||
let font_family = self.saved_font_family.take();
|
||||
let font_size = self.saved_font_size.take();
|
||||
let mut _skip_font_family = false;
|
||||
|
||||
/// The default font type (which is stored in FontFamilyList's
|
||||
/// `mDefaultFontType`) depends on the current lang group and generic font
|
||||
/// family, so we may need to recompute it if or the family changed.
|
||||
///
|
||||
/// Also, we prioritize non-document fonts here if we need to (see the pref
|
||||
/// `browser.display.use_document_fonts`).
|
||||
#[inline]
|
||||
#[cfg(feature = "gecko")]
|
||||
{
|
||||
// <svg:text> is not affected by text zoom, and it uses a preshint
|
||||
// to disable it. We fix up the struct when this happens by
|
||||
// unzooming its contained font values, which will have been zoomed
|
||||
// in the parent.
|
||||
//
|
||||
// FIXME(emilio): Could be cleaner if we just removed this property
|
||||
// and made a style adjustment o something like that.
|
||||
if self.seen.contains(LonghandId::XTextZoom) {
|
||||
fn recompute_default_font_family_type_if_needed(&mut self) {
|
||||
use crate::gecko_bindings::{bindings, structs};
|
||||
|
||||
if !self.seen.contains(LonghandId::XLang) &&
|
||||
!self.seen.contains(LonghandId::FontFamily) {
|
||||
return;
|
||||
}
|
||||
|
||||
let use_document_fonts = unsafe { structs::StaticPrefs_sVarCache_browser_display_use_document_fonts != 0 };
|
||||
let builder = &mut self.context.builder;
|
||||
let (default_font_type, prioritize_user_fonts) = {
|
||||
let font = builder.get_font().gecko();
|
||||
|
||||
// System fonts are all right, and should have the default font type
|
||||
// set to none already, so bail out early.
|
||||
if font.mFont.systemFont {
|
||||
debug_assert_eq!(font.mFont.fontlist.mDefaultFontType, structs::FontFamilyType::eFamily_none);
|
||||
return;
|
||||
}
|
||||
|
||||
let default_font_type = unsafe {
|
||||
bindings::Gecko_nsStyleFont_ComputeDefaultFontType(
|
||||
builder.device.document(),
|
||||
font.mGenericID,
|
||||
font.mLanguage.mRawPtr,
|
||||
)
|
||||
};
|
||||
|
||||
// We prioritize user fonts over document fonts if the pref is set,
|
||||
// and we don't have a generic family already (or we're using
|
||||
// cursive or fantasy, since they're ignored, see bug 789788), and
|
||||
// we have a generic family to actually replace it with.
|
||||
let prioritize_user_fonts =
|
||||
!use_document_fonts &&
|
||||
matches!(
|
||||
font.mGenericID,
|
||||
structs::kGenericFont_NONE |
|
||||
structs::kGenericFont_fantasy |
|
||||
structs::kGenericFont_cursive
|
||||
) &&
|
||||
default_font_type != structs::FontFamilyType::eFamily_none;
|
||||
|
||||
if !prioritize_user_fonts && default_font_type == font.mFont.fontlist.mDefaultFontType {
|
||||
// Nothing to do.
|
||||
return;
|
||||
}
|
||||
(default_font_type, prioritize_user_fonts)
|
||||
};
|
||||
|
||||
let font = builder.mutate_font().gecko_mut();
|
||||
font.mFont.fontlist.mDefaultFontType = default_font_type;
|
||||
if prioritize_user_fonts {
|
||||
unsafe {
|
||||
bindings::Gecko_nsStyleFont_PrioritizeUserFonts(font, default_font_type)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Some keyword sizes depend on the font family and language.
|
||||
#[cfg(feature = "gecko")]
|
||||
fn recompute_keyword_font_size_if_needed(&mut self) {
|
||||
use crate::values::computed::ToComputedValue;
|
||||
use crate::values::specified;
|
||||
|
||||
if !self.seen.contains(LonghandId::XLang) &&
|
||||
!self.seen.contains(LonghandId::FontFamily) {
|
||||
return;
|
||||
}
|
||||
|
||||
let new_size = {
|
||||
let font = self.context.builder.get_font();
|
||||
let new_size = match font.clone_font_size().keyword_info {
|
||||
Some(info) => {
|
||||
self.context.for_non_inherited_property = None;
|
||||
specified::FontSize::Keyword(info).to_computed_value(self.context)
|
||||
}
|
||||
None => return,
|
||||
};
|
||||
|
||||
if font.gecko().mScriptUnconstrainedSize == new_size.size().0 {
|
||||
return;
|
||||
}
|
||||
|
||||
new_size
|
||||
};
|
||||
|
||||
self.context.builder.mutate_font().set_font_size(new_size);
|
||||
}
|
||||
|
||||
/// Some properties, plus setting font-size itself, may make us go out of
|
||||
/// our minimum font-size range.
|
||||
#[cfg(feature = "gecko")]
|
||||
fn constrain_font_size_if_needed(&mut self) {
|
||||
use crate::gecko_bindings::bindings;
|
||||
|
||||
if !self.seen.contains(LonghandId::XLang) &&
|
||||
!self.seen.contains(LonghandId::FontFamily) &&
|
||||
!self.seen.contains(LonghandId::MozMinFontSizeRatio) &&
|
||||
!self.seen.contains(LonghandId::FontSize) {
|
||||
return;
|
||||
}
|
||||
|
||||
let builder = &mut self.context.builder;
|
||||
let min_font_size = {
|
||||
let font = builder.get_font().gecko();
|
||||
let min_font_size = unsafe {
|
||||
bindings::Gecko_nsStyleFont_ComputeMinSize(
|
||||
font,
|
||||
builder.device.document(),
|
||||
)
|
||||
};
|
||||
|
||||
if font.mFont.size >= min_font_size {
|
||||
return;
|
||||
}
|
||||
|
||||
min_font_size
|
||||
};
|
||||
|
||||
builder.mutate_font().gecko_mut().mFont.size = min_font_size;
|
||||
}
|
||||
|
||||
/// <svg:text> is not affected by text zoom, and it uses a preshint
|
||||
/// to disable it. We fix up the struct when this happens by
|
||||
/// unzooming its contained font values, which will have been zoomed
|
||||
/// in the parent.
|
||||
///
|
||||
/// FIXME(emilio): Also, why doing this _before_ handling font-size? That
|
||||
/// sounds wrong.
|
||||
#[cfg(feature = "gecko")]
|
||||
fn unzoom_fonts_if_needed(&mut self) {
|
||||
if !self.seen.contains(LonghandId::XTextZoom) {
|
||||
return;
|
||||
}
|
||||
|
||||
let builder = &mut self.context.builder;
|
||||
|
||||
let parent_zoom = builder.get_parent_font().gecko().mAllowZoom;
|
||||
let zoom = builder.get_font().gecko().mAllowZoom;
|
||||
if zoom != parent_zoom {
|
||||
if zoom == parent_zoom {
|
||||
return;
|
||||
}
|
||||
debug_assert!(
|
||||
!zoom,
|
||||
"We only ever disable text zoom (in svg:text), never enable it"
|
||||
|
@ -733,111 +830,92 @@ impl<'a, 'b: 'a> Cascade<'a, 'b> {
|
|||
let device = builder.device;
|
||||
builder.mutate_font().unzoom_fonts(device);
|
||||
}
|
||||
|
||||
/// MathML script* attributes do some very weird shit with font-size.
|
||||
///
|
||||
/// Handle them specially here, separate from other font-size stuff.
|
||||
///
|
||||
/// How this should interact with lang="" and font-family-dependent sizes is
|
||||
/// not clear to me. For now just pretend those don't exist here.
|
||||
#[cfg(feature = "gecko")]
|
||||
fn handle_mathml_scriptlevel_if_needed(&mut self) {
|
||||
use app_units::Au;
|
||||
use std::cmp;
|
||||
|
||||
if !self.seen.contains(LonghandId::MozScriptLevel) &&
|
||||
!self.seen.contains(LonghandId::MozScriptMinSize) &&
|
||||
!self.seen.contains(LonghandId::MozScriptSizeMultiplier) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Whenever a single generic value is specified, Gecko used to do a
|
||||
// bunch of recalculation walking up the rule tree, including
|
||||
// handling the font-size stuff.
|
||||
//
|
||||
// It basically repopulated the font struct with the default font
|
||||
// for a given generic and language. We handle the font-size stuff
|
||||
// separately, so this boils down to just copying over the
|
||||
// font-family lists (no other aspect of the default font can be
|
||||
// configured).
|
||||
if self.seen.contains(LonghandId::XLang) || self.seen.contains(LonghandId::FontFamily) {
|
||||
// If just the language changed, the inherited generic is all we
|
||||
// need.
|
||||
let mut generic = self.context.builder.get_parent_font().gecko().mGenericID;
|
||||
|
||||
// FIXME(emilio): Isn't this bogus for CSS wide keywords like
|
||||
// reset or such?
|
||||
if let Some(ref declaration) = font_family {
|
||||
if let PropertyDeclaration::FontFamily(ref fam) = *declaration {
|
||||
if let Some(id) = fam.single_generic() {
|
||||
generic = id;
|
||||
// In case of a specified font family with a single
|
||||
// generic, we will end up setting font family
|
||||
// below, but its value would get overwritten later
|
||||
// in the pipeline when cascading.
|
||||
//
|
||||
// We instead skip cascading font-family in that
|
||||
// case.
|
||||
//
|
||||
// In case of the language changing, we wish for a
|
||||
// specified font-family to override this, so we do
|
||||
// not skip cascading then.
|
||||
_skip_font_family = true;
|
||||
}
|
||||
}
|
||||
// If the user specifies a font-size, just let it be.
|
||||
if self.seen.contains(LonghandId::FontSize) {
|
||||
return;
|
||||
}
|
||||
|
||||
// FIXME(emilio): Why both setting the generic and passing it
|
||||
// down?
|
||||
let doc = self.context.builder.device.document();
|
||||
let gecko_font = self.context.builder.mutate_font().gecko_mut();
|
||||
gecko_font.mGenericID = generic;
|
||||
unsafe {
|
||||
crate::gecko_bindings::bindings::Gecko_nsStyleFont_PrefillDefaultForGeneric(
|
||||
gecko_font,
|
||||
doc,
|
||||
generic,
|
||||
);
|
||||
}
|
||||
}
|
||||
let builder = &mut self.context.builder;
|
||||
let (new_size, new_unconstrained_size) = {
|
||||
let font = builder.get_font().gecko();
|
||||
let parent_font = builder.get_parent_font().gecko();
|
||||
|
||||
let delta =
|
||||
font.mScriptLevel.saturating_sub(parent_font.mScriptLevel);
|
||||
|
||||
if delta == 0 {
|
||||
return;
|
||||
}
|
||||
|
||||
// It is important that font-size is computed before the late
|
||||
// properties (for em units), but after font-family (for the
|
||||
// base-font-size dependence for default and keyword font-sizes).
|
||||
//
|
||||
// It's important that font-family comes after the other font properties
|
||||
// to support system fonts.
|
||||
//
|
||||
// NOTE(emilio): I haven't verified that comment, but it was there.
|
||||
// Verify, and if it's false make font-size the only weird property?
|
||||
if !_skip_font_family {
|
||||
if let Some(ref declaration) = font_family {
|
||||
self.apply_declaration_ignoring_phase(LonghandId::FontFamily, declaration);
|
||||
let mut min = Au(parent_font.mScriptMinSize);
|
||||
if font.mAllowZoom {
|
||||
min = builder.device.zoom_text(min);
|
||||
}
|
||||
|
||||
let scale = (parent_font.mScriptSizeMultiplier as f32).powi(delta as i32);
|
||||
let parent_size = Au(parent_font.mSize);
|
||||
let parent_unconstrained_size = Au(parent_font.mScriptUnconstrainedSize);
|
||||
let new_size = parent_size.scale_by(scale);
|
||||
let new_unconstrained_size = parent_unconstrained_size.scale_by(scale);
|
||||
|
||||
if scale <= 1. {
|
||||
// The parent size can be smaller than scriptminsize, e.g. if it
|
||||
// was specified explicitly. Don't scale in this case, but we
|
||||
// don't want to set it to scriptminsize either since that will
|
||||
// make it larger.
|
||||
if parent_size <= min {
|
||||
(parent_size, new_unconstrained_size)
|
||||
} else {
|
||||
(cmp::max(min, new_size), new_unconstrained_size)
|
||||
}
|
||||
} else {
|
||||
// If the new unconstrained size is larger than the min size,
|
||||
// this means we have escaped the grasp of scriptminsize and can
|
||||
// revert to using the unconstrained size.
|
||||
// However, if the new size is even larger (perhaps due to usage
|
||||
// of em units), use that instead.
|
||||
(
|
||||
cmp::min(new_size, cmp::max(new_unconstrained_size, min)),
|
||||
new_unconstrained_size
|
||||
)
|
||||
}
|
||||
};
|
||||
let font = builder.mutate_font().gecko_mut();
|
||||
font.mFont.size = new_size.0;
|
||||
font.mSize = new_size.0;
|
||||
font.mScriptUnconstrainedSize = new_unconstrained_size.0;
|
||||
}
|
||||
|
||||
/// Various properties affect how font-size and font-family are computed.
|
||||
///
|
||||
/// These need to be handled here, since relative lengths and ex / ch units
|
||||
/// for late properties depend on these.
|
||||
fn fixup_font_stuff(&mut self) {
|
||||
#[cfg(feature = "gecko")]
|
||||
{
|
||||
let context = &mut self.context;
|
||||
let device = context.builder.device;
|
||||
if let PropertyDeclaration::FontFamily(ref val) = *declaration {
|
||||
if val.get_system().is_some() {
|
||||
let default = context
|
||||
.cached_system_font
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.default_font_type;
|
||||
context.builder.mutate_font().fixup_system(default);
|
||||
} else {
|
||||
context.builder.mutate_font().fixup_none_generic(device);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(declaration) = font_size {
|
||||
self.apply_declaration_ignoring_phase(LonghandId::FontSize, &declaration);
|
||||
} else {
|
||||
#[cfg(feature = "gecko")]
|
||||
{
|
||||
if self.seen.contains(LonghandId::XLang) ||
|
||||
self.seen.contains(LonghandId::MozScriptLevel) ||
|
||||
self.seen.contains(LonghandId::MozMinFontSizeRatio) ||
|
||||
self.seen.contains(LonghandId::FontFamily)
|
||||
{
|
||||
use crate::values::computed::FontSize;
|
||||
|
||||
// font-size must be explicitly inherited to handle lang
|
||||
// changes and scriptlevel changes.
|
||||
//
|
||||
// FIXME(emilio): That looks a bit bogus...
|
||||
self.context.for_non_inherited_property = None;
|
||||
FontSize::cascade_inherit_font_size(&mut self.context);
|
||||
}
|
||||
}
|
||||
self.unzoom_fonts_if_needed();
|
||||
self.recompute_default_font_family_type_if_needed();
|
||||
self.recompute_keyword_font_size_if_needed();
|
||||
self.handle_mathml_scriptlevel_if_needed();
|
||||
self.constrain_font_size_if_needed()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -56,10 +56,13 @@ bitflags! {
|
|||
/// Whether the child explicitly inherits any reset property.
|
||||
const INHERITS_RESET_STYLE = 1 << 8;
|
||||
|
||||
/// Whether any value on our style is font-metric-dependent.
|
||||
const DEPENDS_ON_FONT_METRICS = 1 << 9;
|
||||
|
||||
/// Whether the style or any of the ancestors has a multicol style.
|
||||
///
|
||||
/// Only used in Servo.
|
||||
const CAN_BE_FRAGMENTED = 1 << 9;
|
||||
const CAN_BE_FRAGMENTED = 1 << 10;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -94,3 +97,22 @@ impl ComputedValueFlags {
|
|||
self & Self::maybe_inherited_flags()
|
||||
}
|
||||
}
|
||||
|
||||
/// Asserts that the relevant servo and Gecko representations match.
|
||||
#[cfg(feature = "gecko")]
|
||||
#[inline]
|
||||
pub fn assert_match() {
|
||||
use crate::gecko_bindings::structs;
|
||||
macro_rules! assert_bit {
|
||||
($rust:ident, $cpp:ident) => {
|
||||
debug_assert_eq!(ComputedValueFlags::$rust.bits, structs::$cpp);
|
||||
}
|
||||
}
|
||||
|
||||
assert_bit!(HAS_TEXT_DECORATION_LINES, ComputedStyleBit_HasTextDecorationLines);
|
||||
assert_bit!(IS_IN_PSEUDO_ELEMENT_SUBTREE, ComputedStyleBit_HasPseudoElementData);
|
||||
assert_bit!(SHOULD_SUPPRESS_LINEBREAK, ComputedStyleBit_SuppressLineBreak);
|
||||
assert_bit!(IS_TEXT_COMBINED, ComputedStyleBit_IsTextCombined);
|
||||
assert_bit!(IS_RELEVANT_LINK_VISITED, ComputedStyleBit_RelevantLinkVisited);
|
||||
assert_bit!(DEPENDS_ON_FONT_METRICS, ComputedStyleBit_DependsOnFontMetrics);
|
||||
}
|
||||
|
|
|
@ -324,6 +324,7 @@ class Longhand(object):
|
|||
"JustifyItems",
|
||||
"JustifySelf",
|
||||
"MozForceBrokenImageIcon",
|
||||
"MozListReversed",
|
||||
"MozScriptLevel",
|
||||
"MozScriptMinSize",
|
||||
"MozScriptSizeMultiplier",
|
||||
|
|
|
@ -66,16 +66,25 @@ use crate::values::generics::url::UrlOrNone;
|
|||
pub mod style_structs {
|
||||
% for style_struct in data.style_structs:
|
||||
pub use super::${style_struct.gecko_struct_name} as ${style_struct.name};
|
||||
|
||||
unsafe impl Send for ${style_struct.name} {}
|
||||
unsafe impl Sync for ${style_struct.name} {}
|
||||
% endfor
|
||||
|
||||
}
|
||||
|
||||
/// FIXME(emilio): This is completely duplicated with the other properties code.
|
||||
pub type ComputedValuesInner = crate::gecko_bindings::structs::ServoComputedData;
|
||||
pub type ComputedValuesInner = structs::ServoComputedData;
|
||||
|
||||
#[repr(C)]
|
||||
pub struct ComputedValues(crate::gecko_bindings::structs::mozilla::ComputedStyle);
|
||||
pub struct ComputedValues(structs::mozilla::ComputedStyle);
|
||||
|
||||
impl ComputedValues {
|
||||
#[inline]
|
||||
pub (crate) fn as_gecko_computed_style(&self) -> &structs::ComputedStyle {
|
||||
&self.0
|
||||
}
|
||||
|
||||
pub fn new(
|
||||
pseudo: Option<<&PseudoElement>,
|
||||
custom_properties: Option<Arc<CustomPropertiesMap>>,
|
||||
|
@ -929,7 +938,7 @@ transform_functions = [
|
|||
debug_assert!(!${item}${index + 1}.0.is_empty());
|
||||
% endif
|
||||
${css_value_setters[item] % (
|
||||
"bindings::Gecko_CSSValue_GetArrayItem(gecko_value, %d)" % (index + 1),
|
||||
"(&mut *bindings::Gecko_CSSValue_GetArrayItem(gecko_value, %d))" % (index + 1),
|
||||
item + str(index + 1)
|
||||
)};
|
||||
% endfor
|
||||
|
@ -980,7 +989,7 @@ transform_functions = [
|
|||
% endif
|
||||
<%
|
||||
getter = css_value_getters[item] % (
|
||||
"bindings::Gecko_CSSValue_GetArrayItemConst(gecko_value, %d)" % (index + 1)
|
||||
"(&*bindings::Gecko_CSSValue_GetArrayItemConst(gecko_value, %d))" % (index + 1)
|
||||
)
|
||||
%>
|
||||
${getter},
|
||||
|
@ -989,6 +998,7 @@ transform_functions = [
|
|||
},
|
||||
</%def>
|
||||
|
||||
#[allow(unused_parens)]
|
||||
fn set_single_transform_function(
|
||||
servo_value: &values::computed::TransformOperation,
|
||||
gecko_value: &mut structs::nsCSSValue /* output */
|
||||
|
@ -1031,6 +1041,7 @@ pub fn convert_transform(
|
|||
output.set_move(list);
|
||||
}
|
||||
|
||||
#[allow(unused_parens)]
|
||||
fn clone_single_transform_function(
|
||||
gecko_value: &structs::nsCSSValue
|
||||
) -> values::computed::TransformOperation {
|
||||
|
@ -1236,6 +1247,7 @@ impl Clone for ${style_struct.gecko_struct_name} {
|
|||
"Length": impl_absolute_length,
|
||||
"LengthOrNormal": impl_style_coord,
|
||||
"LengthPercentageOrAuto": impl_style_coord,
|
||||
"MozListReversed": impl_simple,
|
||||
"MozScriptMinSize": impl_absolute_length,
|
||||
"RGBAColor": impl_rgba_color,
|
||||
"SVGLength": impl_svg_length,
|
||||
|
@ -1971,25 +1983,19 @@ fn static_assert() {
|
|||
<% impl_font_settings("font_feature_settings", "gfxFontFeature", "FeatureTagValue", "i32", "u32") %>
|
||||
<% impl_font_settings("font_variation_settings", "gfxFontVariation", "VariationValue", "f32", "f32") %>
|
||||
|
||||
pub fn fixup_none_generic(&mut self, device: &Device) {
|
||||
self.gecko.mFont.systemFont = false;
|
||||
unsafe {
|
||||
bindings::Gecko_nsStyleFont_FixupNoneGeneric(&mut self.gecko, device.document())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fixup_system(&mut self, default_font_type: structs::FontFamilyType) {
|
||||
self.gecko.mFont.systemFont = true;
|
||||
self.gecko.mGenericID = structs::kGenericFont_NONE;
|
||||
self.gecko.mFont.fontlist.mDefaultFontType = default_font_type;
|
||||
}
|
||||
|
||||
pub fn set_font_family(&mut self, v: longhands::font_family::computed_value::T) {
|
||||
self.gecko.mGenericID = structs::kGenericFont_NONE;
|
||||
if let Some(generic) = v.0.single_generic() {
|
||||
self.gecko.mGenericID = generic;
|
||||
}
|
||||
self.gecko.mFont.fontlist.mFontlist.mBasePtr.set_move((v.0).0.clone());
|
||||
use crate::gecko_bindings::structs::FontFamilyType;
|
||||
|
||||
let is_system_font = v.is_system_font;
|
||||
self.gecko.mFont.systemFont = is_system_font;
|
||||
self.gecko.mGenericID = if is_system_font {
|
||||
structs::kGenericFont_NONE
|
||||
} else {
|
||||
v.families.single_generic().unwrap_or(structs::kGenericFont_NONE)
|
||||
};
|
||||
self.gecko.mFont.fontlist.mFontlist.mBasePtr.set_move(v.families.0.clone());
|
||||
// Fixed-up if needed in Cascade::fixup_font_stuff.
|
||||
self.gecko.mFont.fontlist.mDefaultFontType = FontFamilyType::eFamily_none;
|
||||
}
|
||||
|
||||
pub fn copy_font_family_from(&mut self, other: &Self) {
|
||||
|
@ -2009,7 +2015,7 @@ fn static_assert() {
|
|||
let fontlist = &self.gecko.mFont.fontlist;
|
||||
let shared_fontlist = unsafe { fontlist.mFontlist.mBasePtr.to_safe() };
|
||||
|
||||
if shared_fontlist.mNames.is_empty() {
|
||||
let families = if shared_fontlist.mNames.is_empty() {
|
||||
let default = fontlist.mDefaultFontType;
|
||||
let default = match default {
|
||||
FontFamilyType::eFamily_serif => {
|
||||
|
@ -2030,9 +2036,14 @@ fn static_assert() {
|
|||
SingleFontFamily::Generic(atom!("sans-serif"))
|
||||
}
|
||||
};
|
||||
FontFamily(FontFamilyList::new(Box::new([default])))
|
||||
FontFamilyList::new(Box::new([default]))
|
||||
} else {
|
||||
FontFamily(FontFamilyList(shared_fontlist))
|
||||
FontFamilyList(shared_fontlist)
|
||||
};
|
||||
|
||||
FontFamily {
|
||||
families,
|
||||
is_system_font: self.gecko.mFont.systemFont,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2042,10 +2053,32 @@ fn static_assert() {
|
|||
self.gecko.mFont.size = device.unzoom_text(Au(self.gecko.mFont.size)).0;
|
||||
}
|
||||
|
||||
pub fn copy_font_size_from(&mut self, other: &Self) {
|
||||
self.gecko.mScriptUnconstrainedSize = other.gecko.mScriptUnconstrainedSize;
|
||||
|
||||
self.gecko.mSize = other.gecko.mScriptUnconstrainedSize;
|
||||
self.gecko.mFont.size = other.gecko.mSize;
|
||||
self.gecko.mFontSizeKeyword = other.gecko.mFontSizeKeyword;
|
||||
|
||||
// TODO(emilio): Should we really copy over these two?
|
||||
self.gecko.mFontSizeFactor = other.gecko.mFontSizeFactor;
|
||||
self.gecko.mFontSizeOffset = other.gecko.mFontSizeOffset;
|
||||
}
|
||||
|
||||
pub fn reset_font_size(&mut self, other: &Self) {
|
||||
self.copy_font_size_from(other)
|
||||
}
|
||||
|
||||
pub fn set_font_size(&mut self, v: FontSize) {
|
||||
use crate::values::generics::font::KeywordSize;
|
||||
self.gecko.mSize = v.size().0;
|
||||
self.gecko.mScriptUnconstrainedSize = v.size().0;
|
||||
|
||||
let size = v.size();
|
||||
self.gecko.mScriptUnconstrainedSize = size.0;
|
||||
|
||||
// These two may be changed from Cascade::fixup_font_stuff.
|
||||
self.gecko.mSize = size.0;
|
||||
self.gecko.mFont.size = size.0;
|
||||
|
||||
if let Some(info) = v.keyword_info {
|
||||
self.gecko.mFontSizeKeyword = match info.kw {
|
||||
KeywordSize::XXSmall => structs::NS_STYLE_FONT_SIZE_XXSMALL,
|
||||
|
@ -2066,196 +2099,6 @@ fn static_assert() {
|
|||
}
|
||||
}
|
||||
|
||||
/// Set font size, taking into account scriptminsize and scriptlevel
|
||||
/// Returns Some(size) if we have to recompute the script unconstrained size
|
||||
pub fn apply_font_size(
|
||||
&mut self,
|
||||
v: FontSize,
|
||||
parent: &Self,
|
||||
device: &Device,
|
||||
) -> Option<NonNegativeLength> {
|
||||
let (adjusted_size, adjusted_unconstrained_size) =
|
||||
self.calculate_script_level_size(parent, device);
|
||||
// In this case, we have been unaffected by scriptminsize, ignore it
|
||||
if parent.gecko.mSize == parent.gecko.mScriptUnconstrainedSize &&
|
||||
adjusted_size == adjusted_unconstrained_size {
|
||||
self.set_font_size(v);
|
||||
self.fixup_font_min_size(device);
|
||||
None
|
||||
} else {
|
||||
self.gecko.mSize = v.size().0;
|
||||
self.fixup_font_min_size(device);
|
||||
Some(Au(parent.gecko.mScriptUnconstrainedSize).into())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fixup_font_min_size(&mut self, device: &Device) {
|
||||
unsafe { bindings::Gecko_nsStyleFont_FixupMinFontSize(&mut self.gecko, device.document()) }
|
||||
}
|
||||
|
||||
pub fn apply_unconstrained_font_size(&mut self, v: NonNegativeLength) {
|
||||
self.gecko.mScriptUnconstrainedSize = v.0.to_i32_au();
|
||||
}
|
||||
|
||||
/// Calculates the constrained and unconstrained font sizes to be inherited
|
||||
/// from the parent.
|
||||
///
|
||||
/// This is a port of Gecko's old ComputeScriptLevelSize function:
|
||||
/// https://searchfox.org/mozilla-central/rev/c05d9d61188d32b8/layout/style/nsRuleNode.cpp#3103
|
||||
///
|
||||
/// scriptlevel is a property that affects how font-size is inherited. If scriptlevel is
|
||||
/// +1, for example, it will inherit as the script size multiplier times
|
||||
/// the parent font. This does not affect cases where the font-size is
|
||||
/// explicitly set.
|
||||
///
|
||||
/// However, this transformation is not allowed to reduce the size below
|
||||
/// scriptminsize. If this inheritance will reduce it to below
|
||||
/// scriptminsize, it will be set to scriptminsize or the parent size,
|
||||
/// whichever is smaller (the parent size could be smaller than the min size
|
||||
/// because it was explicitly specified).
|
||||
///
|
||||
/// Now, within a node that has inherited a font-size which was
|
||||
/// crossing scriptminsize once the scriptlevel was applied, a negative
|
||||
/// scriptlevel may be used to increase the size again.
|
||||
///
|
||||
/// This should work, however if we have already been capped by the
|
||||
/// scriptminsize multiple times, this can lead to a jump in the size.
|
||||
///
|
||||
/// For example, if we have text of the form:
|
||||
///
|
||||
/// huge large medium small tiny reallytiny tiny small medium huge
|
||||
///
|
||||
/// which is represented by progressive nesting and scriptlevel values of
|
||||
/// +1 till the center after which the scriptlevel is -1, the "tiny"s should
|
||||
/// be the same size, as should be the "small"s and "medium"s, etc.
|
||||
///
|
||||
/// However, if scriptminsize kicked it at around "medium", then
|
||||
/// medium/tiny/reallytiny will all be the same size (the min size).
|
||||
/// A -1 scriptlevel change after this will increase the min size by the
|
||||
/// multiplier, making the second tiny larger than medium.
|
||||
///
|
||||
/// Instead, we wish for the second "tiny" to still be capped by the script
|
||||
/// level, and when we reach the second "large", it should be the same size
|
||||
/// as the original one.
|
||||
///
|
||||
/// We do this by cascading two separate font sizes. The font size (mSize)
|
||||
/// is the actual displayed font size. The unconstrained font size
|
||||
/// (mScriptUnconstrainedSize) is the font size in the situation where
|
||||
/// scriptminsize never applied.
|
||||
///
|
||||
/// We calculate the proposed inherited font size based on scriptlevel and
|
||||
/// the parent unconstrained size, instead of using the parent font size.
|
||||
/// This is stored in the node's unconstrained size and will also be stored
|
||||
/// in the font size provided that it is above the min size.
|
||||
///
|
||||
/// All of this only applies when inheriting. When the font size is
|
||||
/// manually set, scriptminsize does not apply, and both the real and
|
||||
/// unconstrained size are set to the explicit value. However, if the font
|
||||
/// size is manually set to an em or percent unit, the unconstrained size
|
||||
/// will be set to the value of that unit computed against the parent
|
||||
/// unconstrained size, whereas the font size will be set computing against
|
||||
/// the parent font size.
|
||||
pub fn calculate_script_level_size(&self, parent: &Self, device: &Device) -> (Au, Au) {
|
||||
use std::cmp;
|
||||
|
||||
let delta = self.gecko.mScriptLevel.saturating_sub(parent.gecko.mScriptLevel);
|
||||
|
||||
let parent_size = Au(parent.gecko.mSize);
|
||||
let parent_unconstrained_size = Au(parent.gecko.mScriptUnconstrainedSize);
|
||||
|
||||
if delta == 0 {
|
||||
return (parent_size, parent_unconstrained_size)
|
||||
}
|
||||
|
||||
|
||||
let mut min = Au(parent.gecko.mScriptMinSize);
|
||||
if self.gecko.mAllowZoom {
|
||||
min = device.zoom_text(min);
|
||||
}
|
||||
|
||||
let scale = (parent.gecko.mScriptSizeMultiplier as f32).powi(delta as i32);
|
||||
|
||||
let new_size = parent_size.scale_by(scale);
|
||||
let new_unconstrained_size = parent_unconstrained_size.scale_by(scale);
|
||||
|
||||
if scale < 1. {
|
||||
// The parent size can be smaller than scriptminsize,
|
||||
// e.g. if it was specified explicitly. Don't scale
|
||||
// in this case, but we don't want to set it to scriptminsize
|
||||
// either since that will make it larger.
|
||||
if parent_size < min {
|
||||
(parent_size, new_unconstrained_size)
|
||||
} else {
|
||||
(cmp::max(min, new_size), new_unconstrained_size)
|
||||
}
|
||||
} else {
|
||||
// If the new unconstrained size is larger than the min size,
|
||||
// this means we have escaped the grasp of scriptminsize
|
||||
// and can revert to using the unconstrained size.
|
||||
// However, if the new size is even larger (perhaps due to usage
|
||||
// of em units), use that instead.
|
||||
(cmp::min(new_size, cmp::max(new_unconstrained_size, min)),
|
||||
new_unconstrained_size)
|
||||
}
|
||||
}
|
||||
|
||||
/// This function will also handle scriptminsize and scriptlevel
|
||||
/// so should not be called when you just want the font sizes to be copied.
|
||||
/// Hence the different name.
|
||||
pub fn inherit_font_size_from(&mut self, parent: &Self,
|
||||
kw_inherited_size: Option<NonNegativeLength>,
|
||||
device: &Device) {
|
||||
let (adjusted_size, adjusted_unconstrained_size)
|
||||
= self.calculate_script_level_size(parent, device);
|
||||
if adjusted_size.0 != parent.gecko.mSize ||
|
||||
adjusted_unconstrained_size.0 != parent.gecko.mScriptUnconstrainedSize {
|
||||
// FIXME(Manishearth): This is incorrect. When there is both a
|
||||
// keyword size being inherited and a scriptlevel change, we must
|
||||
// handle the keyword size the same way we handle em units. This
|
||||
// complicates things because we now have to keep track of the
|
||||
// adjusted and unadjusted ratios in the kw font size. This only
|
||||
// affects the use case of a generic font being used in MathML.
|
||||
//
|
||||
// If we were to fix this I would prefer doing it not doing
|
||||
// something like the ruletree walk that Gecko used to do in
|
||||
// nsRuleNode::SetGenericFont and instead using extra bookkeeping in
|
||||
// the mSize and mScriptUnconstrainedSize values, and reusing those
|
||||
// instead of font_size_keyword.
|
||||
|
||||
// In the case that MathML has given us an adjusted size, apply it.
|
||||
// Keep track of the unconstrained adjusted size.
|
||||
self.gecko.mSize = adjusted_size.0;
|
||||
|
||||
// Technically the MathML constrained size may also be keyword-derived
|
||||
// but we ignore this since it would be too complicated
|
||||
// to correctly track and it's mostly unnecessary.
|
||||
self.gecko.mFontSizeKeyword = structs::NS_STYLE_FONT_SIZE_NO_KEYWORD as u8;
|
||||
self.gecko.mFontSizeFactor = 1.;
|
||||
self.gecko.mFontSizeOffset = 0;
|
||||
|
||||
self.gecko.mScriptUnconstrainedSize = adjusted_unconstrained_size.0;
|
||||
} else if let Some(size) = kw_inherited_size {
|
||||
// Parent element was a keyword-derived size.
|
||||
self.gecko.mSize = size.0.to_i32_au();
|
||||
// Copy keyword info over.
|
||||
self.gecko.mFontSizeFactor = parent.gecko.mFontSizeFactor;
|
||||
self.gecko.mFontSizeOffset = parent.gecko.mFontSizeOffset;
|
||||
self.gecko.mFontSizeKeyword = parent.gecko.mFontSizeKeyword;
|
||||
// MathML constraints didn't apply here, so we can ignore this.
|
||||
self.gecko.mScriptUnconstrainedSize = size.0.to_i32_au();
|
||||
} else {
|
||||
// MathML isn't affecting us, and our parent element does not
|
||||
// have a keyword-derived size. Set things normally.
|
||||
self.gecko.mSize = parent.gecko.mSize;
|
||||
// copy keyword info over
|
||||
self.gecko.mFontSizeKeyword = structs::NS_STYLE_FONT_SIZE_NO_KEYWORD as u8;
|
||||
self.gecko.mFontSizeFactor = 1.;
|
||||
self.gecko.mFontSizeOffset = 0;
|
||||
self.gecko.mScriptUnconstrainedSize = parent.gecko.mScriptUnconstrainedSize;
|
||||
}
|
||||
self.fixup_font_min_size(device);
|
||||
}
|
||||
|
||||
pub fn clone_font_size(&self) -> FontSize {
|
||||
use crate::values::generics::font::{KeywordInfo, KeywordSize};
|
||||
let size = Au(self.gecko.mSize).into();
|
||||
|
@ -2270,16 +2113,16 @@ fn static_assert() {
|
|||
structs::NS_STYLE_FONT_SIZE_XXXLARGE => KeywordSize::XXXLarge,
|
||||
structs::NS_STYLE_FONT_SIZE_NO_KEYWORD => {
|
||||
return FontSize {
|
||||
size: size,
|
||||
size,
|
||||
keyword_info: None,
|
||||
}
|
||||
}
|
||||
_ => unreachable!("mFontSizeKeyword should be an absolute keyword or NO_KEYWORD")
|
||||
};
|
||||
FontSize {
|
||||
size: size,
|
||||
size,
|
||||
keyword_info: Some(KeywordInfo {
|
||||
kw: kw,
|
||||
kw,
|
||||
factor: self.gecko.mFontSizeFactor,
|
||||
offset: Au(self.gecko.mFontSizeOffset).into()
|
||||
})
|
||||
|
@ -2751,7 +2594,7 @@ fn static_assert() {
|
|||
transform-style
|
||||
rotate scroll-snap-points-x scroll-snap-points-y
|
||||
scroll-snap-coordinate -moz-binding will-change
|
||||
offset-path shape-outside contain touch-action
|
||||
offset-path shape-outside
|
||||
translate scale""" %>
|
||||
<%self:impl_trait style_struct_name="Box" skip_longhands="${skip_box_longhands}">
|
||||
#[inline]
|
||||
|
@ -3109,10 +2952,10 @@ fn static_assert() {
|
|||
|
||||
pub fn set_will_change(&mut self, v: longhands::will_change::computed_value::T) {
|
||||
use crate::gecko_bindings::bindings::{Gecko_AppendWillChange, Gecko_ClearWillChange};
|
||||
use crate::properties::longhands::will_change::computed_value::T;
|
||||
use crate::values::specified::box_::{WillChangeBits, WillChange};
|
||||
|
||||
match v {
|
||||
T::AnimateableFeatures { features, bits } => {
|
||||
WillChange::AnimateableFeatures { features, bits } => {
|
||||
unsafe {
|
||||
Gecko_ClearWillChange(&mut self.gecko, features.len());
|
||||
}
|
||||
|
@ -3123,13 +2966,13 @@ fn static_assert() {
|
|||
}
|
||||
}
|
||||
|
||||
self.gecko.mWillChangeBitField = bits.bits();
|
||||
self.gecko.mWillChangeBitField = bits;
|
||||
},
|
||||
T::Auto => {
|
||||
WillChange::Auto => {
|
||||
unsafe {
|
||||
Gecko_ClearWillChange(&mut self.gecko, 0);
|
||||
}
|
||||
self.gecko.mWillChangeBitField = 0;
|
||||
self.gecko.mWillChangeBitField = WillChangeBits::empty();
|
||||
},
|
||||
};
|
||||
}
|
||||
|
@ -3139,7 +2982,7 @@ fn static_assert() {
|
|||
|
||||
self.gecko.mWillChangeBitField = other.gecko.mWillChangeBitField;
|
||||
unsafe {
|
||||
Gecko_CopyWillChangeFrom(&mut self.gecko, &other.gecko as *const _ as *mut _);
|
||||
Gecko_CopyWillChangeFrom(&mut self.gecko, &other.gecko);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3148,116 +2991,27 @@ fn static_assert() {
|
|||
}
|
||||
|
||||
pub fn clone_will_change(&self) -> longhands::will_change::computed_value::T {
|
||||
use crate::properties::longhands::will_change::computed_value::T;
|
||||
use crate::gecko_bindings::structs::nsAtom;
|
||||
use crate::values::CustomIdent;
|
||||
use crate::values::specified::box_::WillChangeBits;
|
||||
use crate::values::specified::box_::WillChange;
|
||||
|
||||
if self.gecko.mWillChange.len() == 0 {
|
||||
return T::Auto
|
||||
return WillChange::Auto
|
||||
}
|
||||
|
||||
let custom_idents: Vec<CustomIdent> = self.gecko.mWillChange.iter().map(|gecko_atom| {
|
||||
unsafe {
|
||||
CustomIdent(Atom::from_raw(gecko_atom.mRawPtr as *mut nsAtom))
|
||||
CustomIdent(Atom::from_raw(gecko_atom.mRawPtr))
|
||||
}
|
||||
}).collect();
|
||||
|
||||
T::AnimateableFeatures {
|
||||
WillChange::AnimateableFeatures {
|
||||
features: custom_idents.into_boxed_slice(),
|
||||
bits: WillChangeBits::from_bits_truncate(self.gecko.mWillChangeBitField),
|
||||
bits: self.gecko.mWillChangeBitField,
|
||||
}
|
||||
}
|
||||
|
||||
<% impl_shape_source("shape_outside", "mShapeOutside") %>
|
||||
|
||||
pub fn set_contain(&mut self, v: longhands::contain::computed_value::T) {
|
||||
use crate::gecko_bindings::structs::NS_STYLE_CONTAIN_NONE;
|
||||
use crate::gecko_bindings::structs::NS_STYLE_CONTAIN_STRICT;
|
||||
use crate::gecko_bindings::structs::NS_STYLE_CONTAIN_CONTENT;
|
||||
use crate::gecko_bindings::structs::NS_STYLE_CONTAIN_SIZE;
|
||||
use crate::gecko_bindings::structs::NS_STYLE_CONTAIN_LAYOUT;
|
||||
use crate::gecko_bindings::structs::NS_STYLE_CONTAIN_PAINT;
|
||||
use crate::gecko_bindings::structs::NS_STYLE_CONTAIN_ALL_BITS;
|
||||
use crate::gecko_bindings::structs::NS_STYLE_CONTAIN_CONTENT_BITS;
|
||||
use crate::properties::longhands::contain::SpecifiedValue;
|
||||
|
||||
if v.is_empty() {
|
||||
self.gecko.mContain = NS_STYLE_CONTAIN_NONE as u8;
|
||||
return;
|
||||
}
|
||||
|
||||
if v.contains(SpecifiedValue::STRICT) {
|
||||
self.gecko.mContain = (NS_STYLE_CONTAIN_STRICT | NS_STYLE_CONTAIN_ALL_BITS) as u8;
|
||||
return;
|
||||
}
|
||||
if v.contains(SpecifiedValue::CONTENT) {
|
||||
self.gecko.mContain = (NS_STYLE_CONTAIN_CONTENT | NS_STYLE_CONTAIN_CONTENT_BITS) as u8;
|
||||
return;
|
||||
}
|
||||
|
||||
let mut bitfield = 0;
|
||||
if v.contains(SpecifiedValue::LAYOUT) {
|
||||
bitfield |= NS_STYLE_CONTAIN_LAYOUT;
|
||||
}
|
||||
if v.contains(SpecifiedValue::PAINT) {
|
||||
bitfield |= NS_STYLE_CONTAIN_PAINT;
|
||||
}
|
||||
if v.contains(SpecifiedValue::SIZE) {
|
||||
bitfield |= NS_STYLE_CONTAIN_SIZE;
|
||||
}
|
||||
|
||||
self.gecko.mContain = bitfield as u8;
|
||||
}
|
||||
|
||||
pub fn clone_contain(&self) -> longhands::contain::computed_value::T {
|
||||
use crate::gecko_bindings::structs::NS_STYLE_CONTAIN_STRICT;
|
||||
use crate::gecko_bindings::structs::NS_STYLE_CONTAIN_CONTENT;
|
||||
use crate::gecko_bindings::structs::NS_STYLE_CONTAIN_SIZE;
|
||||
use crate::gecko_bindings::structs::NS_STYLE_CONTAIN_LAYOUT;
|
||||
use crate::gecko_bindings::structs::NS_STYLE_CONTAIN_PAINT;
|
||||
use crate::gecko_bindings::structs::NS_STYLE_CONTAIN_ALL_BITS;
|
||||
use crate::gecko_bindings::structs::NS_STYLE_CONTAIN_CONTENT_BITS;
|
||||
use crate::properties::longhands::contain::{self, SpecifiedValue};
|
||||
|
||||
let mut servo_flags = contain::computed_value::T::empty();
|
||||
let gecko_flags = self.gecko.mContain;
|
||||
|
||||
if gecko_flags & (NS_STYLE_CONTAIN_STRICT as u8) != 0 {
|
||||
debug_assert_eq!(
|
||||
gecko_flags & (NS_STYLE_CONTAIN_ALL_BITS as u8),
|
||||
NS_STYLE_CONTAIN_ALL_BITS as u8,
|
||||
"When strict is specified, ALL_BITS should be specified as well"
|
||||
);
|
||||
servo_flags.insert(SpecifiedValue::STRICT | SpecifiedValue::STRICT_BITS);
|
||||
return servo_flags;
|
||||
}
|
||||
if gecko_flags & (NS_STYLE_CONTAIN_CONTENT as u8) != 0 {
|
||||
debug_assert_eq!(
|
||||
gecko_flags & (NS_STYLE_CONTAIN_CONTENT_BITS as u8),
|
||||
NS_STYLE_CONTAIN_CONTENT_BITS as u8,
|
||||
"When content is specified, CONTENT_BITS should be specified as well"
|
||||
);
|
||||
servo_flags.insert(SpecifiedValue::CONTENT | SpecifiedValue::CONTENT_BITS);
|
||||
return servo_flags;
|
||||
}
|
||||
if gecko_flags & (NS_STYLE_CONTAIN_LAYOUT as u8) != 0 {
|
||||
servo_flags.insert(SpecifiedValue::LAYOUT);
|
||||
}
|
||||
if gecko_flags & (NS_STYLE_CONTAIN_PAINT as u8) != 0 {
|
||||
servo_flags.insert(SpecifiedValue::PAINT);
|
||||
}
|
||||
if gecko_flags & (NS_STYLE_CONTAIN_SIZE as u8) != 0 {
|
||||
servo_flags.insert(SpecifiedValue::SIZE);
|
||||
}
|
||||
|
||||
return servo_flags;
|
||||
}
|
||||
|
||||
${impl_simple_copy("contain", "mContain")}
|
||||
|
||||
${impl_simple_type_with_conversion("touch_action")}
|
||||
|
||||
pub fn set_offset_path(&mut self, v: longhands::offset_path::computed_value::T) {
|
||||
use crate::gecko_bindings::bindings::{Gecko_NewStyleMotion, Gecko_SetStyleMotion};
|
||||
use crate::gecko_bindings::structs::StyleShapeSourceType;
|
||||
|
@ -4250,9 +4004,7 @@ fn static_assert() {
|
|||
</%self:impl_trait>
|
||||
|
||||
<%self:impl_trait style_struct_name="Text"
|
||||
skip_longhands="text-decoration-line text-overflow initial-letter">
|
||||
|
||||
${impl_simple_type_with_conversion("text_decoration_line")}
|
||||
skip_longhands="text-overflow initial-letter">
|
||||
|
||||
fn clear_overflow_sides_if_string(&mut self) {
|
||||
use crate::gecko_bindings::structs::nsStyleTextOverflowSide;
|
||||
|
@ -4366,21 +4118,6 @@ fn static_assert() {
|
|||
InitialLetter::Specified(self.gecko.mInitialLetterSize, Some(self.gecko.mInitialLetterSink))
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn has_underline(&self) -> bool {
|
||||
(self.gecko.mTextDecorationLine & (structs::NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE as u8)) != 0
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn has_overline(&self) -> bool {
|
||||
(self.gecko.mTextDecorationLine & (structs::NS_STYLE_TEXT_DECORATION_LINE_OVERLINE as u8)) != 0
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn has_line_through(&self) -> bool {
|
||||
(self.gecko.mTextDecorationLine & (structs::NS_STYLE_TEXT_DECORATION_LINE_LINE_THROUGH as u8)) != 0
|
||||
}
|
||||
</%self:impl_trait>
|
||||
|
||||
// Set SVGPathData to StyleShapeSource.
|
||||
|
@ -4823,7 +4560,7 @@ clip-path
|
|||
</%self:impl_trait>
|
||||
|
||||
<%self:impl_trait style_struct_name="Counters"
|
||||
skip_longhands="content counter-increment counter-reset">
|
||||
skip_longhands="content counter-increment counter-reset counter-set">
|
||||
pub fn ineffective_content_property(&self) -> bool {
|
||||
self.gecko.mContents.is_empty()
|
||||
}
|
||||
|
@ -5052,7 +4789,7 @@ clip-path
|
|||
)
|
||||
}
|
||||
|
||||
% for counter_property in ["Increment", "Reset"]:
|
||||
% for counter_property in ["Increment", "Reset", "Set"]:
|
||||
pub fn set_counter_${counter_property.lower()}(
|
||||
&mut self,
|
||||
v: longhands::counter_${counter_property.lower()}::computed_value::T
|
||||
|
|
|
@ -332,13 +332,9 @@
|
|||
CSSWideKeyword::Initial => {
|
||||
% if not property.style_struct.inherited:
|
||||
debug_assert!(false, "Should be handled in apply_properties");
|
||||
% else:
|
||||
% if property.name == "font-size":
|
||||
computed::FontSize::cascade_initial_font_size(context);
|
||||
% else:
|
||||
context.builder.reset_${property.ident}();
|
||||
% endif
|
||||
% endif
|
||||
},
|
||||
% if property.style_struct.inherited:
|
||||
CSSWideKeyword::Unset |
|
||||
|
@ -394,16 +390,8 @@
|
|||
% else:
|
||||
let computed = specified_value.to_computed_value(context);
|
||||
% endif
|
||||
% if property.ident == "font_size":
|
||||
specified::FontSize::cascade_specified_font_size(
|
||||
context,
|
||||
&specified_value,
|
||||
computed,
|
||||
);
|
||||
% else:
|
||||
context.builder.set_${property.ident}(computed)
|
||||
% endif
|
||||
% endif
|
||||
}
|
||||
|
||||
pub fn parse_declared<'i, 't>(
|
||||
|
|
|
@ -365,7 +365,7 @@ ${helpers.predefined_type(
|
|||
"generics::transform::Rotate::None",
|
||||
animation_value_type="ComputedValue",
|
||||
boxed=True,
|
||||
flags="CREATES_STACKING_CONTEXT FIXPOS_CB",
|
||||
flags="CREATES_STACKING_CONTEXT FIXPOS_CB CAN_ANIMATE_ON_COMPOSITOR",
|
||||
gecko_pref="layout.css.individual-transform.enabled",
|
||||
spec="https://drafts.csswg.org/css-transforms-2/#individual-transforms",
|
||||
servo_restyle_damage = "reflow_out_of_flow",
|
||||
|
@ -377,7 +377,7 @@ ${helpers.predefined_type(
|
|||
"generics::transform::Scale::None",
|
||||
animation_value_type="ComputedValue",
|
||||
boxed=True,
|
||||
flags="CREATES_STACKING_CONTEXT FIXPOS_CB",
|
||||
flags="CREATES_STACKING_CONTEXT FIXPOS_CB CAN_ANIMATE_ON_COMPOSITOR",
|
||||
gecko_pref="layout.css.individual-transform.enabled",
|
||||
spec="https://drafts.csswg.org/css-transforms-2/#individual-transforms",
|
||||
servo_restyle_damage = "reflow_out_of_flow",
|
||||
|
@ -389,7 +389,7 @@ ${helpers.predefined_type(
|
|||
"generics::transform::Translate::None",
|
||||
animation_value_type="ComputedValue",
|
||||
boxed=True,
|
||||
flags="CREATES_STACKING_CONTEXT FIXPOS_CB",
|
||||
flags="CREATES_STACKING_CONTEXT FIXPOS_CB CAN_ANIMATE_ON_COMPOSITOR",
|
||||
gecko_pref="layout.css.individual-transform.enabled",
|
||||
spec="https://drafts.csswg.org/css-transforms-2/#individual-transforms",
|
||||
servo_restyle_damage="reflow_out_of_flow",
|
||||
|
|
|
@ -27,9 +27,19 @@ ${helpers.predefined_type(
|
|||
|
||||
${helpers.predefined_type(
|
||||
"counter-reset",
|
||||
"CounterReset",
|
||||
"CounterSetOrReset",
|
||||
initial_value="Default::default()",
|
||||
animation_value_type="discrete",
|
||||
spec="https://drafts.csswg.org/css-lists-3/#propdef-counter-reset",
|
||||
servo_restyle_damage="rebuild_and_reflow",
|
||||
)}
|
||||
|
||||
${helpers.predefined_type(
|
||||
"counter-set",
|
||||
"CounterSetOrReset",
|
||||
initial_value="Default::default()",
|
||||
animation_value_type="discrete",
|
||||
spec="https://drafts.csswg.org/css-lists-3/#propdef-counter-set",
|
||||
servo_restyle_damage="rebuild_and_reflow",
|
||||
products="gecko",
|
||||
)}
|
||||
|
|
|
@ -379,7 +379,7 @@ ${helpers.predefined_type(
|
|||
use crate::gecko_bindings::structs::{LookAndFeel_FontID, nsFont};
|
||||
use std::mem;
|
||||
use crate::values::computed::Percentage;
|
||||
use crate::values::computed::font::{FontSize, FontStretch, FontStyle, FontFamilyList};
|
||||
use crate::values::computed::font::{FontFamily, FontSize, FontStretch, FontStyle, FontFamilyList};
|
||||
use crate::values::generics::NonNegative;
|
||||
|
||||
let id = match *self {
|
||||
|
@ -405,11 +405,12 @@ ${helpers.predefined_type(
|
|||
})));
|
||||
let font_style = FontStyle::from_gecko(system.style);
|
||||
let ret = ComputedSystemFont {
|
||||
font_family: longhands::font_family::computed_value::T(
|
||||
FontFamilyList(
|
||||
unsafe { system.fontlist.mFontlist.mBasePtr.to_safe() }
|
||||
)
|
||||
),
|
||||
font_family: FontFamily {
|
||||
families: FontFamilyList(unsafe {
|
||||
system.fontlist.mFontlist.mBasePtr.to_safe()
|
||||
}),
|
||||
is_system_font: true,
|
||||
},
|
||||
font_size: FontSize {
|
||||
size: Au(system.size).into(),
|
||||
keyword_info: None
|
||||
|
|
|
@ -68,3 +68,15 @@ ${helpers.predefined_type(
|
|||
boxed=True,
|
||||
spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-image-region)",
|
||||
)}
|
||||
|
||||
${helpers.predefined_type(
|
||||
"-moz-list-reversed",
|
||||
"MozListReversed",
|
||||
"computed::MozListReversed::False",
|
||||
animation_value_type="discrete",
|
||||
products="gecko",
|
||||
enabled_in="ua",
|
||||
needs_context=False,
|
||||
spec="Internal implementation detail for <ol reversed>",
|
||||
servo_restyle_damage="rebuild_and_reflow",
|
||||
)}
|
||||
|
|
|
@ -5,16 +5,7 @@
|
|||
<%namespace name="helpers" file="/helpers.mako.rs" />
|
||||
<% from data import Method %>
|
||||
|
||||
<% data.new_style_struct(
|
||||
"Text",
|
||||
inherited=False,
|
||||
gecko_name="TextReset",
|
||||
additional_methods=[
|
||||
Method("has_underline", "bool"),
|
||||
Method("has_overline", "bool"),
|
||||
Method("has_line_through", "bool"),
|
||||
]
|
||||
) %>
|
||||
<% data.new_style_struct("Text", inherited=False, gecko_name="TextReset") %>
|
||||
|
||||
${helpers.predefined_type(
|
||||
"text-overflow",
|
||||
|
|
|
@ -45,6 +45,7 @@ use crate::rule_tree::StrongRuleNode;
|
|||
use crate::Zero;
|
||||
use self::computed_value_flags::*;
|
||||
use crate::str::{CssString, CssStringBorrow, CssStringWriter};
|
||||
use std::cell::Cell;
|
||||
|
||||
pub use self::declaration_block::*;
|
||||
pub use self::cascade::*;
|
||||
|
@ -1257,8 +1258,12 @@ impl LonghandId {
|
|||
LonghandId::MozScriptLevel |
|
||||
% endif
|
||||
|
||||
// Needed to compute font-relative lengths correctly.
|
||||
// Needed to compute the first available font, in order to
|
||||
// compute font-relative units correctly.
|
||||
LonghandId::FontSize |
|
||||
LonghandId::FontWeight |
|
||||
LonghandId::FontStretch |
|
||||
LonghandId::FontStyle |
|
||||
LonghandId::FontFamily |
|
||||
|
||||
// Needed to resolve currentcolor at computed value time properly.
|
||||
|
@ -2634,24 +2639,6 @@ pub mod style_structs {
|
|||
use crate::Zero;
|
||||
!self.outline_width.is_zero()
|
||||
}
|
||||
% elif style_struct.name == "Text":
|
||||
/// Whether the text decoration has an underline.
|
||||
#[inline]
|
||||
pub fn has_underline(&self) -> bool {
|
||||
self.text_decoration_line.contains(longhands::text_decoration_line::SpecifiedValue::UNDERLINE)
|
||||
}
|
||||
|
||||
/// Whether the text decoration has an overline.
|
||||
#[inline]
|
||||
pub fn has_overline(&self) -> bool {
|
||||
self.text_decoration_line.contains(longhands::text_decoration_line::SpecifiedValue::OVERLINE)
|
||||
}
|
||||
|
||||
/// Whether the text decoration has a line through.
|
||||
#[inline]
|
||||
pub fn has_line_through(&self) -> bool {
|
||||
self.text_decoration_line.contains(longhands::text_decoration_line::SpecifiedValue::LINE_THROUGH)
|
||||
}
|
||||
% elif style_struct.name == "Box":
|
||||
/// Sets the display property, but without touching original_display,
|
||||
/// except when the adjustment comes from root or item display fixups.
|
||||
|
@ -3336,8 +3323,10 @@ pub struct StyleBuilder<'a> {
|
|||
///
|
||||
/// TODO(emilio): Make private.
|
||||
pub writing_mode: WritingMode,
|
||||
|
||||
/// Flags for the computed value.
|
||||
pub flags: ComputedValueFlags,
|
||||
pub flags: Cell<ComputedValueFlags>,
|
||||
|
||||
/// The element's style if visited, only computed if there's a relevant link
|
||||
/// for this element. A element's "relevant link" is the element being
|
||||
/// matched if it is a link or the nearest ancestor link.
|
||||
|
@ -3379,7 +3368,7 @@ impl<'a> StyleBuilder<'a> {
|
|||
modified_reset: false,
|
||||
custom_properties,
|
||||
writing_mode: inherited_style.writing_mode,
|
||||
flags,
|
||||
flags: Cell::new(flags),
|
||||
visited_style: None,
|
||||
% for style_struct in data.active_style_structs():
|
||||
% if style_struct.inherited:
|
||||
|
@ -3418,7 +3407,7 @@ impl<'a> StyleBuilder<'a> {
|
|||
rules: None,
|
||||
custom_properties: style_to_derive_from.custom_properties().cloned(),
|
||||
writing_mode: style_to_derive_from.writing_mode,
|
||||
flags: style_to_derive_from.flags,
|
||||
flags: Cell::new(style_to_derive_from.flags),
|
||||
visited_style: None,
|
||||
% for style_struct in data.active_style_structs():
|
||||
${style_struct.ident}: StyleStructRef::Borrowed(
|
||||
|
@ -3448,14 +3437,14 @@ impl<'a> StyleBuilder<'a> {
|
|||
.get_${property.style_struct.name_lower}();
|
||||
|
||||
self.modified_reset = true;
|
||||
self.flags.insert(ComputedValueFlags::INHERITS_RESET_STYLE);
|
||||
self.add_flags(ComputedValueFlags::INHERITS_RESET_STYLE);
|
||||
|
||||
% if property.ident == "content":
|
||||
self.flags.insert(ComputedValueFlags::INHERITS_CONTENT);
|
||||
self.add_flags(ComputedValueFlags::INHERITS_CONTENT);
|
||||
% endif
|
||||
|
||||
% if property.ident == "display":
|
||||
self.flags.insert(ComputedValueFlags::INHERITS_DISPLAY);
|
||||
self.add_flags(ComputedValueFlags::INHERITS_DISPLAY);
|
||||
% endif
|
||||
|
||||
if self.${property.style_struct.ident}.ptr_eq(inherited_struct) {
|
||||
|
@ -3470,7 +3459,7 @@ impl<'a> StyleBuilder<'a> {
|
|||
% endif
|
||||
);
|
||||
}
|
||||
% elif property.name != "font-size":
|
||||
% else:
|
||||
/// Reset `${property.ident}` to the initial value.
|
||||
#[allow(non_snake_case)]
|
||||
pub fn reset_${property.ident}(&mut self) {
|
||||
|
@ -3642,13 +3631,33 @@ impl<'a> StyleBuilder<'a> {
|
|||
self.modified_reset
|
||||
}
|
||||
|
||||
/// Return the current flags.
|
||||
#[inline]
|
||||
pub fn flags(&self) -> ComputedValueFlags {
|
||||
self.flags.get()
|
||||
}
|
||||
|
||||
/// Add a flag to the current builder.
|
||||
#[inline]
|
||||
pub fn add_flags(&self, flag: ComputedValueFlags) {
|
||||
let flags = self.flags() | flag;
|
||||
self.flags.set(flags);
|
||||
}
|
||||
|
||||
/// Removes a flag to the current builder.
|
||||
#[inline]
|
||||
pub fn remove_flags(&self, flag: ComputedValueFlags) {
|
||||
let flags = self.flags() & !flag;
|
||||
self.flags.set(flags);
|
||||
}
|
||||
|
||||
/// Turns this `StyleBuilder` into a proper `ComputedValues` instance.
|
||||
pub fn build(self) -> Arc<ComputedValues> {
|
||||
ComputedValues::new(
|
||||
self.pseudo,
|
||||
self.custom_properties,
|
||||
self.writing_mode,
|
||||
self.flags,
|
||||
self.flags.get(),
|
||||
self.rules,
|
||||
self.visited_style,
|
||||
% for style_struct in data.active_style_structs():
|
||||
|
@ -3710,8 +3719,8 @@ mod lazy_static_module {
|
|||
use super::{ComputedValues, ComputedValuesInner, longhands, style_structs};
|
||||
use super::computed_value_flags::ComputedValueFlags;
|
||||
|
||||
/// The initial values for all style structs as defined by the specification.
|
||||
lazy_static! {
|
||||
/// The initial values for all style structs as defined by the specification.
|
||||
pub static ref INITIAL_SERVO_VALUES: ComputedValues = ComputedValues {
|
||||
inner: ComputedValuesInner {
|
||||
% for style_struct in data.active_style_structs():
|
||||
|
|
|
@ -142,6 +142,12 @@ impl PseudoElement {
|
|||
false
|
||||
}
|
||||
|
||||
/// Whether this pseudo-element is the ::marker pseudo.
|
||||
#[inline]
|
||||
pub fn is_marker(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
/// Whether this pseudo-element is the ::before pseudo.
|
||||
#[inline]
|
||||
pub fn is_before(&self) -> bool {
|
||||
|
|
|
@ -174,10 +174,14 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
|
|||
|
||||
/// Apply the blockification rules based on the table in CSS 2.2 section 9.7.
|
||||
/// <https://drafts.csswg.org/css2/visuren.html#dis-pos-flo>
|
||||
/// A ::marker pseudo-element with 'list-style-position:outside' needs to
|
||||
/// have its 'display' blockified.
|
||||
fn blockify_if_necessary<E>(&mut self, layout_parent_style: &ComputedValues, element: Option<E>)
|
||||
where
|
||||
E: TElement,
|
||||
{
|
||||
use crate::computed_values::list_style_position::T as ListStylePosition;
|
||||
|
||||
let mut blockify = false;
|
||||
macro_rules! blockify_if {
|
||||
($if_what:expr) => {
|
||||
|
@ -200,6 +204,11 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
|
|||
|
||||
blockify_if!(self.style.floated());
|
||||
blockify_if!(self.style.out_of_flow_positioned());
|
||||
blockify_if!(
|
||||
self.style.pseudo.map_or(false, |p| p.is_marker()) &&
|
||||
self.style.get_parent_list().clone_list_style_position() ==
|
||||
ListStylePosition::Outside
|
||||
);
|
||||
|
||||
if !blockify {
|
||||
return;
|
||||
|
@ -226,22 +235,18 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
|
|||
.is_empty()
|
||||
{
|
||||
self.style
|
||||
.flags
|
||||
.insert(ComputedValueFlags::HAS_TEXT_DECORATION_LINES);
|
||||
.add_flags(ComputedValueFlags::HAS_TEXT_DECORATION_LINES);
|
||||
}
|
||||
|
||||
if self.style.is_pseudo_element() {
|
||||
self.style
|
||||
.flags
|
||||
.insert(ComputedValueFlags::IS_IN_PSEUDO_ELEMENT_SUBTREE);
|
||||
.add_flags(ComputedValueFlags::IS_IN_PSEUDO_ELEMENT_SUBTREE);
|
||||
}
|
||||
|
||||
#[cfg(feature = "servo")]
|
||||
{
|
||||
if self.style.get_parent_column().is_multicol() {
|
||||
self.style
|
||||
.flags
|
||||
.insert(ComputedValueFlags::CAN_BE_FRAGMENTED);
|
||||
self.style.add_flags(ComputedValueFlags::CAN_BE_FRAGMENTED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -280,9 +285,7 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
|
|||
if writing_mode != WritingMode::HorizontalTb &&
|
||||
text_combine_upright == TextCombineUpright::All
|
||||
{
|
||||
self.style
|
||||
.flags
|
||||
.insert(ComputedValueFlags::IS_TEXT_COMBINED);
|
||||
self.style.add_flags(ComputedValueFlags::IS_TEXT_COMBINED);
|
||||
self.style
|
||||
.mutate_inherited_box()
|
||||
.set_writing_mode(WritingMode::HorizontalTb);
|
||||
|
@ -304,8 +307,7 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
|
|||
.contains(ComputedValueFlags::SHOULD_SUPPRESS_LINEBREAK)
|
||||
{
|
||||
self.style
|
||||
.flags
|
||||
.insert(ComputedValueFlags::SHOULD_SUPPRESS_LINEBREAK);
|
||||
.add_flags(ComputedValueFlags::SHOULD_SUPPRESS_LINEBREAK);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -592,8 +594,7 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
|
|||
// Check whether line break should be suppressed for this element.
|
||||
if self.should_suppress_linebreak(layout_parent_style) {
|
||||
self.style
|
||||
.flags
|
||||
.insert(ComputedValueFlags::SHOULD_SUPPRESS_LINEBREAK);
|
||||
.add_flags(ComputedValueFlags::SHOULD_SUPPRESS_LINEBREAK);
|
||||
// Inlinify the display type if allowed.
|
||||
if !self.skip_item_display_fixup(element) {
|
||||
let inline_display = self_display.inlinify();
|
||||
|
@ -652,13 +653,11 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
|
|||
|
||||
if element.unwrap().is_visited_link() {
|
||||
self.style
|
||||
.flags
|
||||
.insert(ComputedValueFlags::IS_RELEVANT_LINK_VISITED);
|
||||
.add_flags(ComputedValueFlags::IS_RELEVANT_LINK_VISITED);
|
||||
} else {
|
||||
// Need to remove to handle unvisited link inside visited.
|
||||
self.style
|
||||
.flags
|
||||
.remove(ComputedValueFlags::IS_RELEVANT_LINK_VISITED);
|
||||
.remove_flags(ComputedValueFlags::IS_RELEVANT_LINK_VISITED);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -724,6 +723,52 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
|
|||
}
|
||||
}
|
||||
|
||||
/// For HTML elements with 'display:list-item' we add a default 'counter-increment:list-item'
|
||||
/// unless 'counter-increment' already has a value for 'list-item'.
|
||||
///
|
||||
/// https://drafts.csswg.org/css-lists-3/#declaring-a-list-item
|
||||
#[cfg(feature = "gecko")]
|
||||
fn adjust_for_list_item<E>(&mut self, element: Option<E>)
|
||||
where
|
||||
E: TElement,
|
||||
{
|
||||
use crate::properties::longhands::counter_increment::computed_value::T as ComputedIncrement;
|
||||
use crate::values::generics::counters::CounterPair;
|
||||
use crate::values::specified::list::MozListReversed;
|
||||
use crate::values::CustomIdent;
|
||||
|
||||
if self.style.get_box().clone_display() != Display::ListItem {
|
||||
return;
|
||||
}
|
||||
if self.style.pseudo.is_some() {
|
||||
return;
|
||||
}
|
||||
if !element.map_or(false, |e| e.is_html_element()) {
|
||||
return;
|
||||
}
|
||||
// Note that we map <li value=INTEGER> to 'counter-set: list-item INTEGER;
|
||||
// counter-increment: list-item 0;' so we'll return here unless the author
|
||||
// explicitly specified something else.
|
||||
let increments = self.style.get_counters().clone_counter_increment();
|
||||
if increments.iter().any(|i| i.name.0 == atom!("list-item")) {
|
||||
return;
|
||||
}
|
||||
|
||||
let reversed = self.style.get_list().clone__moz_list_reversed() == MozListReversed::True;
|
||||
let increment = if reversed { -1 } else { 1 };
|
||||
let list_increment = CounterPair {
|
||||
name: CustomIdent(atom!("list-item")),
|
||||
value: increment,
|
||||
};
|
||||
let increments = increments
|
||||
.iter()
|
||||
.cloned()
|
||||
.chain(std::iter::once(list_increment));
|
||||
self.style
|
||||
.mutate_counters()
|
||||
.set_counter_increment(ComputedIncrement::new(increments.collect()));
|
||||
}
|
||||
|
||||
/// Adjusts the style to account for various fixups that don't fit naturally
|
||||
/// into the cascade.
|
||||
///
|
||||
|
@ -788,6 +833,7 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
|
|||
#[cfg(feature = "gecko")]
|
||||
{
|
||||
self.adjust_for_appearance(element);
|
||||
self.adjust_for_list_item(element);
|
||||
}
|
||||
self.set_bits();
|
||||
}
|
||||
|
|
|
@ -189,6 +189,13 @@ impl<'a, 'i> AtRuleParser<'i> for TopLevelRuleParser<'a> {
|
|||
return Err(input.new_custom_error(StyleParseErrorKind::UnexpectedImportRule))
|
||||
}
|
||||
|
||||
// FIXME(emilio): We should always be able to have a loader
|
||||
// around! See bug 1533783.
|
||||
if self.loader.is_none() {
|
||||
error!("Saw @import rule, but no way to trigger the load");
|
||||
return Err(input.new_custom_error(StyleParseErrorKind::UnexpectedImportRule))
|
||||
}
|
||||
|
||||
let url_string = input.expect_url_or_string()?.as_ref().to_owned();
|
||||
let url = CssUrl::parse_from_string(url_string, &self.context);
|
||||
|
||||
|
|
|
@ -27,7 +27,6 @@ use cssparser::CowRcStr;
|
|||
use cssparser::{parse_important, AtRuleParser, DeclarationListParser, DeclarationParser, Parser};
|
||||
use euclid::TypedSize2D;
|
||||
use selectors::parser::SelectorParseErrorKind;
|
||||
use servo_config::pref;
|
||||
use std::borrow::Cow;
|
||||
use std::cell::RefCell;
|
||||
use std::fmt::{self, Write};
|
||||
|
@ -39,6 +38,7 @@ use style_traits::{CssWriter, ParseError, PinchZoomFactor, StyleParseErrorKind,
|
|||
/// Whether parsing and processing of `@viewport` rules is enabled.
|
||||
#[cfg(feature = "servo")]
|
||||
pub fn enabled() -> bool {
|
||||
use servo_config::pref;
|
||||
pref!(layout.viewport.enabled)
|
||||
}
|
||||
|
||||
|
|
|
@ -7,13 +7,13 @@
|
|||
use crate::values::computed::url::ComputedImageUrl;
|
||||
use crate::values::generics::counters as generics;
|
||||
use crate::values::generics::counters::CounterIncrement as GenericCounterIncrement;
|
||||
use crate::values::generics::counters::CounterReset as GenericCounterReset;
|
||||
use crate::values::generics::counters::CounterSetOrReset as GenericCounterSetOrReset;
|
||||
|
||||
/// A computed value for the `counter-increment` property.
|
||||
pub type CounterIncrement = GenericCounterIncrement<i32>;
|
||||
|
||||
/// A computed value for the `counter-increment` property.
|
||||
pub type CounterReset = GenericCounterReset<i32>;
|
||||
/// A computed value for the `counter-set` and `counter-reset` properties.
|
||||
pub type CounterSetOrReset = GenericCounterSetOrReset<i32>;
|
||||
|
||||
/// A computed value for the `content` property.
|
||||
pub type Content = generics::Content<ComputedImageUrl>;
|
||||
|
|
|
@ -152,49 +152,6 @@ impl FontSize {
|
|||
keyword_info: Some(KeywordInfo::medium()),
|
||||
}
|
||||
}
|
||||
|
||||
/// FIXME(emilio): This is very complex. Also, it should move to
|
||||
/// StyleBuilder.
|
||||
pub fn cascade_inherit_font_size(context: &mut Context) {
|
||||
// If inheriting, we must recompute font-size in case of language
|
||||
// changes using the font_size_keyword. We also need to do this to
|
||||
// handle mathml scriptlevel changes
|
||||
let kw_inherited_size = context
|
||||
.builder
|
||||
.get_parent_font()
|
||||
.clone_font_size()
|
||||
.keyword_info
|
||||
.map(|info| {
|
||||
specified::FontSize::Keyword(info)
|
||||
.to_computed_value(context)
|
||||
.size
|
||||
});
|
||||
let mut font = context.builder.take_font();
|
||||
font.inherit_font_size_from(
|
||||
context.builder.get_parent_font(),
|
||||
kw_inherited_size,
|
||||
context.builder.device,
|
||||
);
|
||||
context.builder.put_font(font);
|
||||
}
|
||||
|
||||
/// Cascade the initial value for the `font-size` property.
|
||||
///
|
||||
/// FIXME(emilio): This is the only function that is outside of the
|
||||
/// `StyleBuilder`, and should really move inside!
|
||||
///
|
||||
/// Can we move the font stuff there?
|
||||
pub fn cascade_initial_font_size(context: &mut Context) {
|
||||
// font-size's default ("medium") does not always
|
||||
// compute to the same value and depends on the font
|
||||
let computed = specified::FontSize::medium().to_computed_value(context);
|
||||
context.builder.mutate_font().set_font_size(computed);
|
||||
#[cfg(feature = "gecko")]
|
||||
{
|
||||
let device = context.builder.device;
|
||||
context.builder.mutate_font().fixup_font_min_size(device);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// XXXManishearth it might be better to
|
||||
|
@ -221,15 +178,21 @@ impl ToAnimatedValue for FontSize {
|
|||
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
|
||||
#[cfg_attr(feature = "servo", derive(MallocSizeOf))]
|
||||
/// Specifies a prioritized list of font family names or generic family names.
|
||||
pub struct FontFamily(pub FontFamilyList);
|
||||
pub struct FontFamily {
|
||||
/// The actual list of family names.
|
||||
pub families: FontFamilyList,
|
||||
/// Whether this font-family came from a specified system-font.
|
||||
pub is_system_font: bool,
|
||||
}
|
||||
|
||||
impl FontFamily {
|
||||
#[inline]
|
||||
/// Get default font family as `serif` which is a generic font-family
|
||||
pub fn serif() -> Self {
|
||||
FontFamily(FontFamilyList::new(Box::new([SingleFontFamily::Generic(
|
||||
atom!("serif"),
|
||||
)])))
|
||||
FontFamily {
|
||||
families: FontFamilyList::new(Box::new([SingleFontFamily::Generic(atom!("serif"))])),
|
||||
is_system_font: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -239,7 +202,9 @@ impl MallocSizeOf for FontFamily {
|
|||
// SharedFontList objects are generally shared from the pointer
|
||||
// stored in the specified value. So only count this if the
|
||||
// SharedFontList is unshared.
|
||||
unsafe { bindings::Gecko_SharedFontList_SizeOfIncludingThisIfUnshared((self.0).0.get()) }
|
||||
unsafe {
|
||||
bindings::Gecko_SharedFontList_SizeOfIncludingThisIfUnshared(self.families.0.get())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -248,7 +213,7 @@ impl ToCss for FontFamily {
|
|||
where
|
||||
W: fmt::Write,
|
||||
{
|
||||
let mut iter = self.0.iter();
|
||||
let mut iter = self.families.iter();
|
||||
iter.next().unwrap().to_css(dest)?;
|
||||
for family in iter {
|
||||
dest.write_str(", ")?;
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#[cfg(feature = "gecko")]
|
||||
pub use crate::values::specified::list::ListStyleType;
|
||||
pub use crate::values::specified::list::MozListReversed;
|
||||
pub use crate::values::specified::list::{QuotePair, Quotes};
|
||||
|
||||
use servo_arc::Arc;
|
||||
|
|
|
@ -45,7 +45,7 @@ pub use self::box_::{OverflowClipBox, OverscrollBehavior, Perspective, Resize};
|
|||
pub use self::box_::{ScrollSnapAlign, ScrollSnapType, TouchAction, VerticalAlign, WillChange};
|
||||
pub use self::color::{Color, ColorOrAuto, ColorPropertyValue, RGBAColor};
|
||||
pub use self::column::ColumnCount;
|
||||
pub use self::counters::{Content, ContentItem, CounterIncrement, CounterReset};
|
||||
pub use self::counters::{Content, ContentItem, CounterIncrement, CounterSetOrReset};
|
||||
pub use self::easing::TimingFunction;
|
||||
pub use self::effects::{BoxShadow, Filter, SimpleShadow};
|
||||
pub use self::flex::FlexBasis;
|
||||
|
@ -64,6 +64,7 @@ pub use self::length::{LengthOrAuto, LengthPercentageOrAuto, MaxSize, Size};
|
|||
pub use self::length::{NonNegativeLengthPercentage, NonNegativeLengthPercentageOrAuto};
|
||||
#[cfg(feature = "gecko")]
|
||||
pub use self::list::ListStyleType;
|
||||
pub use self::list::MozListReversed;
|
||||
pub use self::list::{QuotePair, Quotes};
|
||||
pub use self::motion::OffsetPath;
|
||||
pub use self::outline::OutlineStyle;
|
||||
|
|
|
@ -19,8 +19,8 @@ use std::fmt::{self, Write};
|
|||
use style_traits::{CssWriter, ToCss};
|
||||
|
||||
pub use crate::values::specified::TextAlignKeyword as TextAlign;
|
||||
pub use crate::values::specified::TextEmphasisPosition;
|
||||
pub use crate::values::specified::{OverflowWrap, WordBreak};
|
||||
pub use crate::values::specified::{TextDecorationLine, TextEmphasisPosition};
|
||||
|
||||
/// A computed value for the `initial-letter` property.
|
||||
pub type InitialLetter = GenericInitialLetter<CSSFloat, CSSInteger>;
|
||||
|
@ -182,11 +182,11 @@ impl TextDecorationsInEffect {
|
|||
.clone(),
|
||||
};
|
||||
|
||||
let text_style = style.get_text();
|
||||
let line = style.get_text().clone_text_decoration_line();
|
||||
|
||||
result.underline |= text_style.has_underline();
|
||||
result.overline |= text_style.has_overline();
|
||||
result.line_through |= text_style.has_line_through();
|
||||
result.underline |= line.contains(TextDecorationLine::UNDERLINE);
|
||||
result.overline |= line.contains(TextDecorationLine::OVERLINE);
|
||||
result.line_through |= line.contains(TextDecorationLine::LINE_THROUGH);
|
||||
|
||||
result
|
||||
}
|
||||
|
|
|
@ -45,21 +45,21 @@ impl<I> Deref for CounterIncrement<I> {
|
|||
}
|
||||
}
|
||||
|
||||
/// A generic value for the `counter-reset` property.
|
||||
/// A generic value for the `counter-set` and `counter-reset` properties.
|
||||
#[derive(
|
||||
Clone, Debug, Default, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss,
|
||||
)]
|
||||
pub struct CounterReset<I>(Counters<I>);
|
||||
pub struct CounterSetOrReset<I>(Counters<I>);
|
||||
|
||||
impl<I> CounterReset<I> {
|
||||
/// Returns a new value for `counter-reset`.
|
||||
impl<I> CounterSetOrReset<I> {
|
||||
/// Returns a new value for `counter-set` / `counter-reset`.
|
||||
#[inline]
|
||||
pub fn new(counters: Vec<CounterPair<I>>) -> Self {
|
||||
CounterReset(Counters(counters.into_boxed_slice()))
|
||||
CounterSetOrReset(Counters(counters.into_boxed_slice()))
|
||||
}
|
||||
}
|
||||
|
||||
impl<I> Deref for CounterReset<I> {
|
||||
impl<I> Deref for CounterSetOrReset<I> {
|
||||
type Target = [CounterPair<I>];
|
||||
|
||||
#[inline]
|
||||
|
|
|
@ -555,9 +555,8 @@ impl WillChange {
|
|||
|
||||
bitflags! {
|
||||
/// The change bits that we care about.
|
||||
///
|
||||
/// These need to be in sync with NS_STYLE_WILL_CHANGE_*.
|
||||
#[derive(MallocSizeOf, SpecifiedValueInfo, ToComputedValue)]
|
||||
#[repr(C)]
|
||||
pub struct WillChangeBits: u8 {
|
||||
/// Whether the stacking context will change.
|
||||
const STACKING_CONTEXT = 1 << 0;
|
||||
|
@ -616,7 +615,7 @@ impl Parse for WillChange {
|
|||
fn parse<'i, 't>(
|
||||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<WillChange, ParseError<'i>> {
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
if input
|
||||
.try(|input| input.expect_ident_matching("auto"))
|
||||
.is_ok()
|
||||
|
@ -650,21 +649,22 @@ impl Parse for WillChange {
|
|||
}
|
||||
|
||||
bitflags! {
|
||||
/// Values for the `touch-action` property.
|
||||
#[cfg_attr(feature = "gecko", derive(MallocSizeOf))]
|
||||
#[derive(SpecifiedValueInfo, ToComputedValue)]
|
||||
/// These constants match Gecko's `NS_STYLE_TOUCH_ACTION_*` constants.
|
||||
#[value_info(other_values = "auto,none,manipulation,pan-x,pan-y")]
|
||||
#[repr(C)]
|
||||
pub struct TouchAction: u8 {
|
||||
/// `none` variant
|
||||
const TOUCH_ACTION_NONE = 1 << 0;
|
||||
const NONE = 1 << 0;
|
||||
/// `auto` variant
|
||||
const TOUCH_ACTION_AUTO = 1 << 1;
|
||||
const AUTO = 1 << 1;
|
||||
/// `pan-x` variant
|
||||
const TOUCH_ACTION_PAN_X = 1 << 2;
|
||||
const PAN_X = 1 << 2;
|
||||
/// `pan-y` variant
|
||||
const TOUCH_ACTION_PAN_Y = 1 << 3;
|
||||
const PAN_Y = 1 << 3;
|
||||
/// `manipulation` variant
|
||||
const TOUCH_ACTION_MANIPULATION = 1 << 4;
|
||||
const MANIPULATION = 1 << 4;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -672,7 +672,7 @@ impl TouchAction {
|
|||
#[inline]
|
||||
/// Get default `touch-action` as `auto`
|
||||
pub fn auto() -> TouchAction {
|
||||
TouchAction::TOUCH_ACTION_AUTO
|
||||
TouchAction::AUTO
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -682,16 +682,14 @@ impl ToCss for TouchAction {
|
|||
W: Write,
|
||||
{
|
||||
match *self {
|
||||
TouchAction::TOUCH_ACTION_NONE => dest.write_str("none"),
|
||||
TouchAction::TOUCH_ACTION_AUTO => dest.write_str("auto"),
|
||||
TouchAction::TOUCH_ACTION_MANIPULATION => dest.write_str("manipulation"),
|
||||
_ if self
|
||||
.contains(TouchAction::TOUCH_ACTION_PAN_X | TouchAction::TOUCH_ACTION_PAN_Y) =>
|
||||
{
|
||||
TouchAction::NONE => dest.write_str("none"),
|
||||
TouchAction::AUTO => dest.write_str("auto"),
|
||||
TouchAction::MANIPULATION => dest.write_str("manipulation"),
|
||||
_ if self.contains(TouchAction::PAN_X | TouchAction::PAN_Y) => {
|
||||
dest.write_str("pan-x pan-y")
|
||||
},
|
||||
_ if self.contains(TouchAction::TOUCH_ACTION_PAN_X) => dest.write_str("pan-x"),
|
||||
_ if self.contains(TouchAction::TOUCH_ACTION_PAN_Y) => dest.write_str("pan-y"),
|
||||
_ if self.contains(TouchAction::PAN_X) => dest.write_str("pan-x"),
|
||||
_ if self.contains(TouchAction::PAN_Y) => dest.write_str("pan-y"),
|
||||
_ => panic!("invalid touch-action value"),
|
||||
}
|
||||
}
|
||||
|
@ -703,68 +701,45 @@ impl Parse for TouchAction {
|
|||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<TouchAction, ParseError<'i>> {
|
||||
try_match_ident_ignore_ascii_case! { input,
|
||||
"auto" => Ok(TouchAction::TOUCH_ACTION_AUTO),
|
||||
"none" => Ok(TouchAction::TOUCH_ACTION_NONE),
|
||||
"manipulation" => Ok(TouchAction::TOUCH_ACTION_MANIPULATION),
|
||||
"auto" => Ok(TouchAction::AUTO),
|
||||
"none" => Ok(TouchAction::NONE),
|
||||
"manipulation" => Ok(TouchAction::MANIPULATION),
|
||||
"pan-x" => {
|
||||
if input.try(|i| i.expect_ident_matching("pan-y")).is_ok() {
|
||||
Ok(TouchAction::TOUCH_ACTION_PAN_X | TouchAction::TOUCH_ACTION_PAN_Y)
|
||||
Ok(TouchAction::PAN_X | TouchAction::PAN_Y)
|
||||
} else {
|
||||
Ok(TouchAction::TOUCH_ACTION_PAN_X)
|
||||
Ok(TouchAction::PAN_X)
|
||||
}
|
||||
},
|
||||
"pan-y" => {
|
||||
if input.try(|i| i.expect_ident_matching("pan-x")).is_ok() {
|
||||
Ok(TouchAction::TOUCH_ACTION_PAN_X | TouchAction::TOUCH_ACTION_PAN_Y)
|
||||
Ok(TouchAction::PAN_X | TouchAction::PAN_Y)
|
||||
} else {
|
||||
Ok(TouchAction::TOUCH_ACTION_PAN_Y)
|
||||
Ok(TouchAction::PAN_Y)
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "gecko")]
|
||||
impl_bitflags_conversions!(TouchAction);
|
||||
|
||||
/// Asserts that all touch-action matches its NS_STYLE_TOUCH_ACTION_* value.
|
||||
#[cfg(feature = "gecko")]
|
||||
#[inline]
|
||||
pub fn assert_touch_action_matches() {
|
||||
use crate::gecko_bindings::structs;
|
||||
|
||||
macro_rules! check_touch_action {
|
||||
( $( $a:ident => $b:path),*, ) => {
|
||||
$(
|
||||
debug_assert_eq!(structs::$a as u8, $b.bits());
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
check_touch_action! {
|
||||
NS_STYLE_TOUCH_ACTION_NONE => TouchAction::TOUCH_ACTION_NONE,
|
||||
NS_STYLE_TOUCH_ACTION_AUTO => TouchAction::TOUCH_ACTION_AUTO,
|
||||
NS_STYLE_TOUCH_ACTION_PAN_X => TouchAction::TOUCH_ACTION_PAN_X,
|
||||
NS_STYLE_TOUCH_ACTION_PAN_Y => TouchAction::TOUCH_ACTION_PAN_Y,
|
||||
NS_STYLE_TOUCH_ACTION_MANIPULATION => TouchAction::TOUCH_ACTION_MANIPULATION,
|
||||
}
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
#[derive(MallocSizeOf, SpecifiedValueInfo, ToComputedValue)]
|
||||
#[value_info(other_values = "none,strict,content,size,layout,paint")]
|
||||
#[repr(C)]
|
||||
/// Constants for contain: https://drafts.csswg.org/css-contain/#contain-property
|
||||
pub struct Contain: u8 {
|
||||
/// `none` variant, just for convenience.
|
||||
const NONE = 0;
|
||||
/// 'size' variant, turns on size containment
|
||||
const SIZE = 0x01;
|
||||
const SIZE = 1 << 0;
|
||||
/// `layout` variant, turns on layout containment
|
||||
const LAYOUT = 0x02;
|
||||
const LAYOUT = 1 << 1;
|
||||
/// `paint` variant, turns on paint containment
|
||||
const PAINT = 0x04;
|
||||
const PAINT = 1 << 2;
|
||||
/// `strict` variant, turns on all types of containment
|
||||
const STRICT = 0x08;
|
||||
const STRICT = 1 << 3;
|
||||
/// 'content' variant, turns on layout and paint containment
|
||||
const CONTENT = 0x10;
|
||||
const CONTENT = 1 << 4;
|
||||
/// variant with all the bits that contain: strict turns on
|
||||
const STRICT_BITS = Contain::LAYOUT.bits | Contain::PAINT.bits | Contain::SIZE.bits;
|
||||
/// variant with all the bits that contain: content turns on
|
||||
|
|
|
@ -10,7 +10,7 @@ use crate::parser::{Parse, ParserContext};
|
|||
use crate::values::generics::counters as generics;
|
||||
use crate::values::generics::counters::CounterIncrement as GenericCounterIncrement;
|
||||
use crate::values::generics::counters::CounterPair;
|
||||
use crate::values::generics::counters::CounterReset as GenericCounterReset;
|
||||
use crate::values::generics::counters::CounterSetOrReset as GenericCounterSetOrReset;
|
||||
#[cfg(feature = "gecko")]
|
||||
use crate::values::generics::CounterStyleOrNone;
|
||||
use crate::values::specified::url::SpecifiedImageUrl;
|
||||
|
@ -34,10 +34,10 @@ impl Parse for CounterIncrement {
|
|||
}
|
||||
}
|
||||
|
||||
/// A specified value for the `counter-increment` property.
|
||||
pub type CounterReset = GenericCounterReset<Integer>;
|
||||
/// A specified value for the `counter-set` and `counter-reset` properties.
|
||||
pub type CounterSetOrReset = GenericCounterSetOrReset<Integer>;
|
||||
|
||||
impl Parse for CounterReset {
|
||||
impl Parse for CounterSetOrReset {
|
||||
fn parse<'i, 't>(
|
||||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
|
|
|
@ -548,13 +548,16 @@ impl ToComputedValue for FontFamily {
|
|||
|
||||
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
|
||||
match *self {
|
||||
FontFamily::Values(ref v) => computed::FontFamily(v.clone()),
|
||||
FontFamily::Values(ref v) => computed::FontFamily {
|
||||
families: v.clone(),
|
||||
is_system_font: false,
|
||||
},
|
||||
FontFamily::System(_) => self.compute_system(context),
|
||||
}
|
||||
}
|
||||
|
||||
fn from_computed_value(other: &computed::FontFamily) -> Self {
|
||||
FontFamily::Values(other.0.clone())
|
||||
FontFamily::Values(other.families.clone())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -958,48 +961,6 @@ impl FontSize {
|
|||
"larger" => Ok(FontSize::Larger),
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused_mut)]
|
||||
/// Cascade `font-size` with specified value
|
||||
pub fn cascade_specified_font_size(
|
||||
context: &mut Context,
|
||||
specified_value: &FontSize,
|
||||
mut computed: computed::FontSize,
|
||||
) {
|
||||
// we could use clone_language and clone_font_family() here but that's
|
||||
// expensive. Do it only in gecko mode for now.
|
||||
#[cfg(feature = "gecko")]
|
||||
{
|
||||
// if the language or generic changed, we need to recalculate
|
||||
// the font size from the stored font-size origin information.
|
||||
if context.builder.get_font().gecko().mLanguage.mRawPtr !=
|
||||
context.builder.get_parent_font().gecko().mLanguage.mRawPtr ||
|
||||
context.builder.get_font().gecko().mGenericID !=
|
||||
context.builder.get_parent_font().gecko().mGenericID
|
||||
{
|
||||
if let Some(info) = computed.keyword_info {
|
||||
computed.size = info.to_computed_value(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let device = context.builder.device;
|
||||
let mut font = context.builder.take_font();
|
||||
let parent_unconstrained = {
|
||||
let parent_font = context.builder.get_parent_font();
|
||||
font.apply_font_size(computed, parent_font, device)
|
||||
};
|
||||
context.builder.put_font(font);
|
||||
|
||||
if let Some(parent) = parent_unconstrained {
|
||||
let new_unconstrained = specified_value
|
||||
.to_computed_value_against(context, FontBaseSize::Custom(Au::from(parent)));
|
||||
context
|
||||
.builder
|
||||
.mutate_font()
|
||||
.apply_unconstrained_font_size(new_unconstrained.size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Parse for FontSize {
|
||||
|
|
|
@ -7,8 +7,9 @@
|
|||
//! [length]: https://drafts.csswg.org/css-values/#lengths
|
||||
|
||||
use super::{AllowQuirks, Number, Percentage, ToComputedValue};
|
||||
use crate::font_metrics::FontMetricsQueryResult;
|
||||
use crate::font_metrics::{FontMetrics, FontMetricsOrientation};
|
||||
use crate::parser::{Parse, ParserContext};
|
||||
use crate::properties::computed_value_flags::ComputedValueFlags;
|
||||
use crate::values::computed::{self, CSSPixelLength, Context};
|
||||
use crate::values::generics::length as generics;
|
||||
use crate::values::generics::length::{
|
||||
|
@ -82,17 +83,12 @@ pub enum FontBaseSize {
|
|||
///
|
||||
/// FIXME(emilio): This is very complex, and should go away.
|
||||
InheritedStyleButStripEmUnits,
|
||||
/// Use a custom base size.
|
||||
///
|
||||
/// FIXME(emilio): This is very dubious, and only used for MathML.
|
||||
Custom(Au),
|
||||
}
|
||||
|
||||
impl FontBaseSize {
|
||||
/// Calculate the actual size for a given context
|
||||
pub fn resolve(&self, context: &Context) -> Au {
|
||||
match *self {
|
||||
FontBaseSize::Custom(size) => size,
|
||||
FontBaseSize::CurrentStyle => context.style().get_font().clone_font_size().size(),
|
||||
FontBaseSize::InheritedStyleButStripEmUnits | FontBaseSize::InheritedStyle => {
|
||||
context.style().get_parent_font().clone_font_size().size()
|
||||
|
@ -136,15 +132,12 @@ impl FontRelativeLength {
|
|||
) -> (Au, CSSFloat) {
|
||||
fn query_font_metrics(
|
||||
context: &Context,
|
||||
reference_font_size: Au,
|
||||
) -> FontMetricsQueryResult {
|
||||
context.font_metrics_provider.query(
|
||||
context.style().get_font(),
|
||||
reference_font_size,
|
||||
context.style().writing_mode,
|
||||
context.in_media_query,
|
||||
context.device(),
|
||||
)
|
||||
base_size: FontBaseSize,
|
||||
orientation: FontMetricsOrientation,
|
||||
) -> FontMetrics {
|
||||
context
|
||||
.font_metrics_provider
|
||||
.query(context, base_size, orientation)
|
||||
}
|
||||
|
||||
let reference_font_size = base_size.resolve(context);
|
||||
|
@ -169,24 +162,40 @@ impl FontRelativeLength {
|
|||
if context.for_non_inherited_property.is_some() {
|
||||
context.rule_cache_conditions.borrow_mut().set_uncacheable();
|
||||
}
|
||||
let reference_size = match query_font_metrics(context, reference_font_size) {
|
||||
FontMetricsQueryResult::Available(metrics) => metrics.x_height,
|
||||
context
|
||||
.builder
|
||||
.add_flags(ComputedValueFlags::DEPENDS_ON_FONT_METRICS);
|
||||
// The x-height is an intrinsically horizontal metric.
|
||||
let metrics =
|
||||
query_font_metrics(context, base_size, FontMetricsOrientation::Horizontal);
|
||||
let reference_size = metrics.x_height.unwrap_or_else(|| {
|
||||
// https://drafts.csswg.org/css-values/#ex
|
||||
//
|
||||
// In the cases where it is impossible or impractical to
|
||||
// determine the x-height, a value of 0.5em must be
|
||||
// assumed.
|
||||
//
|
||||
FontMetricsQueryResult::NotAvailable => reference_font_size.scale_by(0.5),
|
||||
};
|
||||
reference_font_size.scale_by(0.5)
|
||||
});
|
||||
(reference_size, length)
|
||||
},
|
||||
FontRelativeLength::Ch(length) => {
|
||||
if context.for_non_inherited_property.is_some() {
|
||||
context.rule_cache_conditions.borrow_mut().set_uncacheable();
|
||||
}
|
||||
let reference_size = match query_font_metrics(context, reference_font_size) {
|
||||
FontMetricsQueryResult::Available(metrics) => metrics.zero_advance_measure,
|
||||
context
|
||||
.builder
|
||||
.add_flags(ComputedValueFlags::DEPENDS_ON_FONT_METRICS);
|
||||
// https://drafts.csswg.org/css-values/#ch:
|
||||
//
|
||||
// Equal to the used advance measure of the “0” (ZERO,
|
||||
// U+0030) glyph in the font used to render it. (The advance
|
||||
// measure of a glyph is its advance width or height,
|
||||
// whichever is in the inline axis of the element.)
|
||||
//
|
||||
let metrics =
|
||||
query_font_metrics(context, base_size, FontMetricsOrientation::MatchContext);
|
||||
let reference_size = metrics.zero_advance_measure.unwrap_or_else(|| {
|
||||
// https://drafts.csswg.org/css-values/#ch
|
||||
//
|
||||
// In the cases where it is impossible or impractical to
|
||||
|
@ -197,14 +206,13 @@ impl FontRelativeLength {
|
|||
// writing-mode is vertical-rl or vertical-lr and
|
||||
// text-orientation is upright).
|
||||
//
|
||||
FontMetricsQueryResult::NotAvailable => {
|
||||
if context.style().writing_mode.is_vertical() {
|
||||
let wm = context.style().writing_mode;
|
||||
if wm.is_vertical() && wm.is_upright() {
|
||||
reference_font_size
|
||||
} else {
|
||||
reference_font_size.scale_by(0.5)
|
||||
}
|
||||
},
|
||||
};
|
||||
});
|
||||
(reference_size, length)
|
||||
},
|
||||
FontRelativeLength::Rem(length) => {
|
||||
|
|
|
@ -123,3 +123,25 @@ impl Parse for Quotes {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Specified and computed `-moz-list-reversed` property (for UA sheets only).
|
||||
#[derive(
|
||||
Clone,
|
||||
Copy,
|
||||
Debug,
|
||||
Eq,
|
||||
Hash,
|
||||
MallocSizeOf,
|
||||
Parse,
|
||||
PartialEq,
|
||||
SpecifiedValueInfo,
|
||||
ToComputedValue,
|
||||
ToCss,
|
||||
)]
|
||||
#[repr(u8)]
|
||||
pub enum MozListReversed {
|
||||
/// the initial value
|
||||
False,
|
||||
/// exclusively used for <ol reversed> in our html.css UA sheet
|
||||
True,
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ pub use self::box_::{ScrollSnapAlign, ScrollSnapType};
|
|||
pub use self::box_::{TouchAction, TransitionProperty, VerticalAlign, WillChange};
|
||||
pub use self::color::{Color, ColorOrAuto, ColorPropertyValue, RGBAColor};
|
||||
pub use self::column::ColumnCount;
|
||||
pub use self::counters::{Content, ContentItem, CounterIncrement, CounterReset};
|
||||
pub use self::counters::{Content, ContentItem, CounterIncrement, CounterSetOrReset};
|
||||
pub use self::easing::TimingFunction;
|
||||
pub use self::effects::{BoxShadow, Filter, SimpleShadow};
|
||||
pub use self::flex::FlexBasis;
|
||||
|
@ -66,6 +66,7 @@ pub use self::length::{NoCalcLength, ViewportPercentageLength};
|
|||
pub use self::length::{NonNegativeLengthPercentage, NonNegativeLengthPercentageOrAuto};
|
||||
#[cfg(feature = "gecko")]
|
||||
pub use self::list::ListStyleType;
|
||||
pub use self::list::MozListReversed;
|
||||
pub use self::list::{QuotePair, Quotes};
|
||||
pub use self::motion::OffsetPath;
|
||||
pub use self::outline::OutlineStyle;
|
||||
|
|
|
@ -22,8 +22,7 @@ use cssparser::{Parser, Token};
|
|||
use selectors::parser::SelectorParseErrorKind;
|
||||
use std::fmt::{self, Write};
|
||||
use style_traits::values::SequenceWriter;
|
||||
use style_traits::{CssWriter, KeywordsCollectFn, ParseError};
|
||||
use style_traits::{SpecifiedValueInfo, StyleParseErrorKind, ToCss};
|
||||
use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss};
|
||||
use unicode_segmentation::UnicodeSegmentation;
|
||||
|
||||
/// A specified type for the `initial-letter` property.
|
||||
|
@ -255,24 +254,22 @@ impl ToComputedValue for TextOverflow {
|
|||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_text_decoration_line {
|
||||
{
|
||||
$(
|
||||
$(#[$($meta:tt)+])*
|
||||
$ident:ident / $css:expr => $value:expr,
|
||||
)+
|
||||
} => {
|
||||
bitflags! {
|
||||
#[derive(MallocSizeOf, ToComputedValue)]
|
||||
#[derive(MallocSizeOf, SpecifiedValueInfo, ToComputedValue)]
|
||||
#[value_info(other_values = "none,underline,overline,line-through,blink")]
|
||||
#[repr(C)]
|
||||
/// Specified keyword values for the text-decoration-line property.
|
||||
pub struct TextDecorationLine: u8 {
|
||||
/// No text decoration line is specified
|
||||
/// No text decoration line is specified.
|
||||
const NONE = 0;
|
||||
$(
|
||||
$(#[$($meta)+])*
|
||||
const $ident = $value;
|
||||
)+
|
||||
#[cfg(feature = "gecko")]
|
||||
/// underline
|
||||
const UNDERLINE = 1 << 0;
|
||||
/// overline
|
||||
const OVERLINE = 1 << 1;
|
||||
/// line-through
|
||||
const LINE_THROUGH = 1 << 2;
|
||||
/// blink
|
||||
const BLINK = 1 << 3;
|
||||
/// Only set by presentation attributes
|
||||
///
|
||||
/// Setting this will mean that text-decorations use the color
|
||||
|
@ -280,6 +277,7 @@ macro_rules! impl_text_decoration_line {
|
|||
///
|
||||
/// For example, this gives <a href=foo><font color="red">text</font></a>
|
||||
/// a red text decoration
|
||||
#[cfg(feature = "gecko")]
|
||||
const COLOR_OVERRIDE = 0x10;
|
||||
}
|
||||
}
|
||||
|
@ -289,35 +287,40 @@ macro_rules! impl_text_decoration_line {
|
|||
fn parse<'i, 't>(
|
||||
_context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<TextDecorationLine, ParseError<'i>> {
|
||||
let mut result = TextDecorationLine::NONE;
|
||||
if input
|
||||
.try(|input| input.expect_ident_matching("none"))
|
||||
.is_ok()
|
||||
{
|
||||
return Ok(result);
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
let mut result = TextDecorationLine::empty();
|
||||
|
||||
// NOTE(emilio): this loop has this weird structure because we run this
|
||||
// code to parse the text-decoration shorthand as well, so we need to
|
||||
// ensure we don't return an error if we don't consume the whole thing
|
||||
// because we find an invalid identifier or other kind of token.
|
||||
loop {
|
||||
let flag: Result<_, ParseError<'i>> = input.try(|input| {
|
||||
let flag = try_match_ident_ignore_ascii_case! { input,
|
||||
"none" if result.is_empty() => TextDecorationLine::NONE,
|
||||
"underline" => TextDecorationLine::UNDERLINE,
|
||||
"overline" => TextDecorationLine::OVERLINE,
|
||||
"line-through" => TextDecorationLine::LINE_THROUGH,
|
||||
"blink" => TextDecorationLine::BLINK,
|
||||
};
|
||||
|
||||
Ok(flag)
|
||||
});
|
||||
|
||||
let flag = match flag {
|
||||
Ok(flag) => flag,
|
||||
Err(..) => break,
|
||||
};
|
||||
|
||||
if flag.is_empty() {
|
||||
return Ok(TextDecorationLine::NONE);
|
||||
}
|
||||
|
||||
loop {
|
||||
let result = input.try(|input| {
|
||||
let ident = input.expect_ident().map_err(|_| ())?;
|
||||
match_ignore_ascii_case! { ident,
|
||||
$(
|
||||
$css => {
|
||||
if result.contains(TextDecorationLine::$ident) {
|
||||
Err(())
|
||||
} else {
|
||||
result.insert(TextDecorationLine::$ident);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
)+
|
||||
_ => Err(()),
|
||||
}
|
||||
});
|
||||
if result.is_err() {
|
||||
break;
|
||||
if result.contains(flag) {
|
||||
return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
|
||||
}
|
||||
|
||||
result.insert(flag)
|
||||
}
|
||||
|
||||
if !result.is_empty() {
|
||||
|
@ -337,38 +340,36 @@ macro_rules! impl_text_decoration_line {
|
|||
return dest.write_str("none");
|
||||
}
|
||||
|
||||
let mut writer = SequenceWriter::new(dest, " ");
|
||||
$(
|
||||
if self.contains(TextDecorationLine::$ident) {
|
||||
writer.raw_item($css)?;
|
||||
#[cfg(feature = "gecko")]
|
||||
{
|
||||
if *self == TextDecorationLine::COLOR_OVERRIDE {
|
||||
return Ok(());
|
||||
}
|
||||
)+
|
||||
}
|
||||
|
||||
let mut writer = SequenceWriter::new(dest, " ");
|
||||
let mut any = false;
|
||||
|
||||
macro_rules! maybe_write {
|
||||
($ident:ident => $str:expr) => {
|
||||
if self.contains(TextDecorationLine::$ident) {
|
||||
any = true;
|
||||
writer.raw_item($str)?;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
maybe_write!(UNDERLINE => "underline");
|
||||
maybe_write!(OVERLINE => "overline");
|
||||
maybe_write!(LINE_THROUGH => "line-through");
|
||||
maybe_write!(BLINK => "blink");
|
||||
|
||||
debug_assert!(any);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl SpecifiedValueInfo for TextDecorationLine {
|
||||
fn collect_completion_keywords(f: KeywordsCollectFn) {
|
||||
f(&["none", $($css,)+]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl_text_decoration_line! {
|
||||
/// Underline
|
||||
UNDERLINE / "underline" => 1 << 0,
|
||||
/// Overline
|
||||
OVERLINE / "overline" => 1 << 1,
|
||||
/// Line through
|
||||
LINE_THROUGH / "line-through" => 1 << 2,
|
||||
/// Blink
|
||||
BLINK / "blink" => 1 << 3,
|
||||
}
|
||||
|
||||
#[cfg(feature = "gecko")]
|
||||
impl_bitflags_conversions!(TextDecorationLine);
|
||||
|
||||
impl TextDecorationLine {
|
||||
#[inline]
|
||||
/// Returns the initial value of text-decoration-line
|
||||
|
|
|
@ -10,7 +10,7 @@ use std::sync::Arc as StdArc;
|
|||
|
||||
/// Type of value that a property supports. This is used by Gecko's
|
||||
/// devtools to make sense about value it parses, and types listed
|
||||
/// here should match TYPE_* constants in InspectorUtils.webidl.
|
||||
/// here should match InspectorPropertyType in InspectorUtils.webidl.
|
||||
///
|
||||
/// XXX This should really be a bitflags rather than a namespace mod,
|
||||
/// but currently we cannot use bitflags in const.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue