gfx: Implement font-stretch per CSS3-FONTS § 3.3 in the Core Text

font backend.
This commit is contained in:
Patrick Walton 2015-01-01 11:21:27 -05:00
parent aba5c16091
commit abddfa742f
8 changed files with 101 additions and 44 deletions

View file

@ -10,7 +10,7 @@ use std::rc::Rc;
use std::cell::RefCell; use std::cell::RefCell;
use servo_util::cache::HashCache; use servo_util::cache::HashCache;
use servo_util::smallvec::{SmallVec, SmallVec8}; use servo_util::smallvec::{SmallVec, SmallVec8};
use style::computed_values::{font_variant, font_weight}; use style::computed_values::{font_stretch, font_variant, font_weight};
use style::style_structs::Font as FontStyle; use style::style_structs::Font as FontStyle;
use std::sync::Arc; use std::sync::Arc;
@ -37,6 +37,7 @@ pub trait FontHandleMethods {
fn face_name(&self) -> String; fn face_name(&self) -> String;
fn is_italic(&self) -> bool; fn is_italic(&self) -> bool;
fn boldness(&self) -> font_weight::T; fn boldness(&self) -> font_weight::T;
fn stretchiness(&self) -> font_stretch::T;
fn glyph_index(&self, codepoint: char) -> Option<GlyphId>; fn glyph_index(&self, codepoint: char) -> Option<GlyphId>;
fn glyph_h_advance(&self, GlyphId) -> Option<FractionalPixel>; fn glyph_h_advance(&self, GlyphId) -> Option<FractionalPixel>;

View file

@ -140,7 +140,9 @@ impl FontContext {
// so they will never be released. Find out a good time to drop them. // so they will never be released. Find out a good time to drop them.
let desc = FontTemplateDescriptor::new(style.font_weight, let desc = FontTemplateDescriptor::new(style.font_weight,
style.font_style == font_style::T::italic || style.font_style == font_style::T::oblique); style.font_stretch,
style.font_style == font_style::T::italic ||
style.font_style == font_style::T::oblique);
let mut fonts = SmallVec8::new(); let mut fonts = SmallVec8::new();
for family in style.font_family.iter() { for family in style.font_family.iter() {

View file

@ -2,14 +2,14 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use style::computed_values::font_weight; use font::FontHandleMethods;
use platform::font_context::FontContextHandle; use platform::font_context::FontContextHandle;
use platform::font::FontHandle; use platform::font::FontHandle;
use platform::font_template::FontTemplateData; use platform::font_template::FontTemplateData;
use std::borrow::ToOwned; use std::borrow::ToOwned;
use std::sync::{Arc, Weak}; use std::sync::{Arc, Weak};
use font::FontHandleMethods; use style::computed_values::{font_stretch, font_weight};
/// Describes how to select a font from a given family. /// Describes how to select a font from a given family.
/// This is very basic at the moment and needs to be /// This is very basic at the moment and needs to be
@ -18,13 +18,17 @@ use font::FontHandleMethods;
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub struct FontTemplateDescriptor { pub struct FontTemplateDescriptor {
pub weight: font_weight::T, pub weight: font_weight::T,
pub stretch: font_stretch::T,
pub italic: bool, pub italic: bool,
} }
impl FontTemplateDescriptor { impl FontTemplateDescriptor {
pub fn new(weight: font_weight::T, italic: bool) -> FontTemplateDescriptor { #[inline]
pub fn new(weight: font_weight::T, stretch: font_stretch::T, italic: bool)
-> FontTemplateDescriptor {
FontTemplateDescriptor { FontTemplateDescriptor {
weight: weight, weight: weight,
stretch: stretch,
italic: italic, italic: italic,
} }
} }
@ -33,6 +37,7 @@ impl FontTemplateDescriptor {
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.is_bold() == other.weight.is_bold() &&
self.stretch == other.stretch &&
self.italic == other.italic self.italic == other.italic
} }
} }
@ -44,7 +49,8 @@ pub struct FontTemplate {
identifier: String, identifier: String,
descriptor: Option<FontTemplateDescriptor>, descriptor: Option<FontTemplateDescriptor>,
weak_ref: Option<Weak<FontTemplateData>>, weak_ref: Option<Weak<FontTemplateData>>,
strong_ref: Option<Arc<FontTemplateData>>, // GWTODO: Add code path to unset the strong_ref for web fonts! // GWTODO: Add code path to unset the strong_ref for web fonts!
strong_ref: Option<Arc<FontTemplateData>>,
is_valid: bool, is_valid: bool,
} }
@ -82,8 +88,10 @@ impl FontTemplate {
} }
/// Get the data for creating a font if it matches a given descriptor. /// Get the data for creating a font if it matches a given descriptor.
pub fn get_if_matches(&mut self, fctx: &FontContextHandle, pub fn get_if_matches(&mut self,
requested_desc: &FontTemplateDescriptor) -> Option<Arc<FontTemplateData>> { fctx: &FontContextHandle,
requested_desc: &FontTemplateDescriptor)
-> Option<Arc<FontTemplateData>> {
// The font template data can be unloaded when nothing is referencing // The font template data can be unloaded when nothing is referencing
// it (via the Weak reference to the Arc above). However, if we have // it (via the Weak reference to the Arc above). However, if we have
// already loaded a font, store the style information about it separately, // already loaded a font, store the style information about it separately,
@ -97,13 +105,14 @@ impl FontTemplate {
None None
} }
}, },
None => { None if self.is_valid => {
if self.is_valid {
let data = self.get_data(); let data = self.get_data();
let handle: Result<FontHandle, ()> = FontHandleMethods::new_from_template(fctx, data.clone(), None); let handle: Result<FontHandle, ()> =
FontHandleMethods::new_from_template(fctx, data.clone(), None);
match handle { match handle {
Ok(handle) => { Ok(handle) => {
let actual_desc = FontTemplateDescriptor::new(handle.boldness(), let actual_desc = FontTemplateDescriptor::new(handle.boldness(),
handle.stretchiness(),
handle.is_italic()); handle.is_italic());
let desc_match = actual_desc == *requested_desc; let desc_match = actual_desc == *requested_desc;
@ -121,18 +130,17 @@ impl FontTemplate {
None None
} }
} }
} else {
None
}
} }
None => None,
} }
} }
/// Get the data for creating a font. /// Get the data for creating a font.
pub fn get(&mut self) -> Option<Arc<FontTemplateData>> { pub fn get(&mut self) -> Option<Arc<FontTemplateData>> {
match self.is_valid { if self.is_valid {
true => Some(self.get_data()), Some(self.get_data())
false => None } else {
None
} }
} }
@ -145,14 +153,13 @@ impl FontTemplate {
None => None, None => None,
}; };
match maybe_data { if let Some(data) = maybe_data {
Some(data) => data, return data
None => { }
assert!(self.strong_ref.is_none()); assert!(self.strong_ref.is_none());
let template_data = Arc::new(FontTemplateData::new(self.identifier.as_slice(), None)); let template_data = Arc::new(FontTemplateData::new(self.identifier.as_slice(), None));
self.weak_ref = Some(template_data.downgrade()); self.weak_ref = Some(template_data.downgrade());
template_data template_data
} }
} }
}
}

