diff options
author | bors-servo <servo-ops@mozilla.com> | 2020-06-12 13:43:51 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-06-12 13:43:51 -0400 |
commit | 721271dcd3c20db5ca8cf146e2b5907647afb4d6 (patch) | |
tree | 75360f129a6172fd64040d46d88bdc2a8b0f66d0 | |
parent | cb92a15600771a69a796f88975d8100f4be296ae (diff) | |
parent | 502f34a9db36202cd89f7a1b48bd138d2ce6f46e (diff) | |
download | servo-721271dcd3c20db5ca8cf146e2b5907647afb4d6.tar.gz servo-721271dcd3c20db5ca8cf146e2b5907647afb4d6.zip |
Auto merge of #26697 - utsavoza:ugo/issue-11681/22-05-2020, r=jdm
Implement CanvasRenderingContext2d.fillText
The PR consists of broadly two main changes:
- Implementation of Canvas2dRenderingContext.font
- Basic implementation of Canvas2dRenderingContext.fillText
Although I am not fully sure about the long term goals for the canvas backend in Servo, I assumed limited scope for font and text handling (should support simple text drawing with font selection) in the current implementation as I believe a more complete implementation would eventually be brought in as a part of #22957.
---
- [x] `./mach build -d` does not report any errors
- [x] `./mach test-tidy` does not report any errors
- [x] These changes fix #11681
- [x] There are tests for these changes
57 files changed, 928 insertions, 183 deletions
diff --git a/Cargo.lock b/Cargo.lock index 4765c9e5262..ac468c29aa1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -504,6 +504,8 @@ dependencies = [ "cssparser", "euclid", "fnv", + "font-kit", + "gfx", "gleam 0.11.0", "half", "ipc-channel", @@ -512,8 +514,10 @@ dependencies = [ "num-traits", "pixels", "raqote", + "servo_arc", "servo_config", "sparkle", + "style", "surfman", "surfman-chains", "surfman-chains-api", @@ -541,6 +545,7 @@ dependencies = [ "serde_bytes", "servo_config", "sparkle", + "style", "time", "webrender_api", "webxr-api", @@ -5429,6 +5434,7 @@ dependencies = [ "encoding_rs", "euclid", "fallible", + "font-kit", "fxhash", "hashglobe", "html5ever", diff --git a/components/canvas/Cargo.toml b/components/canvas/Cargo.toml index 5486dc4c9ea..7285776ddec 100644 --- a/components/canvas/Cargo.toml +++ b/components/canvas/Cargo.toml @@ -22,7 +22,9 @@ canvas_traits = { path = "../canvas_traits" } crossbeam-channel = "0.4" cssparser = "0.27" euclid = "0.20" +font-kit = "0.7" fnv = "1.0" +gfx = { path = "../gfx" } gleam = "0.11" half = "1" ipc-channel = "0.14" @@ -30,9 +32,11 @@ log = "0.4" lyon_geom = "0.14" num-traits = "0.2" pixels = { path = "../pixels" } -raqote = "0.8" +raqote = { version = "0.8", features = ["text"] } +servo_arc = { path = "../servo_arc" } servo_config = { path = "../config" } sparkle = "0.1.24" +style = { path = "../style" } # NOTE: the sm-angle feature only enables ANGLE on Windows, not other platforms! surfman = { version = "0.2", features = ["sm-angle", "sm-angle-default"] } surfman-chains = "0.3" diff --git a/components/canvas/canvas_data.rs b/components/canvas/canvas_data.rs index 33da592c235..402c2690257 100644 --- a/components/canvas/canvas_data.rs +++ b/components/canvas/canvas_data.rs @@ -7,12 +7,24 @@ use crate::raqote_backend::Repetition; use canvas_traits::canvas::*; use cssparser::RGBA; use euclid::default::{Point2D, Rect, Size2D, Transform2D, Vector2D}; +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; +use gfx::font_cache_thread::FontCacheThread; +use gfx::font_context::FontContext; use ipc_channel::ipc::{IpcSender, IpcSharedMemory}; use num_traits::ToPrimitive; +use servo_arc::Arc as ServoArc; +use std::cell::RefCell; #[allow(unused_imports)] use std::marker::PhantomData; use std::mem; -use std::sync::Arc; +use std::sync::{Arc, Mutex}; +use style::properties::style_structs::Font as FontStyleStruct; use webrender_api::units::RectExt as RectExt_; /// The canvas data stores a state machine for the current status of @@ -264,6 +276,15 @@ pub trait GenericDrawTarget { operator: CompositionOp, ); fn fill(&mut self, path: &Path, pattern: Pattern, draw_options: &DrawOptions); + fn fill_text( + &mut self, + font: &Font, + point_size: f32, + text: &str, + start: Point2D<f32>, + pattern: &Pattern, + draw_options: &DrawOptions, + ); fn fill_rect(&mut self, rect: &Rect<f32>, pattern: Pattern, draw_options: Option<&DrawOptions>); fn get_format(&self) -> SurfaceFormat; fn get_size(&self) -> Size2D<i32>; @@ -360,6 +381,21 @@ pub enum Filter { Point, } +pub(crate) type CanvasFontContext = FontContext<FontCacheThread>; + +thread_local!(static FONT_CONTEXT: RefCell<Option<CanvasFontContext>> = RefCell::new(None)); + +pub(crate) fn with_thread_local_font_context<F, R>(canvas_data: &CanvasData, f: F) -> R +where + F: FnOnce(&mut CanvasFontContext) -> R, +{ + FONT_CONTEXT.with(|font_context| { + f(font_context.borrow_mut().get_or_insert_with(|| { + FontContext::new(canvas_data.font_cache_thread.lock().unwrap().clone()) + })) + }) +} + pub struct CanvasData<'a> { backend: Box<dyn Backend>, drawtarget: Box<dyn GenericDrawTarget>, @@ -372,7 +408,7 @@ pub struct CanvasData<'a> { old_image_key: Option<webrender_api::ImageKey>, /// An old webrender image key that can be deleted when the current epoch ends. very_old_image_key: Option<webrender_api::ImageKey>, - pub canvas_id: CanvasId, + font_cache_thread: Mutex<FontCacheThread>, } fn create_backend() -> Box<dyn Backend> { @@ -384,7 +420,7 @@ impl<'a> CanvasData<'a> { size: Size2D<u64>, webrender_api: Box<dyn WebrenderApi>, antialias: AntialiasMode, - canvas_id: CanvasId, + font_cache_thread: FontCacheThread, ) -> CanvasData<'a> { let backend = create_backend(); let draw_target = backend.create_drawtarget(size); @@ -398,7 +434,7 @@ impl<'a> CanvasData<'a> { image_key: None, old_image_key: None, very_old_image_key: None, - canvas_id: canvas_id, + font_cache_thread: Mutex::new(font_cache_thread), } } @@ -456,11 +492,114 @@ impl<'a> CanvasData<'a> { } } - pub fn fill_text(&self, text: String, x: f64, y: f64, max_width: Option<f64>) { - error!( - "Unimplemented canvas2d.fillText. Values received: {}, {}, {}, {:?}.", - text, x, y, max_width + // https://html.spec.whatwg.org/multipage/#text-preparation-algorithm + pub fn fill_text( + &mut self, + text: String, + x: f64, + y: f64, + max_width: Option<f64>, + is_rtl: bool, + ) { + // Step 2. + let text = replace_ascii_whitespace(text); + + // Step 3. + let point_size = self + .state + .font_style + .as_ref() + .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(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("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))) + } else { + load_system_font_from_style(Some(style)) + } + }) + }, + ); + let font_width = font_width(&text, point_size, &font); + + // 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. + 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>) { @@ -1042,6 +1181,18 @@ impl<'a> CanvasData<'a> { self.backend.set_shadow_color(value, &mut self.state); } + pub fn set_font(&mut self, font_style: FontStyleStruct) { + self.state.font_style = Some(font_style) + } + + pub fn set_text_align(&mut self, text_align: TextAlign) { + self.state.text_align = text_align; + } + + pub fn set_text_baseline(&mut self, text_baseline: TextBaseline) { + self.state.text_baseline = text_baseline; + } + // https://html.spec.whatwg.org/multipage/#when-shadows-are-drawn fn need_to_draw_shadow(&self) -> bool { self.backend.need_to_draw_shadow(&self.state.shadow_color) && @@ -1121,6 +1272,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, @@ -1133,6 +1287,9 @@ pub struct CanvasPaintState<'a> { pub shadow_offset_y: f64, pub shadow_blur: f64, pub shadow_color: Color, + pub font_style: Option<FontStyleStruct>, + pub text_align: TextAlign, + pub text_baseline: TextBaseline, } /// It writes an image to the destination target @@ -1214,3 +1371,64 @@ impl RectExt for Rect<u32> { self.cast() } } + +fn load_system_font_from_style(font_style: Option<&FontStyleStruct>) -> Font { + let mut properties = Properties::new(); + let style = match font_style { + Some(style) => style, + None => return load_default_system_fallback_font(&properties), + }; + let family_names = style + .font_family + .families + .iter() + .map(|family_name| family_name.into()) + .collect::<Vec<FamilyName>>(); + let properties = properties + .style(style.font_style.into()) + .weight(style.font_weight.into()) + .stretch(style.font_stretch.into()); + let font_handle = match SystemSource::new().select_best_match(&family_names, &properties) { + Ok(handle) => handle, + Err(e) => { + error!("error getting font handle for style {:?}: {}", style, e); + return 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) + .expect("error getting font handle for default system font") + .load() + .expect("error loading default system font") +} + +fn replace_ascii_whitespace(text: String) -> String { + text.chars() + .map(|c| match c { + ' ' | '\t' | '\n' | '\r' | '\x0C' => '\x20', + _ => c, + }) + .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 +} diff --git a/components/canvas/canvas_paint_thread.rs b/components/canvas/canvas_paint_thread.rs index 3c6bbfb53a8..b426d398a72 100644 --- a/components/canvas/canvas_paint_thread.rs +++ b/components/canvas/canvas_paint_thread.rs @@ -7,6 +7,7 @@ use canvas_traits::canvas::*; use canvas_traits::ConstellationCanvasMsg; use crossbeam_channel::{select, unbounded, Sender}; use euclid::default::Size2D; +use gfx::font_cache_thread::FontCacheThread; use ipc_channel::ipc::{self, IpcSender}; use ipc_channel::router::ROUTER; use std::borrow::ToOwned; @@ -35,14 +36,19 @@ pub struct CanvasPaintThread<'a> { canvases: HashMap<CanvasId, CanvasData<'a>>, next_canvas_id: CanvasId, webrender_api: Box<dyn WebrenderApi>, + font_cache_thread: FontCacheThread, } impl<'a> CanvasPaintThread<'a> { - fn new(webrender_api: Box<dyn WebrenderApi>) -> CanvasPaintThread<'a> { + fn new( + webrender_api: Box<dyn WebrenderApi>, + font_cache_thread: FontCacheThread, + ) -> CanvasPaintThread<'a> { CanvasPaintThread { canvases: HashMap::new(), next_canvas_id: CanvasId(0), webrender_api, + font_cache_thread, } } @@ -50,6 +56,7 @@ impl<'a> CanvasPaintThread<'a> { /// communicate with it. pub fn start( webrender_api: Box<dyn WebrenderApi + Send>, + font_cache_thread: FontCacheThread, ) -> (Sender<ConstellationCanvasMsg>, IpcSender<CanvasMsg>) { let (ipc_sender, ipc_receiver) = ipc::channel::<CanvasMsg>().unwrap(); let msg_receiver = ROUTER.route_ipc_receiver_to_new_crossbeam_receiver(ipc_receiver); @@ -57,7 +64,7 @@ impl<'a> CanvasPaintThread<'a> { thread::Builder::new() .name("CanvasThread".to_owned()) .spawn(move || { - let mut canvas_paint_thread = CanvasPaintThread::new(webrender_api); + let mut canvas_paint_thread = CanvasPaintThread::new(webrender_api, font_cache_thread); loop { select! { recv(msg_receiver) -> msg => { @@ -118,6 +125,8 @@ impl<'a> CanvasPaintThread<'a> { AntialiasMode::None }; + let font_cache_thread = self.font_cache_thread.clone(); + let canvas_id = self.next_canvas_id.clone(); self.next_canvas_id.0 += 1; @@ -125,7 +134,7 @@ impl<'a> CanvasPaintThread<'a> { size, self.webrender_api.clone(), antialias, - canvas_id.clone(), + font_cache_thread, ); self.canvases.insert(canvas_id.clone(), canvas_data); @@ -134,9 +143,10 @@ impl<'a> CanvasPaintThread<'a> { fn process_canvas_2d_message(&mut self, message: Canvas2dMsg, canvas_id: CanvasId) { match message { - Canvas2dMsg::FillText(text, x, y, max_width, style) => { + Canvas2dMsg::FillText(text, x, y, max_width, style, is_rtl) => { self.canvas(canvas_id).set_fill_style(style); - self.canvas(canvas_id).fill_text(text, x, y, max_width); + self.canvas(canvas_id) + .fill_text(text, x, y, max_width, is_rtl); }, Canvas2dMsg::FillRect(rect, style) => { self.canvas(canvas_id).set_fill_style(style); @@ -247,6 +257,13 @@ impl<'a> CanvasPaintThread<'a> { }, Canvas2dMsg::SetShadowBlur(value) => self.canvas(canvas_id).set_shadow_blur(value), Canvas2dMsg::SetShadowColor(color) => self.canvas(canvas_id).set_shadow_color(color), + Canvas2dMsg::SetFont(font_style) => self.canvas(canvas_id).set_font(font_style), + Canvas2dMsg::SetTextAlign(text_align) => { + self.canvas(canvas_id).set_text_align(text_align) + }, + Canvas2dMsg::SetTextBaseline(text_baseline) => { + self.canvas(canvas_id).set_text_baseline(text_baseline) + }, } } diff --git a/components/canvas/raqote_backend.rs b/components/canvas/raqote_backend.rs index 72eae8b40c8..5f39a1260b3 100644 --- a/components/canvas/raqote_backend.rs +++ b/components/canvas/raqote_backend.rs @@ -13,6 +13,7 @@ use canvas_traits::canvas::*; use cssparser::RGBA; use euclid::default::{Point2D, Rect, Size2D, Transform2D, Vector2D}; use euclid::Angle; +use font_kit::font::Font; use lyon_geom::Arc; use raqote::PathOp; use std::marker::PhantomData; @@ -87,6 +88,9 @@ impl<'a> CanvasPaintState<'a> { shadow_offset_y: 0.0, shadow_blur: 0.0, shadow_color: Color::Raqote(raqote::SolidSource::from_unpremultiplied_argb(0, 0, 0, 0)), + font_style: None, + text_align: TextAlign::default(), + text_baseline: TextBaseline::default(), } } } @@ -513,6 +517,26 @@ impl GenericDrawTarget for raqote::DrawTarget { ), } } + + fn fill_text( + &mut self, + font: &Font, + point_size: f32, + text: &str, + start: Point2D<f32>, + pattern: &canvas_data::Pattern, + options: &DrawOptions, + ) { + self.draw_text( + font, + point_size, + text, + start, + &pattern.source(), + options.as_raqote(), + ); + } + fn fill_rect( &mut self, rect: &Rect<f32>, diff --git a/components/canvas_traits/Cargo.toml b/components/canvas_traits/Cargo.toml index 0625221a484..8414349939c 100644 --- a/components/canvas_traits/Cargo.toml +++ b/components/canvas_traits/Cargo.toml @@ -27,6 +27,7 @@ serde = "1.0" serde_bytes = "0.11" servo_config = { path = "../config" } sparkle = "0.1" +style = { path = "../style" } time = { version = "0.1.0", optional = true } webrender_api = { git = "https://github.com/servo/webrender" } webxr-api = { git = "https://github.com/servo/webxr", features = ["ipc"] } diff --git a/components/canvas_traits/canvas.rs b/components/canvas_traits/canvas.rs index 13fc6eaa800..f302aaa8e3e 100644 --- a/components/canvas_traits/canvas.rs +++ b/components/canvas_traits/canvas.rs @@ -8,6 +8,7 @@ use ipc_channel::ipc::{IpcBytesReceiver, IpcBytesSender, IpcSender, IpcSharedMem use serde_bytes::ByteBuf; use std::default::Default; use std::str::FromStr; +use style::properties::style_structs::Font as FontStyleStruct; #[derive(Clone, Debug, Deserialize, Serialize)] pub enum FillRule { @@ -45,7 +46,7 @@ pub enum Canvas2dMsg { ClosePath, Ellipse(Point2D<f32>, f32, f32, f32, f32, f32, bool), Fill(FillOrStrokeStyle), - FillText(String, f64, f64, Option<f64>, FillOrStrokeStyle), + FillText(String, f64, f64, Option<f64>, FillOrStrokeStyle, bool), FillRect(Rect<f32>, FillOrStrokeStyle), GetImageData(Rect<u64>, Size2D<u64>, IpcBytesSender), GetTransform(IpcSender<Transform2D<f32>>), @@ -70,6 +71,9 @@ pub enum Canvas2dMsg { SetShadowOffsetY(f64), SetShadowBlur(f64), SetShadowColor(RGBA), + SetFont(FontStyleStruct), + SetTextAlign(TextAlign), + SetTextBaseline(TextBaseline), } #[derive(Clone, Debug, Deserialize, Serialize)] @@ -392,3 +396,91 @@ impl FromStr for CompositionOrBlending { Err(()) } } + +#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize)] +pub enum TextAlign { + Start, + End, + Left, + Right, + Center, +} + +impl FromStr for TextAlign { + type Err = (); + + fn from_str(string: &str) -> Result<TextAlign, ()> { + match string { + "start" => Ok(TextAlign::Start), + "end" => Ok(TextAlign::End), + "left" => Ok(TextAlign::Left), + "right" => Ok(TextAlign::Right), + "center" => Ok(TextAlign::Center), + _ => Err(()), + } + } +} + +impl Default for TextAlign { + fn default() -> TextAlign { + TextAlign::Start + } +} + +#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize)] +pub enum TextBaseline { + Top, + Hanging, + Middle, + Alphabetic, + Ideographic, + Bottom, +} + +impl FromStr for TextBaseline { + type Err = (); + + fn from_str(string: &str) -> Result<TextBaseline, ()> { + match string { + "top" => Ok(TextBaseline::Top), + "hanging" => Ok(TextBaseline::Hanging), + "middle" => Ok(TextBaseline::Middle), + "alphabetic" => Ok(TextBaseline::Alphabetic), + "ideographic" => Ok(TextBaseline::Ideographic), + "bottom" => Ok(TextBaseline::Bottom), + _ => Err(()), + } + } +} + +impl Default for TextBaseline { + fn default() -> TextBaseline { + TextBaseline::Alphabetic + } +} + +#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize)] +pub enum Direction { + Ltr, + Rtl, + Inherit, +} + +impl FromStr for Direction { + type Err = (); + + fn from_str(string: &str) -> Result<Direction, ()> { + match string { + "ltr" => Ok(Direction::Ltr), + "rtl" => Ok(Direction::Rtl), + "inherit" => Ok(Direction::Inherit), + _ => Err(()), + } + } +} + +impl Default for Direction { + fn default() -> Direction { + Direction::Inherit + } +} diff --git a/components/layout/query.rs b/components/layout/query.rs index a5f66cb9dcd..56b1fc7d0f8 100644 --- a/components/layout/query.rs +++ b/components/layout/query.rs @@ -29,18 +29,25 @@ use script_layout_interface::wrapper_traits::{ use script_layout_interface::{LayoutElementType, LayoutNodeType}; use script_traits::LayoutMsg as ConstellationMsg; use script_traits::UntrustedNodeAddress; +use servo_arc::Arc as ServoArc; +use servo_url::ServoUrl; use std::cmp::{max, min}; use std::ops::Deref; use std::sync::{Arc, Mutex}; use style::computed_values::display::T as Display; use style::computed_values::position::T as Position; use style::computed_values::visibility::T as Visibility; -use style::context::{StyleContext, ThreadLocalStyleContext}; +use style::context::{QuirksMode, SharedStyleContext, StyleContext, ThreadLocalStyleContext}; use style::dom::TElement; use style::logical_geometry::{BlockFlowDirection, InlineBaseDirection, WritingMode}; -use style::properties::{style_structs, LonghandId, PropertyDeclarationId, PropertyId}; +use style::properties::style_structs::{self, Font}; +use style::properties::{ + parse_one_declaration_into, ComputedValues, Importance, LonghandId, PropertyDeclarationBlock, + PropertyDeclarationId, PropertyId, SourcePropertyDeclaration, +}; use style::selector_parser::PseudoElement; -use style_traits::{CSSPixel, ToCss}; +use style::shared_lock::SharedRwLock; +use style_traits::{CSSPixel, ParsingMode, ToCss}; use webrender_api::ExternalScrollId; /// Mutable data belonging to the LayoutThread. @@ -73,6 +80,9 @@ pub struct LayoutThreadData { /// A queued response for the resolved style property of an element. pub resolved_style_response: String, + /// A queued response for the resolved font style for canvas. + pub resolved_font_style_response: Option<ServoArc<Font>>, + /// A queued response for the offset parent/rect of a node. pub offset_parent_response: OffsetParentResponse, @@ -170,6 +180,12 @@ impl LayoutRPC for LayoutRPCImpl { ResolvedStyleResponse(rw_data.resolved_style_response.clone()) } + fn resolved_font_style(&self) -> Option<ServoArc<Font>> { + let &LayoutRPCImpl(ref rw_data) = self; + let rw_data = rw_data.lock().unwrap(); + rw_data.resolved_font_style_response.clone() + } + fn offset_parent(&self) -> OffsetParentResponse { let &LayoutRPCImpl(ref rw_data) = self; let rw_data = rw_data.lock().unwrap(); @@ -735,6 +751,112 @@ pub fn process_node_scroll_area_request( } } +fn create_font_declaration( + value: &str, + property: &PropertyId, + url_data: &ServoUrl, + quirks_mode: QuirksMode, +) -> Option<PropertyDeclarationBlock> { + let mut declarations = SourcePropertyDeclaration::new(); + let result = parse_one_declaration_into( + &mut declarations, + property.clone(), + value, + url_data, + None, + ParsingMode::DEFAULT, + quirks_mode, + ); + let declarations = match result { + Ok(()) => { + let mut block = PropertyDeclarationBlock::new(); + block.extend(declarations.drain(), Importance::Normal); + block + }, + Err(_) => return None, + }; + // TODO: Force to set line-height property to 'normal' font property. + Some(declarations) +} + +fn resolve_for_declarations<'dom, E>( + context: &SharedStyleContext, + parent_style: Option<&ComputedValues>, + declarations: PropertyDeclarationBlock, + shared_lock: &SharedRwLock, +) -> ServoArc<ComputedValues> +where + E: LayoutNode<'dom>, +{ + let parent_style = match parent_style { + Some(parent) => &*parent, + None => context.stylist.device().default_computed_values(), + }; + context + .stylist + .compute_for_declarations::<E::ConcreteElement>( + &context.guards, + &*parent_style, + ServoArc::new(shared_lock.wrap(declarations)), + ) +} + +pub fn process_resolved_font_style_request<'dom, E>( + context: &LayoutContext, + node: E, + value: &str, + property: &PropertyId, + url_data: ServoUrl, + shared_lock: &SharedRwLock, +) -> Option<ServoArc<Font>> +where + E: LayoutNode<'dom>, +{ + use style::stylist::RuleInclusion; + use style::traversal::resolve_style; + + // 1. Parse the given font property value + let quirks_mode = context.style_context.quirks_mode(); + let declarations = create_font_declaration(value, property, &url_data, quirks_mode)?; + + // TODO: Reject 'inherit' and 'initial' values for the font property. + + // 2. Get resolved styles for the parent element + let element = node.as_element().unwrap(); + let parent_style = if node.is_connected() { + if element.has_data() { + node.to_threadsafe().as_element().unwrap().resolved_style() + } else { + let mut tlc = ThreadLocalStyleContext::new(&context.style_context); + let mut context = StyleContext { + shared: &context.style_context, + thread_local: &mut tlc, + }; + let styles = resolve_style(&mut context, element, RuleInclusion::All, None); + styles.primary().clone() + } + } else { + let default_declarations = + create_font_declaration("10px sans-serif", property, &url_data, quirks_mode).unwrap(); + resolve_for_declarations::<E>( + &context.style_context, + None, + default_declarations, + shared_lock, + ) + }; + + // 3. Resolve the parsed value with resolved styles of the parent element + let computed_values = resolve_for_declarations::<E>( + &context.style_context, + Some(&*parent_style), + declarations, + shared_lock, + ); + + Some(computed_values.clone_font()) +} + /// Return the resolved value of property for a given (pseudo)element. /// <https://drafts.csswg.org/cssom/#resolved-value> pub fn process_resolved_style_request<'dom>( diff --git a/components/layout_2020/query.rs b/components/layout_2020/query.rs index 4b895025e11..6df2e789e64 100644 --- a/components/layout_2020/query.rs +++ b/components/layout_2020/query.rs @@ -21,12 +21,14 @@ use script_layout_interface::wrapper_traits::{ }; use script_traits::LayoutMsg as ConstellationMsg; use script_traits::UntrustedNodeAddress; +use servo_arc::Arc as ServoArc; use std::collections::HashMap; use std::sync::{Arc, Mutex}; use style::computed_values::position::T as Position; use style::context::{StyleContext, ThreadLocalStyleContext}; use style::dom::OpaqueNode; use style::dom::TElement; +use style::properties::style_structs::Font; use style::properties::{LonghandId, PropertyDeclarationId, PropertyId}; use style::selector_parser::PseudoElement; use style::stylist::RuleInclusion; @@ -65,6 +67,9 @@ pub struct LayoutThreadData { /// A queued response for the resolved style property of an element. pub resolved_style_response: String, + /// A queued response for the resolved font style for canvas. + pub resolved_font_style_response: Option<ServoArc<Font>>, + /// A queued response for the offset parent/rect of a node. pub offset_parent_response: OffsetParentResponse, @@ -139,6 +144,12 @@ impl LayoutRPC for LayoutRPCImpl { ResolvedStyleResponse(rw_data.resolved_style_response.clone()) } + fn resolved_font_style(&self) -> Option<ServoArc<Font>> { + let &LayoutRPCImpl(ref rw_data) = self; + let rw_data = rw_data.lock().unwrap(); + rw_data.resolved_font_style_response.clone() + } + fn offset_parent(&self) -> OffsetParentResponse { let &LayoutRPCImpl(ref rw_data) = self; let rw_data = rw_data.lock().unwrap(); @@ -376,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 { TextIndexResponse(None) } + +pub fn process_resolved_font_style_query<'dom>( + _node: impl LayoutNode<'dom>, + _property: &PropertyId, + _value: &str, +) -> Option<ServoArc<Font>> { + None +} diff --git a/components/layout_thread/lib.rs b/components/layout_thread/lib.rs index 6819027564c..14dbfc0c80e 100644 --- a/components/layout_thread/lib.rs +++ b/components/layout_thread/lib.rs @@ -49,12 +49,13 @@ use layout::flow_ref::FlowRef; use layout::incremental::{RelayoutMode, SpecialRestyleDamage}; use layout::layout_debug; use layout::parallel; -use layout::query::{process_client_rect_query, process_element_inner_text_query}; use layout::query::{ - process_content_box_request, process_content_boxes_request, LayoutRPCImpl, LayoutThreadData, + process_client_rect_query, process_content_box_request, process_content_boxes_request, + process_element_inner_text_query, process_node_scroll_area_request, + process_node_scroll_id_request, process_offset_parent_query, + process_resolved_font_style_request, process_resolved_style_request, LayoutRPCImpl, + LayoutThreadData, }; -use layout::query::{process_node_scroll_area_request, process_node_scroll_id_request}; -use layout::query::{process_offset_parent_query, process_resolved_style_request}; use layout::sequential; use layout::traversal::{ construct_flows_at_ancestors, ComputeStackingRelativePositions, PreorderFlowTraversal, @@ -558,6 +559,7 @@ impl LayoutThread { scroll_id_response: None, scroll_area_response: Rect::zero(), resolved_style_response: String::new(), + resolved_font_style_response: None, offset_parent_response: OffsetParentResponse::empty(), scroll_offsets: HashMap::new(), text_index_response: TextIndexResponse(None), @@ -1231,6 +1233,9 @@ impl LayoutThread { &QueryMsg::ElementInnerTextQuery(_) => { rw_data.element_inner_text_response = String::new(); }, + &QueryMsg::ResolvedFontStyleQuery(..) => { + rw_data.resolved_font_style_response = None; + }, &QueryMsg::InnerWindowDimensionsQuery(_) => { rw_data.inner_window_dimensions_response = None; }, @@ -1498,6 +1503,7 @@ impl LayoutThread { &mut *rw_data, &mut layout_context, data.result.borrow_mut().as_mut().unwrap(), + document_shared_lock, ); } @@ -1507,6 +1513,7 @@ impl LayoutThread { rw_data: &mut LayoutThreadData, context: &mut LayoutContext, reflow_result: &mut ReflowComplete, + shared_lock: &SharedRwLock, ) { reflow_result.pending_images = std::mem::replace(&mut *context.pending_images.lock().unwrap(), vec![]); @@ -1549,6 +1556,18 @@ impl LayoutThread { rw_data.resolved_style_response = process_resolved_style_request(context, node, pseudo, property, root_flow); }, + &QueryMsg::ResolvedFontStyleQuery(node, ref property, ref value) => { + let node = unsafe { ServoLayoutNode::new(&node) }; + let url = self.url.clone(); + rw_data.resolved_font_style_response = process_resolved_font_style_request( + context, + node, + value, + property, + url, + shared_lock, + ); + }, &QueryMsg::OffsetParentQuery(node) => { rw_data.offset_parent_response = process_offset_parent_query(node, root_flow); }, diff --git a/components/layout_thread_2020/lib.rs b/components/layout_thread_2020/lib.rs index 3bb0a7a3353..4ae69e6255a 100644 --- a/components/layout_thread_2020/lib.rs +++ b/components/layout_thread_2020/lib.rs @@ -37,7 +37,8 @@ use layout::context::LayoutContext; use layout::display_list::{DisplayListBuilder, WebRenderImageInfo}; use layout::layout_debug; 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_node_scroll_area_request, process_node_scroll_id_request}; @@ -525,6 +526,7 @@ impl LayoutThread { scroll_id_response: None, scroll_area_response: Rect::zero(), resolved_style_response: String::new(), + resolved_font_style_response: None, offset_parent_response: OffsetParentResponse::empty(), scroll_offsets: HashMap::new(), text_index_response: TextIndexResponse(None), @@ -914,6 +916,9 @@ impl LayoutThread { &QueryMsg::ResolvedStyleQuery(_, _, _) => { rw_data.resolved_style_response = String::new(); }, + &QueryMsg::ResolvedFontStyleQuery(_, _, _) => { + rw_data.resolved_font_style_response = None; + }, &QueryMsg::OffsetParentQuery(_) => { rw_data.offset_parent_response = OffsetParentResponse::empty(); }, @@ -1206,6 +1211,11 @@ impl LayoutThread { fragment_tree, ); }, + &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) => { rw_data.offset_parent_response = process_offset_parent_query(node); }, diff --git a/components/script/canvas_state.rs b/components/script/canvas_state.rs index 2376d6f8d85..0a6fba842e4 100644 --- a/components/script/canvas_state.rs +++ b/components/script/canvas_state.rs @@ -3,10 +3,13 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ use crate::dom::bindings::cell::DomRefCell; +use crate::dom::bindings::codegen::Bindings::CanvasRenderingContext2DBinding::CanvasDirection; use crate::dom::bindings::codegen::Bindings::CanvasRenderingContext2DBinding::CanvasFillRule; use crate::dom::bindings::codegen::Bindings::CanvasRenderingContext2DBinding::CanvasImageSource; use crate::dom::bindings::codegen::Bindings::CanvasRenderingContext2DBinding::CanvasLineCap; use crate::dom::bindings::codegen::Bindings::CanvasRenderingContext2DBinding::CanvasLineJoin; +use crate::dom::bindings::codegen::Bindings::CanvasRenderingContext2DBinding::CanvasTextAlign; +use crate::dom::bindings::codegen::Bindings::CanvasRenderingContext2DBinding::CanvasTextBaseline; use crate::dom::bindings::codegen::Bindings::ImageDataBinding::ImageDataMethods; use crate::dom::bindings::codegen::UnionTypes::StringOrCanvasGradientOrCanvasPattern; use crate::dom::bindings::error::{Error, ErrorResult, Fallible}; @@ -22,12 +25,12 @@ use crate::dom::element::Element; use crate::dom::globalscope::GlobalScope; use crate::dom::htmlcanvaselement::{CanvasContext, HTMLCanvasElement}; use crate::dom::imagedata::ImageData; -use crate::dom::node::{Node, NodeDamage}; +use crate::dom::node::{window_from_node, Node, NodeDamage}; use crate::dom::offscreencanvas::{OffscreenCanvas, OffscreenCanvasContext}; use crate::dom::paintworkletglobalscope::PaintWorkletGlobalScope; use crate::dom::textmetrics::TextMetrics; use crate::unpremultiplytable::UNPREMULTIPLY_TABLE; -use canvas_traits::canvas::{Canvas2dMsg, CanvasId, CanvasMsg}; +use canvas_traits::canvas::{Canvas2dMsg, CanvasId, CanvasMsg, Direction, TextAlign, TextBaseline}; use canvas_traits::canvas::{CompositionOrBlending, FillOrStrokeStyle, FillRule}; use canvas_traits::canvas::{LineCapStyle, LineJoinStyle, LinearGradientStyle}; use canvas_traits::canvas::{RadialGradientStyle, RepetitionStyle}; @@ -49,6 +52,10 @@ use std::cell::Cell; use std::fmt; use std::str::FromStr; use std::sync::Arc; +use style::properties::longhands::font_variant_caps::computed_value::T as FontVariantCaps; +use style::properties::style_structs::Font; +use style::values::computed::font::FontStyle; +use style_traits::values::ToCss; #[unrooted_must_root_lint::must_root] #[derive(Clone, JSTraceable, MallocSizeOf)] @@ -86,9 +93,15 @@ pub(crate) struct CanvasContextState { shadow_offset_y: f64, shadow_blur: f64, shadow_color: RGBA, + font_style: Option<Font>, + text_align: TextAlign, + text_baseline: TextBaseline, + direction: Direction, } impl CanvasContextState { + const DEFAULT_FONT_STYLE: &'static str = "10px sans-serif"; + pub(crate) fn new() -> CanvasContextState { let black = RGBA::new(0, 0, 0, 255); CanvasContextState { @@ -106,6 +119,10 @@ impl CanvasContextState { shadow_offset_y: 0.0, shadow_blur: 0.0, shadow_color: RGBA::transparent(), + font_style: None, + text_align: Default::default(), + text_baseline: Default::default(), + direction: Default::default(), } } } @@ -987,10 +1004,39 @@ impl CanvasState { } // https://html.spec.whatwg.org/multipage/#dom-context-2d-filltext - pub fn fill_text(&self, text: DOMString, x: f64, y: f64, max_width: Option<f64>) { - let parsed_text: String = text.into(); + pub fn fill_text( + &self, + canvas: Option<&HTMLCanvasElement>, + text: DOMString, + x: f64, + y: f64, + max_width: Option<f64>, + ) { + if !x.is_finite() || !y.is_finite() { + return; + } + if max_width.map_or(false, |max_width| !max_width.is_finite() || max_width <= 0.) { + return; + } + if self.state.borrow().font_style.is_none() { + self.set_font(canvas, CanvasContextState::DEFAULT_FONT_STYLE.into()) + } + + 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(); - self.send_canvas_2d_msg(Canvas2dMsg::FillText(parsed_text, x, y, max_width, style)); + self.send_canvas_2d_msg(Canvas2dMsg::FillText( + text.into(), + x, + y, + max_width, + style, + is_rtl, + )); } // https://html.spec.whatwg.org/multipage/#textmetrics @@ -1002,6 +1048,101 @@ impl CanvasState { ) } + // https://html.spec.whatwg.org/multipage/#dom-context-2d-font + pub fn set_font(&self, canvas: Option<&HTMLCanvasElement>, value: DOMString) { + let canvas = match canvas { + Some(element) => element, + None => return, // offscreen canvas doesn't have a placeholder canvas + }; + let node = canvas.upcast::<Node>(); + let window = window_from_node(&*canvas); + let resolved_font_style = match window.resolved_font_style_query(&node, value.to_string()) { + Some(value) => value, + None => return, // syntax error + }; + self.state.borrow_mut().font_style = Some((*resolved_font_style).clone()); + self.send_canvas_2d_msg(Canvas2dMsg::SetFont((*resolved_font_style).clone())); + } + + // https://html.spec.whatwg.org/multipage/#dom-context-2d-font + pub fn font(&self) -> DOMString { + self.state.borrow().font_style.as_ref().map_or_else( + || CanvasContextState::DEFAULT_FONT_STYLE.into(), + |style| { + let mut result = String::new(); + serialize_font(style, &mut result).unwrap(); + DOMString::from(result) + }, + ) + } + + // https://html.spec.whatwg.org/multipage/#dom-context-2d-textalign + pub fn text_align(&self) -> CanvasTextAlign { + match self.state.borrow().text_align { + TextAlign::Start => CanvasTextAlign::Start, + TextAlign::End => CanvasTextAlign::End, + TextAlign::Left => CanvasTextAlign::Left, + TextAlign::Right => CanvasTextAlign::Right, + TextAlign::Center => CanvasTextAlign::Center, + } + } + + // https://html.spec.whatwg.org/multipage/#dom-context-2d-textalign + pub fn set_text_align(&self, value: CanvasTextAlign) { + let text_align = match value { + CanvasTextAlign::Start => TextAlign::Start, + CanvasTextAlign::End => TextAlign::End, + CanvasTextAlign::Left => TextAlign::Left, + CanvasTextAlign::Right => TextAlign::Right, + CanvasTextAlign::Center => TextAlign::Center, + }; + self.state.borrow_mut().text_align = text_align; + self.send_canvas_2d_msg(Canvas2dMsg::SetTextAlign(text_align)); + } + + pub fn text_baseline(&self) -> CanvasTextBaseline { + match self.state.borrow().text_baseline { + TextBaseline::Top => CanvasTextBaseline::Top, + TextBaseline::Hanging => CanvasTextBaseline::Hanging, + TextBaseline::Middle => CanvasTextBaseline::Middle, + TextBaseline::Alphabetic => CanvasTextBaseline::Alphabetic, + TextBaseline::Ideographic => CanvasTextBaseline::Ideographic, + TextBaseline::Bottom => CanvasTextBaseline::Bottom, + } + } + + pub fn set_text_baseline(&self, value: CanvasTextBaseline) { + let text_baseline = match value { + CanvasTextBaseline::Top => TextBaseline::Top, + CanvasTextBaseline::Hanging => TextBaseline::Hanging, + CanvasTextBaseline::Middle => TextBaseline::Middle, + CanvasTextBaseline::Alphabetic => TextBaseline::Alphabetic, + CanvasTextBaseline::Ideographic => TextBaseline::Ideographic, + CanvasTextBaseline::Bottom => TextBaseline::Bottom, + }; + self.state.borrow_mut().text_baseline = text_baseline; + self.send_canvas_2d_msg(Canvas2dMsg::SetTextBaseline(text_baseline)); + } + + // https://html.spec.whatwg.org/multipage/#dom-context-2d-direction + pub fn direction(&self) -> CanvasDirection { + match self.state.borrow().direction { + Direction::Ltr => CanvasDirection::Ltr, + Direction::Rtl => CanvasDirection::Rtl, + Direction::Inherit => CanvasDirection::Inherit, + } + } + + // https://html.spec.whatwg.org/multipage/#dom-context-2d-direction + pub fn set_direction(&self, value: CanvasDirection) { + let direction = match value { + CanvasDirection::Ltr => Direction::Ltr, + CanvasDirection::Rtl => Direction::Rtl, + CanvasDirection::Inherit => Direction::Inherit, + }; + self.state.borrow_mut().direction = direction; + } + // https://html.spec.whatwg.org/multipage/#dom-context-2d-linewidth pub fn line_width(&self) -> f64 { self.state.borrow().line_width @@ -1627,3 +1768,24 @@ pub fn adjust_size_sign( } (origin, size.to_u32()) } + +fn serialize_font<W>(style: &Font, dest: &mut W) -> fmt::Result +where + W: fmt::Write, +{ + if style.font_style == FontStyle::Italic { + write!(dest, "{} ", style.font_style.to_css_string())?; + } + if style.font_weight.is_bold() { + write!(dest, "{} ", style.font_weight.to_css_string())?; + } + if style.font_variant_caps == FontVariantCaps::SmallCaps { + write!(dest, "{} ", style.font_variant_caps.to_css_string())?; + } + write!( + dest, + "{} {}", + style.font_size.to_css_string(), + style.font_family.to_css_string() + ) +} diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs index 1f6d15a191a..9518a2c0989 100644 --- a/components/script/dom/bindings/trace.rs +++ b/components/script/dom/bindings/trace.rs @@ -47,7 +47,10 @@ use app_units::Au; use canvas_traits::canvas::{ CanvasGradientStop, CanvasId, LinearGradientStyle, RadialGradientStyle, }; -use canvas_traits::canvas::{CompositionOrBlending, LineCapStyle, LineJoinStyle, RepetitionStyle}; +use canvas_traits::canvas::{ + CompositionOrBlending, Direction, LineCapStyle, LineJoinStyle, RepetitionStyle, TextAlign, + TextBaseline, +}; use canvas_traits::webgl::WebGLVertexArrayId; use canvas_traits::webgl::{ ActiveAttribInfo, ActiveUniformBlockInfo, ActiveUniformInfo, GlType, TexDataType, TexFormat, @@ -144,6 +147,7 @@ use style::context::QuirksMode; use style::dom::OpaqueNode; use style::element_state::*; use style::media_queries::MediaList; +use style::properties::style_structs::Font; use style::properties::PropertyDeclarationBlock; use style::selector_parser::{PseudoElement, Snapshot}; use style::shared_lock::{Locked as StyleLocked, SharedRwLock as StyleSharedRwLock}; @@ -479,6 +483,7 @@ unsafe_no_jsmanaged_fields!(NetworkError); unsafe_no_jsmanaged_fields!(Atom, Prefix, LocalName, Namespace, QualName); unsafe_no_jsmanaged_fields!(TrustedPromise); unsafe_no_jsmanaged_fields!(PropertyDeclarationBlock); +unsafe_no_jsmanaged_fields!(Font); // These three are interdependent, if you plan to put jsmanaged data // in one of these make sure it is propagated properly to containing structs unsafe_no_jsmanaged_fields!(DocumentActivity, WindowSizeData, WindowSizeType); @@ -501,6 +506,7 @@ unsafe_no_jsmanaged_fields!(RGBA); unsafe_no_jsmanaged_fields!(StorageType); unsafe_no_jsmanaged_fields!(CanvasGradientStop, LinearGradientStyle, RadialGradientStyle); unsafe_no_jsmanaged_fields!(LineCapStyle, LineJoinStyle, CompositionOrBlending); +unsafe_no_jsmanaged_fields!(TextAlign, TextBaseline, Direction); unsafe_no_jsmanaged_fields!(RepetitionStyle); unsafe_no_jsmanaged_fields!(WebGLError, GLLimits, GlType); unsafe_no_jsmanaged_fields!(TimeProfilerChan); diff --git a/components/script/dom/canvasrenderingcontext2d.rs b/components/script/dom/canvasrenderingcontext2d.rs index 4820a3bbfd7..3ebf8f130d9 100644 --- a/components/script/dom/canvasrenderingcontext2d.rs +++ b/components/script/dom/canvasrenderingcontext2d.rs @@ -3,11 +3,14 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ use crate::canvas_state::CanvasState; +use crate::dom::bindings::codegen::Bindings::CanvasRenderingContext2DBinding::CanvasDirection; use crate::dom::bindings::codegen::Bindings::CanvasRenderingContext2DBinding::CanvasFillRule; use crate::dom::bindings::codegen::Bindings::CanvasRenderingContext2DBinding::CanvasImageSource; use crate::dom::bindings::codegen::Bindings::CanvasRenderingContext2DBinding::CanvasLineCap; use crate::dom::bindings::codegen::Bindings::CanvasRenderingContext2DBinding::CanvasLineJoin; use crate::dom::bindings::codegen::Bindings::CanvasRenderingContext2DBinding::CanvasRenderingContext2DMethods; +use crate::dom::bindings::codegen::Bindings::CanvasRenderingContext2DBinding::CanvasTextAlign; +use crate::dom::bindings::codegen::Bindings::CanvasRenderingContext2DBinding::CanvasTextBaseline; use crate::dom::bindings::codegen::UnionTypes::StringOrCanvasGradientOrCanvasPattern; use crate::dom::bindings::error::{ErrorResult, Fallible}; use crate::dom::bindings::num::Finite; @@ -288,7 +291,8 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D { // https://html.spec.whatwg.org/multipage/#dom-context-2d-filltext fn FillText(&self, text: DOMString, x: f64, y: f64, max_width: Option<f64>) { - self.canvas_state.fill_text(text, x, y, max_width); + self.canvas_state + .fill_text(self.canvas.as_ref().map(|c| &**c), text, x, y, max_width); self.mark_as_dirty(); } @@ -297,6 +301,47 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D { self.canvas_state.measure_text(&self.global(), text) } + // https://html.spec.whatwg.org/multipage/#dom-context-2d-font + fn Font(&self) -> DOMString { + self.canvas_state.font() + } + + // https://html.spec.whatwg.org/multipage/#dom-context-2d-font + fn SetFont(&self, value: DOMString) { + self.canvas_state + .set_font(self.canvas.as_ref().map(|c| &**c), value) + } + + // https://html.spec.whatwg.org/multipage/#dom-context-2d-textalign + fn TextAlign(&self) -> CanvasTextAlign { + self.canvas_state.text_align() + } + + // https://html.spec.whatwg.org/multipage/#dom-context-2d-textalign + fn SetTextAlign(&self, value: CanvasTextAlign) { + self.canvas_state.set_text_align(value) + } + + // https://html.spec.whatwg.org/multipage/#dom-context-2d-textbaseline + fn TextBaseline(&self) -> CanvasTextBaseline { + self.canvas_state.text_baseline() + } + + // https://html.spec.whatwg.org/multipage/#dom-context-2d-textbaseline + fn SetTextBaseline(&self, value: CanvasTextBaseline) { + self.canvas_state.set_text_baseline(value) + } + + // https://html.spec.whatwg.org/multipage/#dom-context-2d-direction + fn Direction(&self) -> CanvasDirection { + self.canvas_state.direction() + } + + // https://html.spec.whatwg.org/multipage/#dom-context-2d-direction + fn SetDirection(&self, value: CanvasDirection) { + self.canvas_state.set_direction(value) + } + // https://html.spec.whatwg.org/multipage/#dom-context-2d-drawimage fn DrawImage(&self, image: CanvasImageSource, dx: f64, dy: f64) -> ErrorResult { self.canvas_state diff --git a/components/script/dom/offscreencanvasrenderingcontext2d.rs b/components/script/dom/offscreencanvasrenderingcontext2d.rs index a3a873250f1..8c3deb001f4 100644 --- a/components/script/dom/offscreencanvasrenderingcontext2d.rs +++ b/components/script/dom/offscreencanvasrenderingcontext2d.rs @@ -3,10 +3,13 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ use crate::canvas_state::CanvasState; +use crate::dom::bindings::codegen::Bindings::CanvasRenderingContext2DBinding::CanvasDirection; use crate::dom::bindings::codegen::Bindings::CanvasRenderingContext2DBinding::CanvasFillRule; use crate::dom::bindings::codegen::Bindings::CanvasRenderingContext2DBinding::CanvasImageSource; use crate::dom::bindings::codegen::Bindings::CanvasRenderingContext2DBinding::CanvasLineCap; use crate::dom::bindings::codegen::Bindings::CanvasRenderingContext2DBinding::CanvasLineJoin; +use crate::dom::bindings::codegen::Bindings::CanvasRenderingContext2DBinding::CanvasTextAlign; +use crate::dom::bindings::codegen::Bindings::CanvasRenderingContext2DBinding::CanvasTextBaseline; use crate::dom::bindings::codegen::Bindings::OffscreenCanvasRenderingContext2DBinding::OffscreenCanvasRenderingContext2DMethods; use crate::dom::bindings::codegen::UnionTypes::StringOrCanvasGradientOrCanvasPattern; use crate::dom::bindings::error::ErrorResult; @@ -60,11 +63,6 @@ impl OffscreenCanvasRenderingContext2D { )); reflect_dom_object(boxed, global) } - /* - pub fn get_canvas_state(&self) -> Ref<CanvasState> { - self.canvas_state.borrow() - } - */ pub fn set_canvas_bitmap_dimensions(&self, size: Size2D<u64>) { self.canvas_state.set_bitmap_dimensions(size); @@ -249,7 +247,13 @@ impl OffscreenCanvasRenderingContext2DMethods for OffscreenCanvasRenderingContex // https://html.spec.whatwg.org/multipage/#dom-context-2d-filltext fn FillText(&self, text: DOMString, x: f64, y: f64, max_width: Option<f64>) { - self.canvas_state.fill_text(text, x, y, max_width) + self.canvas_state.fill_text( + self.htmlcanvas.as_ref().map(|c| &**c), + text, + x, + y, + max_width, + ) } // https://html.spec.whatwg.org/multipage/#textmetrics @@ -257,6 +261,47 @@ impl OffscreenCanvasRenderingContext2DMethods for OffscreenCanvasRenderingContex self.canvas_state.measure_text(&self.global(), text) } + // https://html.spec.whatwg.org/multipage/#dom-context-2d-font + fn Font(&self) -> DOMString { + self.canvas_state.font() + } + + // https://html.spec.whatwg.org/multipage/#dom-context-2d-font + fn SetFont(&self, value: DOMString) { + self.canvas_state + .set_font(self.htmlcanvas.as_ref().map(|c| &**c), value) + } + + // https://html.spec.whatwg.org/multipage/#dom-context-2d-textalign + fn TextAlign(&self) -> CanvasTextAlign { + self.canvas_state.text_align() + } + + // https://html.spec.whatwg.org/multipage/#dom-context-2d-textalign + fn SetTextAlign(&self, value: CanvasTextAlign) { + self.canvas_state.set_text_align(value) + } + + // https://html.spec.whatwg.org/multipage/#dom-context-2d-textbaseline + fn TextBaseline(&self) -> CanvasTextBaseline { + self.canvas_state.text_baseline() + } + + // https://html.spec.whatwg.org/multipage/#dom-context-2d-textbaseline + fn SetTextBaseline(&self, value: CanvasTextBaseline) { + self.canvas_state.set_text_baseline(value) + } + + // https://html.spec.whatwg.org/multipage/#dom-context-2d-direction + fn Direction(&self) -> CanvasDirection { + self.canvas_state.direction() + } + + // https://html.spec.whatwg.org/multipage/#dom-context-2d-direction + fn SetDirection(&self, value: CanvasDirection) { + self.canvas_state.set_direction(value) + } + // https://html.spec.whatwg.org/multipage/#dom-context-2d-linewidth fn LineWidth(&self) -> f64 { self.canvas_state.line_width() diff --git a/components/script/dom/webidls/CanvasRenderingContext2D.webidl b/components/script/dom/webidls/CanvasRenderingContext2D.webidl index af88cfe9281..62669f4c2ba 100644 --- a/components/script/dom/webidls/CanvasRenderingContext2D.webidl +++ b/components/script/dom/webidls/CanvasRenderingContext2D.webidl @@ -211,11 +211,11 @@ interface mixin CanvasPathDrawingStyles { [Exposed=(PaintWorklet, Window, Worker)] interface mixin CanvasTextDrawingStyles { // text - //attribute DOMString font; // (default 10px sans-serif) - //attribute CanvasTextAlign textAlign; // "start", "end", "left", "right", "center" (default: "start") - //attribute CanvasTextBaseline textBaseline; // "top", "hanging", "middle", "alphabetic", + attribute DOMString font; // (default 10px sans-serif) + attribute CanvasTextAlign textAlign; // "start", "end", "left", "right", "center" (default: "start") + attribute CanvasTextBaseline textBaseline; // "top", "hanging", "middle", "alphabetic", // "ideographic", "bottom" (default: "alphabetic") - //attribute CanvasDirection direction; // "ltr", "rtl", "inherit" (default: "inherit") + attribute CanvasDirection direction; // "ltr", "rtl", "inherit" (default: "inherit") }; [Exposed=(PaintWorklet, Window, Worker)] diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index c050579918e..d7fde4f27d5 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -118,6 +118,7 @@ use script_traits::{ }; use script_traits::{TimerSchedulerMsg, WebrenderIpcSender, WindowSizeData, WindowSizeType}; use selectors::attr::CaseSensitivity; +use servo_arc::Arc as ServoArc; use servo_geometry::{f32_rect_to_au_rect, MaxRect}; use servo_url::{ImmutableOrigin, MutableOrigin, ServoUrl}; use std::borrow::Cow; @@ -136,7 +137,8 @@ use style::dom::OpaqueNode; use style::error_reporting::{ContextualParseError, ParseErrorReporter}; use style::media_queries; use style::parser::ParserContext as CssParserContext; -use style::properties::PropertyId; +use style::properties::style_structs::Font; +use style::properties::{PropertyId, ShorthandId}; use style::selector_parser::PseudoElement; use style::str::HTML_SPACE_CHARACTERS; use style::stylesheets::CssRuleType; @@ -1847,6 +1849,18 @@ impl Window { ) } + pub fn resolved_font_style_query(&self, node: &Node, value: String) -> Option<ServoArc<Font>> { + let id = PropertyId::Shorthand(ShorthandId::Font); + if !self.layout_reflow(QueryMsg::ResolvedFontStyleQuery( + node.to_trusted_node_address(), + id, + value, + )) { + return None; + } + self.layout_rpc.resolved_font_style() + } + pub fn layout(&self) -> &dyn LayoutRPC { &*self.layout_rpc } @@ -2500,6 +2514,7 @@ fn debug_reflow_events(id: PipelineId, reflow_goal: &ReflowGoal, reason: &Reflow &QueryMsg::NodeScrollGeometryQuery(_n) => "\tNodeScrollGeometryQuery", &QueryMsg::NodeScrollIdQuery(_n) => "\tNodeScrollIdQuery", &QueryMsg::ResolvedStyleQuery(_, _, _) => "\tResolvedStyleQuery", + &QueryMsg::ResolvedFontStyleQuery(..) => "\nResolvedFontStyleQuery", &QueryMsg::OffsetParentQuery(_n) => "\tOffsetParentQuery", &QueryMsg::StyleQuery => "\tStyleQuery", &QueryMsg::TextIndexQuery(..) => "\tTextIndexQuery", diff --git a/components/script_layout_interface/message.rs b/components/script_layout_interface/message.rs index 8495d61fc8a..724cd2b79e7 100644 --- a/components/script_layout_interface/message.rs +++ b/components/script_layout_interface/message.rs @@ -117,6 +117,7 @@ pub enum QueryMsg { ResolvedStyleQuery(TrustedNodeAddress, Option<PseudoElement>, PropertyId), StyleQuery, ElementInnerTextQuery(TrustedNodeAddress), + ResolvedFontStyleQuery(TrustedNodeAddress, PropertyId, String), InnerWindowDimensionsQuery(BrowsingContextId), } @@ -145,6 +146,7 @@ impl ReflowGoal { QueryMsg::NodeScrollGeometryQuery(_) | QueryMsg::NodeScrollIdQuery(_) | QueryMsg::ResolvedStyleQuery(..) | + QueryMsg::ResolvedFontStyleQuery(..) | QueryMsg::OffsetParentQuery(_) | QueryMsg::StyleQuery => false, }, @@ -166,6 +168,7 @@ impl ReflowGoal { QueryMsg::NodeScrollGeometryQuery(_) | QueryMsg::NodeScrollIdQuery(_) | QueryMsg::ResolvedStyleQuery(..) | + QueryMsg::ResolvedFontStyleQuery(..) | QueryMsg::OffsetParentQuery(_) | QueryMsg::InnerWindowDimensionsQuery(_) | QueryMsg::StyleQuery => false, diff --git a/components/script_layout_interface/rpc.rs b/components/script_layout_interface/rpc.rs index 991437553cd..232fecabe6b 100644 --- a/components/script_layout_interface/rpc.rs +++ b/components/script_layout_interface/rpc.rs @@ -6,6 +6,8 @@ use app_units::Au; use euclid::default::Rect; use euclid::Size2D; use script_traits::UntrustedNodeAddress; +use servo_arc::Arc; +use style::properties::style_structs::Font; use style_traits::CSSPixel; use webrender_api::ExternalScrollId; @@ -30,6 +32,8 @@ pub trait LayoutRPC { fn node_scroll_id(&self) -> NodeScrollIdResponse; /// Query layout for the resolved value of a given CSS property fn resolved_style(&self) -> ResolvedStyleResponse; + /// Query layout to get the resolved font style for canvas. + fn resolved_font_style(&self) -> Option<Arc<Font>>; fn offset_parent(&self) -> OffsetParentResponse; fn text_index(&self) -> TextIndexResponse; /// Requests the list of nodes from the given point. diff --git a/components/servo/lib.rs b/components/servo/lib.rs index 390bd2c6ea0..83527952666 100644 --- a/components/servo/lib.rs +++ b/components/servo/lib.rs @@ -879,8 +879,13 @@ fn create_constellation( Box::new(FontCacheWR(compositor_proxy.clone())), ); + let (canvas_chan, ipc_canvas_chan) = CanvasPaintThread::start( + Box::new(CanvasWebrenderApi(compositor_proxy.clone())), + font_cache_thread.clone(), + ); + let initial_state = InitialConstellationState { - compositor_proxy: compositor_proxy.clone(), + compositor_proxy, embedder_proxy, debugger_chan, devtools_chan, @@ -899,9 +904,6 @@ fn create_constellation( user_agent, }; - let (canvas_chan, ipc_canvas_chan) = - CanvasPaintThread::start(Box::new(CanvasWebrenderApi(compositor_proxy))); - let constellation_chan = Constellation::< script_layout_interface::message::Msg, layout_thread::LayoutThread, diff --git a/components/style/Cargo.toml b/components/style/Cargo.toml index bf66228c8fb..956a2c3f3d7 100644 --- a/components/style/Cargo.toml +++ b/components/style/Cargo.toml @@ -39,6 +39,7 @@ derive_more = "0.99" encoding_rs = { version = "0.8", optional = true } euclid = "0.20" fallible = { path = "../fallible" } +font-kit = "0.7" fxhash = "0.2" hashglobe = { path = "../hashglobe" } html5ever = { version = "0.25", optional = true } diff --git a/components/style/lib.rs b/components/style/lib.rs index 52b77a7507e..7ff69ed3c7b 100644 --- a/components/style/lib.rs +++ b/components/style/lib.rs @@ -40,6 +40,8 @@ extern crate debug_unreachable; extern crate derive_more; extern crate euclid; extern crate fallible; +#[cfg(feature = "servo")] +extern crate font_kit; extern crate fxhash; #[cfg(feature = "gecko")] #[macro_use] diff --git a/components/style/properties/properties.mako.rs b/components/style/properties/properties.mako.rs index 619b5b2fc54..b9cd617027b 100644 --- a/components/style/properties/properties.mako.rs +++ b/components/style/properties/properties.mako.rs @@ -2602,6 +2602,7 @@ pub mod style_structs { % for style_struct in data.active_style_structs(): % if style_struct.name == "Font": #[derive(Clone, Debug, MallocSizeOf)] + #[cfg_attr(feature = "servo", derive(Serialize, Deserialize))] % else: #[derive(Clone, Debug, MallocSizeOf, PartialEq)] % endif diff --git a/components/style/values/computed/font.rs b/components/style/values/computed/font.rs index ed00f42d678..25a93d68348 100644 --- a/components/style/values/computed/font.rs +++ b/components/style/values/computed/font.rs @@ -22,6 +22,12 @@ use crate::values::specified::length::{FontBaseSize, NoCalcLength}; use crate::values::CSSFloat; use crate::Atom; use cssparser::{serialize_identifier, CssStringWriter, Parser}; +#[cfg(feature = "servo")] +use font_kit::family_name::FamilyName as FontKitFamilyName; +#[cfg(feature = "servo")] +use font_kit::properties::{ + Stretch as FontKitFontStretch, Style as FontKitFontStyle, Weight as FontKitFontWeight, +}; #[cfg(feature = "gecko")] use malloc_size_of::{MallocSizeOf, MallocSizeOfOps}; use std::fmt::{self, Write}; @@ -69,6 +75,13 @@ impl ToAnimatedValue for FontWeight { } } +#[cfg(feature = "servo")] +impl From<FontWeight> for FontKitFontWeight { + fn from(font_weight: FontWeight) -> Self { + FontKitFontWeight(font_weight.0) + } +} + #[derive( Animate, Clone, @@ -81,6 +94,7 @@ impl ToAnimatedValue for FontWeight { ToCss, ToResolvedValue, )] +#[cfg_attr(feature = "servo", derive(Serialize, Deserialize))] /// The computed value of font-size pub struct FontSize { /// The size. @@ -179,7 +193,7 @@ impl ToAnimatedValue for FontSize { } #[derive(Clone, Debug, Eq, PartialEq, ToComputedValue, ToResolvedValue)] -#[cfg_attr(feature = "servo", derive(Hash, MallocSizeOf))] +#[cfg_attr(feature = "servo", derive(Hash, MallocSizeOf, Serialize, Deserialize))] /// Specifies a prioritized list of font family names or generic family names. pub struct FontFamily { /// The actual list of family names. @@ -444,9 +458,29 @@ impl SingleFontFamily { } #[cfg(feature = "servo")] +impl From<&SingleFontFamily> for FontKitFamilyName { + fn from(font_family: &SingleFontFamily) -> Self { + match font_family { + SingleFontFamily::FamilyName(family_name) => { + FontKitFamilyName::Title(family_name.to_css_string()) + }, + SingleFontFamily::Generic(GenericFontFamily::Serif) => FontKitFamilyName::Serif, + SingleFontFamily::Generic(GenericFontFamily::SansSerif) => FontKitFamilyName::SansSerif, + SingleFontFamily::Generic(GenericFontFamily::Monospace) => FontKitFamilyName::Monospace, + SingleFontFamily::Generic(GenericFontFamily::Fantasy) => FontKitFamilyName::Fantasy, + SingleFontFamily::Generic(GenericFontFamily::Cursive) => FontKitFamilyName::Cursive, + SingleFontFamily::Generic(family_name) => { + warn!("unsupported font family name: {:?}", family_name); + FontKitFamilyName::SansSerif + }, + } + } +} + #[derive( Clone, Debug, Eq, Hash, MallocSizeOf, PartialEq, ToComputedValue, ToResolvedValue, ToShmem, )] +#[cfg_attr(feature = "servo", derive(Serialize, Deserialize))] /// A list of SingleFontFamily pub struct FontFamilyList(Box<[SingleFontFamily]>); @@ -931,6 +965,17 @@ impl ToCss for FontStyle { } } +#[cfg(feature = "servo")] +impl From<FontStyle> for FontKitFontStyle { + fn from(font_style: FontStyle) -> Self { + match font_style { + FontStyle::Normal => FontKitFontStyle::Normal, + FontStyle::Italic => FontKitFontStyle::Italic, + FontStyle::Oblique(_) => FontKitFontStyle::Oblique, + } + } +} + /// A value for the font-stretch property per: /// /// https://drafts.csswg.org/css-fonts-4/#propdef-font-stretch @@ -953,6 +998,13 @@ impl FontStretch { } } +#[cfg(feature = "servo")] +impl From<FontStretch> for FontKitFontStretch { + fn from(stretch: FontStretch) -> Self { + FontKitFontStretch(stretch.value()) + } +} + impl ToAnimatedValue for FontStretch { type AnimatedValue = Percentage; diff --git a/components/style/values/specified/font.rs b/components/style/values/specified/font.rs index dd9f9d3b86d..1a77a3864ef 100644 --- a/components/style/values/specified/font.rs +++ b/components/style/values/specified/font.rs @@ -497,6 +497,7 @@ impl ToComputedValue for FontStretch { ToResolvedValue, ToShmem, )] +#[cfg_attr(feature = "servo", derive(Serialize, Deserialize))] #[allow(missing_docs)] pub enum KeywordSize { #[css(keyword = "xx-small")] @@ -541,6 +542,7 @@ impl Default for KeywordSize { ToResolvedValue, ToShmem, )] +#[cfg_attr(feature = "servo", derive(Serialize, Deserialize))] /// Additional information for keyword-derived font sizes. pub struct KeywordInfo { /// The keyword used diff --git a/tests/wpt/metadata/html/canvas/element/manual/text-styles/canvas_text_font_001.htm.ini b/tests/wpt/metadata/html/canvas/element/manual/text-styles/canvas_text_font_001.htm.ini new file mode 100644 index 00000000000..7b5158316c0 --- /dev/null +++ b/tests/wpt/metadata/html/canvas/element/manual/text-styles/canvas_text_font_001.htm.ini @@ -0,0 +1,2 @@ +[canvas_text_font_001.htm] + expected: FAIL diff --git a/tests/wpt/metadata/html/canvas/element/text-styles/2d.text.align.default.html.ini b/tests/wpt/metadata/html/canvas/element/text-styles/2d.text.align.default.html.ini deleted file mode 100644 index 2b8793d28be..00000000000 --- a/tests/wpt/metadata/html/canvas/element/text-styles/2d.text.align.default.html.ini +++ /dev/null @@ -1,4 +0,0 @@ -[2d.text.align.default.html] - [Canvas test: 2d.text.align.default] - expected: FAIL - diff --git a/tests/wpt/metadata/html/canvas/element/text-styles/2d.text.align.invalid.html.ini b/tests/wpt/metadata/html/canvas/element/text-styles/2d.text.align.invalid.html.ini deleted file mode 100644 index 100c6551344..00000000000 --- a/tests/wpt/metadata/html/canvas/element/text-styles/2d.text.align.invalid.html.ini +++ /dev/null @@ -1,4 +0,0 @@ -[2d.text.align.invalid.html] - [Canvas test: 2d.text.align.invalid] - expected: FAIL - diff --git a/tests/wpt/metadata/html/canvas/element/text-styles/2d.text.baseline.default.html.ini b/tests/wpt/metadata/html/canvas/element/text-styles/2d.text.baseline.default.html.ini deleted file mode 100644 index f09249c129c..00000000000 --- a/tests/wpt/metadata/html/canvas/element/text-styles/2d.text.baseline.default.html.ini +++ /dev/null @@ -1,4 +0,0 @@ -[2d.text.baseline.default.html] - [Canvas test: 2d.text.baseline.default] - expected: FAIL - diff --git a/tests/wpt/metadata/html/canvas/element/text-styles/2d.text.baseline.invalid.html.ini b/tests/wpt/metadata/html/canvas/element/text-styles/2d.text.baseline.invalid.html.ini deleted file mode 100644 index 23f93163a60..00000000000 --- a/tests/wpt/metadata/html/canvas/element/text-styles/2d.text.baseline.invalid.html.ini +++ /dev/null @@ -1,4 +0,0 @@ -[2d.text.baseline.invalid.html] - [Canvas test: 2d.text.baseline.invalid] - expected: FAIL - diff --git a/tests/wpt/metadata/html/canvas/element/text-styles/2d.text.font.default.html.ini b/tests/wpt/metadata/html/canvas/element/text-styles/2d.text.font.default.html.ini deleted file mode 100644 index 71a00e76d9d..00000000000 --- a/tests/wpt/metadata/html/canvas/element/text-styles/2d.text.font.default.html.ini +++ /dev/null @@ -1,4 +0,0 @@ -[2d.text.font.default.html] - [Canvas test: 2d.text.font.default] - expected: FAIL - diff --git a/tests/wpt/metadata/html/canvas/element/text-styles/2d.text.font.parse.basic.html.ini b/tests/wpt/metadata/html/canvas/element/text-styles/2d.text.font.parse.basic.html.ini deleted file mode 100644 index cbfa7e019c8..00000000000 --- a/tests/wpt/metadata/html/canvas/element/text-styles/2d.text.font.parse.basic.html.ini +++ /dev/null @@ -1,4 +0,0 @@ -[2d.text.font.parse.basic.html] - [Canvas test: 2d.text.font.parse.basic] - expected: FAIL - diff --git a/tests/wpt/metadata/html/canvas/element/text-styles/2d.text.font.parse.size.percentage.default.html.ini b/tests/wpt/metadata/html/canvas/element/text-styles/2d.text.font.parse.size.percentage.default.html.ini deleted file mode 100644 index e38e31fc416..00000000000 --- a/tests/wpt/metadata/html/canvas/element/text-styles/2d.text.font.parse.size.percentage.default.html.ini +++ /dev/null @@ -1,4 +0,0 @@ -[2d.text.font.parse.size.percentage.default.html] - [Canvas test: 2d.text.font.parse.size.percentage.default] - expected: FAIL - diff --git a/tests/wpt/metadata/html/canvas/element/text-styles/2d.text.font.parse.size.percentage.html.ini b/tests/wpt/metadata/html/canvas/element/text-styles/2d.text.font.parse.size.percentage.html.ini deleted file mode 100644 index f88a6906139..00000000000 --- a/tests/wpt/metadata/html/canvas/element/text-styles/2d.text.font.parse.size.percentage.html.ini +++ /dev/null @@ -1,4 +0,0 @@ -[2d.text.font.parse.size.percentage.html] - [Canvas test: 2d.text.font.parse.size.percentage] - expected: FAIL - diff --git a/tests/wpt/metadata/html/canvas/element/text-styles/2d.text.font.parse.system.html.ini b/tests/wpt/metadata/html/canvas/element/text-styles/2d.text.font.parse.system.html.ini deleted file mode 100644 index 4011e6441bf..00000000000 --- a/tests/wpt/metadata/html/canvas/element/text-styles/2d.text.font.parse.system.html.ini +++ /dev/null @@ -1,4 +0,0 @@ -[2d.text.font.parse.system.html] - [System fonts must be computed to explicit values] - expected: FAIL - diff --git a/tests/wpt/metadata/html/canvas/element/text-styles/2d.text.font.relative_size.html.ini b/tests/wpt/metadata/html/canvas/element/text-styles/2d.text.font.relative_size.html.ini deleted file mode 100644 index 5353ddbe2dc..00000000000 --- a/tests/wpt/metadata/html/canvas/element/text-styles/2d.text.font.relative_size.html.ini +++ /dev/null @@ -1,4 +0,0 @@ -[2d.text.font.relative_size.html] - [Canvas test: 2d.text.font.relative_size] - expected: FAIL - diff --git a/tests/wpt/metadata/html/canvas/element/the-canvas-state/2d.state.saverestore.font.html.ini b/tests/wpt/metadata/html/canvas/element/the-canvas-state/2d.state.saverestore.font.html.ini deleted file mode 100644 index afb4feba894..00000000000 --- a/tests/wpt/metadata/html/canvas/element/the-canvas-state/2d.state.saverestore.font.html.ini +++ /dev/null @@ -1,4 +0,0 @@ -[2d.state.saverestore.font.html] - [save()/restore() works for font] - expected: FAIL - diff --git a/tests/wpt/metadata/html/canvas/element/the-canvas-state/2d.state.saverestore.textAlign.html.ini b/tests/wpt/metadata/html/canvas/element/the-canvas-state/2d.state.saverestore.textAlign.html.ini deleted file mode 100644 index 0b2a17d1d9d..00000000000 --- a/tests/wpt/metadata/html/canvas/element/the-canvas-state/2d.state.saverestore.textAlign.html.ini +++ /dev/null @@ -1,4 +0,0 @@ -[2d.state.saverestore.textAlign.html] - [save()/restore() works for textAlign] - expected: FAIL - diff --git a/tests/wpt/metadata/html/canvas/element/the-canvas-state/2d.state.saverestore.textBaseline.html.ini b/tests/wpt/metadata/html/canvas/element/the-canvas-state/2d.state.saverestore.textBaseline.html.ini deleted file mode 100644 index 4c754240145..00000000000 --- a/tests/wpt/metadata/html/canvas/element/the-canvas-state/2d.state.saverestore.textBaseline.html.ini +++ /dev/null @@ -1,4 +0,0 @@ -[2d.state.saverestore.textBaseline.html] - [save()/restore() works for textBaseline] - expected: FAIL - diff --git a/tests/wpt/metadata/html/canvas/offscreen/text/2d.text.align.default.html.ini b/tests/wpt/metadata/html/canvas/offscreen/text/2d.text.align.default.html.ini deleted file mode 100644 index cfc8b5f9e74..00000000000 --- a/tests/wpt/metadata/html/canvas/offscreen/text/2d.text.align.default.html.ini +++ /dev/null @@ -1,4 +0,0 @@ -[2d.text.align.default.html] - [OffscreenCanvas test: 2d.text.align.default] - expected: FAIL - diff --git a/tests/wpt/metadata/html/canvas/offscreen/text/2d.text.align.default.worker.js.ini b/tests/wpt/metadata/html/canvas/offscreen/text/2d.text.align.default.worker.js.ini deleted file mode 100644 index 38fffadbee9..00000000000 --- a/tests/wpt/metadata/html/canvas/offscreen/text/2d.text.align.default.worker.js.ini +++ /dev/null @@ -1,4 +0,0 @@ -[2d.text.align.default.worker.html] - [2d] - expected: FAIL - diff --git a/tests/wpt/metadata/html/canvas/offscreen/text/2d.text.align.invalid.html.ini b/tests/wpt/metadata/html/canvas/offscreen/text/2d.text.align.invalid.html.ini deleted file mode 100644 index 1e8afd14191..00000000000 --- a/tests/wpt/metadata/html/canvas/offscreen/text/2d.text.align.invalid.html.ini +++ /dev/null @@ -1,4 +0,0 @@ -[2d.text.align.invalid.html] - [OffscreenCanvas test: 2d.text.align.invalid] - expected: FAIL - diff --git a/tests/wpt/metadata/html/canvas/offscreen/text/2d.text.align.invalid.worker.js.ini b/tests/wpt/metadata/html/canvas/offscreen/text/2d.text.align.invalid.worker.js.ini deleted file mode 100644 index fd2751fa4fe..00000000000 --- a/tests/wpt/metadata/html/canvas/offscreen/text/2d.text.align.invalid.worker.js.ini +++ /dev/null @@ -1,4 +0,0 @@ -[2d.text.align.invalid.worker.html] - [2d] - expected: FAIL - diff --git a/tests/wpt/metadata/html/canvas/offscreen/text/2d.text.baseline.default.html.ini b/tests/wpt/metadata/html/canvas/offscreen/text/2d.text.baseline.default.html.ini deleted file mode 100644 index 660b1093d74..00000000000 --- a/tests/wpt/metadata/html/canvas/offscreen/text/2d.text.baseline.default.html.ini +++ /dev/null @@ -1,4 +0,0 @@ -[2d.text.baseline.default.html] - [OffscreenCanvas test: 2d.text.baseline.default] - expected: FAIL - diff --git a/tests/wpt/metadata/html/canvas/offscreen/text/2d.text.baseline.default.worker.js.ini b/tests/wpt/metadata/html/canvas/offscreen/text/2d.text.baseline.default.worker.js.ini deleted file mode 100644 index 15f63c7a2f4..00000000000 --- a/tests/wpt/metadata/html/canvas/offscreen/text/2d.text.baseline.default.worker.js.ini +++ /dev/null @@ -1,4 +0,0 @@ -[2d.text.baseline.default.worker.html] - [2d] - expected: FAIL - diff --git a/tests/wpt/metadata/html/canvas/offscreen/text/2d.text.baseline.invalid.html.ini b/tests/wpt/metadata/html/canvas/offscreen/text/2d.text.baseline.invalid.html.ini deleted file mode 100644 index fc890c7ba66..00000000000 --- a/tests/wpt/metadata/html/canvas/offscreen/text/2d.text.baseline.invalid.html.ini +++ /dev/null @@ -1,4 +0,0 @@ -[2d.text.baseline.invalid.html] - [OffscreenCanvas test: 2d.text.baseline.invalid] - expected: FAIL - diff --git a/tests/wpt/metadata/html/canvas/offscreen/text/2d.text.baseline.invalid.worker.js.ini b/tests/wpt/metadata/html/canvas/offscreen/text/2d.text.baseline.invalid.worker.js.ini deleted file mode 100644 index 15d3ef67d1e..00000000000 --- a/tests/wpt/metadata/html/canvas/offscreen/text/2d.text.baseline.invalid.worker.js.ini +++ /dev/null @@ -1,4 +0,0 @@ -[2d.text.baseline.invalid.worker.html] - [2d] - expected: FAIL - diff --git a/tests/wpt/metadata/html/canvas/offscreen/text/2d.text.font.default.html.ini b/tests/wpt/metadata/html/canvas/offscreen/text/2d.text.font.default.html.ini deleted file mode 100644 index cbef4aaf060..00000000000 --- a/tests/wpt/metadata/html/canvas/offscreen/text/2d.text.font.default.html.ini +++ /dev/null @@ -1,4 +0,0 @@ -[2d.text.font.default.html] - [OffscreenCanvas test: 2d.text.font.default] - expected: FAIL - diff --git a/tests/wpt/metadata/html/canvas/offscreen/text/2d.text.font.default.worker.js.ini b/tests/wpt/metadata/html/canvas/offscreen/text/2d.text.font.default.worker.js.ini deleted file mode 100644 index 181525db750..00000000000 --- a/tests/wpt/metadata/html/canvas/offscreen/text/2d.text.font.default.worker.js.ini +++ /dev/null @@ -1,4 +0,0 @@ -[2d.text.font.default.worker.html] - [2d] - expected: FAIL - diff --git a/tests/wpt/metadata/html/canvas/offscreen/text/2d.text.font.parse.system.html.ini b/tests/wpt/metadata/html/canvas/offscreen/text/2d.text.font.parse.system.html.ini deleted file mode 100644 index 4011e6441bf..00000000000 --- a/tests/wpt/metadata/html/canvas/offscreen/text/2d.text.font.parse.system.html.ini +++ /dev/null @@ -1,4 +0,0 @@ -[2d.text.font.parse.system.html] - [System fonts must be computed to explicit values] - expected: FAIL - diff --git a/tests/wpt/metadata/html/canvas/offscreen/text/2d.text.font.parse.system.worker.js.ini b/tests/wpt/metadata/html/canvas/offscreen/text/2d.text.font.parse.system.worker.js.ini deleted file mode 100644 index 38ba0ec527b..00000000000 --- a/tests/wpt/metadata/html/canvas/offscreen/text/2d.text.font.parse.system.worker.js.ini +++ /dev/null @@ -1,4 +0,0 @@ -[2d.text.font.parse.system.worker.html] - [System fonts must be computed to explicit values] - expected: FAIL - diff --git a/tests/wpt/metadata/html/canvas/offscreen/text/2d.text.font.parse.tiny.html.ini b/tests/wpt/metadata/html/canvas/offscreen/text/2d.text.font.parse.tiny.html.ini new file mode 100644 index 00000000000..f69fc85b936 --- /dev/null +++ b/tests/wpt/metadata/html/canvas/offscreen/text/2d.text.font.parse.tiny.html.ini @@ -0,0 +1,4 @@ +[2d.text.font.parse.tiny.html] + [OffscreenCanvas test: 2d.text.font.parse.tiny] + expected: FAIL + diff --git a/tests/wpt/metadata/html/canvas/offscreen/text/2d.text.font.parse.tiny.worker.js.ini b/tests/wpt/metadata/html/canvas/offscreen/text/2d.text.font.parse.tiny.worker.js.ini new file mode 100644 index 00000000000..c2449239def --- /dev/null +++ b/tests/wpt/metadata/html/canvas/offscreen/text/2d.text.font.parse.tiny.worker.js.ini @@ -0,0 +1,4 @@ +[2d.text.font.parse.tiny.worker.html] + [2d] + expected: FAIL + diff --git a/tests/wpt/metadata/html/canvas/offscreen/text/2d.text.font.relative_size.html.ini b/tests/wpt/metadata/html/canvas/offscreen/text/2d.text.font.relative_size.html.ini deleted file mode 100644 index 3b0a22523af..00000000000 --- a/tests/wpt/metadata/html/canvas/offscreen/text/2d.text.font.relative_size.html.ini +++ /dev/null @@ -1,4 +0,0 @@ -[2d.text.font.relative_size.html] - [OffscreenCanvas test: 2d.text.font.relative_size] - expected: FAIL - diff --git a/tests/wpt/metadata/html/canvas/offscreen/text/2d.text.font.relative_size.worker.js.ini b/tests/wpt/metadata/html/canvas/offscreen/text/2d.text.font.relative_size.worker.js.ini deleted file mode 100644 index d8ba1ee8817..00000000000 --- a/tests/wpt/metadata/html/canvas/offscreen/text/2d.text.font.relative_size.worker.js.ini +++ /dev/null @@ -1,4 +0,0 @@ -[2d.text.font.relative_size.worker.html] - [2d] - expected: FAIL - diff --git a/tests/wpt/metadata/html/dom/idlharness.https.html.ini b/tests/wpt/metadata/html/dom/idlharness.https.html.ini index b0b337f71d8..bbc23fe7631 100644 --- a/tests/wpt/metadata/html/dom/idlharness.https.html.ini +++ b/tests/wpt/metadata/html/dom/idlharness.https.html.ini @@ -110,9 +110,6 @@ [History interface: window.history must inherit property "scrollRestoration" with the proper type] expected: FAIL - [CanvasRenderingContext2D interface: document.createElement("canvas").getContext("2d") must inherit property "direction" with the proper type] - expected: FAIL - [ApplicationCache interface: constant UPDATEREADY on interface prototype object] expected: FAIL @@ -152,9 +149,6 @@ [Navigator interface: attribute hardwareConcurrency] expected: FAIL - [CanvasRenderingContext2D interface: attribute textAlign] - expected: FAIL - [OffscreenCanvasRenderingContext2D interface: operation restore()] expected: FAIL @@ -341,9 +335,6 @@ [DataTransfer interface: existence and properties of interface prototype object] expected: FAIL - [CanvasRenderingContext2D interface: attribute direction] - expected: FAIL - [DataTransferItemList interface: existence and properties of interface object] expected: FAIL @@ -419,9 +410,6 @@ [SVGElement interface: attribute onsecuritypolicyviolation] expected: FAIL - [CanvasRenderingContext2D interface: document.createElement("canvas").getContext("2d") must inherit property "font" with the proper type] - expected: FAIL - [OffscreenCanvasRenderingContext2D interface: operation quadraticCurveTo(unrestricted double, unrestricted double, unrestricted double, unrestricted double)] expected: FAIL @@ -899,9 +887,6 @@ [ApplicationCache interface: existence and properties of interface prototype object's @@unscopables property] expected: FAIL - [CanvasRenderingContext2D interface: attribute font] - expected: FAIL - [OffscreenCanvas interface: existence and properties of interface prototype object's @@unscopables property] expected: FAIL @@ -1076,9 +1061,6 @@ [OffscreenCanvasRenderingContext2D interface: operation closePath()] expected: FAIL - [CanvasRenderingContext2D interface: document.createElement("canvas").getContext("2d") must inherit property "textAlign" with the proper type] - expected: FAIL - [Path2D interface: operation arcTo(unrestricted double, unrestricted double, unrestricted double, unrestricted double, unrestricted double)] expected: FAIL @@ -1136,9 +1118,6 @@ [SVGElement interface: attribute onvolumechange] expected: FAIL - [CanvasRenderingContext2D interface: attribute textBaseline] - expected: FAIL - [ImageBitmapRenderingContext interface object length] expected: FAIL @@ -1259,9 +1238,6 @@ [ElementInternals interface: attribute validity] expected: FAIL - [CanvasRenderingContext2D interface: document.createElement("canvas").getContext("2d") must inherit property "textBaseline" with the proper type] - expected: FAIL - [SVGElement interface: attribute autofocus] expected: FAIL diff --git a/tests/wpt/metadata/html/semantics/embedded-content/the-canvas-element/initial.reset.2dstate.html.ini b/tests/wpt/metadata/html/semantics/embedded-content/the-canvas-element/initial.reset.2dstate.html.ini deleted file mode 100644 index 2f98ac94dff..00000000000 --- a/tests/wpt/metadata/html/semantics/embedded-content/the-canvas-element/initial.reset.2dstate.html.ini +++ /dev/null @@ -1,5 +0,0 @@ -[initial.reset.2dstate.html] - type: testharness - [Resetting the canvas state resets 2D state variables] - expected: FAIL - |