Format the rest of gfx #21373

This commit is contained in:
kingdido999 2018-09-08 08:05:42 +08:00
parent f7630dad87
commit 3a3c4b8c8e
8 changed files with 502 additions and 401 deletions

View file

@ -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())
},
}
}
}

View file

@ -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,
}
}
}

View file

@ -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)
}
}

View file

@ -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());

View file

@ -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;

View file

@ -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"
);
}

View file

@ -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,
}
);
}

View file

@ -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;