View file

@ -12,7 +12,7 @@ use servo_util::str::c_str_to_string;
use platform::font_context::FontContextHandle; use platform::font_context::FontContextHandle;
use text::glyph::GlyphId; use text::glyph::GlyphId;
use text::util::{float_to_fixed, fixed_to_float}; use text::util::{float_to_fixed, fixed_to_float};
use style::computed_values::font_weight; use style::computed_values::{font_stretch, font_weight};
use platform::font_template::FontTemplateData; use platform::font_template::FontTemplateData;
use freetype::freetype::{FT_Get_Char_Index, FT_Get_Postscript_Name}; use freetype::freetype::{FT_Get_Char_Index, FT_Get_Postscript_Name};
@ -161,6 +161,10 @@ impl FontHandleMethods for FontHandle {
} }
} }
} }
fn stretchiness(&self) -> font_stretch::T {
// TODO(pcwalton): Implement this.
font_stretch::T::normal
}
fn glyph_index(&self, codepoint: char) -> Option<GlyphId> { fn glyph_index(&self, codepoint: char) -> Option<GlyphId> {
assert!(!self.face.is_null()); assert!(!self.face.is_null());

View file

@ -15,7 +15,7 @@ use servo_util::geometry::{Au, px_to_pt};
use servo_util::geometry; use servo_util::geometry;
use platform::macos::font_context::FontContextHandle; use platform::macos::font_context::FontContextHandle;
use text::glyph::GlyphId; use text::glyph::GlyphId;
use style::computed_values::font_weight; use style::computed_values::{font_stretch, font_weight};
use platform::font_template::FontTemplateData; use platform::font_template::FontTemplateData;
use core_foundation::base::CFIndex; use core_foundation::base::CFIndex;
@ -111,6 +111,21 @@ impl FontHandleMethods for FontHandle {
return font_weight::T::Weight900; return font_weight::T::Weight900;
} }
fn stretchiness(&self) -> font_stretch::T {
let normalized = self.ctfont.all_traits().normalized_width(); // [-1.0, 1.0]
match (normalized + 1.0) / 2.0 * 9.0 { // [0.0, 9.0]
v if v < 1.0 => font_stretch::T::ultra_condensed,
v if v < 2.0 => font_stretch::T::extra_condensed,
v if v < 3.0 => font_stretch::T::condensed,
v if v < 4.0 => font_stretch::T::semi_condensed,
v if v < 5.0 => font_stretch::T::normal,
v if v < 6.0 => font_stretch::T::semi_expanded,
v if v < 7.0 => font_stretch::T::expanded,
v if v < 8.0 => font_stretch::T::extra_expanded,
_ => font_stretch::T::ultra_expanded,
}
}
fn glyph_index(&self, codepoint: char) -> Option<GlyphId> { fn glyph_index(&self, codepoint: char) -> Option<GlyphId> {
let characters: [UniChar; 1] = [codepoint as UniChar]; let characters: [UniChar; 1] = [codepoint as UniChar];
let mut glyphs: [CGGlyph; 1] = [0 as CGGlyph]; let mut glyphs: [CGGlyph; 1] = [0 as CGGlyph];

View file

@ -127,6 +127,7 @@ partial interface CSSStyleDeclaration {
[TreatNullAs=EmptyString] attribute DOMString font; [TreatNullAs=EmptyString] attribute DOMString font;
[TreatNullAs=EmptyString] attribute DOMString fontFamily; [TreatNullAs=EmptyString] attribute DOMString fontFamily;
[TreatNullAs=EmptyString] attribute DOMString fontSize; [TreatNullAs=EmptyString] attribute DOMString fontSize;
[TreatNullAs=EmptyString] attribute DOMString fontStretch;
[TreatNullAs=EmptyString] attribute DOMString fontStyle; [TreatNullAs=EmptyString] attribute DOMString fontStyle;
[TreatNullAs=EmptyString] attribute DOMString fontVariant; [TreatNullAs=EmptyString] attribute DOMString fontVariant;
[TreatNullAs=EmptyString] attribute DOMString fontWeight; [TreatNullAs=EmptyString] attribute DOMString fontWeight;

View file

@ -1149,6 +1149,9 @@ pub mod longhands {
} }
</%self:longhand> </%self:longhand>
${single_keyword("font-stretch",
"normal ultra-condensed extra-condensed condensed semi-condensed semi-expanded expanded extra-expanded ultra-expanded")}
// CSS 2.1, Section 16 - Text // CSS 2.1, Section 16 - Text
${new_style_struct("InheritedText", is_inherited=True)} ${new_style_struct("InheritedText", is_inherited=True)}

View file

@ -0,0 +1,24 @@
<!DOCTYPE html>
<html>
<head>
<style>
body {
font-size: 36pt;
font-family: "Helvetica Neue";
font-weight: bold;
font-style: normal;
}
#a {
font-stretch: normal;
}
#b {
font-stretch: condensed;
}
</style>
</head>
<body>
<div id=a>Felis silvestris catus</div>
<div id=b>Felis silvestris catus</div>
</body>
</html>