Fix ./mach build --release --with-layout-2020

This commit is contained in:
Utsav Oza 2020-06-09 12:42:38 +05:30
parent 34d0c313dc
commit d1241a8d06
6 changed files with 136 additions and 32 deletions

View file

@ -7,9 +7,10 @@ use crate::raqote_backend::Repetition;
use canvas_traits::canvas::*;
use cssparser::RGBA;
use euclid::default::{Point2D, Rect, Size2D, Transform2D, Vector2D};
use euclid::point2;
use euclid::{point2, vec2};
use font_kit::family_name::FamilyName;
use font_kit::font::Font;
use font_kit::metrics::Metrics;
use font_kit::properties::Properties;
use font_kit::source::SystemSource;
use gfx::font::FontHandleMethods;
@ -281,7 +282,7 @@ pub trait GenericDrawTarget {
point_size: f32,
text: &str,
start: Point2D<f32>,
pattern: Pattern,
pattern: &Pattern,
draw_options: &DrawOptions,
);
fn fill_rect(&mut self, rect: &Rect<f32>, pattern: Pattern, draw_options: Option<&DrawOptions>);
@ -499,13 +500,13 @@ impl<'a> CanvasData<'a> {
text: String,
x: f64,
y: f64,
_max_width: Option<f64>,
_is_rtl: bool,
max_width: Option<f64>,
is_rtl: bool,
) {
// Step 2. Replace all ASCII whitespace in text with U+0020 SPACE characters.
// Step 2.
let text = replace_ascii_whitespace(text);
// Step 3. Let font be the current font of target, as given by that object's font attribute.
// Step 3.
let point_size = self
.state
.font_style
@ -513,12 +514,18 @@ impl<'a> CanvasData<'a> {
.map_or(10., |style| style.font_size.size().px());
let font_style = self.state.font_style.as_ref();
let font = font_style.map_or_else(
|| load_system_font_from_style(font_style),
|| load_system_font_from_style(None),
|style| {
with_thread_local_font_context(&self, |font_context| {
let font_group = font_context.font_group(ServoArc::new(style.clone()));
let font = font_group.borrow_mut().first(font_context).expect("");
let font = font_group
.borrow_mut()
.first(font_context)
.expect("couldn't find font");
let font = font.borrow_mut();
// Retrieving bytes from font template seems to panic for some core text fonts.
// This check avoids having to obtain bytes from the font template data if they
// are not already in the memory.
if let Some(bytes) = font.handle.template().bytes_if_in_memory() {
Font::from_bytes(Arc::new(bytes), 0)
.unwrap_or_else(|_| load_system_font_from_style(Some(style)))
@ -528,15 +535,73 @@ impl<'a> CanvasData<'a> {
})
},
);
let start = point2(x as f32, y as f32);
let font_width = font_width(&text, point_size, &font);
// TODO: Process bidi text
// Step 6.
let max_width = max_width.map(|width| width as f32);
let (width, scale_factor) = match max_width {
Some(max_width) if max_width > font_width => (max_width, 1.),
Some(max_width) => (font_width, max_width / font_width),
None => (font_width, 1.),
};
// Step 7.
let start = self.text_origin(x as f32, y as f32, &font.metrics(), width, is_rtl);
// TODO: Bidi text layout
let old_transform = self.get_transform();
self.set_transform(
&old_transform
.pre_translate(vec2(start.x, 0.))
.pre_scale(scale_factor, 1.)
.pre_translate(vec2(-start.x, 0.)),
);
// Step 8.
let fill_style = self.state.fill_style.clone();
let draw_options = &self.state.draw_options;
self.drawtarget
.fill_text(&font, point_size, &text, start, fill_style, draw_options);
self.drawtarget.fill_text(
&font,
point_size,
&text,
start,
&self.state.fill_style,
&self.state.draw_options,
);
self.set_transform(&old_transform);
}
fn text_origin(
&self,
x: f32,
y: f32,
metrics: &Metrics,
width: f32,
is_rtl: bool,
) -> Point2D<f32> {
let text_align = match self.state.text_align {
TextAlign::Start if is_rtl => TextAlign::Right,
TextAlign::Start => TextAlign::Left,
TextAlign::End if is_rtl => TextAlign::Left,
TextAlign::End => TextAlign::Right,
text_align => text_align,
};
let anchor_x = match text_align {
TextAlign::Center => -width / 2.,
TextAlign::Right => -width,
_ => 0.,
};
let anchor_y = match self.state.text_baseline {
TextBaseline::Top => metrics.ascent,
TextBaseline::Hanging => metrics.ascent * HANGING_BASELINE_DEFAULT,
TextBaseline::Ideographic => -metrics.descent * IDEOGRAPHIC_BASELINE_DEFAULT,
TextBaseline::Middle => (metrics.ascent - metrics.descent) / 2.,
TextBaseline::Alphabetic => 0.,
TextBaseline::Bottom => -metrics.descent,
};
point2(x + anchor_x, y + anchor_y)
}
pub fn fill_rect(&mut self, rect: &Rect<f32>) {
@ -1206,6 +1271,9 @@ impl<'a> Drop for CanvasData<'a> {
}
}
const HANGING_BASELINE_DEFAULT: f32 = 0.8;
const IDEOGRAPHIC_BASELINE_DEFAULT: f32 = 0.5;
#[derive(Clone)]
pub struct CanvasPaintState<'a> {
pub draw_options: DrawOptions,
@ -1321,19 +1389,23 @@ fn load_system_font_from_style(font_style: Option<&FontStyleStruct>) -> Font {
.stretch(style.font_stretch.into());
let font_handle = match SystemSource::new().select_best_match(&family_names, &properties) {
Ok(handle) => handle,
Err(_) => return load_default_system_fallback_font(&properties),
Err(e) => {
error!("error getting font handle for style {:?}: {}", style, e);
return load_default_system_fallback_font(&properties);
},
};
font_handle
.load()
.unwrap_or_else(|_| load_default_system_fallback_font(&properties))
font_handle.load().unwrap_or_else(|e| {
error!("error loading font for style {:?}: {}", style, e);
load_default_system_fallback_font(&properties)
})
}
fn load_default_system_fallback_font(properties: &Properties) -> Font {
SystemSource::new()
.select_best_match(&[FamilyName::SansSerif], properties)
.unwrap()
.expect("error getting font handle for default system font")
.load()
.unwrap()
.expect("error loading default system font")
}
fn replace_ascii_whitespace(text: String) -> String {
@ -1344,3 +1416,18 @@ fn replace_ascii_whitespace(text: String) -> String {
})
.collect()
}
// TODO: This currently calculates the width using just advances and doesn't
// determine the fallback font in case a character glyph isn't found.
fn font_width(text: &str, point_size: f32, font: &Font) -> f32 {
let metrics = font.metrics();
let mut width = 0.;
for c in text.chars() {
if let Some(glyph_id) = font.glyph_for_char(c) {
if let Ok(advance) = font.advance(glyph_id) {
width += advance.x() * point_size / metrics.units_per_em as f32;
}
}
}
width
}