Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement CanvasRenderingContext2d.fillText #26697

Merged
merged 13 commits into from Jun 12, 2020

Query layout to resolve canvas font property value

  • Loading branch information
utsavoza committed Jun 10, 2020
commit 7883718c125f2580490254efdf0aac952b50ce3d
@@ -522,7 +522,7 @@ impl GenericDrawTarget for raqote::DrawTarget {
text: String,
x: f64,
y: f64,
max_width: Option<f64>,
_max_width: Option<f64>,
pattern: canvas_data::Pattern,
draw_options: &DrawOptions,
) {
@@ -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<ServoArc<ComputedValues>>,

/// 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<ServoArc<ComputedValues>> {
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<ServoArc<ComputedValues>>
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::<E::ConcreteElement>(
&context.style_context.guards,
&*parent_style,
ServoArc::new(shared_lock.wrap(declarations)),
),
)
}

/// 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>(
@@ -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);
},
@@ -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 => {},
}
@@ -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
@@ -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
@@ -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()
@@ -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")
@@ -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<ServoArc<ComputedValues>> {
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",
},
};
@@ -117,6 +117,7 @@ pub enum QueryMsg {
ResolvedStyleQuery(TrustedNodeAddress, Option<PseudoElement>, 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,
@@ -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<Arc<ComputedValues>>;
fn offset_parent(&self) -> OffsetParentResponse;
fn text_index(&self) -> TextIndexResponse;
/// Requests the list of nodes from the given point.
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.