mirror of
https://github.com/servo/servo.git
synced 2025-08-04 13:10:20 +01:00
fonts: Add support for the CSS font matching algorithm (#32366)
* fonts: Add support for the CSS font matching algorithm This is a port from Gecko of the CSS font matching algorithm distance functions as well as the "simple family" concept for optimizing matching when dealing with simple fonts. Fixes #189. Fixes #190. Fixes #20686. Fixes #20684. Co-authored-by: Mukilan Thiyagarajan <mukilan@igalia.com> Signed-off-by: Martin Robinson <mrobinson@igalia.com> * Ensure that simple faces are removed for removed stylesheets --------- Signed-off-by: Martin Robinson <mrobinson@igalia.com> Co-authored-by: Mukilan Thiyagarajan <mukilan@igalia.com>
This commit is contained in:
parent
45ef2c4abf
commit
60a81a7032
6 changed files with 442 additions and 671 deletions
|
@ -7,14 +7,16 @@ use std::sync::Arc;
|
||||||
|
|
||||||
use app_units::Au;
|
use app_units::Au;
|
||||||
use atomic_refcell::AtomicRefCell;
|
use atomic_refcell::AtomicRefCell;
|
||||||
|
use log::warn;
|
||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
use style::stylesheets::DocumentStyleSheet;
|
use style::stylesheets::DocumentStyleSheet;
|
||||||
|
use style::values::computed::{FontStyle, FontWeight};
|
||||||
use webrender_api::{FontInstanceFlags, FontInstanceKey, FontKey};
|
use webrender_api::{FontInstanceFlags, FontInstanceKey, FontKey};
|
||||||
|
|
||||||
use crate::font::FontDescriptor;
|
use crate::font::FontDescriptor;
|
||||||
use crate::font_cache_thread::{FontIdentifier, FontSource, LowercaseString};
|
use crate::font_cache_thread::{FontIdentifier, FontSource, LowercaseString};
|
||||||
use crate::font_context::WebFontDownloadState;
|
use crate::font_context::WebFontDownloadState;
|
||||||
use crate::font_template::{FontTemplate, FontTemplateRef, FontTemplateRefMethods};
|
use crate::font_template::{FontTemplate, FontTemplateRef, FontTemplateRefMethods, IsOblique};
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct FontStore {
|
pub struct FontStore {
|
||||||
|
@ -132,10 +134,69 @@ impl WebRenderFontStore {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A list of font templates that make up a given font family.
|
/// A struct that represents the available templates in a "simple family." A simple family
|
||||||
|
/// is one that contains <= 4 available faces: regular, bold, italic, and bold italic. Having
|
||||||
|
/// this simple family abstraction makes font matching much faster for families that don't
|
||||||
|
/// have a complex set of fonts.
|
||||||
|
///
|
||||||
|
/// This optimization is taken from:
|
||||||
|
/// https://searchfox.org/mozilla-central/source/gfx/thebes/gfxFontEntry.cpp.
|
||||||
#[derive(Clone, Debug, Default)]
|
#[derive(Clone, Debug, Default)]
|
||||||
|
struct SimpleFamily {
|
||||||
|
regular: Option<FontTemplateRef>,
|
||||||
|
bold: Option<FontTemplateRef>,
|
||||||
|
italic: Option<FontTemplateRef>,
|
||||||
|
bold_italic: Option<FontTemplateRef>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SimpleFamily {
|
||||||
|
/// Find a font in this family that matches a given descriptor.
|
||||||
|
fn find_for_descriptor(&self, descriptor_to_match: &FontDescriptor) -> Option<FontTemplateRef> {
|
||||||
|
let want_bold = descriptor_to_match.weight >= FontWeight::BOLD_THRESHOLD;
|
||||||
|
let want_italic = descriptor_to_match.style != FontStyle::NORMAL;
|
||||||
|
|
||||||
|
// This represents the preference of which font to return from the [`SimpleFamily`],
|
||||||
|
// given what kind of font we are requesting.
|
||||||
|
let preference = match (want_bold, want_italic) {
|
||||||
|
(true, true) => [&self.bold_italic, &self.italic, &self.bold, &self.regular],
|
||||||
|
(true, false) => [&self.bold, &self.regular, &self.bold_italic, &self.italic],
|
||||||
|
(false, true) => [&self.italic, &self.bold_italic, &self.regular, &self.bold],
|
||||||
|
(false, false) => [&self.regular, &self.bold, &self.italic, &self.bold_italic],
|
||||||
|
};
|
||||||
|
preference
|
||||||
|
.iter()
|
||||||
|
.filter_map(|template| (*template).clone())
|
||||||
|
.next()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn remove_templates_for_stylesheet(&mut self, stylesheet: &DocumentStyleSheet) {
|
||||||
|
let remove_if_template_matches = |template: &mut Option<FontTemplateRef>| {
|
||||||
|
if template.as_ref().map_or(false, |template| {
|
||||||
|
template.borrow().stylesheet.as_ref() == Some(stylesheet)
|
||||||
|
}) {
|
||||||
|
*template = None;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
remove_if_template_matches(&mut self.regular);
|
||||||
|
remove_if_template_matches(&mut self.bold);
|
||||||
|
remove_if_template_matches(&mut self.italic);
|
||||||
|
remove_if_template_matches(&mut self.bold_italic);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// A list of font templates that make up a given font family.
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
pub struct FontTemplates {
|
pub struct FontTemplates {
|
||||||
pub(crate) templates: Vec<FontTemplateRef>,
|
pub(crate) templates: Vec<FontTemplateRef>,
|
||||||
|
simple_family: Option<SimpleFamily>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for FontTemplates {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
templates: Default::default(),
|
||||||
|
simple_family: Some(SimpleFamily::default()),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FontTemplates {
|
impl FontTemplates {
|
||||||
|
@ -148,21 +209,18 @@ impl FontTemplates {
|
||||||
return self.templates.clone();
|
return self.templates.clone();
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO(Issue #189): optimize lookup for
|
if self.templates.len() == 1 {
|
||||||
// regular/bold/italic/bolditalic with fixed offsets and a
|
return vec![self.templates[0].clone()];
|
||||||
// static decision table for fallback between these values.
|
}
|
||||||
let matching_templates: Vec<FontTemplateRef> = self
|
|
||||||
.templates
|
if let Some(template) = self
|
||||||
.iter()
|
.simple_family
|
||||||
.filter(|template| template.matches_font_descriptor(descriptor_to_match))
|
.as_ref()
|
||||||
.cloned()
|
.and_then(|simple_family| simple_family.find_for_descriptor(descriptor_to_match))
|
||||||
.collect();
|
{
|
||||||
if !matching_templates.is_empty() {
|
return vec![template];
|
||||||
return matching_templates;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// We didn't find an exact match. Do more expensive fuzzy matching.
|
|
||||||
// TODO(#190): Do a better job.
|
|
||||||
let mut best_templates = Vec::new();
|
let mut best_templates = Vec::new();
|
||||||
let mut best_distance = f32::MAX;
|
let mut best_distance = f32::MAX;
|
||||||
for template in self.templates.iter() {
|
for template in self.templates.iter() {
|
||||||
|
@ -198,8 +256,62 @@ impl FontTemplates {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.templates
|
|
||||||
.push(Arc::new(AtomicRefCell::new(new_template)));
|
let new_template = Arc::new(AtomicRefCell::new(new_template));
|
||||||
|
self.templates.push(new_template.clone());
|
||||||
|
self.update_simple_family(new_template);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_simple_family(&mut self, added_template: FontTemplateRef) {
|
||||||
|
// If this was detected to not be a simple family before, it cannot ever be one
|
||||||
|
// in the future.
|
||||||
|
let Some(simple_family) = self.simple_family.as_mut() else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
if self.templates.len() > 4 {
|
||||||
|
self.simple_family = None;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Variation fonts are never simple families.
|
||||||
|
if added_template.descriptor().is_variation_font() {
|
||||||
|
self.simple_family = None;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let Some(first) = self.templates.first() else {
|
||||||
|
warn!("Called before adding any templates.");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
// If the stretch between any of these fonts differ, it cannot be a simple family nor if this
|
||||||
|
// font is oblique.
|
||||||
|
let stretch = added_template.descriptor().stretch.0;
|
||||||
|
let style = added_template.descriptor().style.0;
|
||||||
|
if first.descriptor().stretch.0 != stretch || style.is_oblique() {
|
||||||
|
self.simple_family = None;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let weight = added_template.descriptor().weight.0;
|
||||||
|
let supports_bold = weight >= FontWeight::BOLD_THRESHOLD;
|
||||||
|
let is_italic = style == FontStyle::ITALIC;
|
||||||
|
let slot = match (supports_bold, is_italic) {
|
||||||
|
(true, true) => &mut simple_family.bold_italic,
|
||||||
|
(true, false) => &mut simple_family.bold,
|
||||||
|
(false, true) => &mut simple_family.italic,
|
||||||
|
(false, false) => &mut simple_family.regular,
|
||||||
|
};
|
||||||
|
|
||||||
|
// If the slot was already filled there are two fonts with the same simple properties
|
||||||
|
// and this isn't a simple family.
|
||||||
|
if slot.is_some() {
|
||||||
|
self.simple_family = None;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
slot.replace(added_template);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn remove_templates_for_stylesheet(
|
pub(crate) fn remove_templates_for_stylesheet(
|
||||||
|
@ -209,6 +321,11 @@ impl FontTemplates {
|
||||||
let length_before = self.templates.len();
|
let length_before = self.templates.len();
|
||||||
self.templates
|
self.templates
|
||||||
.retain(|template| template.borrow().stylesheet.as_ref() != Some(stylesheet));
|
.retain(|template| template.borrow().stylesheet.as_ref() != Some(stylesheet));
|
||||||
|
|
||||||
|
if let Some(simple_family) = self.simple_family.as_mut() {
|
||||||
|
simple_family.remove_templates_for_stylesheet(stylesheet);
|
||||||
|
}
|
||||||
|
|
||||||
length_before != self.templates.len()
|
length_before != self.templates.len()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,14 +48,6 @@ impl Default for FontTemplateDescriptor {
|
||||||
/// we know they will never be NaN, so we can manually implement Eq.
|
/// we know they will never be NaN, so we can manually implement Eq.
|
||||||
impl Eq for FontTemplateDescriptor {}
|
impl Eq for FontTemplateDescriptor {}
|
||||||
|
|
||||||
fn style_to_number(s: &FontStyle) -> f32 {
|
|
||||||
match *s {
|
|
||||||
FontStyle::NORMAL => 0.,
|
|
||||||
FontStyle::ITALIC => FontStyle::DEFAULT_OBLIQUE_DEGREES as f32,
|
|
||||||
_ => s.oblique_degrees(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FontTemplateDescriptor {
|
impl FontTemplateDescriptor {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new(weight: FontWeight, stretch: FontStretch, style: FontStyle) -> Self {
|
pub fn new(weight: FontWeight, stretch: FontStretch, style: FontStyle) -> Self {
|
||||||
|
@ -67,27 +59,45 @@ impl FontTemplateDescriptor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_variation_font(&self) -> bool {
|
||||||
|
self.weight.0 != self.weight.1 ||
|
||||||
|
self.stretch.0 != self.stretch.1 ||
|
||||||
|
self.style.0 != self.style.1
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns a score indicating how far apart visually the two font descriptors are. This is
|
/// Returns a score indicating how far apart visually the two font descriptors are. This is
|
||||||
/// used for fuzzy font selection.
|
/// used for implmenting the CSS Font Matching algorithm:
|
||||||
|
/// <https://drafts.csswg.org/css-fonts/#font-matching-algorithm>.
|
||||||
///
|
///
|
||||||
/// The smaller the score, the better the fonts match. 0 indicates an exact match. This must
|
/// The smaller the score, the better the fonts match. 0 indicates an exact match. This must
|
||||||
/// be commutative (distance(A, B) == distance(B, A)).
|
/// be commutative (distance(A, B) == distance(B, A)).
|
||||||
///
|
|
||||||
/// The policy is to care most about differences in italicness, then weight, then stretch
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn distance_from(&self, other: &FontDescriptor) -> f32 {
|
fn distance_from(&self, target: &FontDescriptor) -> f32 {
|
||||||
let weight = self.weight.0;
|
let stretch_distance = target.stretch.match_distance(&self.stretch);
|
||||||
let style = self.style.0;
|
let style_distance = target.style.match_distance(&self.style);
|
||||||
let stretch = self.stretch.0;
|
let weight_distance = target.weight.match_distance(&self.weight);
|
||||||
|
|
||||||
// 0 <= style_part <= 180, since font-style obliqueness should be
|
// Sanity-check that the distances are within the expected range
|
||||||
// between -90 and +90deg.
|
// (update if implementation of the distance functions is changed).
|
||||||
let style_part = (style_to_number(&style) - style_to_number(&other.style)).abs();
|
assert!(stretch_distance >= 0.0 && stretch_distance <= 2000.0);
|
||||||
// 0 <= weightPart <= 800
|
assert!(style_distance >= 0.0 && style_distance <= 500.0);
|
||||||
let weight_part = (weight.value() - other.weight.value()).abs();
|
assert!(weight_distance >= 0.0 && weight_distance <= 1600.0);
|
||||||
// 0 <= stretchPart <= 8
|
|
||||||
let stretch_part = (stretch.to_percentage().0 - other.stretch.to_percentage().0).abs();
|
// Factors used to weight the distances between the available and target font
|
||||||
style_part + weight_part + stretch_part
|
// properties during font-matching. These ensure that we respect the CSS-fonts
|
||||||
|
// requirement that font-stretch >> font-style >> font-weight; and in addition,
|
||||||
|
// a mismatch between the desired and actual glyph presentation (emoji vs text)
|
||||||
|
// will take precedence over any of the style attributes.
|
||||||
|
//
|
||||||
|
// TODO: Take into account Unicode presentation preferences here, in order to properly
|
||||||
|
// choose a font for emoji clusters that start with non-emoji characters.
|
||||||
|
const STRETCH_FACTOR: f32 = 1.0e8;
|
||||||
|
const STYLE_FACTOR: f32 = 1.0e4;
|
||||||
|
const WEIGHT_FACTOR: f32 = 1.0e0;
|
||||||
|
|
||||||
|
return stretch_distance * STRETCH_FACTOR +
|
||||||
|
style_distance * STYLE_FACTOR +
|
||||||
|
weight_distance * WEIGHT_FACTOR;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn matches(&self, descriptor_to_match: &FontDescriptor) -> bool {
|
fn matches(&self, descriptor_to_match: &FontDescriptor) -> bool {
|
||||||
|
@ -286,3 +296,278 @@ impl FontTemplateRefMethods for FontTemplateRef {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A trait for implementing the CSS font matching algorithm against various font features.
|
||||||
|
/// See <https://drafts.csswg.org/css-fonts/#font-matching-algorithm>.
|
||||||
|
///
|
||||||
|
/// This implementation is ported from Gecko at:
|
||||||
|
/// <https://searchfox.org/mozilla-central/rev/0529464f0d2981347ef581f7521ace8b7af7f7ac/gfx/thebes/gfxFontUtils.h#1217>.
|
||||||
|
trait FontMatchDistanceMethod: Sized {
|
||||||
|
fn match_distance(&self, range: &(Self, Self)) -> f32;
|
||||||
|
fn to_float(&self) -> f32;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FontMatchDistanceMethod for FontStretch {
|
||||||
|
fn match_distance(&self, range: &(Self, Self)) -> f32 {
|
||||||
|
// stretch distance ==> [0,2000]
|
||||||
|
const REVERSE_DISTANCE: f32 = 1000.0;
|
||||||
|
|
||||||
|
let min_stretch = range.0;
|
||||||
|
let max_stretch = range.1;
|
||||||
|
|
||||||
|
// The stretch value is a (non-negative) percentage; currently we support
|
||||||
|
// values in the range 0 .. 1000. (If the upper limit is ever increased,
|
||||||
|
// the kReverseDistance value used here may need to be adjusted.)
|
||||||
|
// If aTargetStretch is >100, we prefer larger values if available;
|
||||||
|
// if <=100, we prefer smaller values if available.
|
||||||
|
if *self < min_stretch {
|
||||||
|
if *self > FontStretch::NORMAL {
|
||||||
|
return min_stretch.to_float() - self.to_float();
|
||||||
|
}
|
||||||
|
return (min_stretch.to_float() - self.to_float()) + REVERSE_DISTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if *self > max_stretch {
|
||||||
|
if *self <= FontStretch::NORMAL {
|
||||||
|
return self.to_float() - max_stretch.to_float();
|
||||||
|
}
|
||||||
|
return (self.to_float() - max_stretch.to_float()) + REVERSE_DISTANCE;
|
||||||
|
}
|
||||||
|
0.0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_float(&self) -> f32 {
|
||||||
|
self.0.to_float()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FontMatchDistanceMethod for FontWeight {
|
||||||
|
// Calculate weight distance with values in the range (0..1000). In general,
|
||||||
|
// heavier weights match towards even heavier weights while lighter weights
|
||||||
|
// match towards even lighter weights. Target weight values in the range
|
||||||
|
// [400..500] are special, since they will first match up to 500, then down
|
||||||
|
// towards 0, then up again towards 999.
|
||||||
|
//
|
||||||
|
// Example: with target 600 and font weight 800, distance will be 200. With
|
||||||
|
// target 300 and font weight 600, distance will be 900, since heavier
|
||||||
|
// weights are farther away than lighter weights. If the target is 5 and the
|
||||||
|
// font weight 995, the distance would be 1590 for the same reason.
|
||||||
|
|
||||||
|
fn match_distance(&self, range: &(Self, Self)) -> f32 {
|
||||||
|
// weight distance ==> [0,1600]
|
||||||
|
const NOT_WITHIN_CENTRAL_RANGE: f32 = 100.0;
|
||||||
|
const REVERSE_DISTANCE: f32 = 600.0;
|
||||||
|
|
||||||
|
let min_weight = range.0;
|
||||||
|
let max_weight = range.1;
|
||||||
|
|
||||||
|
if *self >= min_weight && *self <= max_weight {
|
||||||
|
// Target is within the face's range, so it's a perfect match
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if *self < FontWeight::NORMAL {
|
||||||
|
// Requested a lighter-than-400 weight
|
||||||
|
if max_weight < *self {
|
||||||
|
return self.to_float() - max_weight.to_float();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add reverse-search penalty for bolder faces
|
||||||
|
return (min_weight.to_float() - self.to_float()) + REVERSE_DISTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if *self > FontWeight::from_float(500.) {
|
||||||
|
// Requested a bolder-than-500 weight
|
||||||
|
if min_weight > *self {
|
||||||
|
return min_weight.to_float() - self.to_float();
|
||||||
|
}
|
||||||
|
// Add reverse-search penalty for lighter faces
|
||||||
|
return (self.to_float() - max_weight.to_float()) + REVERSE_DISTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Special case for requested weight in the [400..500] range
|
||||||
|
if min_weight > *self {
|
||||||
|
if min_weight <= FontWeight::from_float(500.) {
|
||||||
|
// Bolder weight up to 500 is first choice
|
||||||
|
return min_weight.to_float() - self.to_float();
|
||||||
|
}
|
||||||
|
// Other bolder weights get a reverse-search penalty
|
||||||
|
return (min_weight.to_float() - self.to_float()) + REVERSE_DISTANCE;
|
||||||
|
}
|
||||||
|
// Lighter weights are not as good as bolder ones within [400..500]
|
||||||
|
return (self.to_float() - max_weight.to_float()) + NOT_WITHIN_CENTRAL_RANGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_float(&self) -> f32 {
|
||||||
|
self.value()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FontMatchDistanceMethod for FontStyle {
|
||||||
|
fn match_distance(&self, range: &(Self, Self)) -> f32 {
|
||||||
|
// style distance ==> [0,500]
|
||||||
|
let min_style = range.0;
|
||||||
|
if *self == min_style {
|
||||||
|
return 0.0; // styles match exactly ==> 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// bias added to angle difference when searching in the non-preferred
|
||||||
|
// direction from a target angle
|
||||||
|
const REVERSE: f32 = 100.0;
|
||||||
|
|
||||||
|
// bias added when we've crossed from positive to negative angles or
|
||||||
|
// vice versa
|
||||||
|
const NEGATE: f32 = 200.0;
|
||||||
|
|
||||||
|
if *self == FontStyle::NORMAL {
|
||||||
|
if min_style.is_oblique() {
|
||||||
|
// to distinguish oblique 0deg from normal, we add 1.0 to the angle
|
||||||
|
let min_angle = min_style.oblique_degrees();
|
||||||
|
if min_angle >= 0.0 {
|
||||||
|
return 1.0 + min_angle;
|
||||||
|
}
|
||||||
|
let max_style = range.1;
|
||||||
|
let max_angle = max_style.oblique_degrees();
|
||||||
|
if max_angle >= 0.0 {
|
||||||
|
// [min,max] range includes 0.0, so just return our minimum
|
||||||
|
return 1.0;
|
||||||
|
}
|
||||||
|
// negative oblique is even worse than italic
|
||||||
|
return NEGATE - max_angle;
|
||||||
|
}
|
||||||
|
// must be italic, which is worse than any non-negative oblique;
|
||||||
|
// treat as a match in the wrong search direction
|
||||||
|
assert!(min_style == FontStyle::ITALIC);
|
||||||
|
return REVERSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
let default_oblique_angle = FontStyle::OBLIQUE.oblique_degrees();
|
||||||
|
if *self == FontStyle::ITALIC {
|
||||||
|
if min_style.is_oblique() {
|
||||||
|
let min_angle = min_style.oblique_degrees();
|
||||||
|
if min_angle >= default_oblique_angle {
|
||||||
|
return 1.0 + (min_angle - default_oblique_angle);
|
||||||
|
}
|
||||||
|
let max_style = range.1;
|
||||||
|
let max_angle = max_style.oblique_degrees();
|
||||||
|
if max_angle >= default_oblique_angle {
|
||||||
|
return 1.0;
|
||||||
|
}
|
||||||
|
if max_angle > 0.0 {
|
||||||
|
// wrong direction but still > 0, add bias of 100
|
||||||
|
return REVERSE + (default_oblique_angle - max_angle);
|
||||||
|
}
|
||||||
|
// negative oblique angle, add bias of 300
|
||||||
|
return REVERSE + NEGATE + (default_oblique_angle - max_angle);
|
||||||
|
}
|
||||||
|
// normal is worse than oblique > 0, but better than oblique <= 0
|
||||||
|
assert!(min_style == FontStyle::NORMAL);
|
||||||
|
return NEGATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// target is oblique <angle>: four different cases depending on
|
||||||
|
// the value of the <angle>, which determines the preferred direction
|
||||||
|
// of search
|
||||||
|
let target_angle = self.oblique_degrees();
|
||||||
|
if target_angle >= default_oblique_angle {
|
||||||
|
if min_style.is_oblique() {
|
||||||
|
let min_angle = min_style.oblique_degrees();
|
||||||
|
if min_angle >= target_angle {
|
||||||
|
return min_angle - target_angle;
|
||||||
|
}
|
||||||
|
let max_style = range.1;
|
||||||
|
let max_angle = max_style.oblique_degrees();
|
||||||
|
if max_angle >= target_angle {
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
if max_angle > 0.0 {
|
||||||
|
return REVERSE + (target_angle - max_angle);
|
||||||
|
}
|
||||||
|
return REVERSE + NEGATE + (target_angle - max_angle);
|
||||||
|
}
|
||||||
|
if min_style == FontStyle::ITALIC {
|
||||||
|
return REVERSE + NEGATE;
|
||||||
|
}
|
||||||
|
return REVERSE + NEGATE + 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if target_angle <= -default_oblique_angle {
|
||||||
|
if min_style.is_oblique() {
|
||||||
|
let max_style = range.1;
|
||||||
|
let max_angle = max_style.oblique_degrees();
|
||||||
|
if max_angle <= target_angle {
|
||||||
|
return target_angle - max_angle;
|
||||||
|
}
|
||||||
|
let min_angle = min_style.oblique_degrees();
|
||||||
|
if min_angle <= target_angle {
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
if min_angle < 0.0 {
|
||||||
|
return REVERSE + (min_angle - target_angle);
|
||||||
|
}
|
||||||
|
return REVERSE + NEGATE + (min_angle - target_angle);
|
||||||
|
}
|
||||||
|
if min_style == FontStyle::ITALIC {
|
||||||
|
return REVERSE + NEGATE;
|
||||||
|
}
|
||||||
|
return REVERSE + NEGATE + 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if target_angle >= 0.0 {
|
||||||
|
if min_style.is_oblique() {
|
||||||
|
let min_angle = min_style.oblique_degrees();
|
||||||
|
if min_angle > target_angle {
|
||||||
|
return REVERSE + (min_angle - target_angle);
|
||||||
|
}
|
||||||
|
let max_style = range.1;
|
||||||
|
let max_angle = max_style.oblique_degrees();
|
||||||
|
if max_angle >= target_angle {
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
if max_angle > 0.0 {
|
||||||
|
return target_angle - max_angle;
|
||||||
|
}
|
||||||
|
return REVERSE + NEGATE + (target_angle - max_angle);
|
||||||
|
}
|
||||||
|
if min_style == FontStyle::ITALIC {
|
||||||
|
return REVERSE + NEGATE - 2.0;
|
||||||
|
}
|
||||||
|
return REVERSE + NEGATE - 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// last case: (targetAngle < 0.0 && targetAngle > kDefaultAngle)
|
||||||
|
if min_style.is_oblique() {
|
||||||
|
let max_style = range.1;
|
||||||
|
let max_angle = max_style.oblique_degrees();
|
||||||
|
if max_angle < target_angle {
|
||||||
|
return REVERSE + (target_angle - max_angle);
|
||||||
|
}
|
||||||
|
let min_angle = min_style.oblique_degrees();
|
||||||
|
if min_angle <= target_angle {
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
if min_angle < 0.0 {
|
||||||
|
return min_angle - target_angle;
|
||||||
|
}
|
||||||
|
return REVERSE + NEGATE + (min_angle - target_angle);
|
||||||
|
}
|
||||||
|
if min_style == FontStyle::ITALIC {
|
||||||
|
return REVERSE + NEGATE - 2.0;
|
||||||
|
}
|
||||||
|
return REVERSE + NEGATE - 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_float(&self) -> f32 {
|
||||||
|
unimplemented!("Don't know how to convert FontStyle to float.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) trait IsOblique {
|
||||||
|
fn is_oblique(&self) -> bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IsOblique for FontStyle {
|
||||||
|
fn is_oblique(&self) -> bool {
|
||||||
|
*self != FontStyle::NORMAL && *self != FontStyle::ITALIC
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,337 +0,0 @@
|
||||||
[at-font-face-font-matching.html]
|
|
||||||
bug: https://github.com/servo/servo/issues/29376
|
|
||||||
[Descriptor mathcing priority: Stretch has higher priority than style]
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Descriptor mathcing priority: Stretch has higher priority than weight]
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-weight: '400' should prefer '500' over '350 399']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-weight: '400' should prefer '350 399' over '351 398']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-weight: '400' should prefer '501 550' over '502 560']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-weight: '500' should prefer '501 550' over '502 560']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique 0deg' should prefer 'oblique -50deg -20deg' over 'oblique -40deg -30deg']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique -10deg' should prefer 'oblique -10deg' over 'oblique -5deg']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique -10deg' should prefer 'oblique -20deg -15deg' over 'oblique -60deg -30deg']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique -10deg' should prefer 'oblique 0deg 10deg' over 'oblique 40deg 50deg']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Descriptor mathcing priority: Style has higher priority than weight]
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-stretch: '110%' should prefer '115% 116%' over '105%']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-stretch: '90%' should prefer '50% 80%' over '60% 70%']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Descriptor matching priority: Stretch has higher priority than weight]
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Descriptor matching priority: Stretch has higher priority than style]
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Descriptor matching priority: Style has higher priority than weight]
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-weight: '430' should prefer '420 440' over '450 460']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique 0deg' should prefer 'oblique 15deg 20deg' over 'oblique 30deg 60deg']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique 20deg' should prefer 'oblique -50deg -20deg' over 'oblique -40deg -30deg']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique 10deg' should prefer 'italic' over 'oblique 0deg']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-style: 'italic' should prefer 'oblique 20deg' over 'oblique 30deg 60deg']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-style: 'normal' should prefer 'oblique 10deg 40deg' over 'oblique 20deg 30deg']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-weight: '399' should prefer '450 460' over '500 501']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-weight: '500' should prefer '400' over '350 399']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-weight: '501' should prefer '501' over '502 510']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique 0deg' should prefer 'oblique 30deg 60deg' over 'oblique 40deg 50deg']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-weight: '400' should prefer '450 460' over '500']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique 0deg' should prefer 'italic' over 'oblique -50deg -20deg']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique -20deg' should prefer 'oblique -10deg' over 'italic']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique -20deg' should prefer 'oblique -20deg' over 'oblique -60deg -40deg']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique 20deg' should prefer 'oblique 10deg' over 'italic']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique 21deg' should prefer 'oblique 21deg' over 'oblique 30deg 60deg']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique -10deg' should prefer 'italic' over 'oblique 0deg 10deg']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-stretch: '100%' should prefer '110% 120%' over '115% 116%']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-style: 'italic' should prefer 'oblique 30deg 60deg' over 'oblique 40deg 50deg']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-weight: '501' should prefer '503 520' over '500']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique 20deg' should prefer 'oblique 20deg' over 'oblique 30deg 60deg']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique 10deg' should prefer 'oblique 5deg' over 'oblique 15deg 20deg']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-weight: '399' should prefer '400' over '450 460']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-weight: '399' should prefer '500 501' over '502 510']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-stretch: '90%' should prefer '110% 140%' over '120% 130%']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique 21deg' should prefer 'oblique -50deg -20deg' over 'oblique -40deg -30deg']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-stretch: '110%' should prefer '50% 80%' over '60% 70%']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-style: 'italic' should prefer 'oblique -60deg -30deg' over 'oblique -50deg -40deg']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-weight: '430' should prefer '500' over '400 425']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-weight: '400' should prefer '351 398' over '501 550']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-weight: '430' should prefer '400 425' over '350 399']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique 21deg' should prefer 'oblique 20deg' over 'oblique 10deg']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique 21deg' should prefer 'oblique 0deg' over 'oblique -50deg -20deg']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique 20deg' should prefer 'italic' over 'oblique 0deg']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique 21deg' should prefer 'italic' over 'oblique 0deg']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-stretch: '110%' should prefer '105%' over '100%']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique 20deg' should prefer 'oblique 30deg 60deg' over 'oblique 40deg 50deg']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique 20deg' should prefer 'oblique 40deg 50deg' over 'oblique 10deg']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-weight: '430' should prefer '450 460' over '500']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique 0deg' should prefer 'oblique 0deg' over 'oblique 5deg']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique -10deg' should prefer 'oblique -5deg' over 'oblique -1deg 0deg']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique -10deg' should prefer 'oblique -50deg -40deg' over 'italic']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique -20deg' should prefer 'oblique -60deg -40deg' over 'oblique -10deg']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique -20deg' should prefer 'italic' over 'oblique 0deg']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique -21deg' should prefer 'oblique -21deg' over 'oblique -60deg -40deg']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-weight: '399' should prefer '340 360' over '200 300']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-stretch: '110%' should prefer '100%' over '50% 80%']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique -10deg' should prefer 'oblique -1deg 0deg' over 'oblique -20deg -15deg']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique 21deg' should prefer 'oblique 30deg 60deg' over 'oblique 40deg 50deg']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique 21deg' should prefer 'oblique 40deg 50deg' over 'oblique 20deg']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique -21deg' should prefer 'oblique 0deg' over 'oblique 30deg 60deg']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique -20deg' should prefer 'oblique 0deg' over 'oblique 30deg 60deg']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique 20deg' should prefer 'oblique 0deg' over 'oblique -50deg -20deg']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique 10deg' should prefer 'oblique 15deg 20deg' over 'oblique 30deg 60deg']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique 10deg' should prefer 'oblique 40deg 50deg' over 'italic']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique -21deg' should prefer 'oblique -60deg -40deg' over 'oblique -10deg']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique -21deg' should prefer 'oblique 30deg 60deg' over 'oblique 40deg 50deg']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-weight: '430' should prefer '350 399' over '340 398']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-weight: '501' should prefer '502 510' over '503 520']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-weight: '501' should prefer '500' over '450 460']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-weight: '501' should prefer '390 410' over '300 350']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-weight: '399' should prefer '350 399' over '340 360']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-stretch: '90%' should prefer '90% 100%' over '50% 80%']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-stretch: '90%' should prefer '60% 70%' over '110% 140%']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-style: 'normal' should prefer 'normal' over 'oblique 0deg']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique 10deg' should prefer 'oblique 30deg 60deg' over 'oblique 40deg 50deg']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-style: 'italic' should prefer 'oblique 5deg' over 'normal']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-weight: '400' should prefer '400' over '450 460']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-weight: '399' should prefer '200 300' over '400']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-stretch: '110%' should prefer '110% 120%' over '115% 116%']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique 21deg' should prefer 'oblique 10deg' over 'italic']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-weight: '501' should prefer '450 460' over '390 410']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-style: 'italic' should prefer 'oblique 40deg 50deg' over 'oblique 5deg 10deg']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique 10deg' should prefer 'oblique -50deg -20deg' over 'oblique -40deg -30deg']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique 0deg' should prefer 'oblique 5deg' over 'oblique 15deg 20deg']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique -21deg' should prefer 'oblique -10deg' over 'italic']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-stretch: '100%' should prefer '100%' over '110% 120%']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-style: 'normal' should prefer 'oblique 20deg 30deg' over 'oblique -50deg -20deg']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-style: 'italic' should prefer 'oblique 5deg 10deg' over 'oblique 5deg']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique 10deg' should prefer 'oblique 10deg' over 'oblique 5deg']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique -21deg' should prefer 'italic' over 'oblique 0deg']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-weight: '500' should prefer '450 460' over '400']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-weight: '430' should prefer '340 398' over '501 550']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-weight: '500' should prefer '351 398' over '501 550']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-style: 'italic' should prefer 'italic' over 'oblique 20deg']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique 10deg' should prefer 'oblique 0deg' over 'oblique -50deg -20deg']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-weight: '500' should prefer '500' over '450 460']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-style: 'normal' should prefer 'oblique 0deg' over 'oblique 10deg 40deg']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-style: 'normal' should prefer 'oblique -50deg -20deg' over 'oblique -40deg -30deg']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-style: 'italic' should prefer 'oblique 0deg' over 'oblique -60deg -30deg']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique -10deg' should prefer 'oblique -60deg -30deg' over 'oblique -50deg -40deg']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique -20deg' should prefer 'oblique 30deg 60deg' over 'oblique 40deg 50deg']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-weight: '430' should prefer '501 550' over '502 560']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-weight: '500' should prefer '350 399' over '351 398']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-style: 'italic' should prefer 'normal' over 'oblique 0deg']
|
|
||||||
expected: [PASS, FAIL]
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique 0deg' should prefer 'oblique 40deg 50deg' over 'italic']
|
|
||||||
expected: [PASS, FAIL]
|
|
|
@ -1,18 +0,0 @@
|
||||||
[font-weight-matching.html]
|
|
||||||
[Test @font-face matching for weight 600]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Test @font-face matching for weight 751]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Test @font-face matching for weight 399]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Test @font-face matching for weight 470]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Test @font-face matching for weight 249]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Test @font-face matching for weight 420]
|
|
||||||
expected: FAIL
|
|
|
@ -1,258 +0,0 @@
|
||||||
[at-font-face-font-matching.html]
|
|
||||||
[Descriptor matching priority: Stretch has higher priority than style]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Descriptor matching priority: Stretch has higher priority than weight]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Descriptor matching priority: Style has higher priority than weight]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Matching font-weight: '400' should prefer '350 399' over '351 398']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Matching font-weight: '500' should prefer '351 398' over '501 550']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Matching font-style: 'normal' should prefer 'oblique 0deg' over 'oblique 10deg 40deg']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique 10deg' should prefer 'oblique -50deg -20deg' over 'oblique -40deg -30deg']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique 0deg' should prefer 'oblique 15deg 20deg' over 'oblique 30deg 60deg']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique 0deg' should prefer 'oblique 30deg 60deg' over 'oblique 40deg 50deg']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique -10deg' should prefer 'oblique -1deg 0deg' over 'oblique -20deg -15deg']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique 21deg' should prefer 'oblique 21deg' over 'oblique 30deg 60deg']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique 21deg' should prefer 'oblique 30deg 60deg' over 'oblique 40deg 50deg']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique 21deg' should prefer 'oblique -50deg -20deg' over 'oblique -40deg -30deg']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Matching font-stretch: '110%' should prefer '50% 80%' over '60% 70%']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Matching font-style: 'italic' should prefer 'oblique -60deg -30deg' over 'oblique -50deg -40deg']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Matching font-weight: '430' should prefer '500' over '400 425']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique 20deg' should prefer 'oblique 0deg' over 'oblique -50deg -20deg']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique 21deg' should prefer 'oblique 0deg' over 'oblique -50deg -20deg']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Matching font-stretch: '110%' should prefer '100%' over '50% 80%']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Matching font-stretch: '90%' should prefer '50% 80%' over '60% 70%']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Matching font-weight: '500' should prefer '350 399' over '351 398']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Matching font-stretch: '90%' should prefer '90% 100%' over '50% 80%']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique 10deg' should prefer 'oblique 30deg 60deg' over 'oblique 40deg 50deg']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique 10deg' should prefer 'oblique 40deg 50deg' over 'italic']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Matching font-style: 'normal' should prefer 'normal' over 'oblique 0deg']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Matching font-style: 'normal' should prefer 'oblique -50deg -20deg' over 'oblique -40deg -30deg']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique 20deg' should prefer 'italic' over 'oblique 0deg']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique -21deg' should prefer 'oblique 0deg' over 'oblique 30deg 60deg']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique -21deg' should prefer 'oblique 30deg 60deg' over 'oblique 40deg 50deg']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Matching font-stretch: '90%' should prefer '110% 140%' over '120% 130%']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Matching font-style: 'italic' should prefer 'oblique 0deg' over 'oblique -60deg -30deg']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique 0deg' should prefer 'oblique 40deg 50deg' over 'italic']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique -20deg' should prefer 'oblique -60deg -40deg' over 'oblique -10deg']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Matching font-stretch: '110%' should prefer '110% 120%' over '115% 116%']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique 20deg' should prefer 'oblique 10deg' over 'italic']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique 21deg' should prefer 'italic' over 'oblique 0deg']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Matching font-weight: '400' should prefer '500' over '350 399']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Matching font-weight: '399' should prefer '200 300' over '400']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Matching font-style: 'italic' should prefer 'oblique 5deg 10deg' over 'oblique 5deg']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique 0deg' should prefer 'italic' over 'oblique -50deg -20deg']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique -10deg' should prefer 'oblique -10deg' over 'oblique -5deg']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique -10deg' should prefer 'oblique -20deg -15deg' over 'oblique -60deg -30deg']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique -10deg' should prefer 'italic' over 'oblique 0deg 10deg']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique -20deg' should prefer 'italic' over 'oblique 0deg']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique -20deg' should prefer 'oblique 30deg 60deg' over 'oblique 40deg 50deg']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique -21deg' should prefer 'oblique -60deg -40deg' over 'oblique -10deg']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique -21deg' should prefer 'italic' over 'oblique 0deg']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique 21deg' should prefer 'oblique 10deg' over 'italic']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique 10deg' should prefer 'oblique 15deg 20deg' over 'oblique 30deg 60deg']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique 0deg' should prefer 'oblique 0deg' over 'oblique 5deg']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique -10deg' should prefer 'oblique -60deg -30deg' over 'oblique -50deg -40deg']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique -10deg' should prefer 'oblique 0deg 10deg' over 'oblique 40deg 50deg']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Matching font-weight: '501' should prefer '503 520' over '500']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Matching font-stretch: '110%' should prefer '115% 116%' over '105%']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Matching font-style: 'italic' should prefer 'oblique 20deg' over 'oblique 30deg 60deg']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique 10deg' should prefer 'oblique 0deg' over 'oblique -50deg -20deg']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique 20deg' should prefer 'oblique 20deg' over 'oblique 30deg 60deg']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique 20deg' should prefer 'oblique -50deg -20deg' over 'oblique -40deg -30deg']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique 21deg' should prefer 'oblique 20deg' over 'oblique 10deg']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique -10deg' should prefer 'oblique -5deg' over 'oblique -1deg 0deg']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique -20deg' should prefer 'oblique -10deg' over 'italic']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Matching font-stretch: '90%' should prefer '60% 70%' over '110% 140%']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Matching font-style: 'italic' should prefer 'normal' over 'oblique 0deg']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique 20deg' should prefer 'oblique 40deg 50deg' over 'oblique 10deg']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique 21deg' should prefer 'oblique 40deg 50deg' over 'oblique 20deg']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique 0deg' should prefer 'oblique 5deg' over 'oblique 15deg 20deg']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Matching font-stretch: '110%' should prefer '105%' over '100%']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Matching font-style: 'italic' should prefer 'oblique 30deg 60deg' over 'oblique 40deg 50deg']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique -20deg' should prefer 'oblique -20deg' over 'oblique -60deg -40deg']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Matching font-stretch: '100%' should prefer '110% 120%' over '115% 116%']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Matching font-style: 'italic' should prefer 'italic' over 'oblique 20deg']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique -21deg' should prefer 'oblique -10deg' over 'italic']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Matching font-weight: '430' should prefer '340 398' over '501 550']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique 20deg' should prefer 'oblique 30deg 60deg' over 'oblique 40deg 50deg']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique 10deg' should prefer 'oblique 5deg' over 'oblique 15deg 20deg']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique -20deg' should prefer 'oblique 0deg' over 'oblique 30deg 60deg']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Matching font-stretch: '100%' should prefer '100%' over '110% 120%']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Matching font-style: 'normal' should prefer 'oblique 10deg 40deg' over 'oblique 20deg 30deg']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Matching font-style: 'normal' should prefer 'oblique 20deg 30deg' over 'oblique -50deg -20deg']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Matching font-style: 'italic' should prefer 'oblique 40deg 50deg' over 'oblique 5deg 10deg']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Matching font-style: 'italic' should prefer 'oblique 5deg' over 'normal']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique 10deg' should prefer 'italic' over 'oblique 0deg']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique 0deg' should prefer 'oblique -50deg -20deg' over 'oblique -40deg -30deg']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique -10deg' should prefer 'oblique -50deg -40deg' over 'italic']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique 10deg' should prefer 'oblique 10deg' over 'oblique 5deg']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique -21deg' should prefer 'oblique -21deg' over 'oblique -60deg -40deg']
|
|
||||||
expected: FAIL
|
|
|
@ -1,18 +0,0 @@
|
||||||
[font-weight-matching.html]
|
|
||||||
[Test @font-face matching for weight 600]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Test @font-face matching for weight 470]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Test @font-face matching for weight 751]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Test @font-face matching for weight 399]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Test @font-face matching for weight 420]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Test @font-face matching for weight 249]
|
|
||||||
expected: FAIL
|
|
Loading…
Add table
Add a link
Reference in a new issue