mirror of
https://github.com/servo/servo.git
synced 2025-08-05 21:50:18 +01:00
Format the rest of gfx #21373
This commit is contained in:
parent
f7630dad87
commit
3a3c4b8c8e
8 changed files with 502 additions and 401 deletions
|
@ -32,9 +32,9 @@ use unicode_script::Script;
|
||||||
use webrender_api;
|
use webrender_api;
|
||||||
|
|
||||||
macro_rules! ot_tag {
|
macro_rules! ot_tag {
|
||||||
($t1:expr, $t2:expr, $t3:expr, $t4:expr) => (
|
($t1:expr, $t2:expr, $t3:expr, $t4:expr) => {
|
||||||
(($t1 as u32) << 24) | (($t2 as u32) << 16) | (($t3 as u32) << 8) | ($t4 as u32)
|
(($t1 as u32) << 24) | (($t2 as u32) << 16) | (($t3 as u32) << 8) | ($t4 as u32)
|
||||||
);
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const GPOS: u32 = ot_tag!('G', 'P', 'O', 'S');
|
pub const GPOS: u32 = ot_tag!('G', 'P', 'O', 'S');
|
||||||
|
@ -87,10 +87,12 @@ trait FontTableTagConversions {
|
||||||
|
|
||||||
impl FontTableTagConversions for FontTableTag {
|
impl FontTableTagConversions for FontTableTag {
|
||||||
fn tag_to_str(&self) -> String {
|
fn tag_to_str(&self) -> String {
|
||||||
let bytes = [(self >> 24) as u8,
|
let bytes = [
|
||||||
(self >> 16) as u8,
|
(self >> 24) as u8,
|
||||||
(self >> 8) as u8,
|
(self >> 16) as u8,
|
||||||
(self >> 0) as u8];
|
(self >> 8) as u8,
|
||||||
|
(self >> 0) as u8,
|
||||||
|
];
|
||||||
str::from_utf8(&bytes).unwrap().to_owned()
|
str::from_utf8(&bytes).unwrap().to_owned()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -101,18 +103,18 @@ pub trait FontTableMethods {
|
||||||
|
|
||||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||||
pub struct FontMetrics {
|
pub struct FontMetrics {
|
||||||
pub underline_size: Au,
|
pub underline_size: Au,
|
||||||
pub underline_offset: Au,
|
pub underline_offset: Au,
|
||||||
pub strikeout_size: Au,
|
pub strikeout_size: Au,
|
||||||
pub strikeout_offset: Au,
|
pub strikeout_offset: Au,
|
||||||
pub leading: Au,
|
pub leading: Au,
|
||||||
pub x_height: Au,
|
pub x_height: Au,
|
||||||
pub em_size: Au,
|
pub em_size: Au,
|
||||||
pub ascent: Au,
|
pub ascent: Au,
|
||||||
pub descent: Au,
|
pub descent: Au,
|
||||||
pub max_advance: Au,
|
pub max_advance: Au,
|
||||||
pub average_advance: Au,
|
pub average_advance: Au,
|
||||||
pub line_gap: Au,
|
pub line_gap: Au,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `FontDescriptor` describes the parameters of a `Font`. It represents rendering a given font
|
/// `FontDescriptor` describes the parameters of a `Font`. It represents rendering a given font
|
||||||
|
@ -149,10 +151,12 @@ pub struct Font {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Font {
|
impl Font {
|
||||||
pub fn new(handle: FontHandle,
|
pub fn new(
|
||||||
descriptor: FontDescriptor,
|
handle: FontHandle,
|
||||||
actual_pt_size: Au,
|
descriptor: FontDescriptor,
|
||||||
font_key: webrender_api::FontInstanceKey) -> Font {
|
actual_pt_size: Au,
|
||||||
|
font_key: webrender_api::FontInstanceKey,
|
||||||
|
) -> Font {
|
||||||
let metrics = handle.metrics();
|
let metrics = handle.metrics();
|
||||||
|
|
||||||
Font {
|
Font {
|
||||||
|
@ -218,28 +222,39 @@ impl Font {
|
||||||
text: text.to_owned(),
|
text: text.to_owned(),
|
||||||
options: *options,
|
options: *options,
|
||||||
};
|
};
|
||||||
let result = self.shape_cache.borrow_mut().entry(lookup_key).or_insert_with(|| {
|
let result = self
|
||||||
let start_time = time::precise_time_ns();
|
.shape_cache
|
||||||
let mut glyphs = GlyphStore::new(text.len(),
|
.borrow_mut()
|
||||||
options.flags.contains(ShapingFlags::IS_WHITESPACE_SHAPING_FLAG),
|
.entry(lookup_key)
|
||||||
options.flags.contains(ShapingFlags::RTL_FLAG));
|
.or_insert_with(|| {
|
||||||
|
let start_time = time::precise_time_ns();
|
||||||
|
let mut glyphs = GlyphStore::new(
|
||||||
|
text.len(),
|
||||||
|
options
|
||||||
|
.flags
|
||||||
|
.contains(ShapingFlags::IS_WHITESPACE_SHAPING_FLAG),
|
||||||
|
options.flags.contains(ShapingFlags::RTL_FLAG),
|
||||||
|
);
|
||||||
|
|
||||||
if self.can_do_fast_shaping(text, options) {
|
if self.can_do_fast_shaping(text, options) {
|
||||||
debug!("shape_text: Using ASCII fast path.");
|
debug!("shape_text: Using ASCII fast path.");
|
||||||
self.shape_text_fast(text, options, &mut glyphs);
|
self.shape_text_fast(text, options, &mut glyphs);
|
||||||
} else {
|
} else {
|
||||||
debug!("shape_text: Using Harfbuzz.");
|
debug!("shape_text: Using Harfbuzz.");
|
||||||
if shaper.is_none() {
|
if shaper.is_none() {
|
||||||
shaper = Some(Shaper::new(this));
|
shaper = Some(Shaper::new(this));
|
||||||
|
}
|
||||||
|
shaper
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.shape_text(text, options, &mut glyphs);
|
||||||
}
|
}
|
||||||
shaper.as_ref().unwrap().shape_text(text, options, &mut glyphs);
|
|
||||||
}
|
|
||||||
|
|
||||||
let end_time = time::precise_time_ns();
|
let end_time = time::precise_time_ns();
|
||||||
TEXT_SHAPING_PERFORMANCE_COUNTER.fetch_add((end_time - start_time) as usize,
|
TEXT_SHAPING_PERFORMANCE_COUNTER
|
||||||
Ordering::Relaxed);
|
.fetch_add((end_time - start_time) as usize, Ordering::Relaxed);
|
||||||
Arc::new(glyphs)
|
Arc::new(glyphs)
|
||||||
}).clone();
|
}).clone();
|
||||||
self.shaper = shaper;
|
self.shaper = shaper;
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
@ -285,12 +300,21 @@ impl Font {
|
||||||
|
|
||||||
pub fn table_for_tag(&self, tag: FontTableTag) -> Option<FontTable> {
|
pub fn table_for_tag(&self, tag: FontTableTag) -> Option<FontTable> {
|
||||||
let result = self.handle.table_for_tag(tag);
|
let result = self.handle.table_for_tag(tag);
|
||||||
let status = if result.is_some() { "Found" } else { "Didn't find" };
|
let status = if result.is_some() {
|
||||||
|
"Found"
|
||||||
|
} else {
|
||||||
|
"Didn't find"
|
||||||
|
};
|
||||||
|
|
||||||
debug!("{} font table[{}] with family={}, face={}",
|
debug!(
|
||||||
status, tag.tag_to_str(),
|
"{} font table[{}] with family={}, face={}",
|
||||||
self.handle.family_name().unwrap_or("unavailable".to_owned()),
|
status,
|
||||||
self.handle.face_name().unwrap_or("unavailable".to_owned()));
|
tag.tag_to_str(),
|
||||||
|
self.handle
|
||||||
|
.family_name()
|
||||||
|
.unwrap_or("unavailable".to_owned()),
|
||||||
|
self.handle.face_name().unwrap_or("unavailable".to_owned())
|
||||||
|
);
|
||||||
|
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
@ -308,18 +332,21 @@ impl Font {
|
||||||
self.glyph_index(codepoint).is_some()
|
self.glyph_index(codepoint).is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn glyph_h_kerning(&self, first_glyph: GlyphId, second_glyph: GlyphId)
|
pub fn glyph_h_kerning(&self, first_glyph: GlyphId, second_glyph: GlyphId) -> FractionalPixel {
|
||||||
-> FractionalPixel {
|
|
||||||
self.handle.glyph_h_kerning(first_glyph, second_glyph)
|
self.handle.glyph_h_kerning(first_glyph, second_glyph)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn glyph_h_advance(&self, glyph: GlyphId) -> FractionalPixel {
|
pub fn glyph_h_advance(&self, glyph: GlyphId) -> FractionalPixel {
|
||||||
*self.glyph_advance_cache.borrow_mut().entry(glyph).or_insert_with(|| {
|
*self
|
||||||
match self.handle.glyph_h_advance(glyph) {
|
.glyph_advance_cache
|
||||||
Some(adv) => adv,
|
.borrow_mut()
|
||||||
None => 10f64 as FractionalPixel // FIXME: Need fallback strategy
|
.entry(glyph)
|
||||||
}
|
.or_insert_with(|| {
|
||||||
})
|
match self.handle.glyph_h_advance(glyph) {
|
||||||
|
Some(adv) => adv,
|
||||||
|
None => 10f64 as FractionalPixel, // FIXME: Need fallback strategy
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -339,10 +366,12 @@ impl FontGroup {
|
||||||
pub fn new(style: &FontStyleStruct) -> FontGroup {
|
pub fn new(style: &FontStyleStruct) -> FontGroup {
|
||||||
let descriptor = FontDescriptor::from(style);
|
let descriptor = FontDescriptor::from(style);
|
||||||
|
|
||||||
let families =
|
let families = style
|
||||||
style.font_family.0.iter()
|
.font_family
|
||||||
.map(|family| FontGroupFamily::new(descriptor.clone(), &family))
|
.0
|
||||||
.collect();
|
.iter()
|
||||||
|
.map(|family| FontGroupFamily::new(descriptor.clone(), &family))
|
||||||
|
.collect();
|
||||||
|
|
||||||
FontGroup {
|
FontGroup {
|
||||||
descriptor,
|
descriptor,
|
||||||
|
@ -358,25 +387,25 @@ impl FontGroup {
|
||||||
pub fn find_by_codepoint<S: FontSource>(
|
pub fn find_by_codepoint<S: FontSource>(
|
||||||
&mut self,
|
&mut self,
|
||||||
mut font_context: &mut FontContext<S>,
|
mut font_context: &mut FontContext<S>,
|
||||||
codepoint: char
|
codepoint: char,
|
||||||
) -> Option<FontRef> {
|
) -> Option<FontRef> {
|
||||||
let has_glyph = |font: &FontRef| font.borrow().has_glyph_for(codepoint);
|
let has_glyph = |font: &FontRef| font.borrow().has_glyph_for(codepoint);
|
||||||
|
|
||||||
let font = self.find(&mut font_context, |font| has_glyph(font));
|
let font = self.find(&mut font_context, |font| has_glyph(font));
|
||||||
if font.is_some() {
|
if font.is_some() {
|
||||||
return font
|
return font;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(ref fallback) = self.last_matching_fallback {
|
if let Some(ref fallback) = self.last_matching_fallback {
|
||||||
if has_glyph(&fallback) {
|
if has_glyph(&fallback) {
|
||||||
return self.last_matching_fallback.clone()
|
return self.last_matching_fallback.clone();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let font = self.find_fallback(&mut font_context, Some(codepoint), has_glyph);
|
let font = self.find_fallback(&mut font_context, Some(codepoint), has_glyph);
|
||||||
if font.is_some() {
|
if font.is_some() {
|
||||||
self.last_matching_fallback = font.clone();
|
self.last_matching_fallback = font.clone();
|
||||||
return font
|
return font;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.first(&mut font_context)
|
self.first(&mut font_context)
|
||||||
|
@ -385,7 +414,7 @@ impl FontGroup {
|
||||||
/// Find the first available font in the group, or the first available fallback font.
|
/// Find the first available font in the group, or the first available fallback font.
|
||||||
pub fn first<S: FontSource>(
|
pub fn first<S: FontSource>(
|
||||||
&mut self,
|
&mut self,
|
||||||
mut font_context: &mut FontContext<S>
|
mut font_context: &mut FontContext<S>,
|
||||||
) -> Option<FontRef> {
|
) -> Option<FontRef> {
|
||||||
self.find(&mut font_context, |_| true)
|
self.find(&mut font_context, |_| true)
|
||||||
.or_else(|| self.find_fallback(&mut font_context, None, |_| true))
|
.or_else(|| self.find_fallback(&mut font_context, None, |_| true))
|
||||||
|
@ -393,16 +422,13 @@ impl FontGroup {
|
||||||
|
|
||||||
/// Find a font which returns true for `predicate`. This method mutates because we may need to
|
/// Find a font which returns true for `predicate`. This method mutates because we may need to
|
||||||
/// load new font data in the process of finding a suitable font.
|
/// load new font data in the process of finding a suitable font.
|
||||||
fn find<S, P>(
|
fn find<S, P>(&mut self, mut font_context: &mut FontContext<S>, predicate: P) -> Option<FontRef>
|
||||||
&mut self,
|
|
||||||
mut font_context: &mut FontContext<S>,
|
|
||||||
predicate: P,
|
|
||||||
) -> Option<FontRef>
|
|
||||||
where
|
where
|
||||||
S: FontSource,
|
S: FontSource,
|
||||||
P: FnMut(&FontRef) -> bool,
|
P: FnMut(&FontRef) -> bool,
|
||||||
{
|
{
|
||||||
self.families.iter_mut()
|
self.families
|
||||||
|
.iter_mut()
|
||||||
.filter_map(|family| family.font(&mut font_context))
|
.filter_map(|family| family.font(&mut font_context))
|
||||||
.find(predicate)
|
.find(predicate)
|
||||||
}
|
}
|
||||||
|
@ -422,15 +448,9 @@ impl FontGroup {
|
||||||
P: FnMut(&FontRef) -> bool,
|
P: FnMut(&FontRef) -> bool,
|
||||||
{
|
{
|
||||||
iter::once(FontFamilyDescriptor::default())
|
iter::once(FontFamilyDescriptor::default())
|
||||||
.chain(
|
.chain(fallback_font_families(codepoint).into_iter().map(|family| {
|
||||||
fallback_font_families(codepoint).into_iter().map(|family| {
|
FontFamilyDescriptor::new(FontFamilyName::from(family), FontSearchScope::Local)
|
||||||
FontFamilyDescriptor::new(
|
})).filter_map(|family| font_context.font(&self.descriptor, &family))
|
||||||
FontFamilyName::from(family),
|
|
||||||
FontSearchScope::Local,
|
|
||||||
)
|
|
||||||
})
|
|
||||||
)
|
|
||||||
.filter_map(|family| font_context.font(&self.descriptor, &family))
|
|
||||||
.find(predicate)
|
.find(predicate)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -448,10 +468,8 @@ struct FontGroupFamily {
|
||||||
|
|
||||||
impl FontGroupFamily {
|
impl FontGroupFamily {
|
||||||
fn new(font_descriptor: FontDescriptor, family: &SingleFontFamily) -> FontGroupFamily {
|
fn new(font_descriptor: FontDescriptor, family: &SingleFontFamily) -> FontGroupFamily {
|
||||||
let family_descriptor = FontFamilyDescriptor::new(
|
let family_descriptor =
|
||||||
FontFamilyName::from(family),
|
FontFamilyDescriptor::new(FontFamilyName::from(family), FontSearchScope::Any);
|
||||||
FontSearchScope::Any
|
|
||||||
);
|
|
||||||
|
|
||||||
FontGroupFamily {
|
FontGroupFamily {
|
||||||
font_descriptor,
|
font_descriptor,
|
||||||
|
@ -477,17 +495,19 @@ impl FontGroupFamily {
|
||||||
pub struct RunMetrics {
|
pub struct RunMetrics {
|
||||||
// may be negative due to negative width (i.e., kerning of '.' in 'P.T.')
|
// may be negative due to negative width (i.e., kerning of '.' in 'P.T.')
|
||||||
pub advance_width: Au,
|
pub advance_width: Au,
|
||||||
pub ascent: Au, // nonzero
|
pub ascent: Au, // nonzero
|
||||||
pub descent: Au, // nonzero
|
pub descent: Au, // nonzero
|
||||||
// this bounding box is relative to the left origin baseline.
|
// this bounding box is relative to the left origin baseline.
|
||||||
// so, bounding_box.position.y = -ascent
|
// so, bounding_box.position.y = -ascent
|
||||||
pub bounding_box: Rect<Au>
|
pub bounding_box: Rect<Au>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RunMetrics {
|
impl RunMetrics {
|
||||||
pub fn new(advance: Au, ascent: Au, descent: Au) -> RunMetrics {
|
pub fn new(advance: Au, ascent: Au, descent: Au) -> RunMetrics {
|
||||||
let bounds = Rect::new(Point2D::new(Au(0), -ascent),
|
let bounds = Rect::new(
|
||||||
Size2D::new(advance, ascent + descent));
|
Point2D::new(Au(0), -ascent),
|
||||||
|
Size2D::new(advance, ascent + descent),
|
||||||
|
);
|
||||||
|
|
||||||
// TODO(Issue #125): support loose and tight bounding boxes; using the
|
// TODO(Issue #125): support loose and tight bounding boxes; using the
|
||||||
// ascent+descent and advance is sometimes too generous and
|
// ascent+descent and advance is sometimes too generous and
|
||||||
|
@ -540,11 +560,13 @@ impl FontFamilyName {
|
||||||
impl<'a> From<&'a SingleFontFamily> for FontFamilyName {
|
impl<'a> From<&'a SingleFontFamily> for FontFamilyName {
|
||||||
fn from(other: &'a SingleFontFamily) -> FontFamilyName {
|
fn from(other: &'a SingleFontFamily) -> FontFamilyName {
|
||||||
match *other {
|
match *other {
|
||||||
SingleFontFamily::FamilyName(ref family_name) =>
|
SingleFontFamily::FamilyName(ref family_name) => {
|
||||||
FontFamilyName::Specific(family_name.name.clone()),
|
FontFamilyName::Specific(family_name.name.clone())
|
||||||
|
},
|
||||||
|
|
||||||
SingleFontFamily::Generic(ref generic_name) =>
|
SingleFontFamily::Generic(ref generic_name) => {
|
||||||
FontFamilyName::Generic(generic_name.clone()),
|
FontFamilyName::Generic(generic_name.clone())
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,14 +40,15 @@ pub struct FontTemplateInfo {
|
||||||
|
|
||||||
impl FontTemplates {
|
impl FontTemplates {
|
||||||
pub fn new() -> FontTemplates {
|
pub fn new() -> FontTemplates {
|
||||||
FontTemplates {
|
FontTemplates { templates: vec![] }
|
||||||
templates: vec!(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Find a font in this family that matches a given descriptor.
|
/// Find a font in this family that matches a given descriptor.
|
||||||
pub fn find_font_for_style(&mut self, desc: &FontTemplateDescriptor, fctx: &FontContextHandle)
|
pub fn find_font_for_style(
|
||||||
-> Option<Arc<FontTemplateData>> {
|
&mut self,
|
||||||
|
desc: &FontTemplateDescriptor,
|
||||||
|
fctx: &FontContextHandle,
|
||||||
|
) -> Option<Arc<FontTemplateData>> {
|
||||||
// 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.
|
||||||
|
@ -63,7 +64,8 @@ impl FontTemplates {
|
||||||
let (mut best_template_data, mut best_distance) = (None, f32::MAX);
|
let (mut best_template_data, mut best_distance) = (None, f32::MAX);
|
||||||
for template in &mut self.templates {
|
for template in &mut self.templates {
|
||||||
if let Some((template_data, distance)) =
|
if let Some((template_data, distance)) =
|
||||||
template.data_for_approximate_descriptor(fctx, desc) {
|
template.data_for_approximate_descriptor(fctx, desc)
|
||||||
|
{
|
||||||
if distance < best_distance {
|
if distance < best_distance {
|
||||||
best_template_data = Some(template_data);
|
best_template_data = Some(template_data);
|
||||||
best_distance = distance
|
best_distance = distance
|
||||||
|
@ -71,7 +73,7 @@ impl FontTemplates {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if best_template_data.is_some() {
|
if best_template_data.is_some() {
|
||||||
return best_template_data
|
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,
|
||||||
|
@ -103,8 +105,16 @@ impl FontTemplates {
|
||||||
/// Commands that the FontContext sends to the font cache thread.
|
/// Commands that the FontContext sends to the font cache thread.
|
||||||
#[derive(Debug, Deserialize, Serialize)]
|
#[derive(Debug, Deserialize, Serialize)]
|
||||||
pub enum Command {
|
pub enum Command {
|
||||||
GetFontTemplate(FontTemplateDescriptor, FontFamilyDescriptor, IpcSender<Reply>),
|
GetFontTemplate(
|
||||||
GetFontInstance(webrender_api::FontKey, Au, IpcSender<webrender_api::FontInstanceKey>),
|
FontTemplateDescriptor,
|
||||||
|
FontFamilyDescriptor,
|
||||||
|
IpcSender<Reply>,
|
||||||
|
),
|
||||||
|
GetFontInstance(
|
||||||
|
webrender_api::FontKey,
|
||||||
|
Au,
|
||||||
|
IpcSender<webrender_api::FontInstanceKey>,
|
||||||
|
),
|
||||||
AddWebFont(LowercaseString, EffectiveSources, IpcSender<()>),
|
AddWebFont(LowercaseString, EffectiveSources, IpcSender<()>),
|
||||||
AddDownloadedWebFont(LowercaseString, ServoUrl, Vec<u8>, IpcSender<()>),
|
AddDownloadedWebFont(LowercaseString, ServoUrl, Vec<u8>, IpcSender<()>),
|
||||||
Exit(IpcSender<()>),
|
Exit(IpcSender<()>),
|
||||||
|
@ -148,7 +158,7 @@ fn populate_generic_fonts() -> HashMap<FontFamilyName, LowercaseString> {
|
||||||
) {
|
) {
|
||||||
let family_name = match system_default_family(generic_name) {
|
let family_name = match system_default_family(generic_name) {
|
||||||
Some(system_default) => LowercaseString::new(&system_default),
|
Some(system_default) => LowercaseString::new(&system_default),
|
||||||
None => LowercaseString::new(mapped_name)
|
None => LowercaseString::new(mapped_name),
|
||||||
};
|
};
|
||||||
|
|
||||||
let generic_name = FontFamilyName::Generic(Atom::from(generic_name));
|
let generic_name = FontFamilyName::Generic(Atom::from(generic_name));
|
||||||
|
@ -156,7 +166,6 @@ fn populate_generic_fonts() -> HashMap<FontFamilyName, LowercaseString> {
|
||||||
generic_fonts.insert(generic_name, family_name);
|
generic_fonts.insert(generic_name, family_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
generic_fonts
|
generic_fonts
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,50 +176,50 @@ impl FontCache {
|
||||||
|
|
||||||
match msg {
|
match msg {
|
||||||
Command::GetFontTemplate(template_descriptor, family_descriptor, result) => {
|
Command::GetFontTemplate(template_descriptor, family_descriptor, result) => {
|
||||||
let maybe_font_template = self.find_font_template(&template_descriptor, &family_descriptor);
|
let maybe_font_template =
|
||||||
|
self.find_font_template(&template_descriptor, &family_descriptor);
|
||||||
let _ = result.send(Reply::GetFontTemplateReply(maybe_font_template));
|
let _ = result.send(Reply::GetFontTemplateReply(maybe_font_template));
|
||||||
}
|
},
|
||||||
Command::GetFontInstance(font_key, size, result) => {
|
Command::GetFontInstance(font_key, size, result) => {
|
||||||
let webrender_api = &self.webrender_api;
|
let webrender_api = &self.webrender_api;
|
||||||
|
|
||||||
let instance_key = *self.font_instances
|
let instance_key =
|
||||||
.entry((font_key, size))
|
*self
|
||||||
.or_insert_with(|| {
|
.font_instances
|
||||||
let key = webrender_api.generate_font_instance_key();
|
.entry((font_key, size))
|
||||||
let mut txn = webrender_api::Transaction::new();
|
.or_insert_with(|| {
|
||||||
txn.add_font_instance(key,
|
let key = webrender_api.generate_font_instance_key();
|
||||||
font_key,
|
let mut txn = webrender_api::Transaction::new();
|
||||||
size,
|
txn.add_font_instance(key, font_key, size, None, None, Vec::new());
|
||||||
None,
|
webrender_api.update_resources(txn.resource_updates);
|
||||||
None,
|
key
|
||||||
Vec::new());
|
});
|
||||||
webrender_api.update_resources(txn.resource_updates);
|
|
||||||
key
|
|
||||||
});
|
|
||||||
|
|
||||||
let _ = result.send(instance_key);
|
let _ = result.send(instance_key);
|
||||||
}
|
},
|
||||||
Command::AddWebFont(family_name, sources, result) => {
|
Command::AddWebFont(family_name, sources, result) => {
|
||||||
self.handle_add_web_font(family_name, sources, result);
|
self.handle_add_web_font(family_name, sources, result);
|
||||||
}
|
},
|
||||||
Command::AddDownloadedWebFont(family_name, url, bytes, result) => {
|
Command::AddDownloadedWebFont(family_name, url, bytes, result) => {
|
||||||
let templates = &mut self.web_families.get_mut(&family_name).unwrap();
|
let templates = &mut self.web_families.get_mut(&family_name).unwrap();
|
||||||
templates.add_template(Atom::from(url.to_string()), Some(bytes));
|
templates.add_template(Atom::from(url.to_string()), Some(bytes));
|
||||||
drop(result.send(()));
|
drop(result.send(()));
|
||||||
}
|
},
|
||||||
Command::Ping => (),
|
Command::Ping => (),
|
||||||
Command::Exit(result) => {
|
Command::Exit(result) => {
|
||||||
let _ = result.send(());
|
let _ = result.send(());
|
||||||
break;
|
break;
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_add_web_font(&mut self,
|
fn handle_add_web_font(
|
||||||
family_name: LowercaseString,
|
&mut self,
|
||||||
mut sources: EffectiveSources,
|
family_name: LowercaseString,
|
||||||
sender: IpcSender<()>) {
|
mut sources: EffectiveSources,
|
||||||
|
sender: IpcSender<()>,
|
||||||
|
) {
|
||||||
let src = if let Some(src) = sources.next() {
|
let src = if let Some(src) = sources.next() {
|
||||||
src
|
src
|
||||||
} else {
|
} else {
|
||||||
|
@ -236,7 +245,7 @@ impl FontCache {
|
||||||
destination: Destination::Font,
|
destination: Destination::Font,
|
||||||
// TODO: Add a proper origin - Can't import GlobalScope from gfx
|
// TODO: Add a proper origin - Can't import GlobalScope from gfx
|
||||||
// We can leave origin to be set by default
|
// We can leave origin to be set by default
|
||||||
.. RequestInit::default()
|
..RequestInit::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
let channel_to_self = self.channel_to_self.clone();
|
let channel_to_self = self.channel_to_self.clone();
|
||||||
|
@ -248,19 +257,27 @@ impl FontCache {
|
||||||
FetchResponseMsg::ProcessRequestBody |
|
FetchResponseMsg::ProcessRequestBody |
|
||||||
FetchResponseMsg::ProcessRequestEOF => (),
|
FetchResponseMsg::ProcessRequestEOF => (),
|
||||||
FetchResponseMsg::ProcessResponse(meta_result) => {
|
FetchResponseMsg::ProcessResponse(meta_result) => {
|
||||||
trace!("@font-face {} metadata ok={:?}", family_name, meta_result.is_ok());
|
trace!(
|
||||||
|
"@font-face {} metadata ok={:?}",
|
||||||
|
family_name,
|
||||||
|
meta_result.is_ok()
|
||||||
|
);
|
||||||
*response_valid.lock().unwrap() = meta_result.is_ok();
|
*response_valid.lock().unwrap() = meta_result.is_ok();
|
||||||
}
|
},
|
||||||
FetchResponseMsg::ProcessResponseChunk(new_bytes) => {
|
FetchResponseMsg::ProcessResponseChunk(new_bytes) => {
|
||||||
trace!("@font-face {} chunk={:?}", family_name, new_bytes);
|
trace!("@font-face {} chunk={:?}", family_name, new_bytes);
|
||||||
if *response_valid.lock().unwrap() {
|
if *response_valid.lock().unwrap() {
|
||||||
bytes.lock().unwrap().extend(new_bytes.into_iter())
|
bytes.lock().unwrap().extend(new_bytes.into_iter())
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
FetchResponseMsg::ProcessResponseEOF(response) => {
|
FetchResponseMsg::ProcessResponseEOF(response) => {
|
||||||
trace!("@font-face {} EOF={:?}", family_name, response);
|
trace!("@font-face {} EOF={:?}", family_name, response);
|
||||||
if response.is_err() || !*response_valid.lock().unwrap() {
|
if response.is_err() || !*response_valid.lock().unwrap() {
|
||||||
let msg = Command::AddWebFont(family_name.clone(), sources.clone(), sender.clone());
|
let msg = Command::AddWebFont(
|
||||||
|
family_name.clone(),
|
||||||
|
sources.clone(),
|
||||||
|
sender.clone(),
|
||||||
|
);
|
||||||
channel_to_self.send(msg).unwrap();
|
channel_to_self.send(msg).unwrap();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -270,23 +287,31 @@ impl FontCache {
|
||||||
Ok(san) => san,
|
Ok(san) => san,
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
// FIXME(servo/fontsan#1): get an error message
|
// FIXME(servo/fontsan#1): get an error message
|
||||||
debug!("Sanitiser rejected web font: \
|
debug!(
|
||||||
family={} url={:?}", family_name, url);
|
"Sanitiser rejected web font: \
|
||||||
let msg = Command::AddWebFont(family_name.clone(), sources.clone(), sender.clone());
|
family={} url={:?}",
|
||||||
|
family_name, url
|
||||||
|
);
|
||||||
|
let msg = Command::AddWebFont(
|
||||||
|
family_name.clone(),
|
||||||
|
sources.clone(),
|
||||||
|
sender.clone(),
|
||||||
|
);
|
||||||
channel_to_self.send(msg).unwrap();
|
channel_to_self.send(msg).unwrap();
|
||||||
return;
|
return;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
let command =
|
let command = Command::AddDownloadedWebFont(
|
||||||
Command::AddDownloadedWebFont(family_name.clone(),
|
family_name.clone(),
|
||||||
url.clone(),
|
url.clone(),
|
||||||
bytes,
|
bytes,
|
||||||
sender.clone());
|
sender.clone(),
|
||||||
|
);
|
||||||
channel_to_self.send(command).unwrap();
|
channel_to_self.send(command).unwrap();
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
Source::Local(ref font) => {
|
Source::Local(ref font) => {
|
||||||
let font_face_name = LowercaseString::new(&font.name);
|
let font_face_name = LowercaseString::new(&font.name);
|
||||||
let templates = &mut self.web_families.get_mut(&family_name).unwrap();
|
let templates = &mut self.web_families.get_mut(&family_name).unwrap();
|
||||||
|
@ -301,7 +326,7 @@ impl FontCache {
|
||||||
let msg = Command::AddWebFont(family_name, sources, sender);
|
let msg = Command::AddWebFont(family_name, sources, sender);
|
||||||
self.channel_to_self.send(msg).unwrap();
|
self.channel_to_self.send(msg).unwrap();
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -319,7 +344,7 @@ impl FontCache {
|
||||||
fn transform_family(&self, family_name: &FontFamilyName) -> LowercaseString {
|
fn transform_family(&self, family_name: &FontFamilyName) -> LowercaseString {
|
||||||
match self.generic_fonts.get(family_name) {
|
match self.generic_fonts.get(family_name) {
|
||||||
None => LowercaseString::from(family_name),
|
None => LowercaseString::from(family_name),
|
||||||
Some(mapped_family) => (*mapped_family).clone()
|
Some(mapped_family) => (*mapped_family).clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -347,7 +372,10 @@ impl FontCache {
|
||||||
|
|
||||||
s.find_font_for_style(template_descriptor, &self.font_context)
|
s.find_font_for_style(template_descriptor, &self.font_context)
|
||||||
} else {
|
} else {
|
||||||
debug!("FontList: Couldn't find font family with name={}", &*family_name);
|
debug!(
|
||||||
|
"FontList: Couldn't find font family with name={}",
|
||||||
|
&*family_name
|
||||||
|
);
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -371,17 +399,19 @@ impl FontCache {
|
||||||
let webrender_api = &self.webrender_api;
|
let webrender_api = &self.webrender_api;
|
||||||
let webrender_fonts = &mut self.webrender_fonts;
|
let webrender_fonts = &mut self.webrender_fonts;
|
||||||
|
|
||||||
let font_key = *webrender_fonts.entry(template.identifier.clone()).or_insert_with(|| {
|
let font_key = *webrender_fonts
|
||||||
let font_key = webrender_api.generate_font_key();
|
.entry(template.identifier.clone())
|
||||||
let mut txn = webrender_api::Transaction::new();
|
.or_insert_with(|| {
|
||||||
match (template.bytes_if_in_memory(), template.native_font()) {
|
let font_key = webrender_api.generate_font_key();
|
||||||
(Some(bytes), _) => txn.add_raw_font(font_key, bytes, 0),
|
let mut txn = webrender_api::Transaction::new();
|
||||||
(None, Some(native_font)) => txn.add_native_font(font_key, native_font),
|
match (template.bytes_if_in_memory(), template.native_font()) {
|
||||||
(None, None) => txn.add_raw_font(font_key, template.bytes().clone(), 0),
|
(Some(bytes), _) => txn.add_raw_font(font_key, bytes, 0),
|
||||||
}
|
(None, Some(native_font)) => txn.add_native_font(font_key, native_font),
|
||||||
webrender_api.update_resources(txn.resource_updates);
|
(None, None) => txn.add_raw_font(font_key, template.bytes().clone(), 0),
|
||||||
font_key
|
}
|
||||||
});
|
webrender_api.update_resources(txn.resource_updates);
|
||||||
|
font_key
|
||||||
|
});
|
||||||
|
|
||||||
FontTemplateInfo {
|
FontTemplateInfo {
|
||||||
font_template: template,
|
font_template: template,
|
||||||
|
@ -395,14 +425,15 @@ impl FontCache {
|
||||||
family_descriptor: &FontFamilyDescriptor,
|
family_descriptor: &FontFamilyDescriptor,
|
||||||
) -> Option<FontTemplateInfo> {
|
) -> Option<FontTemplateInfo> {
|
||||||
match family_descriptor.scope {
|
match family_descriptor.scope {
|
||||||
FontSearchScope::Any => {
|
FontSearchScope::Any => self
|
||||||
self.find_font_in_web_family(&template_descriptor, &family_descriptor.name)
|
.find_font_in_web_family(&template_descriptor, &family_descriptor.name)
|
||||||
.or_else(|| self.find_font_in_local_family(&template_descriptor, &family_descriptor.name))
|
.or_else(|| {
|
||||||
}
|
self.find_font_in_local_family(&template_descriptor, &family_descriptor.name)
|
||||||
|
}),
|
||||||
|
|
||||||
FontSearchScope::Local => {
|
FontSearchScope::Local => {
|
||||||
self.find_font_in_local_family(&template_descriptor, &family_descriptor.name)
|
self.find_font_in_local_family(&template_descriptor, &family_descriptor.name)
|
||||||
}
|
},
|
||||||
}.map(|t| self.get_font_template_info(t))
|
}.map(|t| self.get_font_template_info(t))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -415,59 +446,82 @@ pub struct FontCacheThread {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FontCacheThread {
|
impl FontCacheThread {
|
||||||
pub fn new(core_resource_thread: CoreResourceThread,
|
pub fn new(
|
||||||
webrender_api: webrender_api::RenderApi) -> FontCacheThread {
|
core_resource_thread: CoreResourceThread,
|
||||||
|
webrender_api: webrender_api::RenderApi,
|
||||||
|
) -> FontCacheThread {
|
||||||
let (chan, port) = ipc::channel().unwrap();
|
let (chan, port) = ipc::channel().unwrap();
|
||||||
|
|
||||||
let channel_to_self = chan.clone();
|
let channel_to_self = chan.clone();
|
||||||
thread::Builder::new().name("FontCacheThread".to_owned()).spawn(move || {
|
thread::Builder::new()
|
||||||
// TODO: Allow users to specify these.
|
.name("FontCacheThread".to_owned())
|
||||||
let generic_fonts = populate_generic_fonts();
|
.spawn(move || {
|
||||||
|
// TODO: Allow users to specify these.
|
||||||
|
let generic_fonts = populate_generic_fonts();
|
||||||
|
|
||||||
let mut cache = FontCache {
|
let mut cache = FontCache {
|
||||||
port: port,
|
port: port,
|
||||||
channel_to_self,
|
channel_to_self,
|
||||||
generic_fonts,
|
generic_fonts,
|
||||||
local_families: HashMap::new(),
|
local_families: HashMap::new(),
|
||||||
web_families: HashMap::new(),
|
web_families: HashMap::new(),
|
||||||
font_context: FontContextHandle::new(),
|
font_context: FontContextHandle::new(),
|
||||||
core_resource_thread,
|
core_resource_thread,
|
||||||
webrender_api,
|
webrender_api,
|
||||||
webrender_fonts: HashMap::new(),
|
webrender_fonts: HashMap::new(),
|
||||||
font_instances: HashMap::new(),
|
font_instances: HashMap::new(),
|
||||||
};
|
};
|
||||||
|
|
||||||
cache.refresh_local_families();
|
cache.refresh_local_families();
|
||||||
cache.run();
|
cache.run();
|
||||||
}).expect("Thread spawning failed");
|
}).expect("Thread spawning failed");
|
||||||
|
|
||||||
FontCacheThread {
|
FontCacheThread { chan: chan }
|
||||||
chan: chan,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_web_font(&self, family: FamilyName, sources: EffectiveSources, sender: IpcSender<()>) {
|
pub fn add_web_font(
|
||||||
self.chan.send(Command::AddWebFont(LowercaseString::new(&family.name), sources, sender)).unwrap();
|
&self,
|
||||||
|
family: FamilyName,
|
||||||
|
sources: EffectiveSources,
|
||||||
|
sender: IpcSender<()>,
|
||||||
|
) {
|
||||||
|
self.chan
|
||||||
|
.send(Command::AddWebFont(
|
||||||
|
LowercaseString::new(&family.name),
|
||||||
|
sources,
|
||||||
|
sender,
|
||||||
|
)).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn exit(&self) {
|
pub fn exit(&self) {
|
||||||
let (response_chan, response_port) = ipc::channel().unwrap();
|
let (response_chan, response_port) = ipc::channel().unwrap();
|
||||||
self.chan.send(Command::Exit(response_chan)).expect("Couldn't send FontCacheThread exit message");
|
self.chan
|
||||||
response_port.recv().expect("Couldn't receive FontCacheThread reply");
|
.send(Command::Exit(response_chan))
|
||||||
|
.expect("Couldn't send FontCacheThread exit message");
|
||||||
|
response_port
|
||||||
|
.recv()
|
||||||
|
.expect("Couldn't receive FontCacheThread reply");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FontSource for FontCacheThread {
|
impl FontSource for FontCacheThread {
|
||||||
fn get_font_instance(&mut self, key: webrender_api::FontKey, size: Au) -> webrender_api::FontInstanceKey {
|
fn get_font_instance(
|
||||||
let (response_chan, response_port) =
|
&mut self,
|
||||||
ipc::channel().expect("failed to create IPC channel");
|
key: webrender_api::FontKey,
|
||||||
self.chan.send(Command::GetFontInstance(key, size, response_chan))
|
size: Au,
|
||||||
|
) -> webrender_api::FontInstanceKey {
|
||||||
|
let (response_chan, response_port) = ipc::channel().expect("failed to create IPC channel");
|
||||||
|
self.chan
|
||||||
|
.send(Command::GetFontInstance(key, size, response_chan))
|
||||||
.expect("failed to send message to font cache thread");
|
.expect("failed to send message to font cache thread");
|
||||||
|
|
||||||
let instance_key = response_port.recv();
|
let instance_key = response_port.recv();
|
||||||
if instance_key.is_err() {
|
if instance_key.is_err() {
|
||||||
let font_thread_has_closed = self.chan.send(Command::Ping).is_err();
|
let font_thread_has_closed = self.chan.send(Command::Ping).is_err();
|
||||||
assert!(font_thread_has_closed, "Failed to receive a response from live font cache");
|
assert!(
|
||||||
|
font_thread_has_closed,
|
||||||
|
"Failed to receive a response from live font cache"
|
||||||
|
);
|
||||||
panic!("Font cache thread has already exited.");
|
panic!("Font cache thread has already exited.");
|
||||||
}
|
}
|
||||||
instance_key.unwrap()
|
instance_key.unwrap()
|
||||||
|
@ -478,23 +532,27 @@ impl FontSource for FontCacheThread {
|
||||||
template_descriptor: FontTemplateDescriptor,
|
template_descriptor: FontTemplateDescriptor,
|
||||||
family_descriptor: FontFamilyDescriptor,
|
family_descriptor: FontFamilyDescriptor,
|
||||||
) -> Option<FontTemplateInfo> {
|
) -> Option<FontTemplateInfo> {
|
||||||
let (response_chan, response_port) =
|
let (response_chan, response_port) = ipc::channel().expect("failed to create IPC channel");
|
||||||
ipc::channel().expect("failed to create IPC channel");
|
self.chan
|
||||||
self.chan.send(Command::GetFontTemplate(template_descriptor, family_descriptor, response_chan))
|
.send(Command::GetFontTemplate(
|
||||||
.expect("failed to send message to font cache thread");
|
template_descriptor,
|
||||||
|
family_descriptor,
|
||||||
|
response_chan,
|
||||||
|
)).expect("failed to send message to font cache thread");
|
||||||
|
|
||||||
let reply = response_port.recv();
|
let reply = response_port.recv();
|
||||||
|
|
||||||
if reply.is_err() {
|
if reply.is_err() {
|
||||||
let font_thread_has_closed = self.chan.send(Command::Ping).is_err();
|
let font_thread_has_closed = self.chan.send(Command::Ping).is_err();
|
||||||
assert!(font_thread_has_closed, "Failed to receive a response from live font cache");
|
assert!(
|
||||||
|
font_thread_has_closed,
|
||||||
|
"Failed to receive a response from live font cache"
|
||||||
|
);
|
||||||
panic!("Font cache thread has already exited.");
|
panic!("Font cache thread has already exited.");
|
||||||
}
|
}
|
||||||
|
|
||||||
match reply.unwrap() {
|
match reply.unwrap() {
|
||||||
Reply::GetFontTemplateReply(data) => {
|
Reply::GetFontTemplateReply(data) => data,
|
||||||
data
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,14 +21,18 @@ use style::computed_values::font_variant_caps::T as FontVariantCaps;
|
||||||
use style::properties::style_structs::Font as FontStyleStruct;
|
use style::properties::style_structs::Font as FontStyleStruct;
|
||||||
use webrender_api;
|
use webrender_api;
|
||||||
|
|
||||||
static SMALL_CAPS_SCALE_FACTOR: f32 = 0.8; // Matches FireFox (see gfxFont.h)
|
static SMALL_CAPS_SCALE_FACTOR: f32 = 0.8; // Matches FireFox (see gfxFont.h)
|
||||||
|
|
||||||
/// An epoch for the font context cache. The cache is flushed if the current epoch does not match
|
/// An epoch for the font context cache. The cache is flushed if the current epoch does not match
|
||||||
/// this one.
|
/// this one.
|
||||||
static FONT_CACHE_EPOCH: AtomicUsize = ATOMIC_USIZE_INIT;
|
static FONT_CACHE_EPOCH: AtomicUsize = ATOMIC_USIZE_INIT;
|
||||||
|
|
||||||
pub trait FontSource {
|
pub trait FontSource {
|
||||||
fn get_font_instance(&mut self, key: webrender_api::FontKey, size: Au) -> webrender_api::FontInstanceKey;
|
fn get_font_instance(
|
||||||
|
&mut self,
|
||||||
|
key: webrender_api::FontKey,
|
||||||
|
size: Au,
|
||||||
|
) -> webrender_api::FontInstanceKey;
|
||||||
|
|
||||||
fn font_template(
|
fn font_template(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
@ -74,7 +78,7 @@ impl<S: FontSource> FontContext<S> {
|
||||||
fn expire_font_caches_if_necessary(&mut self) {
|
fn expire_font_caches_if_necessary(&mut self) {
|
||||||
let current_epoch = FONT_CACHE_EPOCH.load(Ordering::SeqCst);
|
let current_epoch = FONT_CACHE_EPOCH.load(Ordering::SeqCst);
|
||||||
if current_epoch == self.epoch {
|
if current_epoch == self.epoch {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.font_cache.clear();
|
self.font_cache.clear();
|
||||||
|
@ -95,7 +99,7 @@ impl<S: FontSource> FontContext<S> {
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(ref font_group) = self.font_group_cache.get(&cache_key) {
|
if let Some(ref font_group) = self.font_group_cache.get(&cache_key) {
|
||||||
return (*font_group).clone()
|
return (*font_group).clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
let font_group = Rc::new(RefCell::new(FontGroup::new(&cache_key.style)));
|
let font_group = Rc::new(RefCell::new(FontGroup::new(&cache_key.style)));
|
||||||
|
@ -115,27 +119,31 @@ impl<S: FontSource> FontContext<S> {
|
||||||
family_descriptor: family_descriptor.clone(),
|
family_descriptor: family_descriptor.clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
self.font_cache.get(&cache_key).map(|v| v.clone()).unwrap_or_else(|| {
|
self.font_cache
|
||||||
debug!(
|
.get(&cache_key)
|
||||||
"FontContext::font cache miss for font_descriptor={:?} family_descriptor={:?}",
|
.map(|v| v.clone())
|
||||||
font_descriptor,
|
.unwrap_or_else(|| {
|
||||||
family_descriptor
|
debug!(
|
||||||
);
|
"FontContext::font cache miss for font_descriptor={:?} family_descriptor={:?}",
|
||||||
|
font_descriptor, family_descriptor
|
||||||
|
);
|
||||||
|
|
||||||
let font =
|
let font = self
|
||||||
self.font_template(&font_descriptor.template_descriptor, family_descriptor)
|
.font_template(&font_descriptor.template_descriptor, family_descriptor)
|
||||||
.and_then(|template_info| self.create_font(template_info, font_descriptor.to_owned()).ok())
|
.and_then(|template_info| {
|
||||||
.map(|font| Rc::new(RefCell::new(font)));
|
self.create_font(template_info, font_descriptor.to_owned())
|
||||||
|
.ok()
|
||||||
|
}).map(|font| Rc::new(RefCell::new(font)));
|
||||||
|
|
||||||
self.font_cache.insert(cache_key, font.clone());
|
self.font_cache.insert(cache_key, font.clone());
|
||||||
font
|
font
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn font_template(
|
fn font_template(
|
||||||
&mut self,
|
&mut self,
|
||||||
template_descriptor: &FontTemplateDescriptor,
|
template_descriptor: &FontTemplateDescriptor,
|
||||||
family_descriptor: &FontFamilyDescriptor
|
family_descriptor: &FontFamilyDescriptor,
|
||||||
) -> Option<FontTemplateInfo> {
|
) -> Option<FontTemplateInfo> {
|
||||||
let cache_key = FontTemplateCacheKey {
|
let cache_key = FontTemplateCacheKey {
|
||||||
template_descriptor: template_descriptor.clone(),
|
template_descriptor: template_descriptor.clone(),
|
||||||
|
@ -164,7 +172,7 @@ impl<S: FontSource> FontContext<S> {
|
||||||
fn create_font(
|
fn create_font(
|
||||||
&mut self,
|
&mut self,
|
||||||
info: FontTemplateInfo,
|
info: FontTemplateInfo,
|
||||||
descriptor: FontDescriptor
|
descriptor: FontDescriptor,
|
||||||
) -> Result<Font, ()> {
|
) -> Result<Font, ()> {
|
||||||
// TODO: (Bug #3463): Currently we only support fake small-caps
|
// TODO: (Bug #3463): Currently we only support fake small-caps
|
||||||
// painting. We should also support true small-caps (where the
|
// painting. We should also support true small-caps (where the
|
||||||
|
@ -177,11 +185,18 @@ impl<S: FontSource> FontContext<S> {
|
||||||
let handle = FontHandle::new_from_template(
|
let handle = FontHandle::new_from_template(
|
||||||
&self.platform_handle,
|
&self.platform_handle,
|
||||||
info.font_template,
|
info.font_template,
|
||||||
Some(actual_pt_size)
|
Some(actual_pt_size),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let font_instance_key = self.font_source.get_font_instance(info.font_key, actual_pt_size);
|
let font_instance_key = self
|
||||||
Ok(Font::new(handle, descriptor.to_owned(), actual_pt_size, font_instance_key))
|
.font_source
|
||||||
|
.get_font_instance(info.font_key, actual_pt_size);
|
||||||
|
Ok(Font::new(
|
||||||
|
handle,
|
||||||
|
descriptor.to_owned(),
|
||||||
|
actual_pt_size,
|
||||||
|
font_instance_key,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -219,7 +234,10 @@ impl PartialEq for FontGroupCacheKey {
|
||||||
impl Eq for FontGroupCacheKey {}
|
impl Eq for FontGroupCacheKey {}
|
||||||
|
|
||||||
impl Hash for FontGroupCacheKey {
|
impl Hash for FontGroupCacheKey {
|
||||||
fn hash<H>(&self, hasher: &mut H) where H: Hasher {
|
fn hash<H>(&self, hasher: &mut H)
|
||||||
|
where
|
||||||
|
H: Hasher,
|
||||||
|
{
|
||||||
self.style.hash.hash(hasher)
|
self.style.hash.hash(hasher)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,6 @@ pub struct FontTemplateDescriptor {
|
||||||
pub style: FontStyle,
|
pub style: FontStyle,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// FontTemplateDescriptor contains floats, which are not Eq because of NaN. However,
|
/// FontTemplateDescriptor contains floats, which are not Eq because of NaN. However,
|
||||||
/// 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 {}
|
||||||
|
@ -41,14 +40,9 @@ fn style_to_number(s: &FontStyle) -> f32 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl FontTemplateDescriptor {
|
impl FontTemplateDescriptor {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new(
|
pub fn new(weight: FontWeight, stretch: FontStretch, style: FontStyle) -> Self {
|
||||||
weight: FontWeight,
|
|
||||||
stretch: FontStretch,
|
|
||||||
style: FontStyle,
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
Self {
|
||||||
weight,
|
weight,
|
||||||
stretch,
|
stretch,
|
||||||
|
@ -138,7 +132,10 @@ impl FontTemplate {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the descriptor. Returns `None` when instantiating the data fails.
|
/// Get the descriptor. Returns `None` when instantiating the data fails.
|
||||||
pub fn descriptor(&mut self, font_context: &FontContextHandle) -> Option<FontTemplateDescriptor> {
|
pub fn descriptor(
|
||||||
|
&mut self,
|
||||||
|
font_context: &FontContextHandle,
|
||||||
|
) -> Option<FontTemplateDescriptor> {
|
||||||
// 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,
|
||||||
|
@ -147,18 +144,22 @@ impl FontTemplate {
|
||||||
|
|
||||||
self.descriptor.or_else(|| {
|
self.descriptor.or_else(|| {
|
||||||
if self.instantiate(font_context).is_err() {
|
if self.instantiate(font_context).is_err() {
|
||||||
return None
|
return None;
|
||||||
};
|
};
|
||||||
|
|
||||||
Some(self.descriptor.expect("Instantiation succeeded but no descriptor?"))
|
Some(
|
||||||
|
self.descriptor
|
||||||
|
.expect("Instantiation succeeded but no descriptor?"),
|
||||||
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 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 data_for_descriptor(&mut self,
|
pub fn data_for_descriptor(
|
||||||
fctx: &FontContextHandle,
|
&mut self,
|
||||||
requested_desc: &FontTemplateDescriptor)
|
fctx: &FontContextHandle,
|
||||||
-> Option<Arc<FontTemplateData>> {
|
requested_desc: &FontTemplateDescriptor,
|
||||||
|
) -> Option<Arc<FontTemplateData>> {
|
||||||
self.descriptor(&fctx).and_then(|descriptor| {
|
self.descriptor(&fctx).and_then(|descriptor| {
|
||||||
if *requested_desc == descriptor {
|
if *requested_desc == descriptor {
|
||||||
self.data().ok()
|
self.data().ok()
|
||||||
|
@ -176,21 +177,20 @@ impl FontTemplate {
|
||||||
requested_descriptor: &FontTemplateDescriptor,
|
requested_descriptor: &FontTemplateDescriptor,
|
||||||
) -> Option<(Arc<FontTemplateData>, f32)> {
|
) -> Option<(Arc<FontTemplateData>, f32)> {
|
||||||
self.descriptor(&font_context).and_then(|descriptor| {
|
self.descriptor(&font_context).and_then(|descriptor| {
|
||||||
self.data().ok().map(|data| {
|
self.data()
|
||||||
(data, descriptor.distance_from(requested_descriptor))
|
.ok()
|
||||||
})
|
.map(|data| (data, descriptor.distance_from(requested_descriptor)))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn instantiate(&mut self, font_context: &FontContextHandle) -> Result<(), ()> {
|
fn instantiate(&mut self, font_context: &FontContextHandle) -> Result<(), ()> {
|
||||||
if !self.is_valid {
|
if !self.is_valid {
|
||||||
return Err(())
|
return Err(());
|
||||||
}
|
}
|
||||||
|
|
||||||
let data = self.data().map_err(|_| ())?;
|
let data = self.data().map_err(|_| ())?;
|
||||||
let handle: Result<FontHandle, ()> = FontHandleMethods::new_from_template(font_context,
|
let handle: Result<FontHandle, ()> =
|
||||||
data,
|
FontHandleMethods::new_from_template(font_context, data, None);
|
||||||
None);
|
|
||||||
self.is_valid = handle.is_ok();
|
self.is_valid = handle.is_ok();
|
||||||
let handle = handle?;
|
let handle = handle?;
|
||||||
self.descriptor = Some(FontTemplateDescriptor::new(
|
self.descriptor = Some(FontTemplateDescriptor::new(
|
||||||
|
@ -220,7 +220,7 @@ impl FontTemplate {
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(data) = maybe_data {
|
if let Some(data) = maybe_data {
|
||||||
return Ok(data)
|
return Ok(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
assert!(self.strong_ref.is_none());
|
assert!(self.strong_ref.is_none());
|
||||||
|
|
|
@ -9,14 +9,20 @@ extern crate app_units;
|
||||||
extern crate bitflags;
|
extern crate bitflags;
|
||||||
|
|
||||||
// Mac OS-specific library dependencies
|
// Mac OS-specific library dependencies
|
||||||
#[cfg(target_os = "macos")] extern crate byteorder;
|
#[cfg(target_os = "macos")]
|
||||||
#[cfg(target_os = "macos")] extern crate core_foundation;
|
extern crate byteorder;
|
||||||
#[cfg(target_os = "macos")] extern crate core_graphics;
|
#[cfg(target_os = "macos")]
|
||||||
#[cfg(target_os = "macos")] extern crate core_text;
|
extern crate core_foundation;
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
extern crate core_graphics;
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
extern crate core_text;
|
||||||
|
|
||||||
// Windows-specific library dependencies
|
// Windows-specific library dependencies
|
||||||
#[cfg(target_os = "windows")] extern crate dwrote;
|
#[cfg(target_os = "windows")]
|
||||||
#[cfg(target_os = "windows")] extern crate truetype;
|
extern crate dwrote;
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
extern crate truetype;
|
||||||
|
|
||||||
extern crate euclid;
|
extern crate euclid;
|
||||||
extern crate fnv;
|
extern crate fnv;
|
||||||
|
@ -24,8 +30,10 @@ extern crate fnv;
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
extern crate fontconfig;
|
extern crate fontconfig;
|
||||||
extern crate fontsan;
|
extern crate fontsan;
|
||||||
#[cfg(any(target_os = "linux", target_os = "android"))] extern crate freetype;
|
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||||
#[cfg(any(target_os = "linux", target_os = "android"))] extern crate servo_allocator;
|
extern crate freetype;
|
||||||
|
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||||
|
extern crate servo_allocator;
|
||||||
extern crate gfx_traits;
|
extern crate gfx_traits;
|
||||||
|
|
||||||
// Eventually we would like the shaper to be pluggable, as many operating systems have their own
|
// Eventually we would like the shaper to be pluggable, as many operating systems have their own
|
||||||
|
@ -35,19 +43,25 @@ extern crate harfbuzz_sys as harfbuzz;
|
||||||
extern crate ipc_channel;
|
extern crate ipc_channel;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate lazy_static;
|
extern crate lazy_static;
|
||||||
#[cfg(any(target_os = "linux", target_os = "android"))] extern crate libc;
|
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||||
|
extern crate libc;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate log;
|
extern crate log;
|
||||||
#[cfg_attr(target_os = "windows", macro_use)]
|
#[cfg_attr(target_os = "windows", macro_use)]
|
||||||
extern crate malloc_size_of;
|
extern crate malloc_size_of;
|
||||||
extern crate net_traits;
|
extern crate net_traits;
|
||||||
extern crate ordered_float;
|
extern crate ordered_float;
|
||||||
#[cfg(all(feature = "unstable", any(target_feature = "sse2", target_feature = "neon")))]
|
#[cfg(all(
|
||||||
|
feature = "unstable",
|
||||||
|
any(target_feature = "sse2", target_feature = "neon")
|
||||||
|
))]
|
||||||
extern crate packed_simd;
|
extern crate packed_simd;
|
||||||
extern crate range;
|
extern crate range;
|
||||||
#[macro_use] extern crate serde;
|
#[macro_use]
|
||||||
|
extern crate serde;
|
||||||
extern crate servo_arc;
|
extern crate servo_arc;
|
||||||
#[macro_use] extern crate servo_atoms;
|
#[macro_use]
|
||||||
|
extern crate servo_atoms;
|
||||||
extern crate servo_url;
|
extern crate servo_url;
|
||||||
extern crate smallvec;
|
extern crate smallvec;
|
||||||
extern crate style;
|
extern crate style;
|
||||||
|
@ -61,7 +75,8 @@ extern crate xi_unicode;
|
||||||
extern crate xml5ever;
|
extern crate xml5ever;
|
||||||
|
|
||||||
// Fonts
|
// Fonts
|
||||||
#[macro_use] pub mod font;
|
#[macro_use]
|
||||||
|
pub mod font;
|
||||||
pub mod font_cache_thread;
|
pub mod font_cache_thread;
|
||||||
pub mod font_context;
|
pub mod font_context;
|
||||||
pub mod font_template;
|
pub mod font_template;
|
||||||
|
|
|
@ -58,26 +58,24 @@ impl TestFontSource {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_face(family: &mut FontTemplates, name: &str, identifier: Option<&str>) {
|
fn add_face(family: &mut FontTemplates, name: &str, identifier: Option<&str>) {
|
||||||
let mut path: PathBuf = [
|
let mut path: PathBuf = [env!("CARGO_MANIFEST_DIR"), "tests", "support", "CSSTest"]
|
||||||
env!("CARGO_MANIFEST_DIR"),
|
.iter()
|
||||||
"tests",
|
.collect();
|
||||||
"support",
|
|
||||||
"CSSTest",
|
|
||||||
].iter().collect();
|
|
||||||
path.push(format!("{}.ttf", name));
|
path.push(format!("{}.ttf", name));
|
||||||
|
|
||||||
let file = File::open(path).unwrap();
|
let file = File::open(path).unwrap();
|
||||||
let identifier = Atom::from(identifier.unwrap_or(name));
|
let identifier = Atom::from(identifier.unwrap_or(name));
|
||||||
|
|
||||||
family.add_template(
|
family.add_template(identifier, Some(file.bytes().map(|b| b.unwrap()).collect()))
|
||||||
identifier,
|
|
||||||
Some(file.bytes().map(|b| b.unwrap()).collect())
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FontSource for TestFontSource {
|
impl FontSource for TestFontSource {
|
||||||
fn get_font_instance(&mut self, _key: webrender_api::FontKey, _size: Au) -> webrender_api::FontInstanceKey {
|
fn get_font_instance(
|
||||||
|
&mut self,
|
||||||
|
_key: webrender_api::FontKey,
|
||||||
|
_size: Au,
|
||||||
|
) -> webrender_api::FontInstanceKey {
|
||||||
webrender_api::FontInstanceKey(webrender_api::IdNamespace(0), 0)
|
webrender_api::FontInstanceKey(webrender_api::IdNamespace(0), 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,11 +90,9 @@ impl FontSource for TestFontSource {
|
||||||
self.families
|
self.families
|
||||||
.get_mut(family_descriptor.name())
|
.get_mut(family_descriptor.name())
|
||||||
.and_then(|family| family.find_font_for_style(&template_descriptor, handle))
|
.and_then(|family| family.find_font_for_style(&template_descriptor, handle))
|
||||||
.map(|template| {
|
.map(|template| FontTemplateInfo {
|
||||||
FontTemplateInfo {
|
font_template: template,
|
||||||
font_template: template,
|
font_key: webrender_api::FontKey(webrender_api::IdNamespace(0), 0),
|
||||||
font_key: webrender_api::FontKey(webrender_api::IdNamespace(0), 0),
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -116,12 +112,14 @@ fn style() -> FontStyleStruct {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn font_family(names: Vec<&str>) -> FontFamily {
|
fn font_family(names: Vec<&str>) -> FontFamily {
|
||||||
let names: Vec<SingleFontFamily> = names.into_iter().map(|name|
|
let names: Vec<SingleFontFamily> = names
|
||||||
SingleFontFamily::FamilyName(FamilyName {
|
.into_iter()
|
||||||
name: Atom::from(name),
|
.map(|name| {
|
||||||
syntax: FamilyNameSyntax::Quoted,
|
SingleFontFamily::FamilyName(FamilyName {
|
||||||
})
|
name: Atom::from(name),
|
||||||
).collect();
|
syntax: FamilyNameSyntax::Quoted,
|
||||||
|
})
|
||||||
|
}).collect();
|
||||||
|
|
||||||
FontFamily(FontFamilyList::new(names.into_boxed_slice()))
|
FontFamily(FontFamilyList::new(names.into_boxed_slice()))
|
||||||
}
|
}
|
||||||
|
@ -156,19 +154,36 @@ fn test_font_group_find_by_codepoint() {
|
||||||
let mut context = FontContext::new(source);
|
let mut context = FontContext::new(source);
|
||||||
|
|
||||||
let mut style = style();
|
let mut style = style();
|
||||||
style.set_font_family(font_family(vec!("CSSTest ASCII", "CSSTest Basic")));
|
style.set_font_family(font_family(vec!["CSSTest ASCII", "CSSTest Basic"]));
|
||||||
|
|
||||||
let group = context.font_group(Arc::new(style));
|
let group = context.font_group(Arc::new(style));
|
||||||
|
|
||||||
let font = group.borrow_mut().find_by_codepoint(&mut context, 'a').unwrap();
|
let font = group
|
||||||
|
.borrow_mut()
|
||||||
|
.find_by_codepoint(&mut context, 'a')
|
||||||
|
.unwrap();
|
||||||
assert_eq!(&*font.borrow().identifier(), "csstest-ascii");
|
assert_eq!(&*font.borrow().identifier(), "csstest-ascii");
|
||||||
assert_eq!(count.get(), 1, "only the first font in the list should have been loaded");
|
assert_eq!(
|
||||||
|
count.get(),
|
||||||
|
1,
|
||||||
|
"only the first font in the list should have been loaded"
|
||||||
|
);
|
||||||
|
|
||||||
let font = group.borrow_mut().find_by_codepoint(&mut context, 'a').unwrap();
|
let font = group
|
||||||
|
.borrow_mut()
|
||||||
|
.find_by_codepoint(&mut context, 'a')
|
||||||
|
.unwrap();
|
||||||
assert_eq!(&*font.borrow().identifier(), "csstest-ascii");
|
assert_eq!(&*font.borrow().identifier(), "csstest-ascii");
|
||||||
assert_eq!(count.get(), 1, "we shouldn't load the same font a second time");
|
assert_eq!(
|
||||||
|
count.get(),
|
||||||
|
1,
|
||||||
|
"we shouldn't load the same font a second time"
|
||||||
|
);
|
||||||
|
|
||||||
let font = group.borrow_mut().find_by_codepoint(&mut context, 'á').unwrap();
|
let font = group
|
||||||
|
.borrow_mut()
|
||||||
|
.find_by_codepoint(&mut context, 'á')
|
||||||
|
.unwrap();
|
||||||
assert_eq!(&*font.borrow().identifier(), "csstest-basic-regular");
|
assert_eq!(&*font.borrow().identifier(), "csstest-basic-regular");
|
||||||
assert_eq!(count.get(), 2, "both fonts should now have been loaded");
|
assert_eq!(count.get(), 2, "both fonts should now have been loaded");
|
||||||
}
|
}
|
||||||
|
@ -179,19 +194,27 @@ fn test_font_fallback() {
|
||||||
let mut context = FontContext::new(source);
|
let mut context = FontContext::new(source);
|
||||||
|
|
||||||
let mut style = style();
|
let mut style = style();
|
||||||
style.set_font_family(font_family(vec!("CSSTest ASCII")));
|
style.set_font_family(font_family(vec!["CSSTest ASCII"]));
|
||||||
|
|
||||||
let group = context.font_group(Arc::new(style));
|
let group = context.font_group(Arc::new(style));
|
||||||
|
|
||||||
let font = group.borrow_mut().find_by_codepoint(&mut context, 'a').unwrap();
|
let font = group
|
||||||
|
.borrow_mut()
|
||||||
|
.find_by_codepoint(&mut context, 'a')
|
||||||
|
.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
&*font.borrow().identifier(), "csstest-ascii",
|
&*font.borrow().identifier(),
|
||||||
|
"csstest-ascii",
|
||||||
"a family in the group should be used if there is a matching glyph"
|
"a family in the group should be used if there is a matching glyph"
|
||||||
);
|
);
|
||||||
|
|
||||||
let font = group.borrow_mut().find_by_codepoint(&mut context, 'á').unwrap();
|
let font = group
|
||||||
|
.borrow_mut()
|
||||||
|
.find_by_codepoint(&mut context, 'á')
|
||||||
|
.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
&*font.borrow().identifier(), "fallback",
|
&*font.borrow().identifier(),
|
||||||
|
"fallback",
|
||||||
"a fallback font should be used if there is no matching glyph in the group"
|
"a fallback font should be used if there is no matching glyph in the group"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -212,10 +235,8 @@ fn test_font_template_is_cached() {
|
||||||
pt_size: Au(10),
|
pt_size: Au(10),
|
||||||
};
|
};
|
||||||
|
|
||||||
let family_descriptor = FontFamilyDescriptor::new(
|
let family_descriptor =
|
||||||
FontFamilyName::from("CSSTest Basic"),
|
FontFamilyDescriptor::new(FontFamilyName::from("CSSTest Basic"), FontSearchScope::Any);
|
||||||
FontSearchScope::Any,
|
|
||||||
);
|
|
||||||
|
|
||||||
let font1 = context.font(&font_descriptor, &family_descriptor).unwrap();
|
let font1 = context.font(&font_descriptor, &family_descriptor).unwrap();
|
||||||
|
|
||||||
|
@ -228,5 +249,9 @@ fn test_font_template_is_cached() {
|
||||||
"the same font should not have been returned"
|
"the same font should not have been returned"
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(count.get(), 1, "we should only have fetched the template data from the cache thread once");
|
assert_eq!(
|
||||||
|
count.get(),
|
||||||
|
1,
|
||||||
|
"we should only have fetched the template data from the cache thread once"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,9 +2,12 @@
|
||||||
* 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/. */
|
||||||
|
|
||||||
#[cfg(not(target_os = "macos"))] extern crate gfx;
|
#[cfg(not(target_os = "macos"))]
|
||||||
#[cfg(not(target_os = "macos"))] extern crate servo_atoms;
|
extern crate gfx;
|
||||||
#[cfg(not(target_os = "macos"))] extern crate style;
|
#[cfg(not(target_os = "macos"))]
|
||||||
|
extern crate servo_atoms;
|
||||||
|
#[cfg(not(target_os = "macos"))]
|
||||||
|
extern crate style;
|
||||||
|
|
||||||
// Test doesn't yet run on Mac, see https://github.com/servo/servo/pull/19928 for explanation.
|
// Test doesn't yet run on Mac, see https://github.com/servo/servo/pull/19928 for explanation.
|
||||||
#[cfg(not(target_os = "macos"))]
|
#[cfg(not(target_os = "macos"))]
|
||||||
|
@ -28,14 +31,16 @@ fn test_font_template_descriptor() {
|
||||||
"support",
|
"support",
|
||||||
"dejavu-fonts-ttf-2.37",
|
"dejavu-fonts-ttf-2.37",
|
||||||
"ttf",
|
"ttf",
|
||||||
].iter().collect();
|
]
|
||||||
|
.iter()
|
||||||
|
.collect();
|
||||||
path.push(format!("{}.ttf", filename));
|
path.push(format!("{}.ttf", filename));
|
||||||
|
|
||||||
let file = File::open(path).unwrap();
|
let file = File::open(path).unwrap();
|
||||||
|
|
||||||
let mut template = FontTemplate::new(
|
let mut template = FontTemplate::new(
|
||||||
Atom::from(filename),
|
Atom::from(filename),
|
||||||
Some(file.bytes().map(|b| b.unwrap()).collect())
|
Some(file.bytes().map(|b| b.unwrap()).collect()),
|
||||||
).unwrap();
|
).unwrap();
|
||||||
|
|
||||||
let context = FontContextHandle::new();
|
let context = FontContextHandle::new();
|
||||||
|
@ -43,27 +48,39 @@ fn test_font_template_descriptor() {
|
||||||
template.descriptor(&context).unwrap()
|
template.descriptor(&context).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
assert_eq!(descriptor("DejaVuSans"), FontTemplateDescriptor {
|
assert_eq!(
|
||||||
weight: FontWeight::normal(),
|
descriptor("DejaVuSans"),
|
||||||
stretch: FontStretch::hundred(),
|
FontTemplateDescriptor {
|
||||||
style: FontStyle::Normal,
|
weight: FontWeight::normal(),
|
||||||
});
|
stretch: FontStretch::hundred(),
|
||||||
|
style: FontStyle::Normal,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
assert_eq!(descriptor("DejaVuSans-Bold"), FontTemplateDescriptor {
|
assert_eq!(
|
||||||
weight: FontWeight::bold(),
|
descriptor("DejaVuSans-Bold"),
|
||||||
stretch: FontStretch::hundred(),
|
FontTemplateDescriptor {
|
||||||
style: FontStyle::Normal,
|
weight: FontWeight::bold(),
|
||||||
});
|
stretch: FontStretch::hundred(),
|
||||||
|
style: FontStyle::Normal,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
assert_eq!(descriptor("DejaVuSans-Oblique"), FontTemplateDescriptor {
|
assert_eq!(
|
||||||
weight: FontWeight::normal(),
|
descriptor("DejaVuSans-Oblique"),
|
||||||
stretch: FontStretch::hundred(),
|
FontTemplateDescriptor {
|
||||||
style: FontStyle::Italic,
|
weight: FontWeight::normal(),
|
||||||
});
|
stretch: FontStretch::hundred(),
|
||||||
|
style: FontStyle::Italic,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
assert_eq!(descriptor("DejaVuSansCondensed-BoldOblique"), FontTemplateDescriptor {
|
assert_eq!(
|
||||||
weight: FontWeight::bold(),
|
descriptor("DejaVuSansCondensed-BoldOblique"),
|
||||||
stretch: FontStretch(NonNegative(Percentage(0.875))),
|
FontTemplateDescriptor {
|
||||||
style: FontStyle::Italic,
|
weight: FontWeight::bold(),
|
||||||
});
|
stretch: FontStretch(NonNegative(Percentage(0.875))),
|
||||||
|
style: FontStyle::Italic,
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,26 +29,13 @@ fn test_transform_compress_none() {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_transform_discard_newline() {
|
fn test_transform_discard_newline() {
|
||||||
let test_strs = [
|
let test_strs = [
|
||||||
(" foo bar",
|
(" foo bar", " foo bar"),
|
||||||
" foo bar"),
|
("foo bar ", "foo bar "),
|
||||||
|
("foo\n bar", "foo bar"),
|
||||||
("foo bar ",
|
("foo \nbar", "foo bar"),
|
||||||
"foo bar "),
|
(" foo bar \nbaz", " foo bar baz"),
|
||||||
|
("foo bar baz", "foo bar baz"),
|
||||||
("foo\n bar",
|
("foobarbaz\n\n", "foobarbaz"),
|
||||||
"foo bar"),
|
|
||||||
|
|
||||||
("foo \nbar",
|
|
||||||
"foo bar"),
|
|
||||||
|
|
||||||
(" foo bar \nbaz",
|
|
||||||
" foo bar baz"),
|
|
||||||
|
|
||||||
("foo bar baz",
|
|
||||||
"foo bar baz"),
|
|
||||||
|
|
||||||
("foobarbaz\n\n",
|
|
||||||
"foobarbaz"),
|
|
||||||
];
|
];
|
||||||
|
|
||||||
let mode = CompressionMode::DiscardNewline;
|
let mode = CompressionMode::DiscardNewline;
|
||||||
|
@ -62,26 +49,13 @@ fn test_transform_discard_newline() {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_transform_compress_whitespace() {
|
fn test_transform_compress_whitespace() {
|
||||||
let test_strs = [
|
let test_strs = [
|
||||||
(" foo bar",
|
(" foo bar", "foo bar"),
|
||||||
"foo bar"),
|
("foo bar ", "foo bar "),
|
||||||
|
("foo\n bar", "foo\n bar"),
|
||||||
("foo bar ",
|
("foo \nbar", "foo \nbar"),
|
||||||
"foo bar "),
|
(" foo bar \nbaz", "foo bar \nbaz"),
|
||||||
|
("foo bar baz", "foo bar baz"),
|
||||||
("foo\n bar",
|
("foobarbaz\n\n", "foobarbaz\n\n"),
|
||||||
"foo\n bar"),
|
|
||||||
|
|
||||||
("foo \nbar",
|
|
||||||
"foo \nbar"),
|
|
||||||
|
|
||||||
(" foo bar \nbaz",
|
|
||||||
"foo bar \nbaz"),
|
|
||||||
|
|
||||||
("foo bar baz",
|
|
||||||
"foo bar baz"),
|
|
||||||
|
|
||||||
("foobarbaz\n\n",
|
|
||||||
"foobarbaz\n\n"),
|
|
||||||
];
|
];
|
||||||
|
|
||||||
let mode = CompressionMode::CompressWhitespace;
|
let mode = CompressionMode::CompressWhitespace;
|
||||||
|
@ -95,26 +69,13 @@ fn test_transform_compress_whitespace() {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_transform_compress_whitespace_newline() {
|
fn test_transform_compress_whitespace_newline() {
|
||||||
let test_strs = vec![
|
let test_strs = vec![
|
||||||
(" foo bar",
|
(" foo bar", "foo bar"),
|
||||||
"foo bar"),
|
("foo bar ", "foo bar "),
|
||||||
|
("foo\n bar", "foo bar"),
|
||||||
("foo bar ",
|
("foo \nbar", "foo bar"),
|
||||||
"foo bar "),
|
(" foo bar \nbaz", "foo bar baz"),
|
||||||
|
("foo bar baz", "foo bar baz"),
|
||||||
("foo\n bar",
|
("foobarbaz\n\n", "foobarbaz "),
|
||||||
"foo bar"),
|
|
||||||
|
|
||||||
("foo \nbar",
|
|
||||||
"foo bar"),
|
|
||||||
|
|
||||||
(" foo bar \nbaz",
|
|
||||||
"foo bar baz"),
|
|
||||||
|
|
||||||
("foo bar baz",
|
|
||||||
"foo bar baz"),
|
|
||||||
|
|
||||||
("foobarbaz\n\n",
|
|
||||||
"foobarbaz "),
|
|
||||||
];
|
];
|
||||||
|
|
||||||
let mode = CompressionMode::CompressWhitespaceNewline;
|
let mode = CompressionMode::CompressWhitespaceNewline;
|
||||||
|
@ -128,29 +89,14 @@ fn test_transform_compress_whitespace_newline() {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_transform_compress_whitespace_newline_no_incoming() {
|
fn test_transform_compress_whitespace_newline_no_incoming() {
|
||||||
let test_strs = [
|
let test_strs = [
|
||||||
(" foo bar",
|
(" foo bar", " foo bar"),
|
||||||
" foo bar"),
|
("\nfoo bar", " foo bar"),
|
||||||
|
("foo bar ", "foo bar "),
|
||||||
("\nfoo bar",
|
("foo\n bar", "foo bar"),
|
||||||
" foo bar"),
|
("foo \nbar", "foo bar"),
|
||||||
|
(" foo bar \nbaz", " foo bar baz"),
|
||||||
("foo bar ",
|
("foo bar baz", "foo bar baz"),
|
||||||
"foo bar "),
|
("foobarbaz\n\n", "foobarbaz "),
|
||||||
|
|
||||||
("foo\n bar",
|
|
||||||
"foo bar"),
|
|
||||||
|
|
||||||
("foo \nbar",
|
|
||||||
"foo bar"),
|
|
||||||
|
|
||||||
(" foo bar \nbaz",
|
|
||||||
" foo bar baz"),
|
|
||||||
|
|
||||||
("foo bar baz",
|
|
||||||
"foo bar baz"),
|
|
||||||
|
|
||||||
("foobarbaz\n\n",
|
|
||||||
"foobarbaz "),
|
|
||||||
];
|
];
|
||||||
|
|
||||||
let mode = CompressionMode::CompressWhitespaceNewline;
|
let mode = CompressionMode::CompressWhitespaceNewline;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue