mirror of
https://github.com/servo/servo.git
synced 2025-08-05 21:50:18 +01:00
Fix ./mach build --release --with-layout-2020
This commit is contained in:
parent
34d0c313dc
commit
d1241a8d06
6 changed files with 136 additions and 32 deletions
|
@ -7,9 +7,10 @@ use crate::raqote_backend::Repetition;
|
||||||
use canvas_traits::canvas::*;
|
use canvas_traits::canvas::*;
|
||||||
use cssparser::RGBA;
|
use cssparser::RGBA;
|
||||||
use euclid::default::{Point2D, Rect, Size2D, Transform2D, Vector2D};
|
use euclid::default::{Point2D, Rect, Size2D, Transform2D, Vector2D};
|
||||||
use euclid::point2;
|
use euclid::{point2, vec2};
|
||||||
use font_kit::family_name::FamilyName;
|
use font_kit::family_name::FamilyName;
|
||||||
use font_kit::font::Font;
|
use font_kit::font::Font;
|
||||||
|
use font_kit::metrics::Metrics;
|
||||||
use font_kit::properties::Properties;
|
use font_kit::properties::Properties;
|
||||||
use font_kit::source::SystemSource;
|
use font_kit::source::SystemSource;
|
||||||
use gfx::font::FontHandleMethods;
|
use gfx::font::FontHandleMethods;
|
||||||
|
@ -281,7 +282,7 @@ pub trait GenericDrawTarget {
|
||||||
point_size: f32,
|
point_size: f32,
|
||||||
text: &str,
|
text: &str,
|
||||||
start: Point2D<f32>,
|
start: Point2D<f32>,
|
||||||
pattern: Pattern,
|
pattern: &Pattern,
|
||||||
draw_options: &DrawOptions,
|
draw_options: &DrawOptions,
|
||||||
);
|
);
|
||||||
fn fill_rect(&mut self, rect: &Rect<f32>, pattern: Pattern, draw_options: Option<&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,
|
text: String,
|
||||||
x: f64,
|
x: f64,
|
||||||
y: f64,
|
y: f64,
|
||||||
_max_width: Option<f64>,
|
max_width: Option<f64>,
|
||||||
_is_rtl: bool,
|
is_rtl: bool,
|
||||||
) {
|
) {
|
||||||
// Step 2. Replace all ASCII whitespace in text with U+0020 SPACE characters.
|
// Step 2.
|
||||||
let text = replace_ascii_whitespace(text);
|
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
|
let point_size = self
|
||||||
.state
|
.state
|
||||||
.font_style
|
.font_style
|
||||||
|
@ -513,12 +514,18 @@ impl<'a> CanvasData<'a> {
|
||||||
.map_or(10., |style| style.font_size.size().px());
|
.map_or(10., |style| style.font_size.size().px());
|
||||||
let font_style = self.state.font_style.as_ref();
|
let font_style = self.state.font_style.as_ref();
|
||||||
let font = font_style.map_or_else(
|
let font = font_style.map_or_else(
|
||||||
|| load_system_font_from_style(font_style),
|
|| load_system_font_from_style(None),
|
||||||
|style| {
|
|style| {
|
||||||
with_thread_local_font_context(&self, |font_context| {
|
with_thread_local_font_context(&self, |font_context| {
|
||||||
let font_group = font_context.font_group(ServoArc::new(style.clone()));
|
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();
|
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() {
|
if let Some(bytes) = font.handle.template().bytes_if_in_memory() {
|
||||||
Font::from_bytes(Arc::new(bytes), 0)
|
Font::from_bytes(Arc::new(bytes), 0)
|
||||||
.unwrap_or_else(|_| load_system_font_from_style(Some(style)))
|
.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.
|
// Step 8.
|
||||||
let fill_style = self.state.fill_style.clone();
|
self.drawtarget.fill_text(
|
||||||
let draw_options = &self.state.draw_options;
|
&font,
|
||||||
self.drawtarget
|
point_size,
|
||||||
.fill_text(&font, point_size, &text, start, fill_style, draw_options);
|
&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>) {
|
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)]
|
#[derive(Clone)]
|
||||||
pub struct CanvasPaintState<'a> {
|
pub struct CanvasPaintState<'a> {
|
||||||
pub draw_options: DrawOptions,
|
pub draw_options: DrawOptions,
|
||||||
|
@ -1321,19 +1389,23 @@ fn load_system_font_from_style(font_style: Option<&FontStyleStruct>) -> Font {
|
||||||
.stretch(style.font_stretch.into());
|
.stretch(style.font_stretch.into());
|
||||||
let font_handle = match SystemSource::new().select_best_match(&family_names, &properties) {
|
let font_handle = match SystemSource::new().select_best_match(&family_names, &properties) {
|
||||||
Ok(handle) => handle,
|
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
|
font_handle.load().unwrap_or_else(|e| {
|
||||||
.load()
|
error!("error loading font for style {:?}: {}", style, e);
|
||||||
.unwrap_or_else(|_| load_default_system_fallback_font(&properties))
|
load_default_system_fallback_font(&properties)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_default_system_fallback_font(properties: &Properties) -> Font {
|
fn load_default_system_fallback_font(properties: &Properties) -> Font {
|
||||||
SystemSource::new()
|
SystemSource::new()
|
||||||
.select_best_match(&[FamilyName::SansSerif], properties)
|
.select_best_match(&[FamilyName::SansSerif], properties)
|
||||||
.unwrap()
|
.expect("error getting font handle for default system font")
|
||||||
.load()
|
.load()
|
||||||
.unwrap()
|
.expect("error loading default system font")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn replace_ascii_whitespace(text: String) -> String {
|
fn replace_ascii_whitespace(text: String) -> String {
|
||||||
|
@ -1344,3 +1416,18 @@ fn replace_ascii_whitespace(text: String) -> String {
|
||||||
})
|
})
|
||||||
.collect()
|
.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
|
||||||
|
}
|
||||||
|
|
|
@ -76,9 +76,6 @@ impl Backend for RaqoteBackend {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> CanvasPaintState<'a> {
|
impl<'a> CanvasPaintState<'a> {
|
||||||
pub const HANGING_BASELINE_DEFAULT: f32 = 0.8; // fraction of ascent
|
|
||||||
pub const IDEOGRAPHIC_BASELINE_DEFAULT: f32 = 0.5; // fraction descent
|
|
||||||
|
|
||||||
pub fn new(_antialias: AntialiasMode) -> CanvasPaintState<'a> {
|
pub fn new(_antialias: AntialiasMode) -> CanvasPaintState<'a> {
|
||||||
let pattern = Pattern::Color(255, 0, 0, 0);
|
let pattern = Pattern::Color(255, 0, 0, 0);
|
||||||
CanvasPaintState {
|
CanvasPaintState {
|
||||||
|
@ -92,8 +89,8 @@ impl<'a> CanvasPaintState<'a> {
|
||||||
shadow_blur: 0.0,
|
shadow_blur: 0.0,
|
||||||
shadow_color: Color::Raqote(raqote::SolidSource::from_unpremultiplied_argb(0, 0, 0, 0)),
|
shadow_color: Color::Raqote(raqote::SolidSource::from_unpremultiplied_argb(0, 0, 0, 0)),
|
||||||
font_style: None,
|
font_style: None,
|
||||||
text_align: Default::default(),
|
text_align: TextAlign::default(),
|
||||||
text_baseline: Default::default(),
|
text_baseline: TextBaseline::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -527,7 +524,7 @@ impl GenericDrawTarget for raqote::DrawTarget {
|
||||||
point_size: f32,
|
point_size: f32,
|
||||||
text: &str,
|
text: &str,
|
||||||
start: Point2D<f32>,
|
start: Point2D<f32>,
|
||||||
pattern: canvas_data::Pattern,
|
pattern: &canvas_data::Pattern,
|
||||||
options: &DrawOptions,
|
options: &DrawOptions,
|
||||||
) {
|
) {
|
||||||
self.draw_text(
|
self.draw_text(
|
||||||
|
|
|
@ -8,7 +8,7 @@ use ipc_channel::ipc::{IpcBytesReceiver, IpcBytesSender, IpcSender, IpcSharedMem
|
||||||
use serde_bytes::ByteBuf;
|
use serde_bytes::ByteBuf;
|
||||||
use std::default::Default;
|
use std::default::Default;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use style::properties::style_structs::Font;
|
use style::properties::style_structs::Font as FontStyleStruct;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||||
pub enum FillRule {
|
pub enum FillRule {
|
||||||
|
@ -71,7 +71,7 @@ pub enum Canvas2dMsg {
|
||||||
SetShadowOffsetY(f64),
|
SetShadowOffsetY(f64),
|
||||||
SetShadowBlur(f64),
|
SetShadowBlur(f64),
|
||||||
SetShadowColor(RGBA),
|
SetShadowColor(RGBA),
|
||||||
SetFont(Font),
|
SetFont(FontStyleStruct),
|
||||||
SetTextAlign(TextAlign),
|
SetTextAlign(TextAlign),
|
||||||
SetTextBaseline(TextBaseline),
|
SetTextBaseline(TextBaseline),
|
||||||
}
|
}
|
||||||
|
|
|
@ -387,3 +387,11 @@ pub fn process_element_inner_text_query<'dom>(_node: impl LayoutNode<'dom>) -> S
|
||||||
pub fn process_text_index_request(_node: OpaqueNode, _point: Point2D<Au>) -> TextIndexResponse {
|
pub fn process_text_index_request(_node: OpaqueNode, _point: Point2D<Au>) -> TextIndexResponse {
|
||||||
TextIndexResponse(None)
|
TextIndexResponse(None)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn process_resolved_font_style_query<'dom>(
|
||||||
|
_node: impl LayoutNode<'dom>,
|
||||||
|
_property: &PropertyId,
|
||||||
|
_value: &str,
|
||||||
|
) -> Option<ServoArc<Font>> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
|
@ -37,7 +37,8 @@ use layout::context::LayoutContext;
|
||||||
use layout::display_list::{DisplayListBuilder, WebRenderImageInfo};
|
use layout::display_list::{DisplayListBuilder, WebRenderImageInfo};
|
||||||
use layout::layout_debug;
|
use layout::layout_debug;
|
||||||
use layout::query::{
|
use layout::query::{
|
||||||
process_content_box_request, process_content_boxes_request, LayoutRPCImpl, LayoutThreadData,
|
process_content_box_request, process_content_boxes_request, process_resolved_font_style_query,
|
||||||
|
LayoutRPCImpl, LayoutThreadData,
|
||||||
};
|
};
|
||||||
use layout::query::{process_element_inner_text_query, process_node_geometry_request};
|
use layout::query::{process_element_inner_text_query, process_node_geometry_request};
|
||||||
use layout::query::{process_node_scroll_area_request, process_node_scroll_id_request};
|
use layout::query::{process_node_scroll_area_request, process_node_scroll_id_request};
|
||||||
|
@ -525,6 +526,7 @@ impl LayoutThread {
|
||||||
scroll_id_response: None,
|
scroll_id_response: None,
|
||||||
scroll_area_response: Rect::zero(),
|
scroll_area_response: Rect::zero(),
|
||||||
resolved_style_response: String::new(),
|
resolved_style_response: String::new(),
|
||||||
|
resolved_font_style_response: None,
|
||||||
offset_parent_response: OffsetParentResponse::empty(),
|
offset_parent_response: OffsetParentResponse::empty(),
|
||||||
scroll_offsets: HashMap::new(),
|
scroll_offsets: HashMap::new(),
|
||||||
text_index_response: TextIndexResponse(None),
|
text_index_response: TextIndexResponse(None),
|
||||||
|
@ -1209,7 +1211,11 @@ impl LayoutThread {
|
||||||
fragment_tree,
|
fragment_tree,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
&QueryMsg::ResolvedFontStyleQuery(_, _, _) => unimplemented!(),
|
&QueryMsg::ResolvedFontStyleQuery(node, ref property, ref value) => {
|
||||||
|
let node = unsafe { ServoLayoutNode::new(&node) };
|
||||||
|
rw_data.resolved_font_style_response =
|
||||||
|
process_resolved_font_style_query(node, property, value);
|
||||||
|
},
|
||||||
&QueryMsg::OffsetParentQuery(node) => {
|
&QueryMsg::OffsetParentQuery(node) => {
|
||||||
rw_data.offset_parent_response = process_offset_parent_query(node);
|
rw_data.offset_parent_response = process_offset_parent_query(node);
|
||||||
},
|
},
|
||||||
|
|
|
@ -1021,7 +1021,13 @@ impl CanvasState {
|
||||||
if self.state.borrow().font_style.is_none() {
|
if self.state.borrow().font_style.is_none() {
|
||||||
self.set_font(canvas, CanvasContextState::DEFAULT_FONT_STYLE.into())
|
self.set_font(canvas, CanvasContextState::DEFAULT_FONT_STYLE.into())
|
||||||
}
|
}
|
||||||
let is_rtl = false; // TODO: resolve is_rtl wrt to canvas element
|
|
||||||
|
let is_rtl = match self.state.borrow().direction {
|
||||||
|
Direction::Ltr => false,
|
||||||
|
Direction::Rtl => true,
|
||||||
|
Direction::Inherit => false, // TODO: resolve direction wrt to canvas element
|
||||||
|
};
|
||||||
|
|
||||||
let style = self.state.borrow().fill_style.to_fill_or_stroke_style();
|
let style = self.state.borrow().fill_style.to_fill_or_stroke_style();
|
||||||
self.send_canvas_2d_msg(Canvas2dMsg::FillText(
|
self.send_canvas_2d_msg(Canvas2dMsg::FillText(
|
||||||
text.into(),
|
text.into(),
|
||||||
|
@ -1046,7 +1052,7 @@ impl CanvasState {
|
||||||
pub fn set_font(&self, canvas: Option<&HTMLCanvasElement>, value: DOMString) {
|
pub fn set_font(&self, canvas: Option<&HTMLCanvasElement>, value: DOMString) {
|
||||||
let canvas = match canvas {
|
let canvas = match canvas {
|
||||||
Some(element) => element,
|
Some(element) => element,
|
||||||
None => return,
|
None => return, // offscreen canvas doesn't have a placeholder canvas
|
||||||
};
|
};
|
||||||
let node = canvas.upcast::<Node>();
|
let node = canvas.upcast::<Node>();
|
||||||
let window = window_from_node(&*canvas);
|
let window = window_from_node(&*canvas);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue