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
|
let families = style
|
||||||
.font_family
|
.font_family
|
||||||
.0
|
.families
|
||||||
.iter()
|
.iter()
|
||||||
.map(|family| FontGroupFamily::new(descriptor.clone(), &family))
|
.map(|family| FontGroupFamily::new(descriptor.clone(), &family))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
|
@ -119,7 +119,10 @@ fn font_family(names: Vec<&str>) -> FontFamily {
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
FontFamily(FontFamilyList::new(names.into_boxed_slice()))
|
FontFamily {
|
||||||
|
families: FontFamilyList::new(names.into_boxed_slice()),
|
||||||
|
is_system_font: false,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -77,7 +77,7 @@ where
|
||||||
|
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
unsafe impl HasFFI for AuthorStyles<crate::gecko::data::GeckoStyleSheet> {
|
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")]
|
#[cfg(feature = "gecko")]
|
||||||
unsafe impl HasSimpleFFI for AuthorStyles<crate::gecko::data::GeckoStyleSheet> {}
|
unsafe impl HasSimpleFFI for AuthorStyles<crate::gecko::data::GeckoStyleSheet> {}
|
||||||
|
|
|
@ -19,7 +19,7 @@ thread_local! {
|
||||||
/// such that they can be reused across style traversals. StyleBloom is responsible
|
/// such that they can be reused across style traversals. StyleBloom is responsible
|
||||||
/// for ensuring that the bloom filter is zeroed when it is dropped.
|
/// for ensuring that the bloom filter is zeroed when it is dropped.
|
||||||
static BLOOM_KEY: Arc<AtomicRefCell<BloomFilter>> =
|
static BLOOM_KEY: Arc<AtomicRefCell<BloomFilter>> =
|
||||||
Arc::new(AtomicRefCell::new(BloomFilter::new()));
|
Arc::new(AtomicRefCell::new(BloomFilter::new()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A struct that allows us to fast-reject deep descendant selectors avoiding
|
/// A struct that allows us to fast-reject deep descendant selectors avoiding
|
||||||
|
|
|
@ -32,7 +32,6 @@ mod bindings {
|
||||||
use toml::value::Table;
|
use toml::value::Table;
|
||||||
|
|
||||||
const STRUCTS_FILE: &'static str = "structs.rs";
|
const STRUCTS_FILE: &'static str = "structs.rs";
|
||||||
const BINDINGS_FILE: &'static str = "bindings.rs";
|
|
||||||
|
|
||||||
fn read_config(path: &PathBuf) -> Table {
|
fn read_config(path: &PathBuf) -> Table {
|
||||||
println!("cargo:rerun-if-changed={}", path.to_str().unwrap());
|
println!("cargo:rerun-if-changed={}", path.to_str().unwrap());
|
||||||
|
@ -128,9 +127,6 @@ mod bindings {
|
||||||
trait BuilderExt {
|
trait BuilderExt {
|
||||||
fn get_initial_builder() -> Builder;
|
fn get_initial_builder() -> Builder;
|
||||||
fn include<T: Into<String>>(self, file: T) -> 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 {
|
impl BuilderExt for Builder {
|
||||||
|
@ -181,42 +177,6 @@ mod bindings {
|
||||||
fn include<T: Into<String>>(self, file: T) -> Builder {
|
fn include<T: Into<String>>(self, file: T) -> Builder {
|
||||||
self.clang_arg("-include").clang_arg(file)
|
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 {
|
struct Fixup {
|
||||||
|
@ -259,58 +219,6 @@ mod bindings {
|
||||||
.expect("Unable to write output");
|
.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> {
|
struct BuilderWithConfig<'a> {
|
||||||
builder: Builder,
|
builder: Builder,
|
||||||
config: &'a Table,
|
config: &'a Table,
|
||||||
|
@ -386,10 +294,13 @@ mod bindings {
|
||||||
fn generate_structs() {
|
fn generate_structs() {
|
||||||
let builder = Builder::get_initial_builder()
|
let builder = Builder::get_initial_builder()
|
||||||
.enable_cxx_namespaces()
|
.enable_cxx_namespaces()
|
||||||
.with_codegen_config(CodegenConfig::TYPES | CodegenConfig::VARS);
|
.with_codegen_config(
|
||||||
|
CodegenConfig::TYPES | CodegenConfig::VARS | CodegenConfig::FUNCTIONS,
|
||||||
|
);
|
||||||
let mut fixups = vec![];
|
let mut fixups = vec![];
|
||||||
let builder = BuilderWithConfig::new(builder, CONFIG["structs"].as_table().unwrap())
|
let builder = BuilderWithConfig::new(builder, CONFIG["structs"].as_table().unwrap())
|
||||||
.handle_common(&mut fixups)
|
.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("bitfield-enums", |b, item| b.bitfield_enum(item))
|
||||||
.handle_str_items("rusty-enums", |b, item| b.rustified_enum(item))
|
.handle_str_items("rusty-enums", |b, item| b.rustified_enum(item))
|
||||||
.handle_str_items("whitelist-vars", |b, item| b.whitelist_var(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() {
|
fn generate_atoms() {
|
||||||
let script = PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").unwrap())
|
let script = PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").unwrap())
|
||||||
.join("gecko")
|
.join("gecko")
|
||||||
|
@ -580,24 +408,9 @@ mod bindings {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate() {
|
pub fn generate() {
|
||||||
use std::thread;
|
setup_logging();
|
||||||
macro_rules! run_tasks {
|
generate_structs();
|
||||||
($($task:expr,)+) => {
|
generate_atoms();
|
||||||
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(),
|
|
||||||
}
|
|
||||||
|
|
||||||
for path in ADDED_PATHS.lock().unwrap().iter() {
|
for path in ADDED_PATHS.lock().unwrap().iter() {
|
||||||
println!("cargo:rerun-if-changed={}", path.to_str().unwrap());
|
println!("cargo:rerun-if-changed={}", path.to_str().unwrap());
|
||||||
|
|
|
@ -103,6 +103,15 @@ include = [
|
||||||
"ZIndex",
|
"ZIndex",
|
||||||
"TransformOrigin",
|
"TransformOrigin",
|
||||||
"WordBreak",
|
"WordBreak",
|
||||||
|
"Contain",
|
||||||
|
"RestyleHint",
|
||||||
|
"TouchAction",
|
||||||
|
"WillChangeBits",
|
||||||
|
"TextDecorationLine",
|
||||||
|
"MozListReversed",
|
||||||
|
"Owned",
|
||||||
|
"OwnedOrNull",
|
||||||
|
"Strong",
|
||||||
]
|
]
|
||||||
item_types = ["enums", "structs", "typedefs"]
|
item_types = ["enums", "structs", "typedefs"]
|
||||||
|
|
||||||
|
@ -196,3 +205,35 @@ item_types = ["enums", "structs", "typedefs"]
|
||||||
"GenericBorderRadius" = """
|
"GenericBorderRadius" = """
|
||||||
inline const StyleLengthPercentage& Get(mozilla::HalfCorner) const;
|
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
|
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
|
/// Execute `f` for each anonymous content child (apart from ::before and
|
||||||
/// ::after) whose originating element is `self`.
|
/// ::after) whose originating element is `self`.
|
||||||
fn each_anonymous_content_child<F>(&self, _f: F)
|
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")]
|
#[cfg(feature = "gecko")]
|
||||||
font_face_descriptors! {
|
font_face_descriptors! {
|
||||||
mandatory descriptors = [
|
mandatory descriptors = [
|
||||||
|
|
|
@ -7,51 +7,42 @@
|
||||||
#![deny(missing_docs)]
|
#![deny(missing_docs)]
|
||||||
|
|
||||||
use crate::context::SharedStyleContext;
|
use crate::context::SharedStyleContext;
|
||||||
use crate::logical_geometry::WritingMode;
|
|
||||||
use crate::media_queries::Device;
|
|
||||||
use crate::properties::style_structs::Font;
|
|
||||||
use crate::Atom;
|
use crate::Atom;
|
||||||
use app_units::Au;
|
use app_units::Au;
|
||||||
|
|
||||||
/// Represents the font metrics that style needs from a font to compute the
|
/// Represents the font metrics that style needs from a font to compute the
|
||||||
/// value of certain CSS units like `ex`.
|
/// value of certain CSS units like `ex`.
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, Default, PartialEq)]
|
||||||
pub struct FontMetrics {
|
pub struct FontMetrics {
|
||||||
/// The x-height of the font.
|
/// The x-height of the font.
|
||||||
pub x_height: Au,
|
pub x_height: Option<Au>,
|
||||||
/// The zero advance. This is usually writing mode dependent
|
/// 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)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub enum FontMetricsQueryResult {
|
pub enum FontMetricsOrientation {
|
||||||
/// The font is available, but we may or may not have found any font metrics
|
/// Get metrics for horizontal or vertical according to the Context's
|
||||||
/// for it.
|
/// writing mode.
|
||||||
Available(FontMetrics),
|
MatchContext,
|
||||||
/// The font is not available.
|
/// Force getting horizontal metrics.
|
||||||
NotAvailable,
|
Horizontal,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A trait used to represent something capable of providing us font metrics.
|
/// A trait used to represent something capable of providing us font metrics.
|
||||||
pub trait FontMetricsProvider {
|
pub trait FontMetricsProvider {
|
||||||
/// Obtain the metrics for given font family.
|
/// 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(
|
fn query(
|
||||||
&self,
|
&self,
|
||||||
_font: &Font,
|
_context: &crate::values::computed::Context,
|
||||||
_font_size: Au,
|
_base_size: crate::values::specified::length::FontBaseSize,
|
||||||
_wm: WritingMode,
|
_orientation: FontMetricsOrientation,
|
||||||
_in_media_query: bool,
|
) -> FontMetrics {
|
||||||
_device: &Device,
|
Default::default()
|
||||||
) -> FontMetricsQueryResult {
|
|
||||||
FontMetricsQueryResult::NotAvailable
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 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;
|
fn get_size(&self, font_name: &Atom, font_family: u8) -> Au;
|
||||||
|
|
||||||
/// Construct from a shared style context
|
/// Construct from a shared style context
|
||||||
|
|
|
@ -9,32 +9,29 @@
|
||||||
#![allow(non_snake_case, missing_docs)]
|
#![allow(non_snake_case, missing_docs)]
|
||||||
|
|
||||||
use crate::gecko::url::CssUrlData;
|
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::RawServoAnimationValue;
|
||||||
|
use crate::gecko_bindings::structs::RawServoCounterStyleRule;
|
||||||
use crate::gecko_bindings::structs::RawServoCssUrlData;
|
use crate::gecko_bindings::structs::RawServoCssUrlData;
|
||||||
use crate::gecko_bindings::structs::RawServoDeclarationBlock;
|
use crate::gecko_bindings::structs::RawServoDeclarationBlock;
|
||||||
use crate::gecko_bindings::structs::RawServoFontFaceRule;
|
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::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::RawServoQuotes;
|
||||||
use crate::gecko_bindings::structs::RawServoStyleRule;
|
use crate::gecko_bindings::structs::RawServoStyleRule;
|
||||||
use crate::gecko_bindings::structs::RawServoStyleSheetContents;
|
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::gecko_bindings::sugar::ownership::{HasArcFFI, HasFFI, Strong};
|
||||||
use crate::media_queries::MediaList;
|
use crate::media_queries::MediaList;
|
||||||
use crate::properties::animated_properties::AnimationValue;
|
use crate::properties::animated_properties::AnimationValue;
|
||||||
use crate::properties::{ComputedValues, PropertyDeclarationBlock};
|
use crate::properties::{ComputedValues, PropertyDeclarationBlock};
|
||||||
use crate::rule_tree::StrongRuleNode;
|
|
||||||
use crate::shared_lock::Locked;
|
use crate::shared_lock::Locked;
|
||||||
use crate::stylesheets::keyframes_rule::Keyframe;
|
use crate::stylesheets::keyframes_rule::Keyframe;
|
||||||
use crate::stylesheets::{CounterStyleRule, CssRules, FontFaceRule, FontFeatureValuesRule};
|
use crate::stylesheets::{CounterStyleRule, CssRules, FontFaceRule, FontFeatureValuesRule};
|
||||||
|
@ -121,31 +118,6 @@ impl_arc_ffi!(CssUrlData => RawServoCssUrlData
|
||||||
impl_arc_ffi!(Box<[QuotePair]> => RawServoQuotes
|
impl_arc_ffi!(Box<[QuotePair]> => RawServoQuotes
|
||||||
[Servo_Quotes_AddRef, Servo_Quotes_Release]);
|
[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.
|
// ComputedStyle is not an opaque type on any side of FFI.
|
||||||
// This means that doing the HasArcFFI type trick is actually unsound,
|
// This means that doing the HasArcFFI type trick is actually unsound,
|
||||||
// since it gives us a way to construct an Arc<ComputedStyle> from
|
// since it gives us a way to construct an Arc<ComputedStyle> from
|
||||||
|
|
|
@ -12,8 +12,7 @@
|
||||||
|
|
||||||
use crate::gecko::values::GeckoStyleCoordConvertible;
|
use crate::gecko::values::GeckoStyleCoordConvertible;
|
||||||
use crate::gecko_bindings::bindings;
|
use crate::gecko_bindings::bindings;
|
||||||
use crate::gecko_bindings::structs::RawGeckoGfxMatrix4x4;
|
use crate::gecko_bindings::structs::{self, nsStyleCoord_CalcValue, Matrix4x4Components};
|
||||||
use crate::gecko_bindings::structs::{self, nsStyleCoord_CalcValue};
|
|
||||||
use crate::gecko_bindings::structs::{nsStyleImage, nsresult, SheetType};
|
use crate::gecko_bindings::structs::{nsStyleImage, nsresult, SheetType};
|
||||||
use crate::gecko_bindings::sugar::ns_style_coord::{CoordData, CoordDataMut, CoordDataValue};
|
use crate::gecko_bindings::sugar::ns_style_coord::{CoordData, CoordDataMut, CoordDataValue};
|
||||||
use crate::stylesheets::{Origin, RulesMutateError};
|
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)
|
String::from_utf16_lossy(char_vec)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> From<&'a RawGeckoGfxMatrix4x4> for Matrix3D {
|
impl<'a> From<&'a Matrix4x4Components> for Matrix3D {
|
||||||
fn from(m: &'a RawGeckoGfxMatrix4x4) -> Matrix3D {
|
fn from(m: &'a Matrix4x4Components) -> Matrix3D {
|
||||||
Matrix3D {
|
Matrix3D {
|
||||||
m11: m[0],
|
m11: m[0],
|
||||||
m12: m[1],
|
m12: m[1],
|
||||||
|
@ -1009,8 +1008,8 @@ impl<'a> From<&'a RawGeckoGfxMatrix4x4> for Matrix3D {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Matrix3D> for RawGeckoGfxMatrix4x4 {
|
impl From<Matrix3D> for Matrix4x4Components {
|
||||||
fn from(matrix: Matrix3D) -> RawGeckoGfxMatrix4x4 {
|
fn from(matrix: Matrix3D) -> Self {
|
||||||
[
|
[
|
||||||
matrix.m11, matrix.m12, matrix.m13, matrix.m14, matrix.m21, matrix.m22, matrix.m23,
|
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,
|
matrix.m24, matrix.m31, matrix.m32, matrix.m33, matrix.m34, matrix.m41, matrix.m42,
|
||||||
|
|
|
@ -6,8 +6,8 @@
|
||||||
|
|
||||||
use crate::context::QuirksMode;
|
use crate::context::QuirksMode;
|
||||||
use crate::dom::TElement;
|
use crate::dom::TElement;
|
||||||
use crate::gecko_bindings::bindings::{self, RawServoStyleSet};
|
use crate::gecko_bindings::bindings;
|
||||||
use crate::gecko_bindings::structs::{self, ServoStyleSetSizes};
|
use crate::gecko_bindings::structs::{self, RawServoStyleSet, ServoStyleSetSizes};
|
||||||
use crate::gecko_bindings::structs::{StyleSheet as DomStyleSheet, StyleSheetInfo};
|
use crate::gecko_bindings::structs::{StyleSheet as DomStyleSheet, StyleSheetInfo};
|
||||||
use crate::gecko_bindings::sugar::ownership::{HasArcFFI, HasBoxFFI, HasFFI, HasSimpleFFI};
|
use crate::gecko_bindings::sugar::ownership::{HasArcFFI, HasBoxFFI, HasFFI, HasSimpleFFI};
|
||||||
use crate::invalidation::media_queries::{MediaListKey, ToMediaListKey};
|
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! {
|
bitflags! {
|
||||||
|
/// https://drafts.csswg.org/mediaqueries-4/#mf-interaction
|
||||||
struct PointerCapabilities: u8 {
|
struct PointerCapabilities: u8 {
|
||||||
const COARSE = structs::PointerCapabilities_Coarse;
|
const COARSE = structs::PointerCapabilities_Coarse;
|
||||||
const FINE = structs::PointerCapabilities_Fine;
|
const FINE = structs::PointerCapabilities_Fine;
|
||||||
|
|
|
@ -33,7 +33,10 @@ impl ::selectors::parser::PseudoElement for PseudoElement {
|
||||||
fn valid_after_slotted(&self) -> bool {
|
fn valid_after_slotted(&self) -> bool {
|
||||||
matches!(
|
matches!(
|
||||||
*self,
|
*self,
|
||||||
PseudoElement::Before | PseudoElement::After | PseudoElement::Placeholder
|
PseudoElement::Before |
|
||||||
|
PseudoElement::After |
|
||||||
|
PseudoElement::Marker |
|
||||||
|
PseudoElement::Placeholder
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,6 +112,12 @@ impl PseudoElement {
|
||||||
*self == PseudoElement::After
|
*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.
|
/// Whether this pseudo-element is ::first-letter.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_first_letter(&self) -> bool {
|
pub fn is_first_letter(&self) -> bool {
|
||||||
|
@ -180,6 +189,8 @@ impl PseudoElement {
|
||||||
/// Whether this pseudo-element should actually exist if it has
|
/// Whether this pseudo-element should actually exist if it has
|
||||||
/// the given styles.
|
/// the given styles.
|
||||||
pub fn should_exist(&self, style: &ComputedValues) -> bool {
|
pub fn should_exist(&self, style: &ComputedValues) -> bool {
|
||||||
|
debug_assert!(self.is_eager());
|
||||||
|
|
||||||
if style.get_box().clone_display() == Display::None {
|
if style.get_box().clone_display() == Display::None {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -195,13 +195,16 @@ impl PseudoElement {
|
||||||
return Some(${pseudo_element_variant(pseudo)})
|
return Some(${pseudo_element_variant(pseudo)})
|
||||||
}
|
}
|
||||||
% endfor
|
% endfor
|
||||||
// Alias "-moz-selection" to "selection" at parse time.
|
// Alias some legacy prefixed pseudos to their standardized name at parse time:
|
||||||
"-moz-selection" => {
|
"-moz-selection" => {
|
||||||
return Some(PseudoElement::Selection);
|
return Some(PseudoElement::Selection);
|
||||||
}
|
}
|
||||||
"-moz-placeholder" => {
|
"-moz-placeholder" => {
|
||||||
return Some(PseudoElement::Placeholder);
|
return Some(PseudoElement::Placeholder);
|
||||||
}
|
}
|
||||||
|
"-moz-list-bullet" | "-moz-list-number" => {
|
||||||
|
return Some(PseudoElement::Marker);
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
if starts_with_ignore_ascii_case(name, "-moz-tree-") {
|
if starts_with_ignore_ascii_case(name, "-moz-tree-") {
|
||||||
return PseudoElement::tree_pseudo_element(name, Box::new([]))
|
return PseudoElement::tree_pseudo_element(name, Box::new([]))
|
||||||
|
|
|
@ -51,8 +51,8 @@ impl GeckoRestyleDamage {
|
||||||
let mut reset_only = false;
|
let mut reset_only = false;
|
||||||
let hint = unsafe {
|
let hint = unsafe {
|
||||||
bindings::Gecko_CalcStyleDifference(
|
bindings::Gecko_CalcStyleDifference(
|
||||||
old_style,
|
old_style.as_gecko_computed_style(),
|
||||||
new_style,
|
new_style.as_gecko_computed_style(),
|
||||||
&mut any_style_changed,
|
&mut any_style_changed,
|
||||||
&mut reset_only,
|
&mut reset_only,
|
||||||
)
|
)
|
||||||
|
|
|
@ -20,7 +20,7 @@ use crate::context::{PostAnimationTasks, QuirksMode, SharedStyleContext, UpdateA
|
||||||
use crate::data::ElementData;
|
use crate::data::ElementData;
|
||||||
use crate::dom::{LayoutIterator, NodeInfo, OpaqueNode, TDocument, TElement, TNode, TShadowRoot};
|
use crate::dom::{LayoutIterator, NodeInfo, OpaqueNode, TDocument, TElement, TNode, TShadowRoot};
|
||||||
use crate::element_state::{DocumentState, ElementState};
|
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::data::GeckoStyleSheet;
|
||||||
use crate::gecko::selector_parser::{NonTSPseudoClass, PseudoElement, SelectorImpl};
|
use crate::gecko::selector_parser::{NonTSPseudoClass, PseudoElement, SelectorImpl};
|
||||||
use crate::gecko::snapshot_helpers;
|
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::bindings::{Gecko_SetNodeFlags, Gecko_UnsetNodeFlags};
|
||||||
use crate::gecko_bindings::structs;
|
use crate::gecko_bindings::structs;
|
||||||
use crate::gecko_bindings::structs::nsChangeHint;
|
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::Document_DocumentTheme as DocumentTheme;
|
||||||
use crate::gecko_bindings::structs::EffectCompositor_CascadeLevel as CascadeLevel;
|
use crate::gecko_bindings::structs::EffectCompositor_CascadeLevel as CascadeLevel;
|
||||||
use crate::gecko_bindings::structs::ELEMENT_HANDLED_SNAPSHOT;
|
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_DESCENDANTS_NEED_FRAMES;
|
||||||
use crate::gecko_bindings::structs::NODE_NEEDS_FRAME;
|
use crate::gecko_bindings::structs::NODE_NEEDS_FRAME;
|
||||||
use crate::gecko_bindings::structs::{nsAtom, nsIContent, nsINode_BooleanFlag};
|
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::gecko_bindings::sugar::ownership::{HasArcFFI, HasSimpleFFI};
|
||||||
use crate::global_style_data::GLOBAL_STYLE_DATA;
|
use crate::global_style_data::GLOBAL_STYLE_DATA;
|
||||||
use crate::hash::FxHashMap;
|
use crate::hash::FxHashMap;
|
||||||
use crate::logical_geometry::WritingMode;
|
use crate::invalidation::element::restyle_hints::RestyleHint;
|
||||||
use crate::media_queries::Device;
|
use crate::media_queries::Device;
|
||||||
use crate::properties::animated_properties::{AnimationValue, AnimationValueMap};
|
use crate::properties::animated_properties::{AnimationValue, AnimationValueMap};
|
||||||
use crate::properties::style_structs::Font;
|
|
||||||
use crate::properties::{ComputedValues, LonghandId};
|
use crate::properties::{ComputedValues, LonghandId};
|
||||||
use crate::properties::{Importance, PropertyDeclaration, PropertyDeclarationBlock};
|
use crate::properties::{Importance, PropertyDeclaration, PropertyDeclarationBlock};
|
||||||
use crate::rule_tree::CascadeLevel as ServoCascadeLevel;
|
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::shared_lock::Locked;
|
||||||
use crate::string_cache::{Atom, Namespace, WeakAtom, WeakNamespace};
|
use crate::string_cache::{Atom, Namespace, WeakAtom, WeakNamespace};
|
||||||
use crate::stylist::CascadeData;
|
use crate::stylist::CascadeData;
|
||||||
|
use crate::values::specified::length::FontBaseSize;
|
||||||
use crate::CaseSensitivityExt;
|
use crate::CaseSensitivityExt;
|
||||||
use app_units::Au;
|
use app_units::Au;
|
||||||
use atomic_refcell::{AtomicRefCell, AtomicRefMut};
|
use atomic_refcell::{AtomicRefCell, AtomicRefMut};
|
||||||
|
@ -169,11 +170,7 @@ impl<'lr> TShadowRoot for GeckoShadowRoot<'lr> {
|
||||||
where
|
where
|
||||||
Self: 'a,
|
Self: 'a,
|
||||||
{
|
{
|
||||||
let author_styles = unsafe {
|
let author_styles = unsafe { self.0.mServoStyles.mPtr.as_ref()? };
|
||||||
(self.0.mServoStyles.mPtr as *const structs::RawServoAuthorStyles
|
|
||||||
as *const bindings::RawServoAuthorStyles)
|
|
||||||
.as_ref()?
|
|
||||||
};
|
|
||||||
|
|
||||||
let author_styles = AuthorStyles::<GeckoStyleSheet>::from_ffi(author_styles);
|
let author_styles = AuthorStyles::<GeckoStyleSheet>::from_ffi(author_styles);
|
||||||
|
|
||||||
|
@ -326,7 +323,11 @@ impl<'ln> GeckoNode<'ln> {
|
||||||
// `flattened_tree_parent`.
|
// `flattened_tree_parent`.
|
||||||
if self.flattened_tree_parent_is_parent() {
|
if self.flattened_tree_parent_is_parent() {
|
||||||
debug_assert_eq!(
|
debug_assert_eq!(
|
||||||
unsafe { bindings::Gecko_GetFlattenedTreeParentNode(self.0).map(GeckoNode) },
|
unsafe {
|
||||||
|
bindings::Gecko_GetFlattenedTreeParentNode(self.0)
|
||||||
|
.as_ref()
|
||||||
|
.map(GeckoNode)
|
||||||
|
},
|
||||||
self.parent_node(),
|
self.parent_node(),
|
||||||
"Fast path stopped holding!"
|
"Fast path stopped holding!"
|
||||||
);
|
);
|
||||||
|
@ -336,7 +337,11 @@ impl<'ln> GeckoNode<'ln> {
|
||||||
|
|
||||||
// NOTE(emilio): If this call is too expensive, we could manually
|
// NOTE(emilio): If this call is too expensive, we could manually
|
||||||
// inline more aggressively.
|
// inline more aggressively.
|
||||||
unsafe { bindings::Gecko_GetFlattenedTreeParentNode(self.0).map(GeckoNode) }
|
unsafe {
|
||||||
|
bindings::Gecko_GetFlattenedTreeParentNode(self.0)
|
||||||
|
.as_ref()
|
||||||
|
.map(GeckoNode)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -381,12 +386,16 @@ impl<'ln> TNode for GeckoNode<'ln> {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn last_child(&self) -> Option<Self> {
|
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]
|
#[inline]
|
||||||
fn prev_sibling(&self) -> Option<Self> {
|
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]
|
#[inline]
|
||||||
|
@ -503,7 +512,9 @@ impl<'a> Iterator for GeckoChildrenIterator<'a> {
|
||||||
// however we can't express this easily with bindgen, and it would
|
// however we can't express this easily with bindgen, and it would
|
||||||
// introduce functions with two input lifetimes into bindgen,
|
// introduce functions with two input lifetimes into bindgen,
|
||||||
// which would be out of scope for elision.
|
// 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);
|
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 {
|
if let Some(data) = data {
|
||||||
let data: &'lb _ = AuthorStyles::<GeckoStyleSheet>::from_ffi(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,
|
// FIXME(heycam): Having trouble with bindgen on nsXULElement,
|
||||||
// where the binding parent is stored in a member variable
|
// where the binding parent is stored in a member variable
|
||||||
// rather than in slots. So just get it through FFI for now.
|
// 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 {
|
} else {
|
||||||
let binding_parent = unsafe { self.non_xul_xbl_binding_parent_raw_content().as_ref() }
|
let binding_parent = unsafe { self.non_xul_xbl_binding_parent_raw_content().as_ref() }
|
||||||
.map(GeckoNode::from_content)
|
.map(GeckoNode::from_content)
|
||||||
|
@ -718,7 +733,11 @@ impl<'le> GeckoElement<'le> {
|
||||||
|
|
||||||
debug_assert!(
|
debug_assert!(
|
||||||
binding_parent ==
|
binding_parent ==
|
||||||
unsafe { bindings::Gecko_GetBindingParent(self.0).map(GeckoElement) }
|
unsafe {
|
||||||
|
bindings::Gecko_GetBindingParent(self.0)
|
||||||
|
.as_ref()
|
||||||
|
.map(GeckoElement)
|
||||||
|
}
|
||||||
);
|
);
|
||||||
binding_parent
|
binding_parent
|
||||||
}
|
}
|
||||||
|
@ -778,7 +797,11 @@ impl<'le> GeckoElement<'le> {
|
||||||
return None;
|
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]
|
#[inline]
|
||||||
|
@ -800,13 +823,8 @@ impl<'le> GeckoElement<'le> {
|
||||||
/// animation.
|
/// animation.
|
||||||
///
|
///
|
||||||
/// Also this function schedules style flush.
|
/// Also this function schedules style flush.
|
||||||
pub unsafe fn note_explicit_hints(
|
pub unsafe fn note_explicit_hints(&self, restyle_hint: RestyleHint, change_hint: nsChangeHint) {
|
||||||
&self,
|
|
||||||
restyle_hint: nsRestyleHint,
|
|
||||||
change_hint: nsChangeHint,
|
|
||||||
) {
|
|
||||||
use crate::gecko::restyle_damage::GeckoRestyleDamage;
|
use crate::gecko::restyle_damage::GeckoRestyleDamage;
|
||||||
use crate::invalidation::element::restyle_hints::RestyleHint;
|
|
||||||
|
|
||||||
let damage = GeckoRestyleDamage::new(change_hint);
|
let damage = GeckoRestyleDamage::new(change_hint);
|
||||||
debug!(
|
debug!(
|
||||||
|
@ -814,7 +832,6 @@ impl<'le> GeckoElement<'le> {
|
||||||
self, restyle_hint, change_hint
|
self, restyle_hint, change_hint
|
||||||
);
|
);
|
||||||
|
|
||||||
let restyle_hint: RestyleHint = restyle_hint.into();
|
|
||||||
debug_assert!(
|
debug_assert!(
|
||||||
!(restyle_hint.has_animation_hint() && restyle_hint.has_non_animation_hint()),
|
!(restyle_hint.has_animation_hint() && restyle_hint.has_non_animation_hint()),
|
||||||
"Animation restyle hints should not appear with non-animation restyle hints"
|
"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());
|
let mut map = FxHashMap::with_capacity_and_hasher(collection_length, Default::default());
|
||||||
|
|
||||||
for i in 0..collection_length {
|
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)
|
let end_value = AnimationValue::arc_from_borrowed(&raw_end_value)
|
||||||
.expect("AnimationValue not found in ElementTransitions");
|
.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 {
|
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();
|
let mut cache = self.font_size_cache.borrow_mut();
|
||||||
if let Some(sizes) = cache.iter().find(|el| el.0 == *font_name) {
|
if let Some(sizes) = cache.iter().find(|el| el.0 == *font_name) {
|
||||||
return sizes.1.size_for_generic(font_family);
|
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));
|
cache.push((font_name.clone(), sizes));
|
||||||
sizes.size_for_generic(font_family)
|
sizes.size_for_generic(font_family)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn query(
|
fn query(
|
||||||
&self,
|
&self,
|
||||||
font: &Font,
|
context: &crate::values::computed::Context,
|
||||||
font_size: Au,
|
base_size: FontBaseSize,
|
||||||
wm: WritingMode,
|
orientation: FontMetricsOrientation,
|
||||||
in_media_query: bool,
|
) -> FontMetrics {
|
||||||
device: &Device,
|
let pc = match context.device().pres_context() {
|
||||||
) -> FontMetricsQueryResult {
|
|
||||||
use crate::gecko_bindings::bindings::Gecko_GetFontMetrics;
|
|
||||||
let pc = match device.pres_context() {
|
|
||||||
Some(pc) => pc,
|
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 {
|
let gecko_metrics = unsafe {
|
||||||
Gecko_GetFontMetrics(
|
bindings::Gecko_GetFontMetrics(
|
||||||
pc,
|
pc,
|
||||||
wm.is_vertical() && !wm.is_sideways(),
|
vertical_metrics,
|
||||||
font.gecko(),
|
font.gecko(),
|
||||||
font_size.0,
|
size.0,
|
||||||
// we don't use the user font set in a media query
|
// we don't use the user font set in a media query
|
||||||
!in_media_query,
|
!context.in_media_query,
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
let metrics = FontMetrics {
|
FontMetrics {
|
||||||
x_height: Au(gecko_metrics.mXSize),
|
x_height: Some(Au(gecko_metrics.mXSize)),
|
||||||
zero_advance_measure: Au(gecko_metrics.mChSize),
|
zero_advance_measure: if gecko_metrics.mChSize >= 0 {
|
||||||
};
|
Some(Au(gecko_metrics.mChSize))
|
||||||
FontMetricsQueryResult::Available(metrics)
|
} else {
|
||||||
|
None
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1125,6 +1158,18 @@ impl<'le> TElement for GeckoElement<'le> {
|
||||||
self.before_or_after_pseudo(/* is_before = */ false)
|
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]
|
#[inline]
|
||||||
fn is_html_element(&self) -> bool {
|
fn is_html_element(&self) -> bool {
|
||||||
self.namespace_id() == structs::kNameSpaceID_XHTML as i32
|
self.namespace_id() == structs::kNameSpaceID_XHTML as i32
|
||||||
|
@ -1254,7 +1299,7 @@ impl<'le> TElement for GeckoElement<'le> {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let declarations = unsafe { Gecko_GetStyleAttrDeclarationBlock(self.0) };
|
let declarations = unsafe { Gecko_GetStyleAttrDeclarationBlock(self.0).as_ref() };
|
||||||
let declarations: Option<&RawOffsetArc<Locked<PropertyDeclarationBlock>>> =
|
let declarations: Option<&RawOffsetArc<Locked<PropertyDeclarationBlock>>> =
|
||||||
declarations.and_then(|s| s.as_arc_opt());
|
declarations.and_then(|s| s.as_arc_opt());
|
||||||
declarations.map(|s| s.borrow_arc())
|
declarations.map(|s| s.borrow_arc())
|
||||||
|
@ -1516,7 +1561,7 @@ impl<'le> TElement for GeckoElement<'le> {
|
||||||
);
|
);
|
||||||
unsafe {
|
unsafe {
|
||||||
self.note_explicit_hints(
|
self.note_explicit_hints(
|
||||||
nsRestyleHint::eRestyle_Subtree,
|
RestyleHint::restyle_subtree(),
|
||||||
nsChangeHint::nsChangeHint_Empty,
|
nsChangeHint::nsChangeHint_Empty,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1535,8 +1580,12 @@ impl<'le> TElement for GeckoElement<'le> {
|
||||||
// should destroy all CSS animations in display:none subtree.
|
// should destroy all CSS animations in display:none subtree.
|
||||||
let computed_data = self.borrow_data();
|
let computed_data = self.borrow_data();
|
||||||
let computed_values = computed_data.as_ref().map(|d| d.styles.primary());
|
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 before_change_values = before_change_style
|
||||||
let computed_values_opt = computed_values.as_ref().map(|x| &***x);
|
.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 {
|
unsafe {
|
||||||
Gecko_UpdateAnimations(
|
Gecko_UpdateAnimations(
|
||||||
self.0,
|
self.0,
|
||||||
|
@ -1812,7 +1861,8 @@ impl<'le> TElement for GeckoElement<'le> {
|
||||||
hints.push(SVG_TEXT_DISABLE_ZOOM_RULE.clone());
|
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>>> =
|
let declarations: Option<&RawOffsetArc<Locked<PropertyDeclarationBlock>>> =
|
||||||
declarations.and_then(|s| s.as_arc_opt());
|
declarations.and_then(|s| s.as_arc_opt());
|
||||||
if let Some(decl) = declarations {
|
if let Some(decl) = declarations {
|
||||||
|
@ -1821,7 +1871,7 @@ impl<'le> TElement for GeckoElement<'le> {
|
||||||
ServoCascadeLevel::PresHints,
|
ServoCascadeLevel::PresHints,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
let declarations = unsafe { Gecko_GetExtraContentStyleDeclarations(self.0) };
|
let declarations = unsafe { Gecko_GetExtraContentStyleDeclarations(self.0).as_ref() };
|
||||||
let declarations: Option<&RawOffsetArc<Locked<PropertyDeclarationBlock>>> =
|
let declarations: Option<&RawOffsetArc<Locked<PropertyDeclarationBlock>>> =
|
||||||
declarations.and_then(|s| s.as_arc_opt());
|
declarations.and_then(|s| s.as_arc_opt());
|
||||||
if let Some(decl) = declarations {
|
if let Some(decl) = declarations {
|
||||||
|
@ -1843,10 +1893,10 @@ impl<'le> TElement for GeckoElement<'le> {
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
VisitedHandlingMode::AllLinksUnvisited => unsafe {
|
VisitedHandlingMode::AllLinksUnvisited => unsafe {
|
||||||
Gecko_GetUnvisitedLinkAttrDeclarationBlock(self.0)
|
Gecko_GetUnvisitedLinkAttrDeclarationBlock(self.0).as_ref()
|
||||||
},
|
},
|
||||||
VisitedHandlingMode::RelevantLinkVisited => unsafe {
|
VisitedHandlingMode::RelevantLinkVisited => unsafe {
|
||||||
Gecko_GetVisitedLinkAttrDeclarationBlock(self.0)
|
Gecko_GetVisitedLinkAttrDeclarationBlock(self.0).as_ref()
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
let declarations: Option<&RawOffsetArc<Locked<PropertyDeclarationBlock>>> =
|
let declarations: Option<&RawOffsetArc<Locked<PropertyDeclarationBlock>>> =
|
||||||
|
@ -1862,7 +1912,8 @@ impl<'le> TElement for GeckoElement<'le> {
|
||||||
.state()
|
.state()
|
||||||
.intersects(NonTSPseudoClass::Active.state_flag());
|
.intersects(NonTSPseudoClass::Active.state_flag());
|
||||||
if active {
|
if active {
|
||||||
let declarations = unsafe { Gecko_GetActiveLinkAttrDeclarationBlock(self.0) };
|
let declarations =
|
||||||
|
unsafe { Gecko_GetActiveLinkAttrDeclarationBlock(self.0).as_ref() };
|
||||||
let declarations: Option<&RawOffsetArc<Locked<PropertyDeclarationBlock>>> =
|
let declarations: Option<&RawOffsetArc<Locked<PropertyDeclarationBlock>>> =
|
||||||
declarations.and_then(|s| s.as_arc_opt());
|
declarations.and_then(|s| s.as_arc_opt());
|
||||||
if let Some(decl) = declarations {
|
if let Some(decl) = declarations {
|
||||||
|
|
|
@ -4,11 +4,6 @@
|
||||||
|
|
||||||
//! Gecko's C++ bindings, along with some rust helpers to ease its use.
|
//! 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
|
// 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
|
// foreign structs to have `PhantomData`. We should remove this once the lint
|
||||||
// ignores this case.
|
// ignores this case.
|
||||||
|
@ -25,4 +20,6 @@ pub mod structs {
|
||||||
include!(concat!(env!("OUT_DIR"), "/gecko/structs.rs"));
|
include!(concat!(env!("OUT_DIR"), "/gecko/structs.rs"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub use self::structs as bindings;
|
||||||
|
|
||||||
pub mod sugar;
|
pub mod sugar;
|
||||||
|
|
|
@ -135,12 +135,12 @@ pub unsafe trait HasArcFFI: HasFFI {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
|
||||||
/// Gecko-FFI-safe Arc (T is an ArcInner).
|
/// Gecko-FFI-safe Arc (T is an ArcInner).
|
||||||
///
|
///
|
||||||
/// This can be null.
|
/// This can be null.
|
||||||
///
|
///
|
||||||
/// Leaks on drop. Please don't drop this.
|
/// Leaks on drop. Please don't drop this.
|
||||||
|
#[repr(C)]
|
||||||
pub struct Strong<GeckoType> {
|
pub struct Strong<GeckoType> {
|
||||||
ptr: *const GeckoType,
|
ptr: *const GeckoType,
|
||||||
_marker: PhantomData<GeckoType>,
|
_marker: PhantomData<GeckoType>,
|
||||||
|
@ -320,27 +320,6 @@ impl<GeckoType> OwnedOrNull<GeckoType> {
|
||||||
self.ptr.is_null()
|
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
|
/// Gets a immutable reference to the underlying Gecko type, or `None` if
|
||||||
/// null.
|
/// null.
|
||||||
pub fn borrow(&self) -> Option<&GeckoType> {
|
pub fn borrow(&self) -> Option<&GeckoType> {
|
||||||
|
|
|
@ -285,7 +285,7 @@ macro_rules! impl_threadsafe_refcount {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_threadsafe_refcount!(
|
impl_threadsafe_refcount!(
|
||||||
structs::RawGeckoURLExtraData,
|
structs::mozilla::URLExtraData,
|
||||||
bindings::Gecko_AddRefURLExtraDataArbitraryThread,
|
bindings::Gecko_AddRefURLExtraDataArbitraryThread,
|
||||||
bindings::Gecko_ReleaseURLExtraDataArbitraryThread
|
bindings::Gecko_ReleaseURLExtraDataArbitraryThread
|
||||||
);
|
);
|
||||||
|
|
|
@ -11,7 +11,6 @@ use crate::parallel::STYLE_THREAD_STACK_SIZE_KB;
|
||||||
use crate::shared_lock::SharedRwLock;
|
use crate::shared_lock::SharedRwLock;
|
||||||
use crate::thread_state;
|
use crate::thread_state;
|
||||||
use rayon;
|
use rayon;
|
||||||
use servo_config::pref;
|
|
||||||
use std::env;
|
use std::env;
|
||||||
|
|
||||||
/// Global style data
|
/// Global style data
|
||||||
|
@ -67,6 +66,7 @@ lazy_static! {
|
||||||
Ok(num) => num,
|
Ok(num) => num,
|
||||||
#[cfg(feature = "servo")]
|
#[cfg(feature = "servo")]
|
||||||
_ => {
|
_ => {
|
||||||
|
use servo_config::pref;
|
||||||
// We always set this pref on startup, before layout or script
|
// We always set this pref on startup, before layout or script
|
||||||
// have had a chance of accessing (and thus creating) the
|
// have had a chance of accessing (and thus creating) the
|
||||||
// thread-pool.
|
// thread-pool.
|
||||||
|
|
|
@ -542,6 +542,10 @@ where
|
||||||
any_descendant |= self.invalidate_dom_descendants_of(anon_content, invalidations);
|
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() {
|
if let Some(before) = self.element.before_pseudo_element() {
|
||||||
any_descendant |= self.invalidate_pseudo_element_or_nac(before, invalidations);
|
any_descendant |= self.invalidate_pseudo_element_or_nac(before, invalidations);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,12 +4,11 @@
|
||||||
|
|
||||||
//! Restyle hints: an optimization to avoid unnecessarily matching selectors.
|
//! Restyle hints: an optimization to avoid unnecessarily matching selectors.
|
||||||
|
|
||||||
#[cfg(feature = "gecko")]
|
|
||||||
use crate::gecko_bindings::structs::nsRestyleHint;
|
|
||||||
use crate::traversal_flags::TraversalFlags;
|
use crate::traversal_flags::TraversalFlags;
|
||||||
|
|
||||||
bitflags! {
|
bitflags! {
|
||||||
/// The kind of restyle we need to do for a given element.
|
/// The kind of restyle we need to do for a given element.
|
||||||
|
#[repr(C)]
|
||||||
pub struct RestyleHint: u8 {
|
pub struct RestyleHint: u8 {
|
||||||
/// Do a selector match of the element.
|
/// Do a selector match of the element.
|
||||||
const RESTYLE_SELF = 1 << 0;
|
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")]
|
#[cfg(feature = "servo")]
|
||||||
malloc_size_of_is_0!(RestyleHint);
|
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>,
|
cascade_mode: CascadeMode<'a>,
|
||||||
seen: LonghandIdSet,
|
seen: LonghandIdSet,
|
||||||
reverted: PerOrigin<LonghandIdSet>,
|
reverted: PerOrigin<LonghandIdSet>,
|
||||||
saved_font_size: Option<PropertyDeclaration>,
|
|
||||||
saved_font_family: Option<PropertyDeclaration>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b: 'a> Cascade<'a, 'b> {
|
impl<'a, 'b: 'a> Cascade<'a, 'b> {
|
||||||
|
@ -395,8 +393,6 @@ impl<'a, 'b: 'a> Cascade<'a, 'b> {
|
||||||
cascade_mode,
|
cascade_mode,
|
||||||
seen: LonghandIdSet::default(),
|
seen: LonghandIdSet::default(),
|
||||||
reverted: Default::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)]
|
#[inline(always)]
|
||||||
fn apply_declaration_ignoring_phase(
|
fn apply_declaration<Phase: CascadePhase>(
|
||||||
&mut self,
|
&mut self,
|
||||||
longhand_id: LonghandId,
|
longhand_id: LonghandId,
|
||||||
declaration: &PropertyDeclaration,
|
declaration: &PropertyDeclaration,
|
||||||
|
@ -577,7 +548,7 @@ impl<'a, 'b: 'a> Cascade<'a, 'b> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if Phase::is_early() {
|
if Phase::is_early() {
|
||||||
self.fixup_font_and_apply_saved_font_properties();
|
self.fixup_font_stuff();
|
||||||
self.compute_writing_mode();
|
self.compute_writing_mode();
|
||||||
} else {
|
} else {
|
||||||
self.finished_applying_properties();
|
self.finished_applying_properties();
|
||||||
|
@ -702,142 +673,249 @@ impl<'a, 'b: 'a> Cascade<'a, 'b> {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME(emilio): It'd be really nice to simplify all this, somehow. This is
|
/// The default font type (which is stored in FontFamilyList's
|
||||||
// very annoying code in lots of ways, and there are various bits about it
|
/// `mDefaultFontType`) depends on the current lang group and generic font
|
||||||
// which I think are broken or could be improved, see the various FIXMEs
|
/// family, so we may need to recompute it if or the family changed.
|
||||||
// below.
|
///
|
||||||
fn fixup_font_and_apply_saved_font_properties(&mut self) {
|
/// Also, we prioritize non-document fonts here if we need to (see the pref
|
||||||
let font_family = self.saved_font_family.take();
|
/// `browser.display.use_document_fonts`).
|
||||||
let font_size = self.saved_font_size.take();
|
#[inline]
|
||||||
let mut _skip_font_family = false;
|
#[cfg(feature = "gecko")]
|
||||||
|
fn recompute_default_font_family_type_if_needed(&mut self) {
|
||||||
|
use crate::gecko_bindings::{bindings, structs};
|
||||||
|
|
||||||
#[cfg(feature = "gecko")]
|
if !self.seen.contains(LonghandId::XLang) &&
|
||||||
{
|
!self.seen.contains(LonghandId::FontFamily) {
|
||||||
// <svg:text> is not affected by text zoom, and it uses a preshint
|
return;
|
||||||
// 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) {
|
|
||||||
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 {
|
|
||||||
debug_assert!(
|
|
||||||
!zoom,
|
|
||||||
"We only ever disable text zoom (in svg:text), never enable it"
|
|
||||||
);
|
|
||||||
let device = builder.device;
|
|
||||||
builder.mutate_font().unzoom_fonts(device);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// It is important that font-size is computed before the late
|
let use_document_fonts = unsafe { structs::StaticPrefs_sVarCache_browser_display_use_document_fonts != 0 };
|
||||||
// properties (for em units), but after font-family (for the
|
let builder = &mut self.context.builder;
|
||||||
// base-font-size dependence for default and keyword font-sizes).
|
let (default_font_type, prioritize_user_fonts) = {
|
||||||
//
|
let font = builder.get_font().gecko();
|
||||||
// It's important that font-family comes after the other font properties
|
|
||||||
// to support system fonts.
|
// System fonts are all right, and should have the default font type
|
||||||
//
|
// set to none already, so bail out early.
|
||||||
// NOTE(emilio): I haven't verified that comment, but it was there.
|
if font.mFont.systemFont {
|
||||||
// Verify, and if it's false make font-size the only weird property?
|
debug_assert_eq!(font.mFont.fontlist.mDefaultFontType, structs::FontFamilyType::eFamily_none);
|
||||||
if !_skip_font_family {
|
return;
|
||||||
if let Some(ref declaration) = font_family {
|
|
||||||
self.apply_declaration_ignoring_phase(LonghandId::FontFamily, declaration);
|
|
||||||
#[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 {
|
let default_font_type = unsafe {
|
||||||
self.apply_declaration_ignoring_phase(LonghandId::FontSize, &declaration);
|
bindings::Gecko_nsStyleFont_ComputeDefaultFontType(
|
||||||
} else {
|
builder.device.document(),
|
||||||
#[cfg(feature = "gecko")]
|
font.mGenericID,
|
||||||
{
|
font.mLanguage.mRawPtr,
|
||||||
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
|
// We prioritize user fonts over document fonts if the pref is set,
|
||||||
// changes and scriptlevel changes.
|
// and we don't have a generic family already (or we're using
|
||||||
//
|
// cursive or fantasy, since they're ignored, see bug 789788), and
|
||||||
// FIXME(emilio): That looks a bit bogus...
|
// we have a generic family to actually replace it with.
|
||||||
self.context.for_non_inherited_property = None;
|
let prioritize_user_fonts =
|
||||||
FontSize::cascade_inherit_font_size(&mut self.context);
|
!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 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
debug_assert!(
|
||||||
|
!zoom,
|
||||||
|
"We only ever disable text zoom (in svg:text), never enable it"
|
||||||
|
);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the user specifies a font-size, just let it be.
|
||||||
|
if self.seen.contains(LonghandId::FontSize) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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")]
|
||||||
|
{
|
||||||
|
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.
|
/// Whether the child explicitly inherits any reset property.
|
||||||
const INHERITS_RESET_STYLE = 1 << 8;
|
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.
|
/// Whether the style or any of the ancestors has a multicol style.
|
||||||
///
|
///
|
||||||
/// Only used in Servo.
|
/// 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()
|
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",
|
"JustifyItems",
|
||||||
"JustifySelf",
|
"JustifySelf",
|
||||||
"MozForceBrokenImageIcon",
|
"MozForceBrokenImageIcon",
|
||||||
|
"MozListReversed",
|
||||||
"MozScriptLevel",
|
"MozScriptLevel",
|
||||||
"MozScriptMinSize",
|
"MozScriptMinSize",
|
||||||
"MozScriptSizeMultiplier",
|
"MozScriptSizeMultiplier",
|
||||||
|
|
|
@ -66,16 +66,25 @@ use crate::values::generics::url::UrlOrNone;
|
||||||
pub mod style_structs {
|
pub mod style_structs {
|
||||||
% for style_struct in data.style_structs:
|
% for style_struct in data.style_structs:
|
||||||
pub use super::${style_struct.gecko_struct_name} as ${style_struct.name};
|
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
|
% endfor
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// FIXME(emilio): This is completely duplicated with the other properties code.
|
/// 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)]
|
#[repr(C)]
|
||||||
pub struct ComputedValues(crate::gecko_bindings::structs::mozilla::ComputedStyle);
|
pub struct ComputedValues(structs::mozilla::ComputedStyle);
|
||||||
|
|
||||||
impl ComputedValues {
|
impl ComputedValues {
|
||||||
|
#[inline]
|
||||||
|
pub (crate) fn as_gecko_computed_style(&self) -> &structs::ComputedStyle {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
|
||||||
pub fn new(
|
pub fn new(
|
||||||
pseudo: Option<<&PseudoElement>,
|
pseudo: Option<<&PseudoElement>,
|
||||||
custom_properties: Option<Arc<CustomPropertiesMap>>,
|
custom_properties: Option<Arc<CustomPropertiesMap>>,
|
||||||
|
@ -929,7 +938,7 @@ transform_functions = [
|
||||||
debug_assert!(!${item}${index + 1}.0.is_empty());
|
debug_assert!(!${item}${index + 1}.0.is_empty());
|
||||||
% endif
|
% endif
|
||||||
${css_value_setters[item] % (
|
${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)
|
item + str(index + 1)
|
||||||
)};
|
)};
|
||||||
% endfor
|
% endfor
|
||||||
|
@ -980,7 +989,7 @@ transform_functions = [
|
||||||
% endif
|
% endif
|
||||||
<%
|
<%
|
||||||
getter = css_value_getters[item] % (
|
getter = css_value_getters[item] % (
|
||||||
"bindings::Gecko_CSSValue_GetArrayItemConst(gecko_value, %d)" % (index + 1)
|
"(&*bindings::Gecko_CSSValue_GetArrayItemConst(gecko_value, %d))" % (index + 1)
|
||||||
)
|
)
|
||||||
%>
|
%>
|
||||||
${getter},
|
${getter},
|
||||||
|
@ -989,6 +998,7 @@ transform_functions = [
|
||||||
},
|
},
|
||||||
</%def>
|
</%def>
|
||||||
|
|
||||||
|
#[allow(unused_parens)]
|
||||||
fn set_single_transform_function(
|
fn set_single_transform_function(
|
||||||
servo_value: &values::computed::TransformOperation,
|
servo_value: &values::computed::TransformOperation,
|
||||||
gecko_value: &mut structs::nsCSSValue /* output */
|
gecko_value: &mut structs::nsCSSValue /* output */
|
||||||
|
@ -1031,6 +1041,7 @@ pub fn convert_transform(
|
||||||
output.set_move(list);
|
output.set_move(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(unused_parens)]
|
||||||
fn clone_single_transform_function(
|
fn clone_single_transform_function(
|
||||||
gecko_value: &structs::nsCSSValue
|
gecko_value: &structs::nsCSSValue
|
||||||
) -> values::computed::TransformOperation {
|
) -> values::computed::TransformOperation {
|
||||||
|
@ -1236,6 +1247,7 @@ impl Clone for ${style_struct.gecko_struct_name} {
|
||||||
"Length": impl_absolute_length,
|
"Length": impl_absolute_length,
|
||||||
"LengthOrNormal": impl_style_coord,
|
"LengthOrNormal": impl_style_coord,
|
||||||
"LengthPercentageOrAuto": impl_style_coord,
|
"LengthPercentageOrAuto": impl_style_coord,
|
||||||
|
"MozListReversed": impl_simple,
|
||||||
"MozScriptMinSize": impl_absolute_length,
|
"MozScriptMinSize": impl_absolute_length,
|
||||||
"RGBAColor": impl_rgba_color,
|
"RGBAColor": impl_rgba_color,
|
||||||
"SVGLength": impl_svg_length,
|
"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_feature_settings", "gfxFontFeature", "FeatureTagValue", "i32", "u32") %>
|
||||||
<% impl_font_settings("font_variation_settings", "gfxFontVariation", "VariationValue", "f32", "f32") %>
|
<% 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) {
|
pub fn set_font_family(&mut self, v: longhands::font_family::computed_value::T) {
|
||||||
self.gecko.mGenericID = structs::kGenericFont_NONE;
|
use crate::gecko_bindings::structs::FontFamilyType;
|
||||||
if let Some(generic) = v.0.single_generic() {
|
|
||||||
self.gecko.mGenericID = generic;
|
let is_system_font = v.is_system_font;
|
||||||
}
|
self.gecko.mFont.systemFont = is_system_font;
|
||||||
self.gecko.mFont.fontlist.mFontlist.mBasePtr.set_move((v.0).0.clone());
|
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) {
|
pub fn copy_font_family_from(&mut self, other: &Self) {
|
||||||
|
@ -2009,7 +2015,7 @@ fn static_assert() {
|
||||||
let fontlist = &self.gecko.mFont.fontlist;
|
let fontlist = &self.gecko.mFont.fontlist;
|
||||||
let shared_fontlist = unsafe { fontlist.mFontlist.mBasePtr.to_safe() };
|
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 = fontlist.mDefaultFontType;
|
||||||
let default = match default {
|
let default = match default {
|
||||||
FontFamilyType::eFamily_serif => {
|
FontFamilyType::eFamily_serif => {
|
||||||
|
@ -2030,9 +2036,14 @@ fn static_assert() {
|
||||||
SingleFontFamily::Generic(atom!("sans-serif"))
|
SingleFontFamily::Generic(atom!("sans-serif"))
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
FontFamily(FontFamilyList::new(Box::new([default])))
|
FontFamilyList::new(Box::new([default]))
|
||||||
} else {
|
} 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;
|
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) {
|
pub fn set_font_size(&mut self, v: FontSize) {
|
||||||
use crate::values::generics::font::KeywordSize;
|
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 {
|
if let Some(info) = v.keyword_info {
|
||||||
self.gecko.mFontSizeKeyword = match info.kw {
|
self.gecko.mFontSizeKeyword = match info.kw {
|
||||||
KeywordSize::XXSmall => structs::NS_STYLE_FONT_SIZE_XXSMALL,
|
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 {
|
pub fn clone_font_size(&self) -> FontSize {
|
||||||
use crate::values::generics::font::{KeywordInfo, KeywordSize};
|
use crate::values::generics::font::{KeywordInfo, KeywordSize};
|
||||||
let size = Au(self.gecko.mSize).into();
|
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_XXXLARGE => KeywordSize::XXXLarge,
|
||||||
structs::NS_STYLE_FONT_SIZE_NO_KEYWORD => {
|
structs::NS_STYLE_FONT_SIZE_NO_KEYWORD => {
|
||||||
return FontSize {
|
return FontSize {
|
||||||
size: size,
|
size,
|
||||||
keyword_info: None,
|
keyword_info: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => unreachable!("mFontSizeKeyword should be an absolute keyword or NO_KEYWORD")
|
_ => unreachable!("mFontSizeKeyword should be an absolute keyword or NO_KEYWORD")
|
||||||
};
|
};
|
||||||
FontSize {
|
FontSize {
|
||||||
size: size,
|
size,
|
||||||
keyword_info: Some(KeywordInfo {
|
keyword_info: Some(KeywordInfo {
|
||||||
kw: kw,
|
kw,
|
||||||
factor: self.gecko.mFontSizeFactor,
|
factor: self.gecko.mFontSizeFactor,
|
||||||
offset: Au(self.gecko.mFontSizeOffset).into()
|
offset: Au(self.gecko.mFontSizeOffset).into()
|
||||||
})
|
})
|
||||||
|
@ -2751,7 +2594,7 @@ fn static_assert() {
|
||||||
transform-style
|
transform-style
|
||||||
rotate scroll-snap-points-x scroll-snap-points-y
|
rotate scroll-snap-points-x scroll-snap-points-y
|
||||||
scroll-snap-coordinate -moz-binding will-change
|
scroll-snap-coordinate -moz-binding will-change
|
||||||
offset-path shape-outside contain touch-action
|
offset-path shape-outside
|
||||||
translate scale""" %>
|
translate scale""" %>
|
||||||
<%self:impl_trait style_struct_name="Box" skip_longhands="${skip_box_longhands}">
|
<%self:impl_trait style_struct_name="Box" skip_longhands="${skip_box_longhands}">
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -3109,10 +2952,10 @@ fn static_assert() {
|
||||||
|
|
||||||
pub fn set_will_change(&mut self, v: longhands::will_change::computed_value::T) {
|
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::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 {
|
match v {
|
||||||
T::AnimateableFeatures { features, bits } => {
|
WillChange::AnimateableFeatures { features, bits } => {
|
||||||
unsafe {
|
unsafe {
|
||||||
Gecko_ClearWillChange(&mut self.gecko, features.len());
|
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 {
|
unsafe {
|
||||||
Gecko_ClearWillChange(&mut self.gecko, 0);
|
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;
|
self.gecko.mWillChangeBitField = other.gecko.mWillChangeBitField;
|
||||||
unsafe {
|
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 {
|
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::CustomIdent;
|
||||||
use crate::values::specified::box_::WillChangeBits;
|
use crate::values::specified::box_::WillChange;
|
||||||
|
|
||||||
if self.gecko.mWillChange.len() == 0 {
|
if self.gecko.mWillChange.len() == 0 {
|
||||||
return T::Auto
|
return WillChange::Auto
|
||||||
}
|
}
|
||||||
|
|
||||||
let custom_idents: Vec<CustomIdent> = self.gecko.mWillChange.iter().map(|gecko_atom| {
|
let custom_idents: Vec<CustomIdent> = self.gecko.mWillChange.iter().map(|gecko_atom| {
|
||||||
unsafe {
|
unsafe {
|
||||||
CustomIdent(Atom::from_raw(gecko_atom.mRawPtr as *mut nsAtom))
|
CustomIdent(Atom::from_raw(gecko_atom.mRawPtr))
|
||||||
}
|
}
|
||||||
}).collect();
|
}).collect();
|
||||||
|
|
||||||
T::AnimateableFeatures {
|
WillChange::AnimateableFeatures {
|
||||||
features: custom_idents.into_boxed_slice(),
|
features: custom_idents.into_boxed_slice(),
|
||||||
bits: WillChangeBits::from_bits_truncate(self.gecko.mWillChangeBitField),
|
bits: self.gecko.mWillChangeBitField,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
<% impl_shape_source("shape_outside", "mShapeOutside") %>
|
<% 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) {
|
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::bindings::{Gecko_NewStyleMotion, Gecko_SetStyleMotion};
|
||||||
use crate::gecko_bindings::structs::StyleShapeSourceType;
|
use crate::gecko_bindings::structs::StyleShapeSourceType;
|
||||||
|
@ -4250,9 +4004,7 @@ fn static_assert() {
|
||||||
</%self:impl_trait>
|
</%self:impl_trait>
|
||||||
|
|
||||||
<%self:impl_trait style_struct_name="Text"
|
<%self:impl_trait style_struct_name="Text"
|
||||||
skip_longhands="text-decoration-line text-overflow initial-letter">
|
skip_longhands="text-overflow initial-letter">
|
||||||
|
|
||||||
${impl_simple_type_with_conversion("text_decoration_line")}
|
|
||||||
|
|
||||||
fn clear_overflow_sides_if_string(&mut self) {
|
fn clear_overflow_sides_if_string(&mut self) {
|
||||||
use crate::gecko_bindings::structs::nsStyleTextOverflowSide;
|
use crate::gecko_bindings::structs::nsStyleTextOverflowSide;
|
||||||
|
@ -4366,21 +4118,6 @@ fn static_assert() {
|
||||||
InitialLetter::Specified(self.gecko.mInitialLetterSize, Some(self.gecko.mInitialLetterSink))
|
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>
|
</%self:impl_trait>
|
||||||
|
|
||||||
// Set SVGPathData to StyleShapeSource.
|
// Set SVGPathData to StyleShapeSource.
|
||||||
|
@ -4823,7 +4560,7 @@ clip-path
|
||||||
</%self:impl_trait>
|
</%self:impl_trait>
|
||||||
|
|
||||||
<%self:impl_trait style_struct_name="Counters"
|
<%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 {
|
pub fn ineffective_content_property(&self) -> bool {
|
||||||
self.gecko.mContents.is_empty()
|
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()}(
|
pub fn set_counter_${counter_property.lower()}(
|
||||||
&mut self,
|
&mut self,
|
||||||
v: longhands::counter_${counter_property.lower()}::computed_value::T
|
v: longhands::counter_${counter_property.lower()}::computed_value::T
|
||||||
|
|
|
@ -333,11 +333,7 @@
|
||||||
% if not property.style_struct.inherited:
|
% if not property.style_struct.inherited:
|
||||||
debug_assert!(false, "Should be handled in apply_properties");
|
debug_assert!(false, "Should be handled in apply_properties");
|
||||||
% else:
|
% else:
|
||||||
% if property.name == "font-size":
|
|
||||||
computed::FontSize::cascade_initial_font_size(context);
|
|
||||||
% else:
|
|
||||||
context.builder.reset_${property.ident}();
|
context.builder.reset_${property.ident}();
|
||||||
% endif
|
|
||||||
% endif
|
% endif
|
||||||
},
|
},
|
||||||
% if property.style_struct.inherited:
|
% if property.style_struct.inherited:
|
||||||
|
@ -394,15 +390,7 @@
|
||||||
% else:
|
% else:
|
||||||
let computed = specified_value.to_computed_value(context);
|
let computed = specified_value.to_computed_value(context);
|
||||||
% endif
|
% endif
|
||||||
% if property.ident == "font_size":
|
context.builder.set_${property.ident}(computed)
|
||||||
specified::FontSize::cascade_specified_font_size(
|
|
||||||
context,
|
|
||||||
&specified_value,
|
|
||||||
computed,
|
|
||||||
);
|
|
||||||
% else:
|
|
||||||
context.builder.set_${property.ident}(computed)
|
|
||||||
% endif
|
|
||||||
% endif
|
% endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -365,7 +365,7 @@ ${helpers.predefined_type(
|
||||||
"generics::transform::Rotate::None",
|
"generics::transform::Rotate::None",
|
||||||
animation_value_type="ComputedValue",
|
animation_value_type="ComputedValue",
|
||||||
boxed=True,
|
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",
|
gecko_pref="layout.css.individual-transform.enabled",
|
||||||
spec="https://drafts.csswg.org/css-transforms-2/#individual-transforms",
|
spec="https://drafts.csswg.org/css-transforms-2/#individual-transforms",
|
||||||
servo_restyle_damage = "reflow_out_of_flow",
|
servo_restyle_damage = "reflow_out_of_flow",
|
||||||
|
@ -377,7 +377,7 @@ ${helpers.predefined_type(
|
||||||
"generics::transform::Scale::None",
|
"generics::transform::Scale::None",
|
||||||
animation_value_type="ComputedValue",
|
animation_value_type="ComputedValue",
|
||||||
boxed=True,
|
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",
|
gecko_pref="layout.css.individual-transform.enabled",
|
||||||
spec="https://drafts.csswg.org/css-transforms-2/#individual-transforms",
|
spec="https://drafts.csswg.org/css-transforms-2/#individual-transforms",
|
||||||
servo_restyle_damage = "reflow_out_of_flow",
|
servo_restyle_damage = "reflow_out_of_flow",
|
||||||
|
@ -389,7 +389,7 @@ ${helpers.predefined_type(
|
||||||
"generics::transform::Translate::None",
|
"generics::transform::Translate::None",
|
||||||
animation_value_type="ComputedValue",
|
animation_value_type="ComputedValue",
|
||||||
boxed=True,
|
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",
|
gecko_pref="layout.css.individual-transform.enabled",
|
||||||
spec="https://drafts.csswg.org/css-transforms-2/#individual-transforms",
|
spec="https://drafts.csswg.org/css-transforms-2/#individual-transforms",
|
||||||
servo_restyle_damage="reflow_out_of_flow",
|
servo_restyle_damage="reflow_out_of_flow",
|
||||||
|
|
|
@ -27,9 +27,19 @@ ${helpers.predefined_type(
|
||||||
|
|
||||||
${helpers.predefined_type(
|
${helpers.predefined_type(
|
||||||
"counter-reset",
|
"counter-reset",
|
||||||
"CounterReset",
|
"CounterSetOrReset",
|
||||||
initial_value="Default::default()",
|
initial_value="Default::default()",
|
||||||
animation_value_type="discrete",
|
animation_value_type="discrete",
|
||||||
spec="https://drafts.csswg.org/css-lists-3/#propdef-counter-reset",
|
spec="https://drafts.csswg.org/css-lists-3/#propdef-counter-reset",
|
||||||
servo_restyle_damage="rebuild_and_reflow",
|
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 crate::gecko_bindings::structs::{LookAndFeel_FontID, nsFont};
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use crate::values::computed::Percentage;
|
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;
|
use crate::values::generics::NonNegative;
|
||||||
|
|
||||||
let id = match *self {
|
let id = match *self {
|
||||||
|
@ -405,11 +405,12 @@ ${helpers.predefined_type(
|
||||||
})));
|
})));
|
||||||
let font_style = FontStyle::from_gecko(system.style);
|
let font_style = FontStyle::from_gecko(system.style);
|
||||||
let ret = ComputedSystemFont {
|
let ret = ComputedSystemFont {
|
||||||
font_family: longhands::font_family::computed_value::T(
|
font_family: FontFamily {
|
||||||
FontFamilyList(
|
families: FontFamilyList(unsafe {
|
||||||
unsafe { system.fontlist.mFontlist.mBasePtr.to_safe() }
|
system.fontlist.mFontlist.mBasePtr.to_safe()
|
||||||
)
|
}),
|
||||||
),
|
is_system_font: true,
|
||||||
|
},
|
||||||
font_size: FontSize {
|
font_size: FontSize {
|
||||||
size: Au(system.size).into(),
|
size: Au(system.size).into(),
|
||||||
keyword_info: None
|
keyword_info: None
|
||||||
|
|
|
@ -68,3 +68,15 @@ ${helpers.predefined_type(
|
||||||
boxed=True,
|
boxed=True,
|
||||||
spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-image-region)",
|
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" />
|
<%namespace name="helpers" file="/helpers.mako.rs" />
|
||||||
<% from data import Method %>
|
<% from data import Method %>
|
||||||
|
|
||||||
<% data.new_style_struct(
|
<% data.new_style_struct("Text", inherited=False, gecko_name="TextReset") %>
|
||||||
"Text",
|
|
||||||
inherited=False,
|
|
||||||
gecko_name="TextReset",
|
|
||||||
additional_methods=[
|
|
||||||
Method("has_underline", "bool"),
|
|
||||||
Method("has_overline", "bool"),
|
|
||||||
Method("has_line_through", "bool"),
|
|
||||||
]
|
|
||||||
) %>
|
|
||||||
|
|
||||||
${helpers.predefined_type(
|
${helpers.predefined_type(
|
||||||
"text-overflow",
|
"text-overflow",
|
||||||
|
|
|
@ -45,6 +45,7 @@ use crate::rule_tree::StrongRuleNode;
|
||||||
use crate::Zero;
|
use crate::Zero;
|
||||||
use self::computed_value_flags::*;
|
use self::computed_value_flags::*;
|
||||||
use crate::str::{CssString, CssStringBorrow, CssStringWriter};
|
use crate::str::{CssString, CssStringBorrow, CssStringWriter};
|
||||||
|
use std::cell::Cell;
|
||||||
|
|
||||||
pub use self::declaration_block::*;
|
pub use self::declaration_block::*;
|
||||||
pub use self::cascade::*;
|
pub use self::cascade::*;
|
||||||
|
@ -1257,8 +1258,12 @@ impl LonghandId {
|
||||||
LonghandId::MozScriptLevel |
|
LonghandId::MozScriptLevel |
|
||||||
% endif
|
% 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::FontSize |
|
||||||
|
LonghandId::FontWeight |
|
||||||
|
LonghandId::FontStretch |
|
||||||
|
LonghandId::FontStyle |
|
||||||
LonghandId::FontFamily |
|
LonghandId::FontFamily |
|
||||||
|
|
||||||
// Needed to resolve currentcolor at computed value time properly.
|
// Needed to resolve currentcolor at computed value time properly.
|
||||||
|
@ -2634,24 +2639,6 @@ pub mod style_structs {
|
||||||
use crate::Zero;
|
use crate::Zero;
|
||||||
!self.outline_width.is_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":
|
% elif style_struct.name == "Box":
|
||||||
/// Sets the display property, but without touching original_display,
|
/// Sets the display property, but without touching original_display,
|
||||||
/// except when the adjustment comes from root or item display fixups.
|
/// except when the adjustment comes from root or item display fixups.
|
||||||
|
@ -3336,8 +3323,10 @@ pub struct StyleBuilder<'a> {
|
||||||
///
|
///
|
||||||
/// TODO(emilio): Make private.
|
/// TODO(emilio): Make private.
|
||||||
pub writing_mode: WritingMode,
|
pub writing_mode: WritingMode,
|
||||||
|
|
||||||
/// Flags for the computed value.
|
/// 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
|
/// 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
|
/// for this element. A element's "relevant link" is the element being
|
||||||
/// matched if it is a link or the nearest ancestor link.
|
/// matched if it is a link or the nearest ancestor link.
|
||||||
|
@ -3379,7 +3368,7 @@ impl<'a> StyleBuilder<'a> {
|
||||||
modified_reset: false,
|
modified_reset: false,
|
||||||
custom_properties,
|
custom_properties,
|
||||||
writing_mode: inherited_style.writing_mode,
|
writing_mode: inherited_style.writing_mode,
|
||||||
flags,
|
flags: Cell::new(flags),
|
||||||
visited_style: None,
|
visited_style: None,
|
||||||
% for style_struct in data.active_style_structs():
|
% for style_struct in data.active_style_structs():
|
||||||
% if style_struct.inherited:
|
% if style_struct.inherited:
|
||||||
|
@ -3418,7 +3407,7 @@ impl<'a> StyleBuilder<'a> {
|
||||||
rules: None,
|
rules: None,
|
||||||
custom_properties: style_to_derive_from.custom_properties().cloned(),
|
custom_properties: style_to_derive_from.custom_properties().cloned(),
|
||||||
writing_mode: style_to_derive_from.writing_mode,
|
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,
|
visited_style: None,
|
||||||
% for style_struct in data.active_style_structs():
|
% for style_struct in data.active_style_structs():
|
||||||
${style_struct.ident}: StyleStructRef::Borrowed(
|
${style_struct.ident}: StyleStructRef::Borrowed(
|
||||||
|
@ -3448,14 +3437,14 @@ impl<'a> StyleBuilder<'a> {
|
||||||
.get_${property.style_struct.name_lower}();
|
.get_${property.style_struct.name_lower}();
|
||||||
|
|
||||||
self.modified_reset = true;
|
self.modified_reset = true;
|
||||||
self.flags.insert(ComputedValueFlags::INHERITS_RESET_STYLE);
|
self.add_flags(ComputedValueFlags::INHERITS_RESET_STYLE);
|
||||||
|
|
||||||
% if property.ident == "content":
|
% if property.ident == "content":
|
||||||
self.flags.insert(ComputedValueFlags::INHERITS_CONTENT);
|
self.add_flags(ComputedValueFlags::INHERITS_CONTENT);
|
||||||
% endif
|
% endif
|
||||||
|
|
||||||
% if property.ident == "display":
|
% if property.ident == "display":
|
||||||
self.flags.insert(ComputedValueFlags::INHERITS_DISPLAY);
|
self.add_flags(ComputedValueFlags::INHERITS_DISPLAY);
|
||||||
% endif
|
% endif
|
||||||
|
|
||||||
if self.${property.style_struct.ident}.ptr_eq(inherited_struct) {
|
if self.${property.style_struct.ident}.ptr_eq(inherited_struct) {
|
||||||
|
@ -3470,7 +3459,7 @@ impl<'a> StyleBuilder<'a> {
|
||||||
% endif
|
% endif
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
% elif property.name != "font-size":
|
% else:
|
||||||
/// Reset `${property.ident}` to the initial value.
|
/// Reset `${property.ident}` to the initial value.
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
pub fn reset_${property.ident}(&mut self) {
|
pub fn reset_${property.ident}(&mut self) {
|
||||||
|
@ -3642,13 +3631,33 @@ impl<'a> StyleBuilder<'a> {
|
||||||
self.modified_reset
|
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.
|
/// Turns this `StyleBuilder` into a proper `ComputedValues` instance.
|
||||||
pub fn build(self) -> Arc<ComputedValues> {
|
pub fn build(self) -> Arc<ComputedValues> {
|
||||||
ComputedValues::new(
|
ComputedValues::new(
|
||||||
self.pseudo,
|
self.pseudo,
|
||||||
self.custom_properties,
|
self.custom_properties,
|
||||||
self.writing_mode,
|
self.writing_mode,
|
||||||
self.flags,
|
self.flags.get(),
|
||||||
self.rules,
|
self.rules,
|
||||||
self.visited_style,
|
self.visited_style,
|
||||||
% for style_struct in data.active_style_structs():
|
% 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::{ComputedValues, ComputedValuesInner, longhands, style_structs};
|
||||||
use super::computed_value_flags::ComputedValueFlags;
|
use super::computed_value_flags::ComputedValueFlags;
|
||||||
|
|
||||||
/// The initial values for all style structs as defined by the specification.
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
|
/// The initial values for all style structs as defined by the specification.
|
||||||
pub static ref INITIAL_SERVO_VALUES: ComputedValues = ComputedValues {
|
pub static ref INITIAL_SERVO_VALUES: ComputedValues = ComputedValues {
|
||||||
inner: ComputedValuesInner {
|
inner: ComputedValuesInner {
|
||||||
% for style_struct in data.active_style_structs():
|
% for style_struct in data.active_style_structs():
|
||||||
|
|
|
@ -142,6 +142,12 @@ impl PseudoElement {
|
||||||
false
|
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.
|
/// Whether this pseudo-element is the ::before pseudo.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_before(&self) -> bool {
|
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.
|
/// 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>
|
/// <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>)
|
fn blockify_if_necessary<E>(&mut self, layout_parent_style: &ComputedValues, element: Option<E>)
|
||||||
where
|
where
|
||||||
E: TElement,
|
E: TElement,
|
||||||
{
|
{
|
||||||
|
use crate::computed_values::list_style_position::T as ListStylePosition;
|
||||||
|
|
||||||
let mut blockify = false;
|
let mut blockify = false;
|
||||||
macro_rules! blockify_if {
|
macro_rules! blockify_if {
|
||||||
($if_what:expr) => {
|
($if_what:expr) => {
|
||||||
|
@ -200,6 +204,11 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
|
||||||
|
|
||||||
blockify_if!(self.style.floated());
|
blockify_if!(self.style.floated());
|
||||||
blockify_if!(self.style.out_of_flow_positioned());
|
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 {
|
if !blockify {
|
||||||
return;
|
return;
|
||||||
|
@ -226,22 +235,18 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
|
||||||
.is_empty()
|
.is_empty()
|
||||||
{
|
{
|
||||||
self.style
|
self.style
|
||||||
.flags
|
.add_flags(ComputedValueFlags::HAS_TEXT_DECORATION_LINES);
|
||||||
.insert(ComputedValueFlags::HAS_TEXT_DECORATION_LINES);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.style.is_pseudo_element() {
|
if self.style.is_pseudo_element() {
|
||||||
self.style
|
self.style
|
||||||
.flags
|
.add_flags(ComputedValueFlags::IS_IN_PSEUDO_ELEMENT_SUBTREE);
|
||||||
.insert(ComputedValueFlags::IS_IN_PSEUDO_ELEMENT_SUBTREE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "servo")]
|
#[cfg(feature = "servo")]
|
||||||
{
|
{
|
||||||
if self.style.get_parent_column().is_multicol() {
|
if self.style.get_parent_column().is_multicol() {
|
||||||
self.style
|
self.style.add_flags(ComputedValueFlags::CAN_BE_FRAGMENTED);
|
||||||
.flags
|
|
||||||
.insert(ComputedValueFlags::CAN_BE_FRAGMENTED);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -280,9 +285,7 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
|
||||||
if writing_mode != WritingMode::HorizontalTb &&
|
if writing_mode != WritingMode::HorizontalTb &&
|
||||||
text_combine_upright == TextCombineUpright::All
|
text_combine_upright == TextCombineUpright::All
|
||||||
{
|
{
|
||||||
self.style
|
self.style.add_flags(ComputedValueFlags::IS_TEXT_COMBINED);
|
||||||
.flags
|
|
||||||
.insert(ComputedValueFlags::IS_TEXT_COMBINED);
|
|
||||||
self.style
|
self.style
|
||||||
.mutate_inherited_box()
|
.mutate_inherited_box()
|
||||||
.set_writing_mode(WritingMode::HorizontalTb);
|
.set_writing_mode(WritingMode::HorizontalTb);
|
||||||
|
@ -304,8 +307,7 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
|
||||||
.contains(ComputedValueFlags::SHOULD_SUPPRESS_LINEBREAK)
|
.contains(ComputedValueFlags::SHOULD_SUPPRESS_LINEBREAK)
|
||||||
{
|
{
|
||||||
self.style
|
self.style
|
||||||
.flags
|
.add_flags(ComputedValueFlags::SHOULD_SUPPRESS_LINEBREAK);
|
||||||
.insert(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.
|
// Check whether line break should be suppressed for this element.
|
||||||
if self.should_suppress_linebreak(layout_parent_style) {
|
if self.should_suppress_linebreak(layout_parent_style) {
|
||||||
self.style
|
self.style
|
||||||
.flags
|
.add_flags(ComputedValueFlags::SHOULD_SUPPRESS_LINEBREAK);
|
||||||
.insert(ComputedValueFlags::SHOULD_SUPPRESS_LINEBREAK);
|
|
||||||
// Inlinify the display type if allowed.
|
// Inlinify the display type if allowed.
|
||||||
if !self.skip_item_display_fixup(element) {
|
if !self.skip_item_display_fixup(element) {
|
||||||
let inline_display = self_display.inlinify();
|
let inline_display = self_display.inlinify();
|
||||||
|
@ -652,13 +653,11 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
|
||||||
|
|
||||||
if element.unwrap().is_visited_link() {
|
if element.unwrap().is_visited_link() {
|
||||||
self.style
|
self.style
|
||||||
.flags
|
.add_flags(ComputedValueFlags::IS_RELEVANT_LINK_VISITED);
|
||||||
.insert(ComputedValueFlags::IS_RELEVANT_LINK_VISITED);
|
|
||||||
} else {
|
} else {
|
||||||
// Need to remove to handle unvisited link inside visited.
|
// Need to remove to handle unvisited link inside visited.
|
||||||
self.style
|
self.style
|
||||||
.flags
|
.remove_flags(ComputedValueFlags::IS_RELEVANT_LINK_VISITED);
|
||||||
.remove(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
|
/// Adjusts the style to account for various fixups that don't fit naturally
|
||||||
/// into the cascade.
|
/// into the cascade.
|
||||||
///
|
///
|
||||||
|
@ -788,6 +833,7 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
{
|
{
|
||||||
self.adjust_for_appearance(element);
|
self.adjust_for_appearance(element);
|
||||||
|
self.adjust_for_list_item(element);
|
||||||
}
|
}
|
||||||
self.set_bits();
|
self.set_bits();
|
||||||
}
|
}
|
||||||
|
|
|
@ -189,6 +189,13 @@ impl<'a, 'i> AtRuleParser<'i> for TopLevelRuleParser<'a> {
|
||||||
return Err(input.new_custom_error(StyleParseErrorKind::UnexpectedImportRule))
|
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_string = input.expect_url_or_string()?.as_ref().to_owned();
|
||||||
let url = CssUrl::parse_from_string(url_string, &self.context);
|
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 cssparser::{parse_important, AtRuleParser, DeclarationListParser, DeclarationParser, Parser};
|
||||||
use euclid::TypedSize2D;
|
use euclid::TypedSize2D;
|
||||||
use selectors::parser::SelectorParseErrorKind;
|
use selectors::parser::SelectorParseErrorKind;
|
||||||
use servo_config::pref;
|
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::fmt::{self, Write};
|
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.
|
/// Whether parsing and processing of `@viewport` rules is enabled.
|
||||||
#[cfg(feature = "servo")]
|
#[cfg(feature = "servo")]
|
||||||
pub fn enabled() -> bool {
|
pub fn enabled() -> bool {
|
||||||
|
use servo_config::pref;
|
||||||
pref!(layout.viewport.enabled)
|
pref!(layout.viewport.enabled)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,13 +7,13 @@
|
||||||
use crate::values::computed::url::ComputedImageUrl;
|
use crate::values::computed::url::ComputedImageUrl;
|
||||||
use crate::values::generics::counters as generics;
|
use crate::values::generics::counters as generics;
|
||||||
use crate::values::generics::counters::CounterIncrement as GenericCounterIncrement;
|
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.
|
/// A computed value for the `counter-increment` property.
|
||||||
pub type CounterIncrement = GenericCounterIncrement<i32>;
|
pub type CounterIncrement = GenericCounterIncrement<i32>;
|
||||||
|
|
||||||
/// A computed value for the `counter-increment` property.
|
/// A computed value for the `counter-set` and `counter-reset` properties.
|
||||||
pub type CounterReset = GenericCounterReset<i32>;
|
pub type CounterSetOrReset = GenericCounterSetOrReset<i32>;
|
||||||
|
|
||||||
/// A computed value for the `content` property.
|
/// A computed value for the `content` property.
|
||||||
pub type Content = generics::Content<ComputedImageUrl>;
|
pub type Content = generics::Content<ComputedImageUrl>;
|
||||||
|
|
|
@ -152,49 +152,6 @@ impl FontSize {
|
||||||
keyword_info: Some(KeywordInfo::medium()),
|
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
|
/// XXXManishearth it might be better to
|
||||||
|
@ -221,15 +178,21 @@ impl ToAnimatedValue for FontSize {
|
||||||
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
|
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
|
||||||
#[cfg_attr(feature = "servo", derive(MallocSizeOf))]
|
#[cfg_attr(feature = "servo", derive(MallocSizeOf))]
|
||||||
/// Specifies a prioritized list of font family names or generic family names.
|
/// 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 {
|
impl FontFamily {
|
||||||
#[inline]
|
#[inline]
|
||||||
/// Get default font family as `serif` which is a generic font-family
|
/// Get default font family as `serif` which is a generic font-family
|
||||||
pub fn serif() -> Self {
|
pub fn serif() -> Self {
|
||||||
FontFamily(FontFamilyList::new(Box::new([SingleFontFamily::Generic(
|
FontFamily {
|
||||||
atom!("serif"),
|
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
|
// SharedFontList objects are generally shared from the pointer
|
||||||
// stored in the specified value. So only count this if the
|
// stored in the specified value. So only count this if the
|
||||||
// SharedFontList is unshared.
|
// 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
|
where
|
||||||
W: fmt::Write,
|
W: fmt::Write,
|
||||||
{
|
{
|
||||||
let mut iter = self.0.iter();
|
let mut iter = self.families.iter();
|
||||||
iter.next().unwrap().to_css(dest)?;
|
iter.next().unwrap().to_css(dest)?;
|
||||||
for family in iter {
|
for family in iter {
|
||||||
dest.write_str(", ")?;
|
dest.write_str(", ")?;
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
pub use crate::values::specified::list::ListStyleType;
|
pub use crate::values::specified::list::ListStyleType;
|
||||||
|
pub use crate::values::specified::list::MozListReversed;
|
||||||
pub use crate::values::specified::list::{QuotePair, Quotes};
|
pub use crate::values::specified::list::{QuotePair, Quotes};
|
||||||
|
|
||||||
use servo_arc::Arc;
|
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::box_::{ScrollSnapAlign, ScrollSnapType, TouchAction, VerticalAlign, WillChange};
|
||||||
pub use self::color::{Color, ColorOrAuto, ColorPropertyValue, RGBAColor};
|
pub use self::color::{Color, ColorOrAuto, ColorPropertyValue, RGBAColor};
|
||||||
pub use self::column::ColumnCount;
|
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::easing::TimingFunction;
|
||||||
pub use self::effects::{BoxShadow, Filter, SimpleShadow};
|
pub use self::effects::{BoxShadow, Filter, SimpleShadow};
|
||||||
pub use self::flex::FlexBasis;
|
pub use self::flex::FlexBasis;
|
||||||
|
@ -64,6 +64,7 @@ pub use self::length::{LengthOrAuto, LengthPercentageOrAuto, MaxSize, Size};
|
||||||
pub use self::length::{NonNegativeLengthPercentage, NonNegativeLengthPercentageOrAuto};
|
pub use self::length::{NonNegativeLengthPercentage, NonNegativeLengthPercentageOrAuto};
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
pub use self::list::ListStyleType;
|
pub use self::list::ListStyleType;
|
||||||
|
pub use self::list::MozListReversed;
|
||||||
pub use self::list::{QuotePair, Quotes};
|
pub use self::list::{QuotePair, Quotes};
|
||||||
pub use self::motion::OffsetPath;
|
pub use self::motion::OffsetPath;
|
||||||
pub use self::outline::OutlineStyle;
|
pub use self::outline::OutlineStyle;
|
||||||
|
|
|
@ -19,8 +19,8 @@ use std::fmt::{self, Write};
|
||||||
use style_traits::{CssWriter, ToCss};
|
use style_traits::{CssWriter, ToCss};
|
||||||
|
|
||||||
pub use crate::values::specified::TextAlignKeyword as TextAlign;
|
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::{OverflowWrap, WordBreak};
|
||||||
|
pub use crate::values::specified::{TextDecorationLine, TextEmphasisPosition};
|
||||||
|
|
||||||
/// A computed value for the `initial-letter` property.
|
/// A computed value for the `initial-letter` property.
|
||||||
pub type InitialLetter = GenericInitialLetter<CSSFloat, CSSInteger>;
|
pub type InitialLetter = GenericInitialLetter<CSSFloat, CSSInteger>;
|
||||||
|
@ -182,11 +182,11 @@ impl TextDecorationsInEffect {
|
||||||
.clone(),
|
.clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let text_style = style.get_text();
|
let line = style.get_text().clone_text_decoration_line();
|
||||||
|
|
||||||
result.underline |= text_style.has_underline();
|
result.underline |= line.contains(TextDecorationLine::UNDERLINE);
|
||||||
result.overline |= text_style.has_overline();
|
result.overline |= line.contains(TextDecorationLine::OVERLINE);
|
||||||
result.line_through |= text_style.has_line_through();
|
result.line_through |= line.contains(TextDecorationLine::LINE_THROUGH);
|
||||||
|
|
||||||
result
|
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(
|
#[derive(
|
||||||
Clone, Debug, Default, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss,
|
Clone, Debug, Default, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss,
|
||||||
)]
|
)]
|
||||||
pub struct CounterReset<I>(Counters<I>);
|
pub struct CounterSetOrReset<I>(Counters<I>);
|
||||||
|
|
||||||
impl<I> CounterReset<I> {
|
impl<I> CounterSetOrReset<I> {
|
||||||
/// Returns a new value for `counter-reset`.
|
/// Returns a new value for `counter-set` / `counter-reset`.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new(counters: Vec<CounterPair<I>>) -> Self {
|
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>];
|
type Target = [CounterPair<I>];
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -555,9 +555,8 @@ impl WillChange {
|
||||||
|
|
||||||
bitflags! {
|
bitflags! {
|
||||||
/// The change bits that we care about.
|
/// The change bits that we care about.
|
||||||
///
|
|
||||||
/// These need to be in sync with NS_STYLE_WILL_CHANGE_*.
|
|
||||||
#[derive(MallocSizeOf, SpecifiedValueInfo, ToComputedValue)]
|
#[derive(MallocSizeOf, SpecifiedValueInfo, ToComputedValue)]
|
||||||
|
#[repr(C)]
|
||||||
pub struct WillChangeBits: u8 {
|
pub struct WillChangeBits: u8 {
|
||||||
/// Whether the stacking context will change.
|
/// Whether the stacking context will change.
|
||||||
const STACKING_CONTEXT = 1 << 0;
|
const STACKING_CONTEXT = 1 << 0;
|
||||||
|
@ -616,7 +615,7 @@ impl Parse for WillChange {
|
||||||
fn parse<'i, 't>(
|
fn parse<'i, 't>(
|
||||||
context: &ParserContext,
|
context: &ParserContext,
|
||||||
input: &mut Parser<'i, 't>,
|
input: &mut Parser<'i, 't>,
|
||||||
) -> Result<WillChange, ParseError<'i>> {
|
) -> Result<Self, ParseError<'i>> {
|
||||||
if input
|
if input
|
||||||
.try(|input| input.expect_ident_matching("auto"))
|
.try(|input| input.expect_ident_matching("auto"))
|
||||||
.is_ok()
|
.is_ok()
|
||||||
|
@ -650,21 +649,22 @@ impl Parse for WillChange {
|
||||||
}
|
}
|
||||||
|
|
||||||
bitflags! {
|
bitflags! {
|
||||||
|
/// Values for the `touch-action` property.
|
||||||
#[cfg_attr(feature = "gecko", derive(MallocSizeOf))]
|
#[cfg_attr(feature = "gecko", derive(MallocSizeOf))]
|
||||||
#[derive(SpecifiedValueInfo, ToComputedValue)]
|
#[derive(SpecifiedValueInfo, ToComputedValue)]
|
||||||
/// These constants match Gecko's `NS_STYLE_TOUCH_ACTION_*` constants.
|
|
||||||
#[value_info(other_values = "auto,none,manipulation,pan-x,pan-y")]
|
#[value_info(other_values = "auto,none,manipulation,pan-x,pan-y")]
|
||||||
|
#[repr(C)]
|
||||||
pub struct TouchAction: u8 {
|
pub struct TouchAction: u8 {
|
||||||
/// `none` variant
|
/// `none` variant
|
||||||
const TOUCH_ACTION_NONE = 1 << 0;
|
const NONE = 1 << 0;
|
||||||
/// `auto` variant
|
/// `auto` variant
|
||||||
const TOUCH_ACTION_AUTO = 1 << 1;
|
const AUTO = 1 << 1;
|
||||||
/// `pan-x` variant
|
/// `pan-x` variant
|
||||||
const TOUCH_ACTION_PAN_X = 1 << 2;
|
const PAN_X = 1 << 2;
|
||||||
/// `pan-y` variant
|
/// `pan-y` variant
|
||||||
const TOUCH_ACTION_PAN_Y = 1 << 3;
|
const PAN_Y = 1 << 3;
|
||||||
/// `manipulation` variant
|
/// `manipulation` variant
|
||||||
const TOUCH_ACTION_MANIPULATION = 1 << 4;
|
const MANIPULATION = 1 << 4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -672,7 +672,7 @@ impl TouchAction {
|
||||||
#[inline]
|
#[inline]
|
||||||
/// Get default `touch-action` as `auto`
|
/// Get default `touch-action` as `auto`
|
||||||
pub fn auto() -> TouchAction {
|
pub fn auto() -> TouchAction {
|
||||||
TouchAction::TOUCH_ACTION_AUTO
|
TouchAction::AUTO
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -682,16 +682,14 @@ impl ToCss for TouchAction {
|
||||||
W: Write,
|
W: Write,
|
||||||
{
|
{
|
||||||
match *self {
|
match *self {
|
||||||
TouchAction::TOUCH_ACTION_NONE => dest.write_str("none"),
|
TouchAction::NONE => dest.write_str("none"),
|
||||||
TouchAction::TOUCH_ACTION_AUTO => dest.write_str("auto"),
|
TouchAction::AUTO => dest.write_str("auto"),
|
||||||
TouchAction::TOUCH_ACTION_MANIPULATION => dest.write_str("manipulation"),
|
TouchAction::MANIPULATION => dest.write_str("manipulation"),
|
||||||
_ if self
|
_ if self.contains(TouchAction::PAN_X | TouchAction::PAN_Y) => {
|
||||||
.contains(TouchAction::TOUCH_ACTION_PAN_X | TouchAction::TOUCH_ACTION_PAN_Y) =>
|
|
||||||
{
|
|
||||||
dest.write_str("pan-x 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::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_Y) => dest.write_str("pan-y"),
|
||||||
_ => panic!("invalid touch-action value"),
|
_ => panic!("invalid touch-action value"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -703,68 +701,45 @@ impl Parse for TouchAction {
|
||||||
input: &mut Parser<'i, 't>,
|
input: &mut Parser<'i, 't>,
|
||||||
) -> Result<TouchAction, ParseError<'i>> {
|
) -> Result<TouchAction, ParseError<'i>> {
|
||||||
try_match_ident_ignore_ascii_case! { input,
|
try_match_ident_ignore_ascii_case! { input,
|
||||||
"auto" => Ok(TouchAction::TOUCH_ACTION_AUTO),
|
"auto" => Ok(TouchAction::AUTO),
|
||||||
"none" => Ok(TouchAction::TOUCH_ACTION_NONE),
|
"none" => Ok(TouchAction::NONE),
|
||||||
"manipulation" => Ok(TouchAction::TOUCH_ACTION_MANIPULATION),
|
"manipulation" => Ok(TouchAction::MANIPULATION),
|
||||||
"pan-x" => {
|
"pan-x" => {
|
||||||
if input.try(|i| i.expect_ident_matching("pan-y")).is_ok() {
|
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 {
|
} else {
|
||||||
Ok(TouchAction::TOUCH_ACTION_PAN_X)
|
Ok(TouchAction::PAN_X)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"pan-y" => {
|
"pan-y" => {
|
||||||
if input.try(|i| i.expect_ident_matching("pan-x")).is_ok() {
|
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 {
|
} 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! {
|
bitflags! {
|
||||||
#[derive(MallocSizeOf, SpecifiedValueInfo, ToComputedValue)]
|
#[derive(MallocSizeOf, SpecifiedValueInfo, ToComputedValue)]
|
||||||
#[value_info(other_values = "none,strict,content,size,layout,paint")]
|
#[value_info(other_values = "none,strict,content,size,layout,paint")]
|
||||||
|
#[repr(C)]
|
||||||
/// Constants for contain: https://drafts.csswg.org/css-contain/#contain-property
|
/// Constants for contain: https://drafts.csswg.org/css-contain/#contain-property
|
||||||
pub struct Contain: u8 {
|
pub struct Contain: u8 {
|
||||||
|
/// `none` variant, just for convenience.
|
||||||
|
const NONE = 0;
|
||||||
/// 'size' variant, turns on size containment
|
/// 'size' variant, turns on size containment
|
||||||
const SIZE = 0x01;
|
const SIZE = 1 << 0;
|
||||||
/// `layout` variant, turns on layout containment
|
/// `layout` variant, turns on layout containment
|
||||||
const LAYOUT = 0x02;
|
const LAYOUT = 1 << 1;
|
||||||
/// `paint` variant, turns on paint containment
|
/// `paint` variant, turns on paint containment
|
||||||
const PAINT = 0x04;
|
const PAINT = 1 << 2;
|
||||||
/// `strict` variant, turns on all types of containment
|
/// `strict` variant, turns on all types of containment
|
||||||
const STRICT = 0x08;
|
const STRICT = 1 << 3;
|
||||||
/// 'content' variant, turns on layout and paint containment
|
/// '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
|
/// variant with all the bits that contain: strict turns on
|
||||||
const STRICT_BITS = Contain::LAYOUT.bits | Contain::PAINT.bits | Contain::SIZE.bits;
|
const STRICT_BITS = Contain::LAYOUT.bits | Contain::PAINT.bits | Contain::SIZE.bits;
|
||||||
/// variant with all the bits that contain: content turns on
|
/// 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 as generics;
|
||||||
use crate::values::generics::counters::CounterIncrement as GenericCounterIncrement;
|
use crate::values::generics::counters::CounterIncrement as GenericCounterIncrement;
|
||||||
use crate::values::generics::counters::CounterPair;
|
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")]
|
#[cfg(feature = "gecko")]
|
||||||
use crate::values::generics::CounterStyleOrNone;
|
use crate::values::generics::CounterStyleOrNone;
|
||||||
use crate::values::specified::url::SpecifiedImageUrl;
|
use crate::values::specified::url::SpecifiedImageUrl;
|
||||||
|
@ -34,10 +34,10 @@ impl Parse for CounterIncrement {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A specified value for the `counter-increment` property.
|
/// A specified value for the `counter-set` and `counter-reset` properties.
|
||||||
pub type CounterReset = GenericCounterReset<Integer>;
|
pub type CounterSetOrReset = GenericCounterSetOrReset<Integer>;
|
||||||
|
|
||||||
impl Parse for CounterReset {
|
impl Parse for CounterSetOrReset {
|
||||||
fn parse<'i, 't>(
|
fn parse<'i, 't>(
|
||||||
context: &ParserContext,
|
context: &ParserContext,
|
||||||
input: &mut Parser<'i, 't>,
|
input: &mut Parser<'i, 't>,
|
||||||
|
|
|
@ -548,13 +548,16 @@ impl ToComputedValue for FontFamily {
|
||||||
|
|
||||||
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
|
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
|
||||||
match *self {
|
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),
|
FontFamily::System(_) => self.compute_system(context),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_computed_value(other: &computed::FontFamily) -> Self {
|
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),
|
"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 {
|
impl Parse for FontSize {
|
||||||
|
|
|
@ -7,8 +7,9 @@
|
||||||
//! [length]: https://drafts.csswg.org/css-values/#lengths
|
//! [length]: https://drafts.csswg.org/css-values/#lengths
|
||||||
|
|
||||||
use super::{AllowQuirks, Number, Percentage, ToComputedValue};
|
use super::{AllowQuirks, Number, Percentage, ToComputedValue};
|
||||||
use crate::font_metrics::FontMetricsQueryResult;
|
use crate::font_metrics::{FontMetrics, FontMetricsOrientation};
|
||||||
use crate::parser::{Parse, ParserContext};
|
use crate::parser::{Parse, ParserContext};
|
||||||
|
use crate::properties::computed_value_flags::ComputedValueFlags;
|
||||||
use crate::values::computed::{self, CSSPixelLength, Context};
|
use crate::values::computed::{self, CSSPixelLength, Context};
|
||||||
use crate::values::generics::length as generics;
|
use crate::values::generics::length as generics;
|
||||||
use crate::values::generics::length::{
|
use crate::values::generics::length::{
|
||||||
|
@ -82,17 +83,12 @@ pub enum FontBaseSize {
|
||||||
///
|
///
|
||||||
/// FIXME(emilio): This is very complex, and should go away.
|
/// FIXME(emilio): This is very complex, and should go away.
|
||||||
InheritedStyleButStripEmUnits,
|
InheritedStyleButStripEmUnits,
|
||||||
/// Use a custom base size.
|
|
||||||
///
|
|
||||||
/// FIXME(emilio): This is very dubious, and only used for MathML.
|
|
||||||
Custom(Au),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FontBaseSize {
|
impl FontBaseSize {
|
||||||
/// Calculate the actual size for a given context
|
/// Calculate the actual size for a given context
|
||||||
pub fn resolve(&self, context: &Context) -> Au {
|
pub fn resolve(&self, context: &Context) -> Au {
|
||||||
match *self {
|
match *self {
|
||||||
FontBaseSize::Custom(size) => size,
|
|
||||||
FontBaseSize::CurrentStyle => context.style().get_font().clone_font_size().size(),
|
FontBaseSize::CurrentStyle => context.style().get_font().clone_font_size().size(),
|
||||||
FontBaseSize::InheritedStyleButStripEmUnits | FontBaseSize::InheritedStyle => {
|
FontBaseSize::InheritedStyleButStripEmUnits | FontBaseSize::InheritedStyle => {
|
||||||
context.style().get_parent_font().clone_font_size().size()
|
context.style().get_parent_font().clone_font_size().size()
|
||||||
|
@ -136,15 +132,12 @@ impl FontRelativeLength {
|
||||||
) -> (Au, CSSFloat) {
|
) -> (Au, CSSFloat) {
|
||||||
fn query_font_metrics(
|
fn query_font_metrics(
|
||||||
context: &Context,
|
context: &Context,
|
||||||
reference_font_size: Au,
|
base_size: FontBaseSize,
|
||||||
) -> FontMetricsQueryResult {
|
orientation: FontMetricsOrientation,
|
||||||
context.font_metrics_provider.query(
|
) -> FontMetrics {
|
||||||
context.style().get_font(),
|
context
|
||||||
reference_font_size,
|
.font_metrics_provider
|
||||||
context.style().writing_mode,
|
.query(context, base_size, orientation)
|
||||||
context.in_media_query,
|
|
||||||
context.device(),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let reference_font_size = base_size.resolve(context);
|
let reference_font_size = base_size.resolve(context);
|
||||||
|
@ -169,24 +162,40 @@ impl FontRelativeLength {
|
||||||
if context.for_non_inherited_property.is_some() {
|
if context.for_non_inherited_property.is_some() {
|
||||||
context.rule_cache_conditions.borrow_mut().set_uncacheable();
|
context.rule_cache_conditions.borrow_mut().set_uncacheable();
|
||||||
}
|
}
|
||||||
let reference_size = match query_font_metrics(context, reference_font_size) {
|
context
|
||||||
FontMetricsQueryResult::Available(metrics) => metrics.x_height,
|
.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
|
// https://drafts.csswg.org/css-values/#ex
|
||||||
//
|
//
|
||||||
// In the cases where it is impossible or impractical to
|
// In the cases where it is impossible or impractical to
|
||||||
// determine the x-height, a value of 0.5em must be
|
// determine the x-height, a value of 0.5em must be
|
||||||
// assumed.
|
// assumed.
|
||||||
//
|
//
|
||||||
FontMetricsQueryResult::NotAvailable => reference_font_size.scale_by(0.5),
|
reference_font_size.scale_by(0.5)
|
||||||
};
|
});
|
||||||
(reference_size, length)
|
(reference_size, length)
|
||||||
},
|
},
|
||||||
FontRelativeLength::Ch(length) => {
|
FontRelativeLength::Ch(length) => {
|
||||||
if context.for_non_inherited_property.is_some() {
|
if context.for_non_inherited_property.is_some() {
|
||||||
context.rule_cache_conditions.borrow_mut().set_uncacheable();
|
context.rule_cache_conditions.borrow_mut().set_uncacheable();
|
||||||
}
|
}
|
||||||
let reference_size = match query_font_metrics(context, reference_font_size) {
|
context
|
||||||
FontMetricsQueryResult::Available(metrics) => metrics.zero_advance_measure,
|
.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
|
// https://drafts.csswg.org/css-values/#ch
|
||||||
//
|
//
|
||||||
// In the cases where it is impossible or impractical to
|
// 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
|
// writing-mode is vertical-rl or vertical-lr and
|
||||||
// text-orientation is upright).
|
// text-orientation is upright).
|
||||||
//
|
//
|
||||||
FontMetricsQueryResult::NotAvailable => {
|
let wm = context.style().writing_mode;
|
||||||
if context.style().writing_mode.is_vertical() {
|
if wm.is_vertical() && wm.is_upright() {
|
||||||
reference_font_size
|
reference_font_size
|
||||||
} else {
|
} else {
|
||||||
reference_font_size.scale_by(0.5)
|
reference_font_size.scale_by(0.5)
|
||||||
}
|
}
|
||||||
},
|
});
|
||||||
};
|
|
||||||
(reference_size, length)
|
(reference_size, length)
|
||||||
},
|
},
|
||||||
FontRelativeLength::Rem(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::box_::{TouchAction, TransitionProperty, VerticalAlign, WillChange};
|
||||||
pub use self::color::{Color, ColorOrAuto, ColorPropertyValue, RGBAColor};
|
pub use self::color::{Color, ColorOrAuto, ColorPropertyValue, RGBAColor};
|
||||||
pub use self::column::ColumnCount;
|
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::easing::TimingFunction;
|
||||||
pub use self::effects::{BoxShadow, Filter, SimpleShadow};
|
pub use self::effects::{BoxShadow, Filter, SimpleShadow};
|
||||||
pub use self::flex::FlexBasis;
|
pub use self::flex::FlexBasis;
|
||||||
|
@ -66,6 +66,7 @@ pub use self::length::{NoCalcLength, ViewportPercentageLength};
|
||||||
pub use self::length::{NonNegativeLengthPercentage, NonNegativeLengthPercentageOrAuto};
|
pub use self::length::{NonNegativeLengthPercentage, NonNegativeLengthPercentageOrAuto};
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
pub use self::list::ListStyleType;
|
pub use self::list::ListStyleType;
|
||||||
|
pub use self::list::MozListReversed;
|
||||||
pub use self::list::{QuotePair, Quotes};
|
pub use self::list::{QuotePair, Quotes};
|
||||||
pub use self::motion::OffsetPath;
|
pub use self::motion::OffsetPath;
|
||||||
pub use self::outline::OutlineStyle;
|
pub use self::outline::OutlineStyle;
|
||||||
|
|
|
@ -22,8 +22,7 @@ use cssparser::{Parser, Token};
|
||||||
use selectors::parser::SelectorParseErrorKind;
|
use selectors::parser::SelectorParseErrorKind;
|
||||||
use std::fmt::{self, Write};
|
use std::fmt::{self, Write};
|
||||||
use style_traits::values::SequenceWriter;
|
use style_traits::values::SequenceWriter;
|
||||||
use style_traits::{CssWriter, KeywordsCollectFn, ParseError};
|
use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss};
|
||||||
use style_traits::{SpecifiedValueInfo, StyleParseErrorKind, ToCss};
|
|
||||||
use unicode_segmentation::UnicodeSegmentation;
|
use unicode_segmentation::UnicodeSegmentation;
|
||||||
|
|
||||||
/// A specified type for the `initial-letter` property.
|
/// A specified type for the `initial-letter` property.
|
||||||
|
@ -255,119 +254,121 @@ impl ToComputedValue for TextOverflow {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! impl_text_decoration_line {
|
bitflags! {
|
||||||
{
|
#[derive(MallocSizeOf, SpecifiedValueInfo, ToComputedValue)]
|
||||||
$(
|
#[value_info(other_values = "none,underline,overline,line-through,blink")]
|
||||||
$(#[$($meta:tt)+])*
|
#[repr(C)]
|
||||||
$ident:ident / $css:expr => $value:expr,
|
/// Specified keyword values for the text-decoration-line property.
|
||||||
)+
|
pub struct TextDecorationLine: u8 {
|
||||||
} => {
|
/// No text decoration line is specified.
|
||||||
bitflags! {
|
const NONE = 0;
|
||||||
#[derive(MallocSizeOf, ToComputedValue)]
|
/// underline
|
||||||
/// Specified keyword values for the text-decoration-line property.
|
const UNDERLINE = 1 << 0;
|
||||||
pub struct TextDecorationLine: u8 {
|
/// overline
|
||||||
/// No text decoration line is specified
|
const OVERLINE = 1 << 1;
|
||||||
const NONE = 0;
|
/// line-through
|
||||||
$(
|
const LINE_THROUGH = 1 << 2;
|
||||||
$(#[$($meta)+])*
|
/// blink
|
||||||
const $ident = $value;
|
const BLINK = 1 << 3;
|
||||||
)+
|
/// Only set by presentation attributes
|
||||||
#[cfg(feature = "gecko")]
|
///
|
||||||
/// Only set by presentation attributes
|
/// Setting this will mean that text-decorations use the color
|
||||||
///
|
/// specified by `color` in quirks mode.
|
||||||
/// Setting this will mean that text-decorations use the color
|
///
|
||||||
/// specified by `color` in quirks mode.
|
/// For example, this gives <a href=foo><font color="red">text</font></a>
|
||||||
///
|
/// a red text decoration
|
||||||
/// For example, this gives <a href=foo><font color="red">text</font></a>
|
#[cfg(feature = "gecko")]
|
||||||
/// a red text decoration
|
const COLOR_OVERRIDE = 0x10;
|
||||||
const COLOR_OVERRIDE = 0x10;
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Parse for TextDecorationLine {
|
||||||
|
/// none | [ underline || overline || line-through || blink ]
|
||||||
|
fn parse<'i, 't>(
|
||||||
|
_context: &ParserContext,
|
||||||
|
input: &mut Parser<'i, 't>,
|
||||||
|
) -> 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if result.contains(flag) {
|
||||||
|
return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
|
||||||
|
}
|
||||||
|
|
||||||
|
result.insert(flag)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parse for TextDecorationLine {
|
if !result.is_empty() {
|
||||||
/// none | [ underline || overline || line-through || blink ]
|
Ok(result)
|
||||||
fn parse<'i, 't>(
|
} else {
|
||||||
_context: &ParserContext,
|
Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
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.is_empty() {
|
|
||||||
Ok(result)
|
|
||||||
} else {
|
|
||||||
Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToCss for TextDecorationLine {
|
|
||||||
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
|
|
||||||
where
|
|
||||||
W: Write,
|
|
||||||
{
|
|
||||||
if self.is_empty() {
|
|
||||||
return dest.write_str("none");
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut writer = SequenceWriter::new(dest, " ");
|
|
||||||
$(
|
|
||||||
if self.contains(TextDecorationLine::$ident) {
|
|
||||||
writer.raw_item($css)?;
|
|
||||||
}
|
|
||||||
)+
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SpecifiedValueInfo for TextDecorationLine {
|
|
||||||
fn collect_completion_keywords(f: KeywordsCollectFn) {
|
|
||||||
f(&["none", $($css,)+]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_text_decoration_line! {
|
impl ToCss for TextDecorationLine {
|
||||||
/// Underline
|
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
|
||||||
UNDERLINE / "underline" => 1 << 0,
|
where
|
||||||
/// Overline
|
W: Write,
|
||||||
OVERLINE / "overline" => 1 << 1,
|
{
|
||||||
/// Line through
|
if self.is_empty() {
|
||||||
LINE_THROUGH / "line-through" => 1 << 2,
|
return dest.write_str("none");
|
||||||
/// Blink
|
}
|
||||||
BLINK / "blink" => 1 << 3,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
impl_bitflags_conversions!(TextDecorationLine);
|
{
|
||||||
|
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 TextDecorationLine {
|
impl TextDecorationLine {
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -10,7 +10,7 @@ use std::sync::Arc as StdArc;
|
||||||
|
|
||||||
/// Type of value that a property supports. This is used by Gecko's
|
/// Type of value that a property supports. This is used by Gecko's
|
||||||
/// devtools to make sense about value it parses, and types listed
|
/// 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,
|
/// XXX This should really be a bitflags rather than a namespace mod,
|
||||||
/// but currently we cannot use bitflags in const.
|
/// but currently we cannot use bitflags in const.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue