mirror of
https://github.com/servo/servo.git
synced 2025-08-04 13:10:20 +01:00
gfx: Implement font-stretch
per CSS3-FONTS § 3.3 in the Core Text
font backend.
This commit is contained in:
parent
aba5c16091
commit
abddfa742f
8 changed files with 101 additions and 44 deletions
|
@ -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>;
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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];
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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)}
|
||||||
|
|
24
tests/html/font_stretch.html
Normal file
24
tests/html/font_stretch.html
Normal 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>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue