mirror of
https://github.com/servo/servo.git
synced 2025-08-03 04:30:10 +01:00
parent
f0ea3c6150
commit
251eeb2c2d
53 changed files with 1566 additions and 262 deletions
|
@ -32,6 +32,7 @@ use crate::dom::globalscope::GlobalScope;
|
|||
use crate::dom::htmlcanvaselement::HTMLCanvasElement;
|
||||
use crate::dom::imagedata::ImageData;
|
||||
use crate::dom::node::{Node, NodeDamage, NodeTraits};
|
||||
use crate::dom::path2d::Path2D;
|
||||
use crate::dom::textmetrics::TextMetrics;
|
||||
use crate::script_runtime::CanGc;
|
||||
|
||||
|
@ -288,23 +289,46 @@ impl CanvasRenderingContext2DMethods<crate::DomTypeHolder> for CanvasRenderingCo
|
|||
self.mark_as_dirty();
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-fill
|
||||
fn Fill_(&self, path: &Path2D, fill_rule: CanvasFillRule) {
|
||||
self.canvas_state.fill_(path.segments(), fill_rule);
|
||||
self.mark_as_dirty();
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-stroke
|
||||
fn Stroke(&self) {
|
||||
self.canvas_state.stroke();
|
||||
self.mark_as_dirty();
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-stroke
|
||||
fn Stroke_(&self, path: &Path2D) {
|
||||
self.canvas_state.stroke_(path.segments());
|
||||
self.mark_as_dirty();
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-clip
|
||||
fn Clip(&self, fill_rule: CanvasFillRule) {
|
||||
self.canvas_state.clip(fill_rule)
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-clip
|
||||
fn Clip_(&self, path: &Path2D, fill_rule: CanvasFillRule) {
|
||||
self.canvas_state.clip_(path.segments(), fill_rule)
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-ispointinpath
|
||||
fn IsPointInPath(&self, x: f64, y: f64, fill_rule: CanvasFillRule) -> bool {
|
||||
self.canvas_state
|
||||
.is_point_in_path(&self.global(), x, y, fill_rule)
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-ispointinpath
|
||||
fn IsPointInPath_(&self, path: &Path2D, x: f64, y: f64, fill_rule: CanvasFillRule) -> bool {
|
||||
self.canvas_state
|
||||
.is_point_in_path_(&self.global(), path.segments(), x, y, fill_rule)
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-filltext
|
||||
fn FillText(&self, text: DOMString, x: f64, y: f64, max_width: Option<f64>, can_gc: CanGc) {
|
||||
self.canvas_state
|
||||
|
|
|
@ -466,6 +466,7 @@ pub(crate) mod paintrenderingcontext2d;
|
|||
pub(crate) mod paintsize;
|
||||
pub(crate) mod paintworkletglobalscope;
|
||||
pub(crate) mod pannernode;
|
||||
pub(crate) mod path2d;
|
||||
pub(crate) mod performance;
|
||||
#[allow(dead_code)]
|
||||
pub(crate) mod performanceentry;
|
||||
|
|
|
@ -27,6 +27,7 @@ use crate::dom::dommatrix::DOMMatrix;
|
|||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::dom::imagedata::ImageData;
|
||||
use crate::dom::offscreencanvas::OffscreenCanvas;
|
||||
use crate::dom::path2d::Path2D;
|
||||
use crate::dom::textmetrics::TextMetrics;
|
||||
use crate::script_runtime::CanGc;
|
||||
|
||||
|
@ -437,21 +438,41 @@ impl OffscreenCanvasRenderingContext2DMethods<crate::DomTypeHolder>
|
|||
self.context.Fill(fill_rule)
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-fill
|
||||
fn Fill_(&self, path: &Path2D, fill_rule: CanvasFillRule) {
|
||||
self.context.Fill_(path, fill_rule)
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-stroke
|
||||
fn Stroke(&self) {
|
||||
self.context.Stroke()
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-stroke
|
||||
fn Stroke_(&self, path: &Path2D) {
|
||||
self.context.Stroke_(path)
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-clip
|
||||
fn Clip(&self, fill_rule: CanvasFillRule) {
|
||||
self.context.Clip(fill_rule)
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-clip
|
||||
fn Clip_(&self, path: &Path2D, fill_rule: CanvasFillRule) {
|
||||
self.context.Clip_(path, fill_rule)
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-ispointinpath
|
||||
fn IsPointInPath(&self, x: f64, y: f64, fill_rule: CanvasFillRule) -> bool {
|
||||
self.context.IsPointInPath(x, y, fill_rule)
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-ispointinpath
|
||||
fn IsPointInPath_(&self, path: &Path2D, x: f64, y: f64, fill_rule: CanvasFillRule) -> bool {
|
||||
self.context.IsPointInPath_(path, x, y, fill_rule)
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-scale
|
||||
fn Scale(&self, x: f64, y: f64) {
|
||||
self.context.Scale(x, y)
|
||||
|
|
|
@ -29,6 +29,7 @@ use crate::dom::canvasgradient::CanvasGradient;
|
|||
use crate::dom::canvaspattern::CanvasPattern;
|
||||
use crate::dom::dommatrix::DOMMatrix;
|
||||
use crate::dom::paintworkletglobalscope::PaintWorkletGlobalScope;
|
||||
use crate::dom::path2d::Path2D;
|
||||
use crate::script_runtime::CanGc;
|
||||
|
||||
#[dom_struct]
|
||||
|
@ -192,22 +193,43 @@ impl PaintRenderingContext2DMethods<crate::DomTypeHolder> for PaintRenderingCont
|
|||
self.canvas_state.fill(fill_rule)
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-fill
|
||||
fn Fill_(&self, path: &Path2D, fill_rule: CanvasFillRule) {
|
||||
self.canvas_state.fill_(path.segments(), fill_rule)
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-stroke
|
||||
fn Stroke(&self) {
|
||||
self.canvas_state.stroke()
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-stroke
|
||||
fn Stroke_(&self, path: &Path2D) {
|
||||
self.canvas_state.stroke_(path.segments())
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-clip
|
||||
fn Clip(&self, fill_rule: CanvasFillRule) {
|
||||
self.canvas_state.clip(fill_rule)
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-clip
|
||||
fn Clip_(&self, path: &Path2D, fill_rule: CanvasFillRule) {
|
||||
self.canvas_state.clip_(path.segments(), fill_rule)
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-ispointinpath
|
||||
fn IsPointInPath(&self, x: f64, y: f64, fill_rule: CanvasFillRule) -> bool {
|
||||
self.canvas_state
|
||||
.is_point_in_path(&self.global(), x, y, fill_rule)
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-ispointinpath
|
||||
fn IsPointInPath_(&self, path: &Path2D, x: f64, y: f64, fill_rule: CanvasFillRule) -> bool {
|
||||
self.canvas_state
|
||||
.is_point_in_path_(&self.global(), path.segments(), x, y, fill_rule)
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-drawimage
|
||||
fn DrawImage(&self, image: CanvasImageSource, dx: f64, dy: f64) -> ErrorResult {
|
||||
self.canvas_state.draw_image(None, image, dx, dy)
|
||||
|
|
313
components/script/dom/path2d.rs
Normal file
313
components/script/dom/path2d.rs
Normal file
|
@ -0,0 +1,313 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use std::cell::RefCell;
|
||||
|
||||
use canvas_traits::canvas::PathSegment;
|
||||
use dom_struct::dom_struct;
|
||||
use js::rust::HandleObject;
|
||||
use script_bindings::str::DOMString;
|
||||
|
||||
use crate::dom::bindings::codegen::Bindings::CanvasRenderingContext2DBinding::Path2DMethods;
|
||||
use crate::dom::bindings::error::{Error, Fallible};
|
||||
use crate::dom::bindings::reflector::{Reflector, reflect_dom_object_with_proto};
|
||||
use crate::dom::bindings::root::DomRoot;
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::script_runtime::CanGc;
|
||||
use crate::svgpath::PathParser;
|
||||
|
||||
#[dom_struct]
|
||||
pub(crate) struct Path2D {
|
||||
reflector_: Reflector,
|
||||
#[no_trace]
|
||||
path: RefCell<Vec<PathSegment>>,
|
||||
}
|
||||
|
||||
impl Path2D {
|
||||
pub(crate) fn new() -> Path2D {
|
||||
Self {
|
||||
reflector_: Reflector::new(),
|
||||
path: RefCell::new(vec![]),
|
||||
}
|
||||
}
|
||||
pub(crate) fn new_with_path(other: &Path2D) -> Path2D {
|
||||
Self {
|
||||
reflector_: Reflector::new(),
|
||||
path: other.path.clone(),
|
||||
}
|
||||
}
|
||||
pub(crate) fn new_with_str(path: &str) -> Path2D {
|
||||
let mut path_segments = Vec::new();
|
||||
|
||||
for segment in PathParser::new(path) {
|
||||
if let Ok(segment) = segment {
|
||||
path_segments.push(segment);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Self {
|
||||
reflector_: Reflector::new(),
|
||||
path: RefCell::new(path_segments),
|
||||
}
|
||||
}
|
||||
pub(crate) fn push(&self, seg: PathSegment) {
|
||||
self.path.borrow_mut().push(seg);
|
||||
}
|
||||
pub(crate) fn segments(&self) -> Vec<PathSegment> {
|
||||
self.path.borrow().clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl Path2DMethods<crate::DomTypeHolder> for Path2D {
|
||||
/// <https://html.spec.whatwg.org/multipage/#dom-path2d-addpath>
|
||||
fn AddPath(&self, other: &Path2D) {
|
||||
// Step 7. Add all the subpaths in c to a.
|
||||
let mut dest = self.path.borrow_mut();
|
||||
dest.extend(other.path.borrow().iter().copied());
|
||||
}
|
||||
|
||||
/// <https://html.spec.whatwg.org/multipage/#dom-context-2d-closepath>
|
||||
fn ClosePath(&self) {
|
||||
self.push(PathSegment::ClosePath);
|
||||
}
|
||||
|
||||
/// <https://html.spec.whatwg.org/multipage/#dom-context-2d-moveto>
|
||||
fn MoveTo(&self, x: f64, y: f64) {
|
||||
// Step 1. If either of the arguments are infinite or NaN, then return.
|
||||
if !(x.is_finite() && y.is_finite()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Step 2. Create a new subpath with the specified point as its first (and only) point.
|
||||
self.push(PathSegment::MoveTo {
|
||||
x: x as f32,
|
||||
y: y as f32,
|
||||
});
|
||||
}
|
||||
|
||||
/// <https://html.spec.whatwg.org/multipage/#dom-context-2d-lineto>
|
||||
fn LineTo(&self, x: f64, y: f64) {
|
||||
// Step 1. If either of the arguments are infinite or NaN, then return.
|
||||
if !(x.is_finite() && y.is_finite()) {
|
||||
return;
|
||||
}
|
||||
|
||||
self.push(PathSegment::LineTo {
|
||||
x: x as f32,
|
||||
y: y as f32,
|
||||
});
|
||||
}
|
||||
|
||||
/// <https://html.spec.whatwg.org/multipage/#dom-context-2d-quadraticcurveto>
|
||||
fn QuadraticCurveTo(&self, cpx: f64, cpy: f64, x: f64, y: f64) {
|
||||
// Step 1. If any of the arguments are infinite or NaN, then return.
|
||||
if !(cpx.is_finite() && cpy.is_finite() && x.is_finite() && y.is_finite()) {
|
||||
return;
|
||||
}
|
||||
|
||||
self.push(PathSegment::Quadratic {
|
||||
cpx: cpx as f32,
|
||||
cpy: cpy as f32,
|
||||
x: x as f32,
|
||||
y: y as f32,
|
||||
});
|
||||
}
|
||||
|
||||
/// <https://html.spec.whatwg.org/multipage/#dom-context-2d-beziercurveto>
|
||||
fn BezierCurveTo(&self, cp1x: f64, cp1y: f64, cp2x: f64, cp2y: f64, x: f64, y: f64) {
|
||||
// Step 1. If any of the arguments are infinite or NaN, then return.
|
||||
if !(cp1x.is_finite() &&
|
||||
cp1y.is_finite() &&
|
||||
cp2x.is_finite() &&
|
||||
cp2y.is_finite() &&
|
||||
x.is_finite() &&
|
||||
y.is_finite())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
self.push(PathSegment::Bezier {
|
||||
cp1x: cp1x as f32,
|
||||
cp1y: cp1y as f32,
|
||||
cp2x: cp2x as f32,
|
||||
cp2y: cp2y as f32,
|
||||
x: x as f32,
|
||||
y: y as f32,
|
||||
});
|
||||
}
|
||||
|
||||
/// <https://html.spec.whatwg.org/multipage/#dom-context-2d-arcto>
|
||||
fn ArcTo(&self, x1: f64, y1: f64, x2: f64, y2: f64, r: f64) -> Fallible<()> {
|
||||
// Step 1. If any of the arguments are infinite or NaN, then return.
|
||||
if !(x1.is_finite() && y1.is_finite() && x2.is_finite() && y2.is_finite() && r.is_finite())
|
||||
{
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// Step 3. If radius is negative, then throw an "IndexSizeError" DOMException.
|
||||
if r < 0.0 {
|
||||
return Err(Error::IndexSize);
|
||||
}
|
||||
|
||||
self.push(PathSegment::ArcTo {
|
||||
cp1x: x1 as f32,
|
||||
cp1y: y1 as f32,
|
||||
cp2x: x2 as f32,
|
||||
cp2y: y2 as f32,
|
||||
radius: r as f32,
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// <https://html.spec.whatwg.org/multipage/#dom-context-2d-rect>
|
||||
fn Rect(&self, x: f64, y: f64, w: f64, h: f64) {
|
||||
// Step 1. If any of the arguments are infinite or NaN, then return.
|
||||
if !(x.is_finite() && y.is_finite() && w.is_finite() && h.is_finite()) {
|
||||
return;
|
||||
}
|
||||
// Step 2. Create a new subpath containing just the four points
|
||||
// (x, y), (x+w, y), (x+w, y+h), (x, y+h), in that order,
|
||||
// with those four points connected by straight lines.
|
||||
self.push(PathSegment::MoveTo {
|
||||
x: x as f32,
|
||||
y: y as f32,
|
||||
});
|
||||
self.push(PathSegment::LineTo {
|
||||
x: (x + w) as f32,
|
||||
y: y as f32,
|
||||
});
|
||||
self.push(PathSegment::LineTo {
|
||||
x: (x + w) as f32,
|
||||
y: (y + h) as f32,
|
||||
});
|
||||
self.push(PathSegment::LineTo {
|
||||
x: x as f32,
|
||||
y: (y + h) as f32,
|
||||
});
|
||||
// Step 3. Mark the subpath as closed.
|
||||
self.push(PathSegment::ClosePath);
|
||||
|
||||
// Step 4. Create a new subpath with the point (x, y) as the only point in the subpath.
|
||||
self.push(PathSegment::MoveTo {
|
||||
x: x as f32,
|
||||
y: y as f32,
|
||||
});
|
||||
}
|
||||
|
||||
/// <https://html.spec.whatwg.org/multipage/#dom-context-2d-arc>
|
||||
fn Arc(
|
||||
&self,
|
||||
x: f64,
|
||||
y: f64,
|
||||
r: f64,
|
||||
start: f64,
|
||||
end: f64,
|
||||
anticlockwise: bool,
|
||||
) -> Fallible<()> {
|
||||
// Step 1. If any of the arguments are infinite or NaN, then return.
|
||||
if !(x.is_finite() &&
|
||||
y.is_finite() &&
|
||||
r.is_finite() &&
|
||||
start.is_finite() &&
|
||||
end.is_finite())
|
||||
{
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// Step 2. If either radiusX or radiusY are negative, then throw an "IndexSizeError" DOMException.
|
||||
if r < 0.0 {
|
||||
return Err(Error::IndexSize);
|
||||
}
|
||||
|
||||
self.push(PathSegment::Ellipse {
|
||||
x: x as f32,
|
||||
y: y as f32,
|
||||
radius_x: r as f32,
|
||||
radius_y: r as f32,
|
||||
rotation: 0.,
|
||||
start_angle: start as f32,
|
||||
end_angle: end as f32,
|
||||
anticlockwise,
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// <https://html.spec.whatwg.org/multipage/#dom-context-2d-ellipse>
|
||||
fn Ellipse(
|
||||
&self,
|
||||
x: f64,
|
||||
y: f64,
|
||||
rx: f64,
|
||||
ry: f64,
|
||||
rotation: f64,
|
||||
start: f64,
|
||||
end: f64,
|
||||
anticlockwise: bool,
|
||||
) -> Fallible<()> {
|
||||
// Step 1. If any of the arguments are infinite or NaN, then return.
|
||||
if !(x.is_finite() &&
|
||||
y.is_finite() &&
|
||||
rx.is_finite() &&
|
||||
ry.is_finite() &&
|
||||
rotation.is_finite() &&
|
||||
start.is_finite() &&
|
||||
end.is_finite())
|
||||
{
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// Step 2. If either radiusX or radiusY are negative, then throw an "IndexSizeError" DOMException.
|
||||
if rx < 0.0 || ry < 0.0 {
|
||||
return Err(Error::IndexSize);
|
||||
}
|
||||
|
||||
self.push(PathSegment::Ellipse {
|
||||
x: x as f32,
|
||||
y: y as f32,
|
||||
radius_x: rx as f32,
|
||||
radius_y: ry as f32,
|
||||
rotation: rotation as f32,
|
||||
start_angle: start as f32,
|
||||
end_angle: end as f32,
|
||||
anticlockwise,
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// <https://html.spec.whatwg.org/multipage/#dom-path2d-dev>
|
||||
fn Constructor(
|
||||
global: &GlobalScope,
|
||||
proto: Option<HandleObject>,
|
||||
can_gc: CanGc,
|
||||
) -> DomRoot<Path2D> {
|
||||
reflect_dom_object_with_proto(Box::new(Self::new()), global, proto, can_gc)
|
||||
}
|
||||
|
||||
/// <https://html.spec.whatwg.org/multipage/#dom-path2d-dev>
|
||||
fn Constructor_(
|
||||
global: &GlobalScope,
|
||||
proto: Option<HandleObject>,
|
||||
can_gc: CanGc,
|
||||
other: &Path2D,
|
||||
) -> DomRoot<Path2D> {
|
||||
reflect_dom_object_with_proto(Box::new(Self::new_with_path(other)), global, proto, can_gc)
|
||||
}
|
||||
|
||||
/// <https://html.spec.whatwg.org/multipage/#dom-path2d-dev>
|
||||
fn Constructor__(
|
||||
global: &GlobalScope,
|
||||
proto: Option<HandleObject>,
|
||||
can_gc: CanGc,
|
||||
path_string: DOMString,
|
||||
) -> DomRoot<Path2D> {
|
||||
reflect_dom_object_with_proto(
|
||||
Box::new(Self::new_with_str(path_string.str())),
|
||||
global,
|
||||
proto,
|
||||
can_gc,
|
||||
)
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue