mirror of
https://github.com/servo/servo.git
synced 2025-08-03 12:40:06 +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;
|
||||
|
||||
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)
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
pub const GPOS: u32 = ot_tag!('G', 'P', 'O', 'S');
|
||||
|
@ -87,10 +87,12 @@ trait FontTableTagConversions {
|
|||
|
||||
impl FontTableTagConversions for FontTableTag {
|
||||
fn tag_to_str(&self) -> String {
|
||||
let bytes = [(self >> 24) as u8,
|
||||
(self >> 16) as u8,
|
||||
(self >> 8) as u8,
|
||||
(self >> 0) as u8];
|
||||
let bytes = [
|
||||
(self >> 24) as u8,
|
||||
(self >> 16) as u8,
|
||||
(self >> 8) as u8,
|
||||
(self >> 0) as u8,
|
||||
];
|
||||
str::from_utf8(&bytes).unwrap().to_owned()
|
||||
}
|
||||
}
|
||||
|
@ -101,18 +103,18 @@ pub trait FontTableMethods {
|
|||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
pub struct FontMetrics {
|
||||
pub underline_size: Au,
|
||||
pub underline_size: Au,
|
||||
pub underline_offset: Au,
|
||||
pub strikeout_size: Au,
|
||||
pub strikeout_size: Au,
|
||||
pub strikeout_offset: Au,
|
||||
pub leading: Au,
|
||||
pub x_height: Au,
|
||||
pub em_size: Au,
|
||||
pub ascent: Au,
|
||||
pub descent: Au,
|
||||
pub max_advance: Au,
|
||||
pub average_advance: Au,
|
||||
pub line_gap: Au,
|
||||
pub leading: Au,
|
||||
pub x_height: Au,
|
||||
pub em_size: Au,
|
||||
pub ascent: Au,
|
||||
pub descent: Au,
|
||||
pub max_advance: Au,
|
||||
pub average_advance: Au,
|
||||
pub line_gap: Au,
|
||||
}
|
||||
|
||||
/// `FontDescriptor` describes the parameters of a `Font`. It represents rendering a given font
|
||||
|
@ -149,10 +151,12 @@ pub struct Font {
|
|||
}
|
||||
|
||||
impl Font {
|
||||
pub fn new(handle: FontHandle,
|
||||
descriptor: FontDescriptor,
|
||||
actual_pt_size: Au,
|
||||
font_key: webrender_api::FontInstanceKey) -> Font {
|
||||
pub fn new(
|
||||
handle: FontHandle,
|
||||
descriptor: FontDescriptor,
|
||||
actual_pt_size: Au,
|
||||
font_key: webrender_api::FontInstanceKey,
|
||||
) -> Font {
|
||||
let metrics = handle.metrics();
|
||||
|
||||
Font {
|
||||
|
@ -218,28 +222,39 @@ impl Font {
|
|||
text: text.to_owned(),
|
||||
options: *options,
|
||||
};
|
||||
let result = self.shape_cache.borrow_mut().entry(lookup_key).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));
|
||||
let result = self
|
||||
.shape_cache
|
||||
.borrow_mut()
|
||||
.entry(lookup_key)
|
||||
.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) {
|
||||
debug!("shape_text: Using ASCII fast path.");
|
||||
self.shape_text_fast(text, options, &mut glyphs);
|
||||
} else {
|
||||
debug!("shape_text: Using Harfbuzz.");
|
||||
if shaper.is_none() {
|
||||
shaper = Some(Shaper::new(this));
|
||||
if self.can_do_fast_shaping(text, options) {
|
||||
debug!("shape_text: Using ASCII fast path.");
|
||||
self.shape_text_fast(text, options, &mut glyphs);
|
||||
} else {
|
||||
debug!("shape_text: Using Harfbuzz.");
|
||||
if shaper.is_none() {
|
||||
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();
|
||||
TEXT_SHAPING_PERFORMANCE_COUNTER.fetch_add((end_time - start_time) as usize,
|
||||
Ordering::Relaxed);
|
||||
Arc::new(glyphs)
|
||||
}).clone();
|
||||
let end_time = time::precise_time_ns();
|
||||
TEXT_SHAPING_PERFORMANCE_COUNTER
|
||||
.fetch_add((end_time - start_time) as usize, Ordering::Relaxed);
|
||||
Arc::new(glyphs)
|
||||
}).clone();
|
||||
self.shaper = shaper;
|
||||
result
|
||||
}
|
||||
|
@ -285,12 +300,21 @@ impl Font {
|
|||
|
||||
pub fn table_for_tag(&self, tag: FontTableTag) -> Option<FontTable> {
|
||||
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={}",
|
||||
status, tag.tag_to_str(),
|
||||
self.handle.family_name().unwrap_or("unavailable".to_owned()),
|
||||
self.handle.face_name().unwrap_or("unavailable".to_owned()));
|
||||
debug!(
|
||||
"{} font table[{}] with family={}, face={}",
|
||||
status,
|
||||
tag.tag_to_str(),
|
||||
self.handle
|
||||
.family_name()
|
||||
.unwrap_or("unavailable".to_owned()),
|
||||
self.handle.face_name().unwrap_or("unavailable".to_owned())
|
||||
);
|
||||
|
||||
result
|
||||
}
|
||||
|
@ -308,18 +332,21 @@ impl Font {
|
|||
self.glyph_index(codepoint).is_some()
|
||||
}
|
||||
|
||||
pub fn glyph_h_kerning(&self, first_glyph: GlyphId, second_glyph: GlyphId)
|
||||
-> FractionalPixel {
|
||||
pub fn glyph_h_kerning(&self, first_glyph: GlyphId, second_glyph: GlyphId) -> FractionalPixel {
|
||||
self.handle.glyph_h_kerning(first_glyph, second_glyph)
|
||||
}
|
||||
|
||||
pub fn glyph_h_advance(&self, glyph: GlyphId) -> FractionalPixel {
|
||||
*self.glyph_advance_cache.borrow_mut().entry(glyph).or_insert_with(|| {
|
||||
match self.handle.glyph_h_advance(glyph) {
|
||||
Some(adv) => adv,
|
||||
None => 10f64 as FractionalPixel // FIXME: Need fallback strategy
|
||||
}
|
||||
})
|
||||
*self
|
||||
.glyph_advance_cache
|
||||
.borrow_mut()
|
||||
.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 {
|
||||
let descriptor = FontDescriptor::from(style);
|
||||
|
||||
let families =
|
||||
style.font_family.0.iter()
|
||||
.map(|family| FontGroupFamily::new(descriptor.clone(), &family))
|
||||
.collect();
|
||||
let families = style
|
||||
.font_family
|
||||
.0
|
||||
.iter()
|
||||
.map(|family| FontGroupFamily::new(descriptor.clone(), &family))
|
||||
.collect();
|
||||
|
||||
FontGroup {
|
||||
descriptor,
|
||||
|
@ -358,25 +387,25 @@ impl FontGroup {
|
|||
pub fn find_by_codepoint<S: FontSource>(
|
||||
&mut self,
|
||||
mut font_context: &mut FontContext<S>,
|
||||
codepoint: char
|
||||
codepoint: char,
|
||||
) -> Option<FontRef> {
|
||||
let has_glyph = |font: &FontRef| font.borrow().has_glyph_for(codepoint);
|
||||
|
||||
let font = self.find(&mut font_context, |font| has_glyph(font));
|
||||
if font.is_some() {
|
||||
return font
|
||||
return font;
|
||||
}
|
||||
|
||||
if let Some(ref fallback) = self.last_matching_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);
|
||||
if font.is_some() {
|
||||
self.last_matching_fallback = font.clone();
|
||||
return font
|
||||
return font;
|
||||
}
|
||||
|
||||
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.
|
||||
pub fn first<S: FontSource>(
|
||||
&mut self,
|
||||
mut font_context: &mut FontContext<S>
|
||||
mut font_context: &mut FontContext<S>,
|
||||
) -> Option<FontRef> {
|
||||
self.find(&mut font_context, |_| 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
|
||||
/// load new font data in the process of finding a suitable font.
|
||||
fn find<S, P>(
|
||||
&mut self,
|
||||
mut font_context: &mut FontContext<S>,
|
||||
predicate: P,
|
||||
) -> Option<FontRef>
|
||||
fn find<S, P>(&mut self, mut font_context: &mut FontContext<S>, predicate: P) -> Option<FontRef>
|
||||
where
|
||||
S: FontSource,
|
||||
P: FnMut(&FontRef) -> bool,
|
||||
{
|
||||
self.families.iter_mut()
|
||||
self.families
|
||||
.iter_mut()
|
||||
.filter_map(|family| family.font(&mut font_context))
|
||||
.find(predicate)
|
||||
}
|
||||
|
@ -422,15 +448,9 @@ impl FontGroup {
|
|||
P: FnMut(&FontRef) -> bool,
|
||||
{
|
||||
iter::once(FontFamilyDescriptor::default())
|
||||
.chain(
|
||||
fallback_font_families(codepoint).into_iter().map(|family| {
|
||||
FontFamilyDescriptor::new(
|
||||
FontFamilyName::from(family),
|
||||
FontSearchScope::Local,
|
||||
)
|
||||
})
|
||||
)
|
||||
.filter_map(|family| font_context.font(&self.descriptor, &family))
|
||||
.chain(fallback_font_families(codepoint).into_iter().map(|family| {
|
||||
FontFamilyDescriptor::new(FontFamilyName::from(family), FontSearchScope::Local)
|
||||
})).filter_map(|family| font_context.font(&self.descriptor, &family))
|
||||
.find(predicate)
|
||||
}
|
||||
}
|
||||
|
@ -448,10 +468,8 @@ struct FontGroupFamily {
|
|||
|
||||
impl FontGroupFamily {
|
||||
fn new(font_descriptor: FontDescriptor, family: &SingleFontFamily) -> FontGroupFamily {
|
||||
let family_descriptor = FontFamilyDescriptor::new(
|
||||
FontFamilyName::from(family),
|
||||
FontSearchScope::Any
|
||||
);
|
||||
let family_descriptor =
|
||||
FontFamilyDescriptor::new(FontFamilyName::from(family), FontSearchScope::Any);
|
||||
|
||||
FontGroupFamily {
|
||||
font_descriptor,
|
||||
|
@ -477,17 +495,19 @@ impl FontGroupFamily {
|
|||
pub struct RunMetrics {
|
||||
// may be negative due to negative width (i.e., kerning of '.' in 'P.T.')
|
||||
pub advance_width: Au,
|
||||
pub ascent: Au, // nonzero
|
||||
pub ascent: Au, // nonzero
|
||||
pub descent: Au, // nonzero
|
||||
// this bounding box is relative to the left origin baseline.
|
||||
// so, bounding_box.position.y = -ascent
|
||||
pub bounding_box: Rect<Au>
|
||||
pub bounding_box: Rect<Au>,
|
||||
}
|
||||
|
||||
impl RunMetrics {
|
||||
pub fn new(advance: Au, ascent: Au, descent: Au) -> RunMetrics {
|
||||
let bounds = Rect::new(Point2D::new(Au(0), -ascent),
|
||||
Size2D::new(advance, ascent + descent));
|
||||
let bounds = Rect::new(
|
||||
Point2D::new(Au(0), -ascent),
|
||||
Size2D::new(advance, ascent + descent),
|
||||
);
|
||||
|
||||
// TODO(Issue #125): support loose and tight bounding boxes; using the
|
||||
// ascent+descent and advance is sometimes too generous and
|
||||
|
@ -540,11 +560,13 @@ impl FontFamilyName {
|
|||
impl<'a> From<&'a SingleFontFamily> for FontFamilyName {
|
||||
fn from(other: &'a SingleFontFamily) -> FontFamilyName {
|
||||
match *other {
|
||||
SingleFontFamily::FamilyName(ref family_name) =>
|
||||
FontFamilyName::Specific(family_name.name.clone()),
|
||||
SingleFontFamily::FamilyName(ref family_name) => {
|
||||
FontFamilyName::Specific(family_name.name.clone())
|
||||
},
|
||||
|
||||
SingleFontFamily::Generic(ref generic_name) =>
|
||||
FontFamilyName::Generic(generic_name.clone()),
|
||||
SingleFontFamily::Generic(ref generic_name) => {
|
||||
FontFamilyName::Generic(generic_name.clone())
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,14 +40,15 @@ pub struct FontTemplateInfo {
|
|||
|
||||
impl FontTemplates {
|
||||
pub fn new() -> FontTemplates {
|
||||
FontTemplates {
|
||||
templates: vec!(),
|
||||
}
|
||||
FontTemplates { templates: vec![] }
|
||||
}
|
||||
|
||||
/// Find a font in this family that matches a given descriptor.
|
||||
pub fn find_font_for_style(&mut self, desc: &FontTemplateDescriptor, fctx: &FontContextHandle)
|
||||
-> Option<Arc<FontTemplateData>> {
|
||||
pub fn find_font_for_style(
|
||||
&mut self,
|
||||
desc: &FontTemplateDescriptor,
|
||||
fctx: &FontContextHandle,
|
||||
) -> Option<Arc<FontTemplateData>> {
|
||||
// TODO(Issue #189): optimize lookup for
|
||||
// regular/bold/italic/bolditalic with fixed offsets and a
|
||||
// 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);
|
||||
for template in &mut self.templates {
|
||||
if let Some((template_data, distance)) =
|
||||
template.data_for_approximate_descriptor(fctx, desc) {
|
||||
template.data_for_approximate_descriptor(fctx, desc)
|
||||
{
|
||||
if distance < best_distance {
|
||||
best_template_data = Some(template_data);
|
||||
best_distance = distance
|
||||
|
@ -71,7 +73,7 @@ impl FontTemplates {
|
|||
}
|
||||
}
|
||||
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,
|
||||
|
@ -103,8 +105,16 @@ impl FontTemplates {
|
|||
/// Commands that the FontContext sends to the font cache thread.
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
pub enum Command {
|
||||
GetFontTemplate(FontTemplateDescriptor, FontFamilyDescriptor, IpcSender<Reply>),
|
||||
GetFontInstance(webrender_api::FontKey, Au, IpcSender<webrender_api::FontInstanceKey>),
|
||||
GetFontTemplate(
|
||||
FontTemplateDescriptor,
|
||||
FontFamilyDescriptor,
|
||||
IpcSender<Reply>,
|
||||
),
|
||||
GetFontInstance(
|
||||
webrender_api::FontKey,
|
||||
Au,
|
||||
IpcSender<webrender_api::FontInstanceKey>,
|
||||
),
|
||||
AddWebFont(LowercaseString, EffectiveSources, IpcSender<()>),
|
||||
AddDownloadedWebFont(LowercaseString, ServoUrl, Vec<u8>, IpcSender<()>),
|
||||
Exit(IpcSender<()>),
|
||||
|
@ -148,7 +158,7 @@ fn populate_generic_fonts() -> HashMap<FontFamilyName, LowercaseString> {
|
|||
) {
|
||||
let family_name = match system_default_family(generic_name) {
|
||||
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));
|
||||
|
@ -156,7 +166,6 @@ fn populate_generic_fonts() -> HashMap<FontFamilyName, LowercaseString> {
|
|||
generic_fonts.insert(generic_name, family_name);
|
||||
}
|
||||
|
||||
|
||||
generic_fonts
|
||||
}
|
||||
|
||||
|
@ -167,50 +176,50 @@ impl FontCache {
|
|||
|
||||
match msg {
|
||||
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));
|
||||
}
|
||||
},
|
||||
Command::GetFontInstance(font_key, size, result) => {
|
||||
let webrender_api = &self.webrender_api;
|
||||
|
||||
let instance_key = *self.font_instances
|
||||
.entry((font_key, size))
|
||||
.or_insert_with(|| {
|
||||
let key = webrender_api.generate_font_instance_key();
|
||||
let mut txn = webrender_api::Transaction::new();
|
||||
txn.add_font_instance(key,
|
||||
font_key,
|
||||
size,
|
||||
None,
|
||||
None,
|
||||
Vec::new());
|
||||
webrender_api.update_resources(txn.resource_updates);
|
||||
key
|
||||
});
|
||||
let instance_key =
|
||||
*self
|
||||
.font_instances
|
||||
.entry((font_key, size))
|
||||
.or_insert_with(|| {
|
||||
let key = webrender_api.generate_font_instance_key();
|
||||
let mut txn = webrender_api::Transaction::new();
|
||||
txn.add_font_instance(key, font_key, size, None, None, Vec::new());
|
||||
webrender_api.update_resources(txn.resource_updates);
|
||||
key
|
||||
});
|
||||
|
||||
let _ = result.send(instance_key);
|
||||
}
|
||||
},
|
||||
Command::AddWebFont(family_name, sources, result) => {
|
||||
self.handle_add_web_font(family_name, sources, result);
|
||||
}
|
||||
},
|
||||
Command::AddDownloadedWebFont(family_name, url, bytes, result) => {
|
||||
let templates = &mut self.web_families.get_mut(&family_name).unwrap();
|
||||
templates.add_template(Atom::from(url.to_string()), Some(bytes));
|
||||
drop(result.send(()));
|
||||
}
|
||||
},
|
||||
Command::Ping => (),
|
||||
Command::Exit(result) => {
|
||||
let _ = result.send(());
|
||||
break;
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_add_web_font(&mut self,
|
||||
family_name: LowercaseString,
|
||||
mut sources: EffectiveSources,
|
||||
sender: IpcSender<()>) {
|
||||
fn handle_add_web_font(
|
||||
&mut self,
|
||||
family_name: LowercaseString,
|
||||
mut sources: EffectiveSources,
|
||||
sender: IpcSender<()>,
|
||||
) {
|
||||
let src = if let Some(src) = sources.next() {
|
||||
src
|
||||
} else {
|
||||
|
@ -236,7 +245,7 @@ impl FontCache {
|
|||
destination: Destination::Font,
|
||||
// TODO: Add a proper origin - Can't import GlobalScope from gfx
|
||||
// We can leave origin to be set by default
|
||||
.. RequestInit::default()
|
||||
..RequestInit::default()
|
||||
};
|
||||
|
||||
let channel_to_self = self.channel_to_self.clone();
|
||||
|
@ -248,19 +257,27 @@ impl FontCache {
|
|||
FetchResponseMsg::ProcessRequestBody |
|
||||
FetchResponseMsg::ProcessRequestEOF => (),
|
||||
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();
|
||||
}
|
||||
},
|
||||
FetchResponseMsg::ProcessResponseChunk(new_bytes) => {
|
||||
trace!("@font-face {} chunk={:?}", family_name, new_bytes);
|
||||
if *response_valid.lock().unwrap() {
|
||||
bytes.lock().unwrap().extend(new_bytes.into_iter())
|
||||
}
|
||||
}
|
||||
},
|
||||
FetchResponseMsg::ProcessResponseEOF(response) => {
|
||||
trace!("@font-face {} EOF={:?}", family_name, response);
|
||||
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();
|
||||
return;
|
||||
}
|
||||
|
@ -270,23 +287,31 @@ impl FontCache {
|
|||
Ok(san) => san,
|
||||
Err(_) => {
|
||||
// FIXME(servo/fontsan#1): get an error message
|
||||
debug!("Sanitiser rejected web font: \
|
||||
family={} url={:?}", family_name, url);
|
||||
let msg = Command::AddWebFont(family_name.clone(), sources.clone(), sender.clone());
|
||||
debug!(
|
||||
"Sanitiser rejected web font: \
|
||||
family={} url={:?}",
|
||||
family_name, url
|
||||
);
|
||||
let msg = Command::AddWebFont(
|
||||
family_name.clone(),
|
||||
sources.clone(),
|
||||
sender.clone(),
|
||||
);
|
||||
channel_to_self.send(msg).unwrap();
|
||||
return;
|
||||
},
|
||||
};
|
||||
let command =
|
||||
Command::AddDownloadedWebFont(family_name.clone(),
|
||||
url.clone(),
|
||||
bytes,
|
||||
sender.clone());
|
||||
let command = Command::AddDownloadedWebFont(
|
||||
family_name.clone(),
|
||||
url.clone(),
|
||||
bytes,
|
||||
sender.clone(),
|
||||
);
|
||||
channel_to_self.send(command).unwrap();
|
||||
}
|
||||
},
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
Source::Local(ref font) => {
|
||||
let font_face_name = LowercaseString::new(&font.name);
|
||||
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);
|
||||
self.channel_to_self.send(msg).unwrap();
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -319,7 +344,7 @@ impl FontCache {
|
|||
fn transform_family(&self, family_name: &FontFamilyName) -> LowercaseString {
|
||||
match self.generic_fonts.get(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)
|
||||
} else {
|
||||
debug!("FontList: Couldn't find font family with name={}", &*family_name);
|
||||
debug!(
|
||||
"FontList: Couldn't find font family with name={}",
|
||||
&*family_name
|
||||
);
|
||||
None
|
||||
}
|
||||
}
|
||||
|
@ -371,17 +399,19 @@ impl FontCache {
|
|||
let webrender_api = &self.webrender_api;
|
||||
let webrender_fonts = &mut self.webrender_fonts;
|
||||
|
||||
let font_key = *webrender_fonts.entry(template.identifier.clone()).or_insert_with(|| {
|
||||
let font_key = webrender_api.generate_font_key();
|
||||
let mut txn = webrender_api::Transaction::new();
|
||||
match (template.bytes_if_in_memory(), template.native_font()) {
|
||||
(Some(bytes), _) => txn.add_raw_font(font_key, bytes, 0),
|
||||
(None, Some(native_font)) => txn.add_native_font(font_key, native_font),
|
||||
(None, None) => txn.add_raw_font(font_key, template.bytes().clone(), 0),
|
||||
}
|
||||
webrender_api.update_resources(txn.resource_updates);
|
||||
font_key
|
||||
});
|
||||
let font_key = *webrender_fonts
|
||||
.entry(template.identifier.clone())
|
||||
.or_insert_with(|| {
|
||||
let font_key = webrender_api.generate_font_key();
|
||||
let mut txn = webrender_api::Transaction::new();
|
||||
match (template.bytes_if_in_memory(), template.native_font()) {
|
||||
(Some(bytes), _) => txn.add_raw_font(font_key, bytes, 0),
|
||||
(None, Some(native_font)) => txn.add_native_font(font_key, native_font),
|
||||
(None, None) => txn.add_raw_font(font_key, template.bytes().clone(), 0),
|
||||
}
|
||||
webrender_api.update_resources(txn.resource_updates);
|
||||
font_key
|
||||
});
|
||||
|
||||
FontTemplateInfo {
|
||||
font_template: template,
|
||||
|
@ -395,14 +425,15 @@ impl FontCache {
|
|||
family_descriptor: &FontFamilyDescriptor,
|
||||
) -> Option<FontTemplateInfo> {
|
||||
match family_descriptor.scope {
|
||||
FontSearchScope::Any => {
|
||||
self.find_font_in_web_family(&template_descriptor, &family_descriptor.name)
|
||||
.or_else(|| self.find_font_in_local_family(&template_descriptor, &family_descriptor.name))
|
||||
}
|
||||
FontSearchScope::Any => self
|
||||
.find_font_in_web_family(&template_descriptor, &family_descriptor.name)
|
||||
.or_else(|| {
|
||||
self.find_font_in_local_family(&template_descriptor, &family_descriptor.name)
|
||||
}),
|
||||
|
||||
FontSearchScope::Local => {
|
||||
self.find_font_in_local_family(&template_descriptor, &family_descriptor.name)
|
||||
}
|
||||
},
|
||||
}.map(|t| self.get_font_template_info(t))
|
||||
}
|
||||
}
|
||||
|
@ -415,59 +446,82 @@ pub struct FontCacheThread {
|
|||
}
|
||||
|
||||
impl FontCacheThread {
|
||||
pub fn new(core_resource_thread: CoreResourceThread,
|
||||
webrender_api: webrender_api::RenderApi) -> FontCacheThread {
|
||||
pub fn new(
|
||||
core_resource_thread: CoreResourceThread,
|
||||
webrender_api: webrender_api::RenderApi,
|
||||
) -> FontCacheThread {
|
||||
let (chan, port) = ipc::channel().unwrap();
|
||||
|
||||
let channel_to_self = chan.clone();
|
||||
thread::Builder::new().name("FontCacheThread".to_owned()).spawn(move || {
|
||||
// TODO: Allow users to specify these.
|
||||
let generic_fonts = populate_generic_fonts();
|
||||
thread::Builder::new()
|
||||
.name("FontCacheThread".to_owned())
|
||||
.spawn(move || {
|
||||
// TODO: Allow users to specify these.
|
||||
let generic_fonts = populate_generic_fonts();
|
||||
|
||||
let mut cache = FontCache {
|
||||
port: port,
|
||||
channel_to_self,
|
||||
generic_fonts,
|
||||
local_families: HashMap::new(),
|
||||
web_families: HashMap::new(),
|
||||
font_context: FontContextHandle::new(),
|
||||
core_resource_thread,
|
||||
webrender_api,
|
||||
webrender_fonts: HashMap::new(),
|
||||
font_instances: HashMap::new(),
|
||||
};
|
||||
let mut cache = FontCache {
|
||||
port: port,
|
||||
channel_to_self,
|
||||
generic_fonts,
|
||||
local_families: HashMap::new(),
|
||||
web_families: HashMap::new(),
|
||||
font_context: FontContextHandle::new(),
|
||||
core_resource_thread,
|
||||
webrender_api,
|
||||
webrender_fonts: HashMap::new(),
|
||||
font_instances: HashMap::new(),
|
||||
};
|
||||
|
||||
cache.refresh_local_families();
|
||||
cache.run();
|
||||
}).expect("Thread spawning failed");
|
||||
cache.refresh_local_families();
|
||||
cache.run();
|
||||
}).expect("Thread spawning failed");
|
||||
|
||||
FontCacheThread {
|
||||
chan: chan,
|
||||
}
|
||||
FontCacheThread { chan: chan }
|
||||
}
|
||||
|
||||
pub fn add_web_font(&self, family: FamilyName, sources: EffectiveSources, sender: IpcSender<()>) {
|
||||
self.chan.send(Command::AddWebFont(LowercaseString::new(&family.name), sources, sender)).unwrap();
|
||||
pub fn add_web_font(
|
||||
&self,
|
||||
family: FamilyName,
|
||||
sources: EffectiveSources,
|
||||
sender: IpcSender<()>,
|
||||
) {
|
||||
self.chan
|
||||
.send(Command::AddWebFont(
|
||||
LowercaseString::new(&family.name),
|
||||
sources,
|
||||
sender,
|
||||
)).unwrap();
|
||||
}
|
||||
|
||||
pub fn exit(&self) {
|
||||
let (response_chan, response_port) = ipc::channel().unwrap();
|
||||
self.chan.send(Command::Exit(response_chan)).expect("Couldn't send FontCacheThread exit message");
|
||||
response_port.recv().expect("Couldn't receive FontCacheThread reply");
|
||||
self.chan
|
||||
.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 {
|
||||
fn get_font_instance(&mut self, key: webrender_api::FontKey, 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))
|
||||
fn get_font_instance(
|
||||
&mut self,
|
||||
key: webrender_api::FontKey,
|
||||
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");
|
||||
|
||||
let instance_key = response_port.recv();
|
||||
if instance_key.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.");
|
||||
}
|
||||
instance_key.unwrap()
|
||||
|
@ -478,23 +532,27 @@ impl FontSource for FontCacheThread {
|
|||
template_descriptor: FontTemplateDescriptor,
|
||||
family_descriptor: FontFamilyDescriptor,
|
||||
) -> Option<FontTemplateInfo> {
|
||||
let (response_chan, response_port) =
|
||||
ipc::channel().expect("failed to create IPC channel");
|
||||
self.chan.send(Command::GetFontTemplate(template_descriptor, family_descriptor, response_chan))
|
||||
.expect("failed to send message to font cache thread");
|
||||
let (response_chan, response_port) = ipc::channel().expect("failed to create IPC channel");
|
||||
self.chan
|
||||
.send(Command::GetFontTemplate(
|
||||
template_descriptor,
|
||||
family_descriptor,
|
||||
response_chan,
|
||||
)).expect("failed to send message to font cache thread");
|
||||
|
||||
let reply = response_port.recv();
|
||||
|
||||
if reply.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.");
|
||||
}
|
||||
|
||||
match reply.unwrap() {
|
||||
Reply::GetFontTemplateReply(data) => {
|
||||
data
|
||||
}
|
||||
Reply::GetFontTemplateReply(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 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
|
||||
/// this one.
|
||||
static FONT_CACHE_EPOCH: AtomicUsize = ATOMIC_USIZE_INIT;
|
||||
|
||||
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(
|
||||
&mut self,
|
||||
|
@ -74,7 +78,7 @@ impl<S: FontSource> FontContext<S> {
|
|||
fn expire_font_caches_if_necessary(&mut self) {
|
||||
let current_epoch = FONT_CACHE_EPOCH.load(Ordering::SeqCst);
|
||||
if current_epoch == self.epoch {
|
||||
return
|
||||
return;
|
||||
}
|
||||
|
||||
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) {
|
||||
return (*font_group).clone()
|
||||
return (*font_group).clone();
|
||||
}
|
||||
|
||||
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(),
|
||||
};
|
||||
|
||||
self.font_cache.get(&cache_key).map(|v| v.clone()).unwrap_or_else(|| {
|
||||
debug!(
|
||||
"FontContext::font cache miss for font_descriptor={:?} family_descriptor={:?}",
|
||||
font_descriptor,
|
||||
family_descriptor
|
||||
);
|
||||
self.font_cache
|
||||
.get(&cache_key)
|
||||
.map(|v| v.clone())
|
||||
.unwrap_or_else(|| {
|
||||
debug!(
|
||||
"FontContext::font cache miss for font_descriptor={:?} family_descriptor={:?}",
|
||||
font_descriptor, family_descriptor
|
||||
);
|
||||
|
||||
let font =
|
||||
self.font_template(&font_descriptor.template_descriptor, family_descriptor)
|
||||
.and_then(|template_info| self.create_font(template_info, font_descriptor.to_owned()).ok())
|
||||
.map(|font| Rc::new(RefCell::new(font)));
|
||||
let font = self
|
||||
.font_template(&font_descriptor.template_descriptor, family_descriptor)
|
||||
.and_then(|template_info| {
|
||||
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());
|
||||
font
|
||||
})
|
||||
self.font_cache.insert(cache_key, font.clone());
|
||||
font
|
||||
})
|
||||
}
|
||||
|
||||
fn font_template(
|
||||
&mut self,
|
||||
template_descriptor: &FontTemplateDescriptor,
|
||||
family_descriptor: &FontFamilyDescriptor
|
||||
family_descriptor: &FontFamilyDescriptor,
|
||||
) -> Option<FontTemplateInfo> {
|
||||
let cache_key = FontTemplateCacheKey {
|
||||
template_descriptor: template_descriptor.clone(),
|
||||
|
@ -164,7 +172,7 @@ impl<S: FontSource> FontContext<S> {
|
|||
fn create_font(
|
||||
&mut self,
|
||||
info: FontTemplateInfo,
|
||||
descriptor: FontDescriptor
|
||||
descriptor: FontDescriptor,
|
||||
) -> Result<Font, ()> {
|
||||
// TODO: (Bug #3463): Currently we only support fake small-caps
|
||||
// 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(
|
||||
&self.platform_handle,
|
||||
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);
|
||||
Ok(Font::new(handle, descriptor.to_owned(), actual_pt_size, font_instance_key))
|
||||
let font_instance_key = self
|
||||
.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 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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,7 +26,6 @@ pub struct FontTemplateDescriptor {
|
|||
pub style: FontStyle,
|
||||
}
|
||||
|
||||
|
||||
/// FontTemplateDescriptor contains floats, which are not Eq because of NaN. However,
|
||||
/// we know they will never be NaN, so we can manually implement Eq.
|
||||
impl Eq for FontTemplateDescriptor {}
|
||||
|
@ -41,14 +40,9 @@ fn style_to_number(s: &FontStyle) -> f32 {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
impl FontTemplateDescriptor {
|
||||
#[inline]
|
||||
pub fn new(
|
||||
weight: FontWeight,
|
||||
stretch: FontStretch,
|
||||
style: FontStyle,
|
||||
) -> Self {
|
||||
pub fn new(weight: FontWeight, stretch: FontStretch, style: FontStyle) -> Self {
|
||||
Self {
|
||||
weight,
|
||||
stretch,
|
||||
|
@ -138,7 +132,10 @@ impl FontTemplate {
|
|||
}
|
||||
|
||||
/// 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
|
||||
// it (via the Weak reference to the Arc above). However, if we have
|
||||
// already loaded a font, store the style information about it separately,
|
||||
|
@ -147,18 +144,22 @@ impl FontTemplate {
|
|||
|
||||
self.descriptor.or_else(|| {
|
||||
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.
|
||||
pub fn data_for_descriptor(&mut self,
|
||||
fctx: &FontContextHandle,
|
||||
requested_desc: &FontTemplateDescriptor)
|
||||
-> Option<Arc<FontTemplateData>> {
|
||||
pub fn data_for_descriptor(
|
||||
&mut self,
|
||||
fctx: &FontContextHandle,
|
||||
requested_desc: &FontTemplateDescriptor,
|
||||
) -> Option<Arc<FontTemplateData>> {
|
||||
self.descriptor(&fctx).and_then(|descriptor| {
|
||||
if *requested_desc == descriptor {
|
||||
self.data().ok()
|
||||
|
@ -176,21 +177,20 @@ impl FontTemplate {
|
|||
requested_descriptor: &FontTemplateDescriptor,
|
||||
) -> Option<(Arc<FontTemplateData>, f32)> {
|
||||
self.descriptor(&font_context).and_then(|descriptor| {
|
||||
self.data().ok().map(|data| {
|
||||
(data, descriptor.distance_from(requested_descriptor))
|
||||
})
|
||||
self.data()
|
||||
.ok()
|
||||
.map(|data| (data, descriptor.distance_from(requested_descriptor)))
|
||||
})
|
||||
}
|
||||
|
||||
fn instantiate(&mut self, font_context: &FontContextHandle) -> Result<(), ()> {
|
||||
if !self.is_valid {
|
||||
return Err(())
|
||||
return Err(());
|
||||
}
|
||||
|
||||
let data = self.data().map_err(|_| ())?;
|
||||
let handle: Result<FontHandle, ()> = FontHandleMethods::new_from_template(font_context,
|
||||
data,
|
||||
None);
|
||||
let handle: Result<FontHandle, ()> =
|
||||
FontHandleMethods::new_from_template(font_context, data, None);
|
||||
self.is_valid = handle.is_ok();
|
||||
let handle = handle?;
|
||||
self.descriptor = Some(FontTemplateDescriptor::new(
|
||||
|
@ -220,7 +220,7 @@ impl FontTemplate {
|
|||
};
|
||||
|
||||
if let Some(data) = maybe_data {
|
||||
return Ok(data)
|
||||
return Ok(data);
|
||||
}
|
||||
|
||||
assert!(self.strong_ref.is_none());
|
||||
|
|
|
@ -9,14 +9,20 @@ extern crate app_units;
|
|||
extern crate bitflags;
|
||||
|
||||
// Mac OS-specific library dependencies
|
||||
#[cfg(target_os = "macos")] extern crate byteorder;
|
||||
#[cfg(target_os = "macos")] extern crate core_foundation;
|
||||
#[cfg(target_os = "macos")] extern crate core_graphics;
|
||||
#[cfg(target_os = "macos")] extern crate core_text;
|
||||
#[cfg(target_os = "macos")]
|
||||
extern crate byteorder;
|
||||
#[cfg(target_os = "macos")]
|
||||
extern crate core_foundation;
|
||||
#[cfg(target_os = "macos")]
|
||||
extern crate core_graphics;
|
||||
#[cfg(target_os = "macos")]
|
||||
extern crate core_text;
|
||||
|
||||
// Windows-specific library dependencies
|
||||
#[cfg(target_os = "windows")] extern crate dwrote;
|
||||
#[cfg(target_os = "windows")] extern crate truetype;
|
||||
#[cfg(target_os = "windows")]
|
||||
extern crate dwrote;
|
||||
#[cfg(target_os = "windows")]
|
||||
extern crate truetype;
|
||||
|
||||
extern crate euclid;
|
||||
extern crate fnv;
|
||||
|
@ -24,8 +30,10 @@ extern crate fnv;
|
|||
#[cfg(target_os = "linux")]
|
||||
extern crate fontconfig;
|
||||
extern crate fontsan;
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))] extern crate freetype;
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))] extern crate servo_allocator;
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
extern crate freetype;
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
extern crate servo_allocator;
|
||||
extern crate gfx_traits;
|
||||
|
||||
// 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;
|
||||
#[macro_use]
|
||||
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]
|
||||
extern crate log;
|
||||
#[cfg_attr(target_os = "windows", macro_use)]
|
||||
extern crate malloc_size_of;
|
||||
extern crate net_traits;
|
||||
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 range;
|
||||
#[macro_use] extern crate serde;
|
||||
#[macro_use]
|
||||
extern crate serde;
|
||||
extern crate servo_arc;
|
||||
#[macro_use] extern crate servo_atoms;
|
||||
#[macro_use]
|
||||
extern crate servo_atoms;
|
||||
extern crate servo_url;
|
||||
extern crate smallvec;
|
||||
extern crate style;
|
||||
|
@ -61,7 +75,8 @@ extern crate xi_unicode;
|
|||
extern crate xml5ever;
|
||||
|
||||
// Fonts
|
||||
#[macro_use] pub mod font;
|
||||
#[macro_use]
|
||||
pub mod font;
|
||||
pub mod font_cache_thread;
|
||||
pub mod font_context;
|
||||
pub mod font_template;
|
||||
|
|
|
@ -58,26 +58,24 @@ impl TestFontSource {
|
|||
}
|
||||
|
||||
fn add_face(family: &mut FontTemplates, name: &str, identifier: Option<&str>) {
|
||||
let mut path: PathBuf = [
|
||||
env!("CARGO_MANIFEST_DIR"),
|
||||
"tests",
|
||||
"support",
|
||||
"CSSTest",
|
||||
].iter().collect();
|
||||
let mut path: PathBuf = [env!("CARGO_MANIFEST_DIR"), "tests", "support", "CSSTest"]
|
||||
.iter()
|
||||
.collect();
|
||||
path.push(format!("{}.ttf", name));
|
||||
|
||||
let file = File::open(path).unwrap();
|
||||
let identifier = Atom::from(identifier.unwrap_or(name));
|
||||
|
||||
family.add_template(
|
||||
identifier,
|
||||
Some(file.bytes().map(|b| b.unwrap()).collect())
|
||||
)
|
||||
family.add_template(identifier, Some(file.bytes().map(|b| b.unwrap()).collect()))
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
|
@ -92,11 +90,9 @@ impl FontSource for TestFontSource {
|
|||
self.families
|
||||
.get_mut(family_descriptor.name())
|
||||
.and_then(|family| family.find_font_for_style(&template_descriptor, handle))
|
||||
.map(|template| {
|
||||
FontTemplateInfo {
|
||||
font_template: template,
|
||||
font_key: webrender_api::FontKey(webrender_api::IdNamespace(0), 0),
|
||||
}
|
||||
.map(|template| FontTemplateInfo {
|
||||
font_template: template,
|
||||
font_key: webrender_api::FontKey(webrender_api::IdNamespace(0), 0),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -116,12 +112,14 @@ fn style() -> FontStyleStruct {
|
|||
}
|
||||
|
||||
fn font_family(names: Vec<&str>) -> FontFamily {
|
||||
let names: Vec<SingleFontFamily> = names.into_iter().map(|name|
|
||||
SingleFontFamily::FamilyName(FamilyName {
|
||||
name: Atom::from(name),
|
||||
syntax: FamilyNameSyntax::Quoted,
|
||||
})
|
||||
).collect();
|
||||
let names: Vec<SingleFontFamily> = names
|
||||
.into_iter()
|
||||
.map(|name| {
|
||||
SingleFontFamily::FamilyName(FamilyName {
|
||||
name: Atom::from(name),
|
||||
syntax: FamilyNameSyntax::Quoted,
|
||||
})
|
||||
}).collect();
|
||||
|
||||
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 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 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!(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!(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!(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 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 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",
|
||||
&*font.borrow().identifier(),
|
||||
"csstest-ascii",
|
||||
"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!(
|
||||
&*font.borrow().identifier(), "fallback",
|
||||
&*font.borrow().identifier(),
|
||||
"fallback",
|
||||
"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),
|
||||
};
|
||||
|
||||
let family_descriptor = FontFamilyDescriptor::new(
|
||||
FontFamilyName::from("CSSTest Basic"),
|
||||
FontSearchScope::Any,
|
||||
);
|
||||
let family_descriptor =
|
||||
FontFamilyDescriptor::new(FontFamilyName::from("CSSTest Basic"), FontSearchScope::Any);
|
||||
|
||||
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"
|
||||
);
|
||||
|
||||
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
|
||||
* 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"))] extern crate servo_atoms;
|
||||
#[cfg(not(target_os = "macos"))] extern crate style;
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
extern crate gfx;
|
||||
#[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.
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
|
@ -28,14 +31,16 @@ fn test_font_template_descriptor() {
|
|||
"support",
|
||||
"dejavu-fonts-ttf-2.37",
|
||||
"ttf",
|
||||
].iter().collect();
|
||||
]
|
||||
.iter()
|
||||
.collect();
|
||||
path.push(format!("{}.ttf", filename));
|
||||
|
||||
let file = File::open(path).unwrap();
|
||||
|
||||
let mut template = FontTemplate::new(
|
||||
Atom::from(filename),
|
||||
Some(file.bytes().map(|b| b.unwrap()).collect())
|
||||
Some(file.bytes().map(|b| b.unwrap()).collect()),
|
||||
).unwrap();
|
||||
|
||||
let context = FontContextHandle::new();
|
||||
|
@ -43,27 +48,39 @@ fn test_font_template_descriptor() {
|
|||
template.descriptor(&context).unwrap()
|
||||
}
|
||||
|
||||
assert_eq!(descriptor("DejaVuSans"), FontTemplateDescriptor {
|
||||
weight: FontWeight::normal(),
|
||||
stretch: FontStretch::hundred(),
|
||||
style: FontStyle::Normal,
|
||||
});
|
||||
assert_eq!(
|
||||
descriptor("DejaVuSans"),
|
||||
FontTemplateDescriptor {
|
||||
weight: FontWeight::normal(),
|
||||
stretch: FontStretch::hundred(),
|
||||
style: FontStyle::Normal,
|
||||
}
|
||||
);
|
||||
|
||||
assert_eq!(descriptor("DejaVuSans-Bold"), FontTemplateDescriptor {
|
||||
weight: FontWeight::bold(),
|
||||
stretch: FontStretch::hundred(),
|
||||
style: FontStyle::Normal,
|
||||
});
|
||||
assert_eq!(
|
||||
descriptor("DejaVuSans-Bold"),
|
||||
FontTemplateDescriptor {
|
||||
weight: FontWeight::bold(),
|
||||
stretch: FontStretch::hundred(),
|
||||
style: FontStyle::Normal,
|
||||
}
|
||||
);
|
||||
|
||||
assert_eq!(descriptor("DejaVuSans-Oblique"), FontTemplateDescriptor {
|
||||
weight: FontWeight::normal(),
|
||||
stretch: FontStretch::hundred(),
|
||||
style: FontStyle::Italic,
|
||||
});
|
||||
assert_eq!(
|
||||
descriptor("DejaVuSans-Oblique"),
|
||||
FontTemplateDescriptor {
|
||||
weight: FontWeight::normal(),
|
||||
stretch: FontStretch::hundred(),
|
||||
style: FontStyle::Italic,
|
||||
}
|
||||
);
|
||||
|
||||
assert_eq!(descriptor("DejaVuSansCondensed-BoldOblique"), FontTemplateDescriptor {
|
||||
weight: FontWeight::bold(),
|
||||
stretch: FontStretch(NonNegative(Percentage(0.875))),
|
||||
style: FontStyle::Italic,
|
||||
});
|
||||
assert_eq!(
|
||||
descriptor("DejaVuSansCondensed-BoldOblique"),
|
||||
FontTemplateDescriptor {
|
||||
weight: FontWeight::bold(),
|
||||
stretch: FontStretch(NonNegative(Percentage(0.875))),
|
||||
style: FontStyle::Italic,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
|
@ -29,26 +29,13 @@ fn test_transform_compress_none() {
|
|||
#[test]
|
||||
fn test_transform_discard_newline() {
|
||||
let test_strs = [
|
||||
(" foo bar",
|
||||
" foo bar"),
|
||||
|
||||
("foo bar ",
|
||||
"foo bar "),
|
||||
|
||||
("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"),
|
||||
(" foo bar", " foo bar"),
|
||||
("foo bar ", "foo bar "),
|
||||
("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::DiscardNewline;
|
||||
|
@ -62,26 +49,13 @@ fn test_transform_discard_newline() {
|
|||
#[test]
|
||||
fn test_transform_compress_whitespace() {
|
||||
let test_strs = [
|
||||
(" foo bar",
|
||||
"foo bar"),
|
||||
|
||||
("foo bar ",
|
||||
"foo bar "),
|
||||
|
||||
("foo\n bar",
|
||||
"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"),
|
||||
(" foo bar", "foo bar"),
|
||||
("foo bar ", "foo bar "),
|
||||
("foo\n bar", "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;
|
||||
|
@ -95,26 +69,13 @@ fn test_transform_compress_whitespace() {
|
|||
#[test]
|
||||
fn test_transform_compress_whitespace_newline() {
|
||||
let test_strs = vec![
|
||||
(" foo bar",
|
||||
"foo bar"),
|
||||
|
||||
("foo bar ",
|
||||
"foo bar "),
|
||||
|
||||
("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 "),
|
||||
(" foo bar", "foo bar"),
|
||||
("foo bar ", "foo bar "),
|
||||
("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;
|
||||
|
@ -128,29 +89,14 @@ fn test_transform_compress_whitespace_newline() {
|
|||
#[test]
|
||||
fn test_transform_compress_whitespace_newline_no_incoming() {
|
||||
let test_strs = [
|
||||
(" foo bar",
|
||||
" foo bar"),
|
||||
|
||||
("\nfoo bar",
|
||||
" foo bar"),
|
||||
|
||||
("foo bar ",
|
||||
"foo bar "),
|
||||
|
||||
("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 "),
|
||||
(" foo bar", " foo bar"),
|
||||
("\nfoo bar", " foo bar"),
|
||||
("foo bar ", "foo bar "),
|
||||
("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;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue