mirror of
https://github.com/servo/servo.git
synced 2025-08-04 05:00:08 +01:00
gfx: Perform fuzzy matching on font weights if an exact match wasn't
found. Partially addresses #190. Partially addresses #9487.
This commit is contained in:
parent
0617727f5b
commit
479c6c9c42
2 changed files with 86 additions and 38 deletions
|
@ -18,6 +18,7 @@ use std::borrow::ToOwned;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
use std::u32;
|
||||||
use string_cache::Atom;
|
use string_cache::Atom;
|
||||||
use style::font_face::Source;
|
use style::font_face::Source;
|
||||||
use style::properties::longhands::font_family::computed_value::FontFamily;
|
use style::properties::longhands::font_family::computed_value::FontFamily;
|
||||||
|
@ -51,9 +52,6 @@ impl FontTemplates {
|
||||||
// TODO(Issue #189): optimize lookup for
|
// TODO(Issue #189): optimize lookup for
|
||||||
// regular/bold/italic/bolditalic with fixed offsets and a
|
// regular/bold/italic/bolditalic with fixed offsets and a
|
||||||
// static decision table for fallback between these values.
|
// static decision table for fallback between these values.
|
||||||
|
|
||||||
// TODO(Issue #190): if not in the fast path above, do
|
|
||||||
// expensive matching of weights, etc.
|
|
||||||
for template in &mut self.templates {
|
for template in &mut self.templates {
|
||||||
let maybe_template = template.data_for_descriptor(fctx, desc);
|
let maybe_template = template.data_for_descriptor(fctx, desc);
|
||||||
if maybe_template.is_some() {
|
if maybe_template.is_some() {
|
||||||
|
@ -61,6 +59,22 @@ impl FontTemplates {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We didn't find an exact match. Do more expensive fuzzy matching.
|
||||||
|
// TODO(#190): Do a better job.
|
||||||
|
let (mut best_template_data, mut best_distance) = (None, u32::MAX);
|
||||||
|
for template in &mut self.templates {
|
||||||
|
if let Some((template_data, distance)) =
|
||||||
|
template.data_for_approximate_descriptor(fctx, desc) {
|
||||||
|
if distance < best_distance {
|
||||||
|
best_template_data = Some(template_data);
|
||||||
|
best_distance = distance
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if best_template_data.is_some() {
|
||||||
|
return best_template_data
|
||||||
|
}
|
||||||
|
|
||||||
// If a request is made for a font family that exists,
|
// If a request is made for a font family that exists,
|
||||||
// pick the first valid font in the family if we failed
|
// pick the first valid font in the family if we failed
|
||||||
// to find an exact match for the descriptor.
|
// to find an exact match for the descriptor.
|
||||||
|
@ -81,8 +95,7 @@ impl FontTemplates {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let template = FontTemplate::new(identifier,
|
let template = FontTemplate::new(identifier, maybe_data);
|
||||||
maybe_data);
|
|
||||||
self.templates.push(template);
|
self.templates.push(template);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ use platform::font::FontHandle;
|
||||||
use platform::font_context::FontContextHandle;
|
use platform::font_context::FontContextHandle;
|
||||||
use platform::font_template::FontTemplateData;
|
use platform::font_template::FontTemplateData;
|
||||||
use std::sync::{Arc, Weak};
|
use std::sync::{Arc, Weak};
|
||||||
|
use std::u32;
|
||||||
use string_cache::Atom;
|
use string_cache::Atom;
|
||||||
use style::computed_values::{font_stretch, font_weight};
|
use style::computed_values::{font_stretch, font_weight};
|
||||||
|
|
||||||
|
@ -31,13 +32,25 @@ impl FontTemplateDescriptor {
|
||||||
italic: italic,
|
italic: italic,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns a score indicating how far apart visually the two font descriptors are. This is
|
||||||
|
/// used for fuzzy font selection.
|
||||||
|
///
|
||||||
|
/// The smaller the score, the better the fonts match. 0 indicates an exact match. This must
|
||||||
|
/// be commutative (distance(A, B) == distance(B, A)).
|
||||||
|
#[inline]
|
||||||
|
fn distance_from(&self, other: &FontTemplateDescriptor) -> u32 {
|
||||||
|
if self.stretch != other.stretch || self.italic != other.italic {
|
||||||
|
// A value higher than all weights.
|
||||||
|
return 1000
|
||||||
|
}
|
||||||
|
((self.weight as i16) - (other.weight as i16)).abs() as u32
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for FontTemplateDescriptor {
|
impl PartialEq for FontTemplateDescriptor {
|
||||||
fn eq(&self, other: &FontTemplateDescriptor) -> bool {
|
fn eq(&self, other: &FontTemplateDescriptor) -> bool {
|
||||||
self.weight.is_bold() == other.weight.is_bold() &&
|
self.weight == other.weight && self.stretch == other.stretch && self.italic == other.italic
|
||||||
self.stretch == other.stretch &&
|
|
||||||
self.italic == other.italic
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,41 +110,63 @@ impl FontTemplate {
|
||||||
// so that we can do font matching against it again in the future
|
// so that we can do font matching against it again in the future
|
||||||
// without having to reload the font (unless it is an actual match).
|
// without having to reload the font (unless it is an actual match).
|
||||||
match self.descriptor {
|
match self.descriptor {
|
||||||
Some(actual_desc) => {
|
Some(actual_desc) if *requested_desc == actual_desc => Some(self.data()),
|
||||||
if *requested_desc == actual_desc {
|
Some(_) => None,
|
||||||
|
None => {
|
||||||
|
if self.instantiate(fctx).is_err() {
|
||||||
|
return None
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.descriptor
|
||||||
|
.as_ref()
|
||||||
|
.expect("Instantiation succeeded but no descriptor?") == requested_desc {
|
||||||
Some(self.data())
|
Some(self.data())
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
None if self.is_valid => {
|
}
|
||||||
let data = self.data();
|
}
|
||||||
let handle: Result<FontHandle, ()> =
|
|
||||||
FontHandleMethods::new_from_template(fctx, data.clone(), None);
|
|
||||||
match handle {
|
|
||||||
Ok(handle) => {
|
|
||||||
let actual_desc = FontTemplateDescriptor::new(handle.boldness(),
|
|
||||||
handle.stretchiness(),
|
|
||||||
handle.is_italic());
|
|
||||||
let desc_match = actual_desc == *requested_desc;
|
|
||||||
|
|
||||||
self.descriptor = Some(actual_desc);
|
/// Returns the font data along with the distance between this font's descriptor and the given
|
||||||
self.is_valid = true;
|
/// descriptor, if the font can be loaded.
|
||||||
if desc_match {
|
pub fn data_for_approximate_descriptor(&mut self,
|
||||||
Some(data)
|
font_context: &FontContextHandle,
|
||||||
|
requested_descriptor: &FontTemplateDescriptor)
|
||||||
|
-> Option<(Arc<FontTemplateData>, u32)> {
|
||||||
|
match self.descriptor {
|
||||||
|
Some(actual_descriptor) => {
|
||||||
|
Some((self.data(), actual_descriptor.distance_from(requested_descriptor)))
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
if self.instantiate(font_context).is_ok() {
|
||||||
|
let distance = self.descriptor
|
||||||
|
.as_ref()
|
||||||
|
.expect("Instantiation successful but no descriptor?")
|
||||||
|
.distance_from(requested_descriptor);
|
||||||
|
Some((self.data(), distance))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(()) => {
|
|
||||||
self.is_valid = false;
|
|
||||||
debug!("Unable to create a font from template {}", self.identifier);
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn instantiate(&mut self, font_context: &FontContextHandle) -> Result<(), ()> {
|
||||||
|
if !self.is_valid {
|
||||||
|
return Err(())
|
||||||
}
|
}
|
||||||
None => None,
|
|
||||||
}
|
let data = self.data();
|
||||||
|
let handle: Result<FontHandle, ()> = FontHandleMethods::new_from_template(font_context,
|
||||||
|
data,
|
||||||
|
None);
|
||||||
|
self.is_valid = handle.is_ok();
|
||||||
|
let handle = try!(handle);
|
||||||
|
self.descriptor = Some(FontTemplateDescriptor::new(handle.boldness(),
|
||||||
|
handle.stretchiness(),
|
||||||
|
handle.is_italic()));
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the data for creating a font.
|
/// Get the data for creating a font.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue