diff --git a/components/canvas/raqote_backend.rs b/components/canvas/raqote_backend.rs index c732d686472..451656d7708 100644 --- a/components/canvas/raqote_backend.rs +++ b/components/canvas/raqote_backend.rs @@ -522,7 +522,7 @@ impl GenericDrawTarget for raqote::DrawTarget { text: String, x: f64, y: f64, - max_width: Option, + _max_width: Option, pattern: canvas_data::Pattern, draw_options: &DrawOptions, ) { diff --git a/components/layout/query.rs b/components/layout/query.rs index a5f66cb9dcd..b78a642ec1d 100644 --- a/components/layout/query.rs +++ b/components/layout/query.rs @@ -29,6 +29,8 @@ 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}; @@ -38,9 +40,13 @@ use style::computed_values::visibility::T as Visibility; use style::context::{StyleContext, ThreadLocalStyleContext}; use style::dom::TElement; use style::logical_geometry::{BlockFlowDirection, InlineBaseDirection, WritingMode}; -use style::properties::{style_structs, LonghandId, PropertyDeclarationId, PropertyId}; +use style::properties::{ + parse_one_declaration_into, style_structs, 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 +79,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 parse_font_response: Option>, + /// A queued response for the offset parent/rect of a node. pub offset_parent_response: OffsetParentResponse, @@ -170,6 +179,12 @@ impl LayoutRPC for LayoutRPCImpl { ResolvedStyleResponse(rw_data.resolved_style_response.clone()) } + fn parsed_font(&self) -> Option> { + let &LayoutRPCImpl(ref rw_data) = self; + let rw_data = rw_data.lock().unwrap(); + rw_data.parse_font_response.clone() + } + fn offset_parent(&self) -> OffsetParentResponse { let &LayoutRPCImpl(ref rw_data) = self; let rw_data = rw_data.lock().unwrap(); @@ -735,6 +750,68 @@ pub fn process_node_scroll_area_request( } } +pub fn process_parse_font_request<'dom, E>( + context: &LayoutContext, + node: E, + font_value: &str, + property: &PropertyId, + url_data: ServoUrl, + shared_lock: &SharedRwLock, +) -> Option> +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 mut declarations = SourcePropertyDeclaration::new(); + let result = parse_one_declaration_into( + &mut declarations, + property.clone(), + font_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, + }; + + // 2. Get resolved styles for the parent element + let element = node.as_element().unwrap(); + let parent_style = 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() + }; + + // 3. Resolve the parsed value with resolved styles of the parent element + Some( + context + .style_context + .stylist + .compute_for_declarations::( + &context.style_context.guards, + &*parent_style, + ServoArc::new(shared_lock.wrap(declarations)), + ), + ) +} + /// Return the resolved value of property for a given (pseudo)element. /// pub fn process_resolved_style_request<'dom>( diff --git a/components/layout_thread/lib.rs b/components/layout_thread/lib.rs index 6819027564c..9ae955789a9 100644 --- a/components/layout_thread/lib.rs +++ b/components/layout_thread/lib.rs @@ -49,12 +49,12 @@ 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_parse_font_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 +558,7 @@ impl LayoutThread { scroll_id_response: None, scroll_area_response: Rect::zero(), resolved_style_response: String::new(), + parse_font_response: None, offset_parent_response: OffsetParentResponse::empty(), scroll_offsets: HashMap::new(), text_index_response: TextIndexResponse(None), @@ -1231,6 +1232,9 @@ impl LayoutThread { &QueryMsg::ElementInnerTextQuery(_) => { rw_data.element_inner_text_response = String::new(); }, + &QueryMsg::ParseFontQuery(..) => { + rw_data.parse_font_response = None; + }, &QueryMsg::InnerWindowDimensionsQuery(_) => { rw_data.inner_window_dimensions_response = None; }, @@ -1498,6 +1502,7 @@ impl LayoutThread { &mut *rw_data, &mut layout_context, data.result.borrow_mut().as_mut().unwrap(), + document_shared_lock, ); } @@ -1507,6 +1512,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 +1555,18 @@ impl LayoutThread { rw_data.resolved_style_response = process_resolved_style_request(context, node, pseudo, property, root_flow); }, + &QueryMsg::ParseFontQuery(node, ref property, ref value) => { + let node = unsafe { ServoLayoutNode::new(&node) }; + let url = self.url.clone(); + rw_data.parse_font_response = process_parse_font_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..a11160ee11f 100644 --- a/components/layout_thread_2020/lib.rs +++ b/components/layout_thread_2020/lib.rs @@ -1242,6 +1242,7 @@ impl LayoutThread { // builder in order to support query iframe sizing. rw_data.inner_window_dimensions_response = None; }, + &QueryMsg::ParseFontQuery(_, _) => unimplemented!(), }, ReflowGoal::Full | ReflowGoal::TickAnimations => {}, } diff --git a/components/script/canvas_state.rs b/components/script/canvas_state.rs index dac2bb04924..ab2f93b5baa 100644 --- a/components/script/canvas_state.rs +++ b/components/script/canvas_state.rs @@ -1006,6 +1006,16 @@ impl CanvasState { ) } + // https://html.spec.whatwg.org/multipage/#dom-context-2d-font + pub fn set_font(&self, _canvas: Option<&HTMLCanvasElement>, _value: DOMString) { + unimplemented!() + } + + // https://html.spec.whatwg.org/multipage/#dom-context-2d-font + pub fn font(&self) -> DOMString { + unimplemented!() + } + // https://html.spec.whatwg.org/multipage/#dom-context-2d-linewidth pub fn line_width(&self) -> f64 { self.state.borrow().line_width diff --git a/components/script/dom/canvasrenderingcontext2d.rs b/components/script/dom/canvasrenderingcontext2d.rs index 4820a3bbfd7..3e0df6bb4b9 100644 --- a/components/script/dom/canvasrenderingcontext2d.rs +++ b/components/script/dom/canvasrenderingcontext2d.rs @@ -297,6 +297,17 @@ 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-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..d36785d71f6 100644 --- a/components/script/dom/offscreencanvasrenderingcontext2d.rs +++ b/components/script/dom/offscreencanvasrenderingcontext2d.rs @@ -257,6 +257,17 @@ 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-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..2267984ce2f 100644 --- a/components/script/dom/webidls/CanvasRenderingContext2D.webidl +++ b/components/script/dom/webidls/CanvasRenderingContext2D.webidl @@ -211,7 +211,7 @@ interface mixin CanvasPathDrawingStyles { [Exposed=(PaintWorklet, Window, Worker)] interface mixin CanvasTextDrawingStyles { // text - //attribute DOMString font; // (default 10px sans-serif) + 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") diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index c050579918e..6209fb72d2f 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,7 @@ 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::{ComputedValues, PropertyId, ShorthandId}; use style::selector_parser::PseudoElement; use style::str::HTML_SPACE_CHARACTERS; use style::stylesheets::CssRuleType; @@ -1847,6 +1848,21 @@ impl Window { ) } + pub fn parse_font_query(&self, node: &Node, value: String) -> Option> { + if !node.is_connected() { + return None; + } + let id = PropertyId::Shorthand(ShorthandId::Font); + if !self.layout_reflow(QueryMsg::ParseFontQuery( + node.to_trusted_node_address(), + id, + value, + )) { + return None; + } + self.layout_rpc.parsed_font() + } + pub fn layout(&self) -> &dyn LayoutRPC { &*self.layout_rpc } @@ -2504,6 +2520,7 @@ fn debug_reflow_events(id: PipelineId, reflow_goal: &ReflowGoal, reason: &Reflow &QueryMsg::StyleQuery => "\tStyleQuery", &QueryMsg::TextIndexQuery(..) => "\tTextIndexQuery", &QueryMsg::ElementInnerTextQuery(_) => "\tElementInnerTextQuery", + &QueryMsg::ParseFontQuery(..) => "\nParseFontQuery", &QueryMsg::InnerWindowDimensionsQuery(_) => "\tInnerWindowDimensionsQuery", }, }; diff --git a/components/script_layout_interface/message.rs b/components/script_layout_interface/message.rs index 8495d61fc8a..5cd6c66345f 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, PropertyId), StyleQuery, ElementInnerTextQuery(TrustedNodeAddress), + ParseFontQuery(TrustedNodeAddress, PropertyId, String), InnerWindowDimensionsQuery(BrowsingContextId), } @@ -145,6 +146,7 @@ impl ReflowGoal { QueryMsg::NodeScrollGeometryQuery(_) | QueryMsg::NodeScrollIdQuery(_) | QueryMsg::ResolvedStyleQuery(..) | + QueryMsg::ParseFontQuery(..) | QueryMsg::OffsetParentQuery(_) | QueryMsg::StyleQuery => false, }, @@ -166,6 +168,7 @@ impl ReflowGoal { QueryMsg::NodeScrollGeometryQuery(_) | QueryMsg::NodeScrollIdQuery(_) | QueryMsg::ResolvedStyleQuery(..) | + QueryMsg::ParseFontQuery(..) | 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..f21982475cb 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::ComputedValues; 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 parsed font property for canvas. + fn parsed_font(&self) -> Option>; fn offset_parent(&self) -> OffsetParentResponse; fn text_index(&self) -> TextIndexResponse; /// Requests the list of nodes from the given point.