servo: Merge #10493 - gfx: Clamp the font size we supply to Core Text to 0.01pt (from pcwalton:inline-font-size-zero); r=mbrubeck

Core Text treats a font size of 0.0 as 12.0, which is obviously not what
we want.

Improves Twitter.
Improves Reddit /r/rust.

Closes #10492.

r? @mbrubeck

Source-Repo: https://github.com/servo/servo
Source-Revision: 65120756c06ee2d0357cca6357e30694a0ec6559
This commit is contained in:
Patrick Walton 2016-04-12 04:10:37 +05:01
parent 53fc411e5c
commit a7b88944ec
3 changed files with 28 additions and 17 deletions

View File

@ -38,7 +38,7 @@ fn create_scaled_font(template: &Arc<FontTemplateData>, pt_size: Au) -> ScaledFo
#[cfg(target_os = "macos")]
fn create_scaled_font(template: &Arc<FontTemplateData>, pt_size: Au) -> ScaledFont {
let cgfont = template.ctfont().as_ref().unwrap().copy_to_CGFont();
let cgfont = template.ctfont(pt_size.to_f64_px()).as_ref().unwrap().copy_to_CGFont();
ScaledFont::new(BackendType::Skia, &cgfont, pt_size.to_f32_px())
}

View File

@ -72,7 +72,7 @@ impl FontHandleMethods for FontHandle {
Some(s) => s.to_f64_px(),
None => 0.0
};
match template.ctfont() {
match template.ctfont(size) {
Some(ref ctfont) => {
Ok(FontHandle {
font_data: template.clone(),

View File

@ -2,6 +2,7 @@
* 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/. */
use app_units::Au;
use core_graphics::data_provider::CGDataProvider;
use core_graphics::font::CGFont;
use core_text;
@ -9,6 +10,7 @@ use core_text::font::CTFont;
use serde::de::{Error, Visitor};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::borrow::ToOwned;
use std::collections::HashMap;
use std::fs::File;
use std::io::Read;
use std::ops::Deref;
@ -26,7 +28,7 @@ pub struct FontTemplateData {
/// `CTFont` instances over and over. It can always be recreated from the `identifier` and/or
/// `font_data` fields.
///
/// When sending a `FontTemplateData` instance across processes, this will be set to `None` on
/// When sending a `FontTemplateData` instance across processes, this will be cleared out on
/// the other side, because `CTFont` instances cannot be sent across processes. This is
/// harmless, however, because it can always be recreated.
ctfont: CachedCTFont,
@ -41,29 +43,38 @@ unsafe impl Sync for FontTemplateData {}
impl FontTemplateData {
pub fn new(identifier: Atom, font_data: Option<Vec<u8>>) -> FontTemplateData {
FontTemplateData {
ctfont: CachedCTFont(Mutex::new(None)),
ctfont: CachedCTFont(Mutex::new(HashMap::new())),
identifier: identifier.to_owned(),
font_data: font_data
}
}
/// Retrieves the Core Text font instance, instantiating it if necessary.
pub fn ctfont(&self) -> Option<CTFont> {
let mut ctfont = self.ctfont.lock().unwrap();
if ctfont.is_none() {
*ctfont = match self.font_data {
pub fn ctfont(&self, pt_size: f64) -> Option<CTFont> {
let mut ctfonts = self.ctfont.lock().unwrap();
let pt_size_key = Au::from_f64_px(pt_size);
if !ctfonts.contains_key(&pt_size_key) {
// If you pass a zero font size to one of the Core Text APIs, it'll replace it with
// 12.0. We don't want that! (Issue #10492.)
let clamped_pt_size = pt_size.max(0.01);
let ctfont = match self.font_data {
Some(ref bytes) => {
let fontprov = CGDataProvider::from_buffer(bytes);
let cgfont_result = CGFont::from_data_provider(fontprov);
match cgfont_result {
Ok(cgfont) => Some(core_text::font::new_from_CGFont(&cgfont, 0.0)),
Ok(cgfont) => {
Some(core_text::font::new_from_CGFont(&cgfont, clamped_pt_size))
}
Err(_) => None
}
}
None => core_text::font::new_from_name(&*self.identifier, 0.0).ok(),
None => core_text::font::new_from_name(&*self.identifier, clamped_pt_size).ok(),
};
if let Some(ctfont) = ctfont {
ctfonts.insert(pt_size_key, ctfont);
}
}
ctfont.as_ref().map(|ctfont| (*ctfont).clone())
ctfonts.get(&pt_size_key).map(|ctfont| (*ctfont).clone())
}
/// Returns a clone of the data in this font. This may be a hugely expensive
@ -75,7 +86,7 @@ impl FontTemplateData {
None => {}
}
let path = Url::parse(&*self.ctfont()
let path = Url::parse(&*self.ctfont(0.0)
.expect("No Core Text font available!")
.url()
.expect("No URL for Core Text font!")
@ -96,16 +107,16 @@ impl FontTemplateData {
/// Returns the native font that underlies this font template, if applicable.
pub fn native_font(&self) -> Option<CGFont> {
self.ctfont().map(|ctfont| ctfont.copy_to_CGFont())
self.ctfont(0.0).map(|ctfont| ctfont.copy_to_CGFont())
}
}
#[derive(Debug)]
pub struct CachedCTFont(Mutex<Option<CTFont>>);
pub struct CachedCTFont(Mutex<HashMap<Au, CTFont>>);
impl Deref for CachedCTFont {
type Target = Mutex<Option<CTFont>>;
fn deref(&self) -> &Mutex<Option<CTFont>> {
type Target = Mutex<HashMap<Au, CTFont>>;
fn deref(&self) -> &Mutex<HashMap<Au, CTFont>> {
&self.0
}
}
@ -126,7 +137,7 @@ impl Deserialize for CachedCTFont {
#[inline]
fn visit_none<E>(&mut self) -> Result<CachedCTFont, E> where E: Error {
Ok(CachedCTFont(Mutex::new(None)))
Ok(CachedCTFont(Mutex::new(HashMap::new())))
}
}