stdweb/webapi/
rendering_context.rs

1use webcore::value::{Reference, ConversionError};
2use webcore::try_from::{TryFrom, TryInto};
3use webcore::value::{Undefined, Value};
4use webapi::html_elements::{CanvasElement, ImageElement};
5use webapi::html_element::IHtmlElement;
6use webapi::dom_exception::{SyntaxError, IndexSizeError, InvalidStateError, SecurityError, NotSupportedError};
7use webapi::error::TypeError;
8
9/// Trait implemented by rendering contexts which can be obtained from a canvas.
10pub trait RenderingContext {
11    /// Type of error which can occur whilst creating this context
12    type Error;
13    /// Name which identifies this kind of rendering context.
14    fn from_canvas(canvas: &CanvasElement) -> Result<Self, Self::Error> where Self: Sized;
15}
16
17/// Used for drawing rectangles, text, images and other objects onto the canvas element.
18///
19/// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D)
20// https://html.spec.whatwg.org/#canvasrenderingcontext2d
21#[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
22#[reference(instance_of = "CanvasRenderingContext2D")]
23pub struct CanvasRenderingContext2d(Reference);
24
25/// The CanvasGradient struct represents an opaque object describing a gradient.
26/// It is returned by the methods CanvasRenderingContext2D.createLinearGradient() or
27/// CanvasRenderingContext2D.createRadialGradient().
28///
29/// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasGradient)
30// https://html.spec.whatwg.org/#canvasgradient
31#[derive(Clone, Debug, Eq, PartialEq, ReferenceType)]
32#[reference(instance_of = "CanvasGradient")]
33pub struct CanvasGradient(Reference);
34
35/// The CanvasPattern struct represents an opaque object describing a pattern, based on an image,
36/// a canvas or a video, created by the CanvasRenderingContext2D.createPattern() method.
37/// Intentionally blank, no non-experimental properties or methods.
38///
39/// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasPattern)
40// https://html.spec.whatwg.org/#canvaspattern
41#[derive(Clone, Debug, Eq, PartialEq, ReferenceType)]
42#[reference(instance_of = "CanvasPattern")]
43pub struct CanvasPattern(Reference);
44
45/// The ImageData struct represents the underlying pixel data of an area of a `<canvas>` element.
46/// You can create a new instance by calling [`CanvasRenderingContext2d::create_image_data`](struct.CanvasRenderingContext2d.html#method.create_image_data)
47/// or [`CanvasRenderingContext2d::create_image_data_size_of`](struct.CanvasRenderingContext2d.html#method.create_image_data_size_of).
48///
49/// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/ImageData)
50// https://html.spec.whatwg.org/#imagedata
51#[derive(Clone, Debug, ReferenceType)]
52#[reference(instance_of = "ImageData")]
53pub struct ImageData(Reference);
54
55/// The TextMetrics struct represents the dimension of a text in the canvas, as created by the CanvasRenderingContext2D.measureText() method.
56///
57/// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/TextMetrics)
58// https://html.spec.whatwg.org/#textmetrics
59#[derive(Clone, Debug, ReferenceType)]
60#[reference(instance_of = "TextMetrics")]
61pub struct TextMetrics(Reference);
62
63/// The type of compositing operation to apply when drawing new shapes
64///
65/// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/globalCompositeOperation)
66#[derive(Debug, Copy, Clone, PartialEq, Eq)]
67pub enum CompositeOperation {
68    /// Draws new shapes over existing canvas content
69    SourceOver,
70    /// Draws new shapes over existing canvas content, but only where existing canvas content overlaps. Anything not in that area becomes transparent.
71    SourceIn,
72    /// New shapes are drawn where there is no existing canvas content. Everything else (including old canvas content) is made transparent.
73    SourceOut,
74    /// Draws new shapes only where there is existing canvas content, over existing canvas content
75    SourceAtop,
76    /// Draws new shapes behind existing canvas content
77    DestinationOver,
78    /// Keeps existing canvas content where it overlaps with the new shape. Everything outside the overlap is made transparent.
79    DestinationIn,
80    /// The existing content is kept where it doesn't overlap with the new shape. Everything else, including the new shape area, is made transparent.
81    DestinationOut,
82    /// Existing content is kept only where it overlaps with the new shape. The new shape is drawn behind the existing content.
83    DestinationAtop,
84    /// Where both shapes overlap, the new color is determined by adding color values
85    Lighter,
86    /// Only the new shape is shown
87    Copy,
88    /// Where both shapes overlap, make it transparent
89    Xor,
90    /// The pixels of the new and old layer are multiplied. (Pixel values are in the range of [0,1], so this makes a darker picture)
91    Multiply,
92    /// Pixels from both new and old are inverted, multiplied together, then inverted again. (Pixel values are in the range of [0,1], so this makes a lighter picture)
93    Screen,
94    /// Applies Multiply to dark colors in the existing content, and Screen to bright colors in the existing content
95    Overlay,
96    /// Retains the darkest pixels
97    Darken,
98    /// Retains the lighest pixels
99    Lighten,
100    /// Divides the bottom layer by the inverted top layer.
101    ColorDodge,
102    /// Divides the inverted bottom layer by the top layer, and then inverts the result.
103    ColorBurn,
104    /// A combination of multiply and screen like overlay, but with top and bottom layer swapped.
105    HardLight,
106    /// A softer version of hard-light. Pure black or white does not result in pure black or white.
107    SoftLight,
108    /// Subtracts the bottom layer from the top layer or the other way round to always get a positive value.
109    Difference,
110    /// Like difference, but with lower contrast.
111    Exclusion,
112    /// Preserves the luma and chroma of the bottom layer, while adopting the hue of the top layer.
113    Hue,
114    /// Preserves the luma and hue of the bottom layer, while adopting the chroma of the top layer.
115    Saturation,
116    /// Preserves the luma of the bottom layer, while adopting the hue and chroma of the top layer.
117    Color,
118    /// Preserves the hue and chroma of the bottom layer, while adopting the luma of the top layer.
119    Luminosity
120}
121
122/// The algorithm by which to determine if a point is inside a path or outside a path.
123///
124/// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/fill)
125// https://html.spec.whatwg.org/#canvasfillrule
126#[derive(Debug, Copy, Clone, PartialEq, Eq)]
127pub enum FillRule {
128    /// [Non-zero winding rule](https://en.wikipedia.org/wiki/Nonzero-rule)
129    NonZero,
130    /// [Even-odd winding rule](https://en.wikipedia.org/wiki/Even%E2%80%93odd_rule)
131    EvenOdd
132}
133
134/// Certain style functions can return multiple types
135#[derive(Debug, Clone, PartialEq, Eq)]
136pub enum CanvasStyle {
137    /// String representing the style
138    String(String),
139    /// CanvasGradient representing the style
140    CanvasGradient(CanvasGradient),
141    /// CanvasPattern representing the style
142    CanvasPattern(CanvasPattern),
143}
144
145/// How the end points of every line are drawn.
146///
147/// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lineCap)
148// https://html.spec.whatwg.org/#canvaslinecap
149#[derive(Debug, Copy, Clone, PartialEq, Eq)]
150pub enum LineCap {
151    /// The ends of lines are squared off at the endpoints
152    Butt,
153    /// The ends of lines are rounded
154    Round,
155    /// The ends of lines are squared off by adding a box with an equal width and half the height of the line's thickness.
156    Square
157}
158
159/// determines how two connecting segments (of lines, arcs or curves) with non-zero lengths in a shape are
160/// joined together (degenerate segments with zero lengths, whose specified endpoints and control points are
161/// exactly at the same position, are skipped).
162///
163/// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lineJoin)
164// https://html.spec.whatwg.org/#canvaslinejoin
165#[derive(Debug, Copy, Clone, PartialEq, Eq)]
166pub enum LineJoin {
167    /// Fills an additional triangular area
168    Bevel,
169    /// Rounds off the corners of a shape
170    Round,
171    /// Connected segments are joined by extending their outside edges to connect at a single point
172    Miter
173}
174
175/// An enum indicating how to repeat the image.
176///
177/// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/createPattern)
178#[derive(Debug, Copy, Clone, PartialEq, Eq)]
179pub enum Repetition {
180    /// Repeat in both directions
181    Repeat,
182    /// Repeat horizontally
183    RepeatX,
184    /// Repeat vertically
185    RepeatY,
186    /// Don't repeat
187    NoRepeat
188}
189
190/// Specifies text alignment
191///
192/// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/textAlign)
193// https://html.spec.whatwg.org/#canvastextalign
194#[derive(Debug, Copy, Clone, PartialEq, Eq)]
195pub enum TextAlign {
196    /// Text is left-aligned
197    Left,
198    /// Text is right-aligned
199    Right,
200    /// Text is centered
201    Center,
202    /// Text is aligned at the normal start of the line for the current locale
203    Start,
204    /// Text is aligned at the normal end of the line for the current locale
205    End
206}
207
208/// Text baseline being used when drawing text
209///
210/// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/textBaseline)
211// https://html.spec.whatwg.org/#canvastextbaseline
212#[derive(Debug, Copy, Clone, PartialEq, Eq)]
213pub enum TextBaseline {
214    /// Text baseline is top of the em square
215    Top,
216    /// Text baseline is the hanging baseline.
217    Hanging,
218    /// Text baseline is the middle of the em square
219    Middle,
220    /// Text baseline is the normal alphabetic baseline. (default)
221    Alphabetic,
222    /// Text baseline is the ideographic baseline
223    Ideographic,
224    /// Text baseline is the bottom of the bounding box.
225    Bottom
226}
227
228error_enum_boilerplate! {
229    /// A enum of the exceptions that CanvasGradient.add_color_stop() may throw
230    // https://html.spec.whatwg.org/multipage/canvas.html#dom-canvasgradient-addcolorstop
231    AddColorStopError,
232    /// A SyntaxError if the color could not be parsed as a valid CSS color
233    SyntaxError,
234    /// An IndexSizeError if the offset was not between 0 and 1, inclusive
235    IndexSizeError
236}
237
238error_enum_boilerplate! {
239    /// A enum of the exceptions that CanvasRenderingContext2D.draw_image() and similar may throw
240    DrawImageError,
241    /// An IndexSizeError if the source or destination rectangle has an width or height of 0
242    IndexSizeError,
243    /// An InvalidStateError if the image has no image data
244    InvalidStateError,
245    /// A NotSupportedError
246    NotSupportedError,
247    /// A TypeError if the specified source element isn't supported
248    TypeError
249}
250
251error_enum_boilerplate! {
252    /// A enum of the exceptions that CanvasRenderingContext2D.get_image_data() may throw
253    GetImageDataError,
254    /// An IndexSizeError if thw width or height is 0
255    IndexSizeError,
256    /// A SecurityError
257    SecurityError
258}
259
260impl TryFrom<Value> for CanvasStyle {
261    type Error = ConversionError;
262
263    /// Performs the conversion.
264    fn try_from(value: Value) -> Result<Self, Self::Error> {
265        if let Ok(v) = String::try_from(value.clone()) {
266            return Ok(CanvasStyle::String(v));
267        }
268        if let Ok(v) = CanvasGradient::try_from(value.clone()) {
269            return Ok(CanvasStyle::CanvasGradient(v));
270        }
271        if let Ok(v) = CanvasPattern::try_from(value.clone()) {
272            return Ok(CanvasStyle::CanvasPattern(v));
273        }
274        Err(::webcore::value::ConversionError::type_mismatch( &value, "String, CanvasGradient or CanvasPattern".into() ))
275    }
276}
277
278impl Default for FillRule {
279    fn default() -> FillRule { FillRule::NonZero }
280}
281
282impl Default for Repetition {
283    fn default() -> Repetition { Repetition::Repeat }
284}
285
286impl RenderingContext for CanvasRenderingContext2d {
287    type Error = ConversionError;
288    fn from_canvas(canvas: &CanvasElement) -> Result<Self, ConversionError> {
289        js!(
290            return @{canvas}.getContext("2d");
291        ).try_into()
292    }
293}
294
295impl CanvasGradient {
296
297    /// Adds a new stop, defined by an offset and a color, to the gradient. If the offset is
298    /// not between 0 and 1, an INDEX_SIZE_ERR is returned, if the color can't be parsed as a
299    /// CSS <color>, a SYNTAX_ERR is returned.
300    ///
301    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasGradient/addColorStop)
302    // https://html.spec.whatwg.org/#2dcontext:dom-canvasgradient-addcolorstop
303    pub fn add_color_stop(&self, offset: f64, color: &str) -> Result<(), AddColorStopError> {
304        js_try! ( @(no_return)
305            @{&self.0}.addColorStop(@{offset}, @{color});
306        ).unwrap()
307    }
308}
309
310impl ImageData {
311
312    /*
313    /// Returns a Uint8ClampedArray representing a one-dimensional array containing the data in the RGBA order,
314    /// with integer values between 0 and 255 (included).
315    ///
316    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/ImageData/data)
317    // https://html.spec.whatwg.org/#2dcontext:dom-imagedata-data
318    // TODO: Return Uint8ClampedArray reference PR 96: https://github.com/koute/stdweb/pull/96
319
320    pub fn get_data(&self) -> TypedArray<u8> {
321        js! (
322            return @{&self.0}.data;
323        ).try_into().unwrap()
324    }*/
325
326    /// Returns the number of rows in the image data object.
327    ///
328    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/ImageData/height)
329    // https://html.spec.whatwg.org/#2dcontext:dom-imagedata-height
330    pub fn get_height(&self) -> u32 {
331        js! (
332            return @{&self.0}.height;
333        ).try_into().unwrap()
334    }
335
336    /// Returns the number of pixels per row in the image data object.
337    ///
338    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/ImageData/width)
339    // https://html.spec.whatwg.org/#2dcontext:dom-imagedata-width
340    pub fn get_width(&self) -> u32 {
341        js! (
342            return @{&self.0}.width;
343        ).try_into().unwrap()
344    }
345}
346
347impl CanvasRenderingContext2d {
348
349    /// The CanvasRenderingContext2D.canvas property is a read-only reference to the HTMLCanvasElement
350    /// object that is associated with the context. It might be null if there is no association with an <canvas> element.
351    ///
352    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/canvas)
353    // https://html.spec.whatwg.org/#2dcontext:dom-context-2d-canvas
354    pub fn get_canvas(&self) -> CanvasElement {
355        js! (
356            return @{&self.0}.canvas;
357        ).try_into().unwrap()
358    }
359
360    /// The CanvasRenderingContext2D.fillStyle property of the Canvas 2D API specifies the color or style to use inside shapes.
361    /// The default is #000 (black).
362    ///
363    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/fillStyle)
364    // https://html.spec.whatwg.org/#2dcontext:dom-context-2d-fillstyle
365    pub fn get_fill_style(&self) -> CanvasStyle {
366        js! (
367            return @{&self.0}.fillStyle
368        ).try_into().unwrap()
369    }
370
371    /// The CanvasRenderingContext2D.fillStyle property of the Canvas 2D API specifies the color or style to use inside shapes.
372    /// The default is #000 (black).
373    ///
374    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/fillStyle)
375    // https://html.spec.whatwg.org/#2dcontext:dom-context-2d-fillstyle
376    pub fn set_fill_style_color(&self, color: &str){
377        js! { @(no_return)
378            @{&self.0}.fillStyle = @{color};
379        }
380    }
381
382    /// The CanvasRenderingContext2D.fillStyle property of the Canvas 2D API specifies the color or style to use inside shapes.
383    /// The default is #000 (black).
384    ///
385    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/fillStyle)
386    // https://html.spec.whatwg.org/#dom-context-2d-fillstyle
387    pub fn set_fill_style_gradient(&self, gradient: &CanvasGradient){
388        js! { @(no_return)
389            @{&self.0}.fillStyle = @{gradient};
390        }
391    }
392
393    /// The CanvasRenderingContext2D.fillStyle property of the Canvas 2D API specifies the color or style to use inside shapes.
394    /// The default is #000 (black).
395    ///
396    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/fillStyle)
397    // https://html.spec.whatwg.org/#dom-context-2d-fillstyle
398    pub fn set_fill_style_pattern(&self, pattern: &CanvasPattern){
399        js! { @(no_return)
400            @{&self.0}.fillStyle = @{pattern};
401        }
402    }
403
404    /// The CanvasRenderingContext2D.font property of the Canvas 2D API specifies the current
405    /// text style being used when drawing text. This string uses the same syntax as the CSS
406    /// font specifier. The default font is 10px sans-serif.
407    ///
408    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/font)
409    // https://html.spec.whatwg.org/#2dcontext:dom-context-2d-font
410    pub fn get_font(&self) -> String {
411        js! (
412            return @{&self.0}.font
413        ).try_into().unwrap()
414    }
415
416    /// The CanvasRenderingContext2D.font property of the Canvas 2D API specifies the current
417    /// text style being used when drawing text. This string uses the same syntax as the CSS
418    /// font specifier. The default font is 10px sans-serif.
419    ///
420    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/font)
421    // https://html.spec.whatwg.org/#2dcontext:dom-context-2d-font
422    pub fn set_font(&self, font: &str) {
423        js! { @(no_return)
424            @{&self.0}.font = @{font};
425        }
426    }
427
428    /// The CanvasRenderingContext2D.globalAlpha property of the Canvas 2D API specifies the alpha
429    /// value that is applied to shapes and images before they are drawn onto the canvas.
430    /// The value is in the range from 0.0 (fully transparent) to 1.0 (fully opaque).
431    ///
432    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/globalAlpha)
433    // https://html.spec.whatwg.org/#2dcontext:dom-context-2d-globalalpha
434    pub fn get_global_alpha(&self) -> f64 {
435        js! (
436            return @{&self.0}.globalAlpha
437        ).try_into().unwrap()
438    }
439
440    /// The CanvasRenderingContext2D.globalAlpha property of the Canvas 2D API specifies the alpha
441    /// value that is applied to shapes and images before they are drawn onto the canvas.
442    /// The value is in the range from 0.0 (fully transparent) to 1.0 (fully opaque).
443    ///
444    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/globalAlpha)
445    // https://html.spec.whatwg.org/#2dcontext:dom-context-2d-globalalpha
446    pub fn set_global_alpha(&self, global_alpha: f64) {
447        js! { @(no_return)
448            @{&self.0}.globalAlpha = @{global_alpha};
449        }
450    }
451
452    /// The CanvasRenderingContext2D.globalCompositeOperation property of the Canvas 2D API sets the
453    /// type of compositing operation to apply when drawing new shapes, where type is a string identifying
454    /// which of the compositing or blending mode operations to use.
455    ///
456    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/globalCompositeOperation)
457    // https://html.spec.whatwg.org/#2dcontext:dom-context-2d-globalcompositeoperation
458    pub fn get_global_composite_operation(&self) -> CompositeOperation {
459        let composite_operation_str: String = js! (
460            return @{&self.0}.globalCompositeOperation
461        ).try_into().unwrap();
462        match composite_operation_str.as_ref() {
463            "source-over" => CompositeOperation::SourceOver,
464            "source-in" => CompositeOperation::SourceIn,
465            "source-out" => CompositeOperation::SourceOut,
466            "source-atop" => CompositeOperation::SourceAtop,
467            "destination-over" => CompositeOperation::DestinationOver,
468            "destination-in" => CompositeOperation::DestinationIn,
469            "destination-out" => CompositeOperation::DestinationOut,
470            "destination-atop" => CompositeOperation::DestinationAtop,
471            "lighter" => CompositeOperation::Lighter,
472            "copy" => CompositeOperation::Copy,
473            "xor" => CompositeOperation::Xor,
474            "multiply" => CompositeOperation::Multiply,
475            "screen" => CompositeOperation::Screen,
476            "overlay" => CompositeOperation::Overlay,
477            "darken" => CompositeOperation::Darken,
478            "lighten" => CompositeOperation::Lighten,
479            "color-dodge" => CompositeOperation::ColorDodge,
480            "color-burn" => CompositeOperation::ColorBurn,
481            "hard-light" => CompositeOperation::HardLight,
482            "soft-light" => CompositeOperation::SoftLight,
483            "difference" => CompositeOperation::Difference,
484            "exclusion" => CompositeOperation::Exclusion,
485            "hue" => CompositeOperation::Hue,
486            "saturation" => CompositeOperation::Saturation,
487            "color" => CompositeOperation::Color,
488            "luminosity" => CompositeOperation::Luminosity,
489            _ => panic!("Unexpected globalCompositeOperation value: {:?}", composite_operation_str),
490        }
491    }
492
493    /// The CanvasRenderingContext2D.globalCompositeOperation property of the Canvas 2D API sets the
494    /// type of compositing operation to apply when drawing new shapes, where type is a string identifying
495    /// which of the compositing or blending mode operations to use.
496    ///
497    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/globalCompositeOperation)
498    // https://html.spec.whatwg.org/#2dcontext:dom-context-2d-globalcompositeoperation
499    pub fn set_global_composite_operation(&self, composite_operation: CompositeOperation) {
500        let composite_string = match composite_operation {
501            CompositeOperation::SourceOver => "source-over",
502            CompositeOperation::SourceIn => "source-in",
503            CompositeOperation::SourceOut => "source-out",
504            CompositeOperation::SourceAtop => "source-atop",
505            CompositeOperation::DestinationOver => "destination-over",
506            CompositeOperation::DestinationIn => "destination-in",
507            CompositeOperation::DestinationOut => "destination-out",
508            CompositeOperation::DestinationAtop => "destination-atop",
509            CompositeOperation::Lighter => "lighter",
510            CompositeOperation::Copy => "copy",
511            CompositeOperation::Xor => "xor",
512            CompositeOperation::Multiply => "multiply",
513            CompositeOperation::Screen => "screen",
514            CompositeOperation::Overlay => "overlay",
515            CompositeOperation::Darken => "darken",
516            CompositeOperation::Lighten => "lighten",
517            CompositeOperation::ColorDodge => "color-dodge",
518            CompositeOperation::ColorBurn => "color-burn",
519            CompositeOperation::HardLight => "hard-light",
520            CompositeOperation::SoftLight => "soft-light",
521            CompositeOperation::Difference => "difference",
522            CompositeOperation::Exclusion => "exclusion",
523            CompositeOperation::Hue => "hue",
524            CompositeOperation::Saturation => "saturation",
525            CompositeOperation::Color => "color",
526            CompositeOperation::Luminosity => "luminosity"
527        };
528        js! {@(no_return)
529            @{&self.0}.globalCompositeOperation = @{composite_string};
530        }
531    }
532
533    /// Determines how the end points of every line are drawn.
534    /// There are three possible values for this property and those are: butt, round and square.
535    /// By default this property is set to butt.
536    ///
537    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lineCap)
538    // https://html.spec.whatwg.org/#2dcontext:dom-context-2d-linecap
539    pub fn get_line_cap(&self) -> LineCap {
540        let line_cap_str: String = js! (
541            return @{&self.0}.lineCap
542        ).try_into().unwrap();
543
544        match line_cap_str.as_ref() {
545            "butt" => LineCap::Butt,
546            "round" => LineCap::Round,
547            "square" => LineCap::Square,
548            _ => panic!("Unexpected lineCap value: {:?}", line_cap_str),
549        }
550    }
551
552    /// Determines how the end points of every line are drawn.
553    /// There are three possible values for this property and those are: butt, round and square.
554    /// By default this property is set to butt.
555    ///
556    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lineCap)
557    // https://html.spec.whatwg.org/#2dcontext:dom-context-2d-linecap
558    pub fn set_line_cap(&self, line_cap: LineCap) {
559        let line_cap_string = match line_cap {
560            LineCap::Butt => "butt",
561            LineCap::Round => "round",
562            LineCap::Square => "square",
563        };
564        js! { @(no_return)
565            @{&self.0}.lineCap = @{line_cap_string};
566        }
567    }
568
569    /// Sets the line dash pattern offset or "phase" to achieve a "marching ants" effect, for example.
570    ///
571    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lineDashOffset)
572    // https://html.spec.whatwg.org/#2dcontext:dom-context-2d-linedashoffset
573    pub fn get_line_dash_offset(&self) -> f64 {
574        js! (
575            return @{&self.0}.lineDashOffset;
576        ).try_into().unwrap()
577    }
578
579    /// Sets the line dash pattern offset or "phase" to achieve a "marching ants" effect, for example.
580    ///
581    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lineDashOffset)
582    // https://html.spec.whatwg.org/#2dcontext:dom-context-2d-linedashoffset
583    pub fn set_line_dash_offset(&self, line_dash_offset: f64) {
584        js! { @(no_return)
585            @{&self.0}.lineDashOffset = @{line_dash_offset};
586        }
587    }
588
589    /// Determines how two connecting segments (of lines, arcs or curves) with non-zero lengths in a shape are
590    /// joined together (degenerate segments with zero lengths, whose specified endpoints and control points are
591    /// exactly at the same position, are skipped).
592    ///
593    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lineJoin)
594    // https://html.spec.whatwg.org/#2dcontext:dom-context-2d-linejoin
595    pub fn get_line_join(&self) -> LineJoin {
596        let line_join_str: String = js! (
597            return @{&self.0}.lineJoin;
598        ).try_into().unwrap();
599        match line_join_str.as_ref() {
600            "bevel" => LineJoin::Bevel,
601            "round" => LineJoin::Round,
602            "miter" => LineJoin::Miter,
603            _ => panic!("Unexpected lineJoin value: {:?}", line_join_str),
604        }
605    }
606
607    /// Determines how two connecting segments (of lines, arcs or curves) with non-zero lengths in a shape are
608    /// joined together (degenerate segments with zero lengths, whose specified endpoints and control points are
609    /// exactly at the same position, are skipped).
610    ///
611    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lineJoin)
612    // https://html.spec.whatwg.org/#2dcontext:dom-context-2d-linejoin
613    pub fn set_line_join(&self, line_join: LineJoin) {
614        let line_join_str = match line_join {
615            LineJoin::Bevel => "bevel",
616            LineJoin::Round => "round",
617            LineJoin::Miter => "miter",
618        };
619        js! { @(no_return)
620            @{&self.0}.lineJoin = @{line_join_str};
621        }
622    }
623
624    /// Sets the thickness of lines in space units. When getting, it returns the current value (1.0 by default).
625    /// When setting, zero, negative, Infinity and NaN values are ignored; otherwise the current value is set to the new value.
626    ///
627    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lineWidth)
628    // https://html.spec.whatwg.org/#2dcontext:dom-context-2d-linewidth
629    pub fn get_line_width(&self) -> f64 {
630        js! (
631            return @{&self.0}.lineWidth;
632        ).try_into().unwrap()
633    }
634
635    /// Sets the thickness of lines in space units. When getting, it returns the current value (1.0 by default).
636    /// When setting, zero, negative, Infinity and NaN values are ignored; otherwise the current value is set to the new value.
637    ///
638    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lineWidth)
639    // https://html.spec.whatwg.org/#2dcontext:dom-context-2d-linewidth
640    pub fn set_line_width(&self, line_width: f64) {
641        js! { @(no_return)
642            @{&self.0}.lineWidth = @{line_width};
643        }
644    }
645
646    /// sets the miter limit ratio in space units. When getting, it returns the current value (10.0 by default).
647    /// When setting, zero, negative, Infinity and NaN values are ignored; otherwise the current value is set to the new value.
648    ///
649    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/miterLimit)
650    // https://html.spec.whatwg.org/#2dcontext:dom-context-2d-miterlimit
651    pub fn get_miter_limit(&self) -> f64 {
652        js! (
653            return @{&self.0}.miterLimit;
654        ).try_into().unwrap()
655    }
656
657    /// sets the miter limit ratio in space units. When getting, it returns the current value (10.0 by default).
658    /// When setting, zero, negative, Infinity and NaN values are ignored; otherwise the current value is set to the new value.
659    ///
660    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/miterLimit)
661    // https://html.spec.whatwg.org/#2dcontext:dom-context-2d-miterlimit
662    pub fn set_miter_limit(&self, miter_limit: f64) {
663        js! { @(no_return)
664            @{&self.0}.miterLimit = @{miter_limit};
665        }
666    }
667
668    /// Specifies the level of the blurring effect; this value doesn't correspond to a number of pixels and is not
669    /// affected by the current transformation matrix. The default value is 0.
670    ///
671    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/shadowBlur)
672    // https://html.spec.whatwg.org/#2dcontext:dom-context-2d-shadowblur
673    pub fn get_shadow_blur(&self) -> f64 {
674        js! (
675            return @{&self.0}.shadowBlur;
676        ).try_into().unwrap()
677    }
678
679    /// Specifies the level of the blurring effect; this value doesn't correspond to a number of pixels and is not
680    /// affected by the current transformation matrix. The default value is 0.
681    ///
682    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/shadowBlur)
683    // https://html.spec.whatwg.org/#2dcontext:dom-context-2d-shadowblur
684    pub fn set_shadow_blur(&self, shadow_blur: f64) {
685        js! { @(no_return)
686            @{&self.0}.shadowBlur = @{shadow_blur};
687        }
688    }
689
690    /// Specifies the color of the shadow.
691    ///
692    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/shadowColor)
693    // https://html.spec.whatwg.org/#2dcontext:dom-context-2d-shadowcolor
694    pub fn get_shadow_color(&self) -> String {
695        js! (
696            return @{&self.0}.shadowColor;
697        ).try_into().unwrap()
698    }
699
700    /// Specifies the color of the shadow.
701    ///
702    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/shadowColor)
703    // https://html.spec.whatwg.org/#2dcontext:dom-context-2d-shadowcolor
704    pub fn set_shadow_color(&self, shadow_color: &str) {
705        js! { @(no_return)
706            @{&self.0}.shadowColor = @{shadow_color};
707        }
708    }
709
710    /// Specifies the distance that the shadow will be offset in horizontal distance.
711    ///
712    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/shadowOffsetX)
713    // https://html.spec.whatwg.org/#2dcontext:dom-context-2d-shadowoffsetx
714    pub fn get_shadow_offset_x(&self) -> f64 {
715        js! (
716            return @{&self.0}.shadowOffsetX;
717        ).try_into().unwrap()
718    }
719
720    /// Specifies the distance that the shadow will be offset in horizontal distance.
721    ///
722    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/shadowOffsetX)
723    // https://html.spec.whatwg.org/#2dcontext:dom-context-2d-shadowoffsetx
724    pub fn set_shadow_offset_x(&self, shadow_offset_x: f64) {
725        js! { @(no_return)
726            @{&self.0}.shadowOffsetX = @{shadow_offset_x};
727        }
728    }
729
730    /// Specifies the distance that the shadow will be offset in vertical distance.
731    ///
732    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/shadowOffsetY)
733    // https://html.spec.whatwg.org/#2dcontext:dom-context-2d-shadowoffsetx
734    pub fn get_shadow_offset_y(&self) -> f64 {
735        js! (
736            return @{&self.0}.shadowOffsetY;
737        ).try_into().unwrap()
738    }
739
740    /// Specifies the distance that the shadow will be offset in vertical distance.
741    ///
742    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/shadowOffsetY)
743    // https://html.spec.whatwg.org/#2dcontext:dom-context-2d-shadowoffsetx
744    pub fn set_shadow_offset_y(&self, shadow_offset_y: f64) {
745        js! { @(no_return)
746            @{&self.0}.shadowOffsetY = @{shadow_offset_y};
747        }
748    }
749
750    /// Specifies the color or style to use for the lines around shapes. The default is #000 (black).
751    ///
752    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/strokeStyle)
753    // https://html.spec.whatwg.org/#2dcontext:dom-context-2d-strokestyle
754    pub fn get_stroke_style(&self) -> CanvasStyle {
755        js! (
756            return @{&self.0}.strokeStyle;
757        ).try_into().unwrap()
758    }
759
760    /// Specifies the color or style to use for the lines around shapes. The default is #000 (black).
761    ///
762    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/strokeStyle)
763    // https://html.spec.whatwg.org/#2dcontext:dom-context-2d-strokestyle
764    pub fn set_stroke_style_color(&self, color: &str){
765        js! { @(no_return)
766            @{&self.0}.strokeStyle = @{color};
767        }
768    }
769
770    /// Specifies the color or style to use for the lines around shapes. The default is #000 (black).
771    ///
772    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/strokeStyle)
773    // https://html.spec.whatwg.org/#2dcontext:dom-context-2d-strokestyle
774    pub fn set_stroke_style_gradient(&self, gradient: &CanvasGradient){
775        js! { @(no_return)
776            @{&self.0}.strokeStyle = @{gradient};
777        }
778    }
779
780    /// Specifies the color or style to use for the lines around shapes. The default is #000 (black).
781    ///
782    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/strokeStyle)
783    // https://html.spec.whatwg.org/#2dcontext:dom-context-2d-strokestyle
784    pub fn set_stroke_style_pattern(&self, pattern: &CanvasPattern){
785        js! { @(no_return)
786            @{&self.0}.strokeStyle = @{pattern};
787        }
788    }
789
790    /// specifies the current text alignment being used when drawing text.
791    /// Beware that the alignment is based on the x value of the fillText() method.
792    /// So if textAlign is "center", then the text would be drawn at x - (width / 2).
793    ///
794    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/textAlign)
795    // https://html.spec.whatwg.org/#2dcontext:dom-context-2d-textalign
796    pub fn get_text_align(&self) -> TextAlign {
797        let text_align_str: String = js! (
798            return @{&self.0}.textAlign;
799        ).try_into().unwrap();
800        match text_align_str.as_ref() {
801            "center" => TextAlign::Center,
802            "end" => TextAlign::End,
803            "left" => TextAlign::Left,
804            "right" => TextAlign::Right,
805            "start" => TextAlign::Start,
806            _ => panic!("Unexpected textAlign value: {:?}", text_align_str),
807        }
808    }
809
810    /// specifies the current text alignment being used when drawing text.
811    /// Beware that the alignment is based on the x value of the fillText() method.
812    /// So if textAlign is "center", then the text would be drawn at x - (width / 2).
813    ///
814    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/textAlign)
815    // https://html.spec.whatwg.org/#2dcontext:dom-context-2d-textalign
816    pub fn set_text_align(&self, text_align: TextAlign) {
817        let text_align_str = match text_align {
818            TextAlign::Center => "center",
819            TextAlign::End => "end",
820            TextAlign::Left => "left",
821            TextAlign::Right => "right",
822            TextAlign::Start => "start",
823        };
824        js! { @(no_return)
825            @{&self.0}.textAlign = @{text_align_str};
826        }
827    }
828
829    /// Specifies the current text baseline being used when drawing text.
830    ///
831    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/textBaseline)
832    // https://html.spec.whatwg.org/#2dcontext:dom-context-2d-textbaseline
833    pub fn get_text_baseline(&self) -> TextBaseline {
834        let text_baseline_str: String = js! (
835            return @{&self.0}.textBaseline;
836        ).try_into().unwrap();
837        match text_baseline_str.as_ref() {
838            "alphabetic" => TextBaseline::Alphabetic,
839            "bottom" => TextBaseline::Bottom,
840            "hanging" => TextBaseline::Hanging,
841            "ideographic" => TextBaseline::Ideographic,
842            "middle" => TextBaseline::Middle,
843            "top" => TextBaseline::Top,
844            _ => panic!("Unexpected textBaseLine value: {:?}", text_baseline_str)
845        }
846    }
847
848    /// Specifies the current text baseline being used when drawing text.
849    ///
850    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/textBaseline)
851    // https://html.spec.whatwg.org/#2dcontext:dom-context-2d-textbaseline
852    pub fn set_text_baseline(&self, text_baseline: TextBaseline) {
853        let text_baseline_str = match text_baseline {
854            TextBaseline::Alphabetic => "alphabetic",
855            TextBaseline::Bottom => "bottom",
856            TextBaseline::Hanging => "hanging",
857            TextBaseline::Ideographic => "ideographic",
858            TextBaseline::Middle => "middle",
859            TextBaseline::Top => "top"
860        };
861        js! { @(no_return)
862            @{&self.0}.textBaseline = @{text_baseline_str};
863        }
864    }
865
866    /// Adds an arc to the path which is centered at (x, y) position with radius r starting
867    /// at startAngle and ending at endAngle going in the given direction by anticlockwise
868    /// (defaulting to clockwise).
869    ///
870    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/arc)
871    // https://html.spec.whatwg.org/#2dcontext:dom-context-2d-arc
872    pub fn arc(&self, x: f64, y: f64, radius: f64, start_angle: f64, end_angle: f64, anticlockwise: bool) {
873        js! { @(no_return)
874            @{&self.0}.arc(@{x}, @{y}, @{radius}, @{start_angle}, @{end_angle}, @{anticlockwise});
875        }
876    }
877
878    /// Adds an arc to the path with the given control points and radius.
879    /// The arc drawn will be a part of a circle, never elliptical.
880    /// Typical use could be making a rounded corner.
881    /// One way to think about the arc drawn is to imagine two straight segments, from the
882    /// starting point (latest point in current path) to the first control point, and then
883    /// from the first control point to the second control point. These two segments form
884    /// a sharp corner with the first control point being in the corner. Using arcTo, the
885    /// corner will instead be an arc with the given radius.
886    /// The arc is tangential to both segments, which can sometimes produce surprising results,
887    /// e.g. if the radius given is larger than the distance between the starting point and the first control point.
888    /// If the radius specified doesn't make the arc meet the starting point (latest point in the current path),
889    /// the starting point is connected to the arc with a straight line segment.
890    ///
891    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/arcTo)
892    // https://html.spec.whatwg.org/#2dcontext:dom-context-2d-arcto
893    pub fn arc_to(&self, x1: f64, y1: f64, x2: f64, y2: f64, radius: f64) -> Result<(), IndexSizeError> {
894        js_try! ( @(no_return)
895            @{&self.0}.arcTo(@{x1}, @{y1}, @{x2}, @{y2}, @{radius});
896        ).unwrap()
897    }
898
899    /// Starts a new path by emptying the list of sub-paths. Call this method when you want to create a new path.
900    ///
901    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/beginPath)
902    // https://html.spec.whatwg.org/#2dcontext:dom-context-2d-beginpath
903    pub fn begin_path(&self) {
904        js! { @(no_return)
905            @{&self.0}.beginPath();
906        }
907    }
908
909    /// Adds a cubic Bézier curve to the path. It requires three points. The first two points
910    /// are control points and the third one is the end point. The starting point is the last
911    /// point in the current path, which can be changed using moveTo() before creating the Bézier curve.
912    ///
913    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/bezierCurveTo)
914    // https://html.spec.whatwg.org/#2dcontext:dom-context-2d-beziercurveto
915    pub fn bezier_curve_to(&self, cp1x: f64, cp1y: f64, cp2x: f64, cp2y: f64, x: f64, y: f64) {
916        js! { @(no_return)
917            @{&self.0}.bezierCurveTo(@{cp1x}, @{cp1y}, @{cp2x}, @{cp2y}, @{x}, @{y});
918        }
919    }
920
921    /// Sets all pixels in the rectangle defined by starting point (x, y) and size (width, height)
922    /// to transparent black, erasing any previously drawn content.
923    ///
924    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/clearRect)
925    // https://html.spec.whatwg.org/#2dcontext:dom-context-2d-clearrect
926    pub fn clear_rect(&self, x: f64, y: f64, width: f64, height: f64) {
927        js! { @(no_return)
928            @{&self.0}.clearRect(@{x}, @{y}, @{width}, @{height});
929        }
930    }
931
932    /// Turns the path currently being built into the current clipping path.
933    /// ctx.clip(path, fillRule) is not supported because [(Path2D)](https://developer.mozilla.org/en-US/docs/Web/API/Path2D) is still experimental
934    ///
935    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/clip)
936    // https://html.spec.whatwg.org/#2dcontext:dom-context-2d-clip
937    pub fn clip(&self, fill_rule: FillRule) {
938        let fill_rule_str = fill_rule_to_str(fill_rule);
939        js! { @(no_return)
940            @{&self.0}.clip(@{fill_rule_str});
941        }
942    }
943
944    /// Causes the point of the pen to move back to the start of the current sub-path. It tries
945    /// to add a straight line (but does not actually draw it) from the current point to the start.
946    /// If the shape has already been closed or has only one point, this function does nothing.
947    ///
948    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/closePath)
949    // https://html.spec.whatwg.org/#2dcontext:dom-context-2d-closepath
950    pub fn close_path(&self) {
951        js! { @(no_return)
952            @{&self.0}.closePath();
953        }
954    }
955
956    /// Creates a gradient along the line given by the coordinates represented by the parameters.
957    ///
958    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/createLinearGradient)
959    // https://html.spec.whatwg.org/#2dcontext:dom-context-2d-createlineargradient
960    pub fn create_linear_gradient(&self, x0: f64, y0: f64, x1: f64, y1: f64) -> CanvasGradient {
961        js! (
962            return @{&self.0}.createLinearGradient(@{x0}, @{y0}, @{x1}, @{y1});
963        ).try_into().unwrap()
964    }
965
966    /// Creates a new, blank ImageData object with the specified dimensions.
967    /// All of the pixels in the new object are transparent black.
968    ///
969    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/createImageData)
970    // https://html.spec.whatwg.org/#2dcontext:dom-context-2d-createimagedata
971    pub fn create_image_data(&self, width: f64, height: f64) -> Result<ImageData, IndexSizeError> {
972        js_try! (
973            return @{&self.0}.createImageData(@{width}, @{height});
974        ).unwrap()
975    }
976
977    /// Creates a new, blank ImageData object with the specified dimensions.
978    /// All of the pixels in the new object are transparent black.
979    ///
980    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/createImageData)
981    // https://html.spec.whatwg.org/#2dcontext:dom-context-2d-createimagedata
982    pub fn create_image_data_size_of(&self, image_data: ImageData) -> ImageData {
983        js! (
984            return @{&self.0}.createImageData(@{image_data});
985        ).try_into().unwrap()
986    }
987
988    /// Creates a pattern using the specified image (a CanvasImageSource). It repeats the source in
989    /// the directions specified by the repetition argument. This method returns a CanvasPattern.
990    ///
991    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/createPattern)
992    // https://html.spec.whatwg.org/#2dcontext:dom-context-2d-createpattern
993    pub fn create_pattern_image(&self, image: ImageElement, repetition: Repetition) -> CanvasPattern {
994        let repetition_string = match repetition {
995            Repetition::Repeat => {
996                "repeat"
997            }
998
999            Repetition::RepeatX => {
1000                "repeat-x"
1001            }
1002
1003            Repetition::RepeatY => {
1004                "repeat-y"
1005            }
1006
1007            Repetition::NoRepeat => {
1008                "no-repeat"
1009            }
1010        };
1011
1012        js! (
1013            return @{&self.0}.createPattern(@{image}, @{repetition_string});
1014        ).try_into().unwrap()
1015    }
1016
1017    /// Creates a radial gradient given by the coordinates of the two circles represented by the parameters.
1018    /// This method returns a CanvasGradient.
1019    ///
1020    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/createRadialGradient)
1021    // https://html.spec.whatwg.org/#2dcontext:dom-context-2d-createradialgradient
1022    pub fn create_radial_gradient(&self, x0: f64, y0: f64, r0: f64, x1: f64, y1: f64, r1: f64) -> Result<CanvasGradient, IndexSizeError> {
1023        js_try! (
1024            return @{&self.0}.createRadialGradient(@{x0}, @{y0}, @{r0}, @{x1}, @{y1}, @{r1});
1025        ).unwrap()
1026    }
1027
1028    /// Draws a focus ring around the current path or given path, If a given element is focused.
1029    ///
1030    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/drawFocusIfNeeded)
1031    // https://html.spec.whatwg.org/#2dcontext:dom-context-2d-drawfocusifneeded
1032    pub fn draw_focus_if_needed< T: IHtmlElement >(&self, element: &T) {
1033        js! { @(no_return)
1034            @{&self.0}.drawFocusIfNeeded(@{element.as_ref()});
1035        }
1036    }
1037
1038    /// Provides different ways to draw an image onto the canvas.
1039    ///
1040    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/drawImage)
1041    // https://html.spec.whatwg.org/#2dcontext:dom-context-2d-drawimage
1042    pub fn draw_image(&self, image: ImageElement, dx: f64, dy: f64) -> Result<(), DrawImageError> {
1043        js_try! (@(no_return)
1044            @{&self.0}.drawImage(@{image}, @{dx}, @{dy});
1045        ).unwrap()
1046    }
1047
1048    /// Provides different ways to draw an image onto the canvas.
1049    ///
1050    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/drawImage)
1051    // https://html.spec.whatwg.org/#2dcontext:dom-context-2d-drawimage
1052    pub fn draw_image_d(&self, image: ImageElement, dx: f64, dy: f64, d_width: f64, d_height: f64) -> Result<(), DrawImageError> {
1053        js_try! (@(no_return)
1054            @{&self.0}.drawImage(@{image}, @{dx}, @{dy}, @{d_width}, @{d_height});
1055        ).unwrap()
1056    }
1057
1058    /// Provides different ways to draw an image onto the canvas.
1059    ///
1060    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/drawImage)
1061    // https://html.spec.whatwg.org/#2dcontext:dom-context-2d-drawimage
1062    pub fn draw_image_s(&self, image: ImageElement,
1063                        sx: f64, sy: f64, s_width: f64, s_height: f64,
1064                        dx: f64, dy: f64, d_width: f64, d_height: f64
1065                    ) -> Result<(), DrawImageError> {
1066        js_try!(@(no_return)
1067            @{&self.0}.drawImage(@{image}, @{sx}, @{sy}, @{s_width}, @{s_height}, @{dx}, @{dy}, @{d_width}, @{d_height});
1068        ).unwrap()
1069    }
1070
1071    /// Fills the current or given path with the current fill style using the non-zero or even-odd winding rule.
1072    ///
1073    /// ctx.fill(path, fillRule) is not supported because [(Path2D)](https://developer.mozilla.org/en-US/docs/Web/API/Path2D) is still experimental
1074    ///
1075    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/fill)
1076    // https://html.spec.whatwg.org/#2dcontext:dom-context-2d-fill
1077    pub fn fill(&self, fill_rule: FillRule) {
1078        let fill_rule_str = fill_rule_to_str(fill_rule);
1079        js! { @(no_return)
1080            @{&self.0}.fill(@{fill_rule_str});
1081        }
1082    }
1083
1084    /// Draws a filled rectangle whose starting point is at the coordinates (x, y) with the
1085    /// specified width and height and whose style is determined by the fillStyle attribute.
1086    ///
1087    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/fillRect)
1088    // https://html.spec.whatwg.org/#2dcontext:dom-context-2d-fillrect
1089    pub fn fill_rect(&self, x: f64, y: f64, width: f64, height: f64) {
1090        js! { @(no_return)
1091            @{&self.0}.fillRect(@{x}, @{y}, @{width}, @{height});
1092        }
1093    }
1094
1095    /// Draws a text string at the specified coordinates, filling the string's characters
1096    /// with the current foreground color. An optional parameter allows specifying a maximum
1097    /// width for the rendered text, which the user agent will achieve by condensing the
1098    /// text or by using a lower font size.
1099    ///
1100    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/fillText)
1101    // https://html.spec.whatwg.org/#2dcontext:dom-context-2d-filltext
1102    pub fn fill_text(&self, text: &str, x: f64, y: f64, max_width: Option<f64>) {
1103        if let Some(max_width) = max_width {
1104            js! { @(no_return)
1105                @{&self.0}.fillText(@{text}, @{x}, @{y}, @{max_width});
1106            }
1107        }
1108        else {
1109            js! { @(no_return)
1110                @{&self.0}.fillText(@{text}, @{x}, @{y});
1111            }
1112        }
1113    }
1114
1115    /// Returns an ImageData object representing the underlying pixel data for the area of the
1116    /// canvas denoted by the rectangle which starts at (sx, sy) and has an sw width and sh height.
1117    /// This method is not affected by the canvas transformation matrix.
1118    /// Pixels outside of the canvas area are present as transparent black values in the returned ImageData.
1119    ///
1120    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/getImageData)
1121    // https://html.spec.whatwg.org/#2dcontext:dom-context-2d-getimagedata
1122    pub fn get_image_data(&self, sx: f64, sy: f64, sw: f64, sh: f64) -> Result<ImageData, GetImageDataError> {
1123        js_try! (
1124            return @{&self.0}.getImageData(@{sx}, @{sy}, @{sw}, @{sh});
1125        ).unwrap()
1126    }
1127
1128    /// Gets the current line dash pattern.
1129    ///
1130    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/getLineDash)
1131    // https://html.spec.whatwg.org/#2dcontext:dom-context-2d-getlinedash
1132    pub fn get_line_dash(&self) -> Vec<f64> {
1133        js! (
1134            return @{&self.0}.getLineDash();
1135        ).try_into().unwrap()
1136    }
1137
1138    /// Reports whether or not the specified point is contained in the current path.
1139    ///
1140    /// ctx.isPointInPath(path, x, y) and ctx.isPointInPath(path, x, y, fillRule)
1141    /// are not supported because [(Path2D)](https://developer.mozilla.org/en-US/docs/Web/API/Path2D) is still experimental
1142    ///
1143    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/isPointInPath)
1144    // https://html.spec.whatwg.org/#2dcontext:dom-context-2d-ispointinpath
1145    pub fn is_point_in_path(&self, x: f64, y: f64, fill_rule: FillRule) -> bool {
1146        let fill_rule_str = fill_rule_to_str(fill_rule);
1147        js! (
1148            return @{&self.0}.isPointInPath(@{x}, @{y}, @{fill_rule_str});
1149        ).try_into().unwrap()
1150    }
1151
1152    /// Reports whether or not the specified point is inside the area contained by the stroking of a path.
1153    ///
1154    /// ctx.isPointInStroke(path, x, y) is not supported because [(Path2D)](https://developer.mozilla.org/en-US/docs/Web/API/Path2D) is still experimental
1155    ///
1156    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/isPointInStroke)
1157    // https://html.spec.whatwg.org/#2dcontext:dom-context-2d-ispointinstroke
1158    pub fn is_point_in_stroke(&self, x: f64, y: f64) -> bool {
1159        js! (
1160            return @{&self.0}.isPointInStroke(@{x}, @{y});
1161        ).try_into().unwrap()
1162    }
1163
1164    /// Connects the last point in the sub-path to the x, y coordinates with a straight line (but does not actually draw it).
1165    ///
1166    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lineTo)
1167    // https://html.spec.whatwg.org/#2dcontext:dom-context-2d-lineto
1168    pub fn line_to(&self, x: f64, y: f64) {
1169        js! { @(no_return)
1170            @{&self.0}.lineTo(@{x}, @{y});
1171        }
1172    }
1173
1174    /// Returns a TextMetrics object that contains information about the measured text (such as its width for example).
1175    ///
1176    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/measureText)
1177    // https://html.spec.whatwg.org/#2dcontext:dom-context-2d-measuretext
1178    pub fn measure_text(&self, text: &str) -> Result<TextMetrics, SecurityError> {
1179        js_try! (
1180            return @{&self.0}.measureText(@{text});
1181        ).unwrap()
1182    }
1183
1184    /// Moves the starting point of a new sub-path to the (x, y) coordinates.
1185    ///
1186    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/moveTo)
1187    // https://html.spec.whatwg.org/#2dcontext:dom-context-2d-moveto
1188    pub fn move_to(&self, x: f64, y: f64) {
1189        js! { @(no_return)
1190            @{&self.0}.moveTo(@{x}, @{y});
1191        }
1192    }
1193
1194    /// Paints data from the given ImageData object onto the bitmap. If a dirty rectangle is provided, only the pixels
1195    /// from that rectangle are painted. This method is not affected by the canvas transformation matrix.
1196    ///
1197    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/putImageData)
1198    // https://html.spec.whatwg.org/#2dcontext:dom-context-2d-putimagedata
1199    pub fn put_image_data(&self,
1200                            image_data: ImageData,
1201                            dx: f32, dy: f32
1202                        ) -> Result<(), InvalidStateError> {
1203        js_try! ( @(no_return)
1204            @{&self.0}.putImageData(@{image_data}, @{dx}, @{dy});
1205        ).unwrap()
1206    }
1207
1208    /// Paints data from the given ImageData object onto the bitmap. If a dirty rectangle is provided, only the pixels
1209    /// from that rectangle are painted. This method is not affected by the canvas transformation matrix.
1210    ///
1211    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/putImageData)
1212    // https://html.spec.whatwg.org/#2dcontext:dom-context-2d-putimagedata
1213    pub fn put_image_data_dirty(&self,
1214                            image_data: ImageData,
1215                            dx: f32, dy: f32,
1216                            dirty_x: f32, dirty_y: f32,
1217                            dirty_width: f32, dirty_height: f32
1218                        ) -> Result<(), InvalidStateError> {
1219        js_try! ( @(no_return)
1220            @{&self.0}.putImageData(@{image_data}, @{dx}, @{dy}, @{dirty_x}, @{dirty_y}, @{dirty_width}, @{dirty_height});
1221        ).unwrap()
1222    }
1223
1224    /// Adds a quadratic Bézier curve to the path. It requires two points.
1225    /// The first point is a control point and the second one is the end point.
1226    /// The starting point is the last point in the current path, which can be changed using
1227    /// moveTo() before creating the quadratic Bézier curve.
1228    ///
1229    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/quadraticCurveTo)
1230    // https://html.spec.whatwg.org/#2dcontext:dom-context-2d-quadraticcurveto
1231    pub fn quadratic_curve_to(&self, cpx: f64, cpy: f64, x:f64, y: f64) {
1232        js! { @(no_return)
1233            @{&self.0}.quadraticCurveTo(@{cpx}, @{cpy}, @{x}, @{y});
1234        }
1235    }
1236
1237    /// Creates a path for a rectangle at position (x, y) with a size that is determined by width and height.
1238    /// Those four points are connected by straight lines and the sub-path is marked as closed,
1239    /// so that you can fill or stroke this rectangle.
1240    ///
1241    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/rect)
1242    // https://html.spec.whatwg.org/#2dcontext:dom-context-2d-rect
1243    pub fn rect(&self, x: f64, y: f64, width: f64, height: f64) {
1244        js! { @(no_return)
1245            @{&self.0}.rect(@{x}, @{y}, @{width}, @{height});
1246        }
1247    }
1248
1249    /// Restores the most recently saved canvas state by popping the top entry in the drawing state stack.
1250    /// If there is no saved state, this method does nothing.
1251    ///
1252    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/restore)
1253    // https://html.spec.whatwg.org/#2dcontext:dom-context-2d-restore
1254    pub fn restore(&self) {
1255        js! { @(no_return)
1256            @{&self.0}.restore();
1257        }
1258    }
1259
1260    /// Adds a rotation to the transformation matrix. The angle argument represents a clockwise rotation angle and is expressed in radians.
1261    ///
1262    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/rotate)
1263    // https://html.spec.whatwg.org/#2dcontext:dom-context-2d-rotate
1264    pub fn rotate(&self, angle: f64) {
1265        js! { @(no_return)
1266            @{&self.0}.rotate(@{angle});
1267        }
1268    }
1269
1270    /// Saves the entire state of the canvas by pushing the current state onto a stack.
1271    ///
1272    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/save)
1273    // https://html.spec.whatwg.org/#2dcontext:dom-context-2d-save
1274    pub fn save(&self) {
1275        js! { @(no_return)
1276            @{&self.0}.save();
1277        }
1278    }
1279
1280    /// adds a scaling transformation to the canvas units by x horizontally and by y vertically.
1281    /// By default, one unit on the canvas is exactly one pixel. If we apply, for instance, a scaling factor of 0.5,
1282    /// the resulting unit would become 0.5 pixels and so shapes would be drawn at half size.
1283    /// In a similar way setting the scaling factor to 2.0 would increase the unit size and one unit now becomes two pixels.
1284    /// This results in shapes being drawn twice as large.
1285    ///
1286    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/scale)
1287    // https://html.spec.whatwg.org/#2dcontext:dom-context-2d-scale
1288    pub fn scale(&self, x: f64, y: f64) {
1289        js! { @(no_return)
1290            @{&self.0}.scale(@{x}, @{y});
1291        }
1292    }
1293
1294    /// Sets the line dash pattern used when stroking lines, using an array of values which specify alternating lengths of lines and gaps which describe the pattern.
1295    ///
1296    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/setLineDash)
1297    // https://html.spec.whatwg.org/#2dcontext:dom-context-2d-setlinedash
1298    pub fn set_line_dash(&self, segments: Vec<f64>) {
1299        js! { @(no_return)
1300            @{&self.0}.setLineDash(@{segments});
1301        }
1302    }
1303
1304    /// Resets (overrides) the current transformation to the identity matrix and then invokes a transformation described by the arguments of this method.
1305    /// See also the transform() method, which does not override the current transform matrix and multiplies it with a given one.
1306    ///
1307    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/setTransform)
1308    // https://html.spec.whatwg.org/#2dcontext:dom-context-2d-settransform
1309    pub fn set_transform(&self, a: f64, b: f64, c: f64, d: f64, e: f64, f: f64) {
1310        js! { @(no_return)
1311            @{&self.0}.setTransform(@{a}, @{b}, @{c}, @{d}, @{e}, @{f});
1312        }
1313    }
1314
1315    /// Strokes the current or given path with the current stroke style using the non-zero winding rule.
1316    ///
1317    /// ctx.stroke(path) is not supported because [(Path2D)](https://developer.mozilla.org/en-US/docs/Web/API/Path2D) is still experimental
1318    ///
1319    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/stroke)
1320    // https://html.spec.whatwg.org/#2dcontext:dom-context-2d-stroke
1321    pub fn stroke(&self) {
1322        js! { @(no_return)
1323            @{&self.0}.stroke();
1324        }
1325    }
1326
1327    /// Paints a rectangle which has a starting point at (x, y) and has a w width and an h height onto the canvas, using the current stroke style.
1328    ///
1329    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/strokeRect)
1330    // https://html.spec.whatwg.org/#2dcontext:dom-context-2d-strokerect
1331    pub fn stroke_rect(&self, x: f64, y: f64, width: f64, height: f64) {
1332        js! { @(no_return)
1333            @{&self.0}.strokeRect(@{x}, @{y}, @{width}, @{height});
1334        }
1335    }
1336
1337    /// Strokes — that is, draws the outlines of — the characters of a specified text string at the given (x, y) position.
1338    /// If the optional fourth parameter for a maximum width is provided, the text is scaled to fit that width.
1339    /// See the CanvasRenderingContext2D.fillText() method to draw the text with the characters filled with color rather than having just their outlines drawn.
1340    ///
1341    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/strokeText)
1342    // https://html.spec.whatwg.org/#2dcontext:dom-context-2d-stroketext
1343    pub fn stroke_text(&self, text: &str, x: f64, y: f64, max_width: Option<f64>) {
1344        if let Some(max_width) = max_width {
1345            js! { @(no_return)
1346                @{&self.0}.strokeText(@{text}, @{x}, @{y}, @{max_width});
1347            }
1348        }
1349        else {
1350            js! { @(no_return)
1351                @{&self.0}.strokeText(@{text}, @{x}, @{y}, @{Undefined});
1352            }
1353        }
1354    }
1355
1356    /// Multiplies the current transformation with the matrix described by the arguments of this method.
1357    /// You are able to scale, rotate, move and skew the context.
1358    /// See also the setTransform() method which resets the current transform to the identity matrix and then invokes transform().
1359    ///
1360    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/transform)
1361    // https://html.spec.whatwg.org/#2dcontext:dom-context-2d-transform
1362    pub fn transform(&self, a: f64, b: f64, c: f64, d: f64, e: f64, f: f64) {
1363        js! { @(no_return)
1364            @{&self.0}.transform(@{a}, @{b}, @{c}, @{d}, @{e}, @{f});
1365        }
1366    }
1367
1368    /// Adds a translation transformation by moving the canvas and its origin x horizontally and y vertically on the grid.
1369    ///
1370    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/translate)
1371    // https://html.spec.whatwg.org/#2dcontext:dom-context-2d-translate
1372    pub fn translate(&self, x: f64, y: f64) {
1373        js! { @(no_return)
1374            @{&self.0}.translate(@{x}, @{y});
1375        }
1376    }
1377}
1378
1379fn fill_rule_to_str(fill_rule: FillRule) -> &'static str {
1380    match fill_rule {
1381        FillRule::NonZero => {
1382            "nonzero"
1383        }
1384
1385        FillRule::EvenOdd => {
1386            "evenodd"
1387        }
1388    }
1389}
1390
1391impl TextMetrics {
1392
1393    /// Contains the text's advance width (the width of that inline box) in CSS pixels.
1394    ///
1395    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/TextMetrics/width)
1396    // https://html.spec.whatwg.org/#2dcontext:dom-textmetrics-width
1397    pub fn get_width(&self) -> f64 {
1398        js! (
1399            return @{&self.0}.width;
1400        ).try_into().unwrap()
1401    }
1402}
1403
1404#[cfg(all(test, feature = "web_test"))]
1405mod test {
1406    use super::*;
1407    use webapi::document::document;
1408
1409    fn new_canvas() -> CanvasRenderingContext2d {
1410        let canvas: CanvasElement = document().create_element("canvas").unwrap().try_into().unwrap();
1411        let ctx: CanvasRenderingContext2d = canvas.get_context().unwrap();
1412        ctx
1413    }
1414
1415    #[test]
1416    fn test_canvas_fill_color() {
1417        let canvas = new_canvas();
1418
1419        canvas.set_fill_style_color("rgb(200,0,0)");
1420        let style = canvas.get_fill_style();
1421        match style {
1422            CanvasStyle::String(s) => assert_eq!(s, "#c80000"),
1423            _ => assert!(false, "Expected style to be a string \"#c80000\" was instead {:?}", style),
1424        }
1425    }
1426
1427    #[test]
1428    fn test_browser_create_radial_gradient() {
1429        let canvas = new_canvas();
1430        canvas.fill_rect(10 as f64, 10 as f64, 55 as f64, 50 as f64);
1431
1432        let res: Result<CanvasGradient, IndexSizeError> = canvas.create_radial_gradient(100 as f64, 100 as f64, -1 as f64, 100 as f64, 100 as f64, 0 as f64);
1433        assert!(res.is_err());
1434    }
1435}