1use dom_struct::dom_struct;
6use euclid::default::Size2D;
7use js::context::{JSContext, NoGC};
8use pixels::Snapshot;
9use script_bindings::reflector::reflect_dom_object;
10use servo_canvas_traits::canvas::CanvasCommand;
11
12use crate::canvas_context::{CanvasContext, HTMLCanvasElementOrOffscreenCanvas};
13use crate::dom::bindings::codegen::Bindings::CanvasRenderingContext2DBinding::{
14 CanvasDirection, CanvasFillRule, CanvasImageSource, CanvasLineCap, CanvasLineJoin,
15 CanvasRenderingContext2DMethods, CanvasRenderingContext2DSettings, CanvasTextAlign,
16 CanvasTextBaseline,
17};
18use crate::dom::bindings::codegen::Bindings::DOMMatrixBinding::DOMMatrix2DInit;
19use crate::dom::bindings::codegen::Bindings::OffscreenCanvasRenderingContext2DBinding::OffscreenCanvasRenderingContext2DMethods;
20use crate::dom::bindings::codegen::UnionTypes::{
21 HTMLCanvasElementOrOffscreenCanvas as RootedHTMLCanvasElementOrOffscreenCanvas,
22 StringOrCanvasGradientOrCanvasPattern,
23 UnrestrictedDoubleOrDOMPointInitOrUnrestrictedDoubleOrDOMPointInitSequence,
24};
25use crate::dom::bindings::error::{ErrorResult, Fallible};
26use crate::dom::bindings::num::Finite;
27use crate::dom::bindings::root::{Dom, DomRoot};
28use crate::dom::bindings::str::DOMString;
29use crate::dom::canvasgradient::CanvasGradient;
30use crate::dom::canvaspattern::CanvasPattern;
31use crate::dom::canvasrenderingcontext2d::CanvasRenderingContext2D;
32use crate::dom::dommatrix::DOMMatrix;
33use crate::dom::globalscope::GlobalScope;
34use crate::dom::imagedata::ImageData;
35use crate::dom::offscreencanvas::OffscreenCanvas;
36use crate::dom::path2d::Path2D;
37use crate::dom::textmetrics::TextMetrics;
38
39#[dom_struct]
40pub(crate) struct OffscreenCanvasRenderingContext2D {
41 context: CanvasRenderingContext2D,
42}
43
44impl OffscreenCanvasRenderingContext2D {
45 #[cfg_attr(crown, expect(crown::unrooted_must_root))]
46 fn new_inherited(
47 global: &GlobalScope,
48 canvas: HTMLCanvasElementOrOffscreenCanvas,
49 size: Size2D<u32>,
50 settings: &CanvasRenderingContext2DSettings,
51 ) -> Option<OffscreenCanvasRenderingContext2D> {
52 Some(OffscreenCanvasRenderingContext2D {
53 context: CanvasRenderingContext2D::new_inherited(global, canvas, size, settings)?,
54 })
55 }
56
57 pub(crate) fn new(
58 cx: &mut JSContext,
59 global: &GlobalScope,
60 canvas: &OffscreenCanvas,
61 size: Size2D<u32>,
62 settings: &CanvasRenderingContext2DSettings,
63 ) -> Option<DomRoot<OffscreenCanvasRenderingContext2D>> {
64 OffscreenCanvasRenderingContext2D::new_inherited(
65 global,
66 HTMLCanvasElementOrOffscreenCanvas::OffscreenCanvas(Dom::from_ref(canvas)),
67 size,
68 settings,
69 )
70 .map(|context| {
71 let context = reflect_dom_object(cx, Box::new(context), global);
72 context.context.update_associated_memory_size();
73 context
74 })
75 }
76
77 pub(crate) fn send_canvas_command_immediate(&self, msg: CanvasCommand) {
78 self.context.send_canvas_command_immediate(msg)
79 }
80}
81
82impl CanvasContext for OffscreenCanvasRenderingContext2D {
83 type ID = <CanvasRenderingContext2D as CanvasContext>::ID;
84
85 fn context_id(&self) -> Self::ID {
86 self.context.context_id()
87 }
88
89 fn canvas(&self) -> Option<RootedHTMLCanvasElementOrOffscreenCanvas> {
90 self.context.canvas()
91 }
92
93 fn resize(&self) {
94 self.context.resize()
95 }
96
97 fn reset_bitmap(&self) {
98 self.context.reset_bitmap()
99 }
100
101 fn get_image_data(&self) -> Option<Snapshot> {
102 self.context.get_image_data()
103 }
104
105 fn origin_is_clean(&self) -> bool {
106 self.context.origin_is_clean()
107 }
108
109 fn mark_as_dirty(&self) {}
110}
111
112impl OffscreenCanvasRenderingContext2DMethods<crate::DomTypeHolder>
113 for OffscreenCanvasRenderingContext2D
114{
115 fn GetContextAttributes(&self) -> CanvasRenderingContext2DSettings {
117 self.context.GetContextAttributes()
121 }
122
123 fn Canvas(&self) -> DomRoot<OffscreenCanvas> {
125 match self.context.canvas() {
126 Some(RootedHTMLCanvasElementOrOffscreenCanvas::OffscreenCanvas(canvas)) => canvas,
127 _ => panic!("Should not be called from onscreen canvas"),
128 }
129 }
130
131 fn FillRect(&self, x: f64, y: f64, width: f64, height: f64) {
133 self.context.FillRect(x, y, width, height);
134 }
135
136 fn ClearRect(&self, x: f64, y: f64, width: f64, height: f64) {
138 self.context.ClearRect(x, y, width, height);
139 }
140
141 fn StrokeRect(&self, x: f64, y: f64, width: f64, height: f64) {
143 self.context.StrokeRect(x, y, width, height);
144 }
145
146 fn ShadowOffsetX(&self) -> f64 {
148 self.context.ShadowOffsetX()
149 }
150
151 fn SetShadowOffsetX(&self, value: f64) {
153 self.context.SetShadowOffsetX(value)
154 }
155
156 fn ShadowOffsetY(&self) -> f64 {
158 self.context.ShadowOffsetY()
159 }
160
161 fn SetShadowOffsetY(&self, value: f64) {
163 self.context.SetShadowOffsetY(value)
164 }
165
166 fn ShadowBlur(&self) -> f64 {
168 self.context.ShadowBlur()
169 }
170
171 fn SetShadowBlur(&self, value: f64) {
173 self.context.SetShadowBlur(value)
174 }
175
176 fn ShadowColor(&self) -> DOMString {
178 self.context.ShadowColor()
179 }
180
181 fn SetShadowColor(&self, value: DOMString) {
183 self.context.SetShadowColor(value)
184 }
185
186 fn StrokeStyle(&self) -> StringOrCanvasGradientOrCanvasPattern {
188 self.context.StrokeStyle()
189 }
190
191 fn SetStrokeStyle(&self, value: StringOrCanvasGradientOrCanvasPattern) {
193 self.context.SetStrokeStyle(value)
194 }
195
196 fn FillStyle(&self) -> StringOrCanvasGradientOrCanvasPattern {
198 self.context.FillStyle()
199 }
200
201 fn SetFillStyle(&self, value: StringOrCanvasGradientOrCanvasPattern) {
203 self.context.SetFillStyle(value)
204 }
205
206 fn CreateLinearGradient(
208 &self,
209 cx: &mut JSContext,
210 x0: Finite<f64>,
211 y0: Finite<f64>,
212 x1: Finite<f64>,
213 y1: Finite<f64>,
214 ) -> DomRoot<CanvasGradient> {
215 self.context.CreateLinearGradient(cx, x0, y0, x1, y1)
216 }
217
218 fn CreateRadialGradient(
220 &self,
221 cx: &mut JSContext,
222 x0: Finite<f64>,
223 y0: Finite<f64>,
224 r0: Finite<f64>,
225 x1: Finite<f64>,
226 y1: Finite<f64>,
227 r1: Finite<f64>,
228 ) -> Fallible<DomRoot<CanvasGradient>> {
229 self.context
230 .CreateRadialGradient(cx, x0, y0, r0, x1, y1, r1)
231 }
232
233 fn CreatePattern(
235 &self,
236 cx: &mut JSContext,
237 image: CanvasImageSource,
238 repetition: DOMString,
239 ) -> Fallible<Option<DomRoot<CanvasPattern>>> {
240 self.context.CreatePattern(cx, image, repetition)
241 }
242
243 fn Save(&self) {
245 self.context.Save()
246 }
247
248 fn Restore(&self) {
250 self.context.Restore()
251 }
252
253 fn Reset(&self) {
255 self.context.Reset()
256 }
257
258 fn GlobalAlpha(&self) -> f64 {
260 self.context.GlobalAlpha()
261 }
262
263 fn SetGlobalAlpha(&self, alpha: f64) {
265 self.context.SetGlobalAlpha(alpha)
266 }
267
268 fn GlobalCompositeOperation(&self) -> DOMString {
270 self.context.GlobalCompositeOperation()
271 }
272
273 fn SetGlobalCompositeOperation(&self, op_str: DOMString) {
275 self.context.SetGlobalCompositeOperation(op_str)
276 }
277
278 fn ImageSmoothingEnabled(&self) -> bool {
280 self.context.ImageSmoothingEnabled()
281 }
282
283 fn SetImageSmoothingEnabled(&self, value: bool) {
285 self.context.SetImageSmoothingEnabled(value)
286 }
287
288 fn FillText(&self, text: DOMString, x: f64, y: f64, max_width: Option<f64>) {
290 self.context.FillText(text, x, y, max_width)
291 }
292
293 fn StrokeText(&self, text: DOMString, x: f64, y: f64, max_width: Option<f64>) {
295 self.context.StrokeText(text, x, y, max_width)
296 }
297
298 fn MeasureText(&self, cx: &mut JSContext, text: DOMString) -> DomRoot<TextMetrics> {
300 self.context.MeasureText(cx, text)
301 }
302
303 fn Font(&self) -> DOMString {
305 self.context.Font()
306 }
307
308 fn SetFont(&self, value: DOMString) {
310 self.context.SetFont(value)
311 }
312
313 fn TextAlign(&self) -> CanvasTextAlign {
315 self.context.TextAlign()
316 }
317
318 fn SetTextAlign(&self, value: CanvasTextAlign) {
320 self.context.SetTextAlign(value)
321 }
322
323 fn TextBaseline(&self) -> CanvasTextBaseline {
325 self.context.TextBaseline()
326 }
327
328 fn SetTextBaseline(&self, value: CanvasTextBaseline) {
330 self.context.SetTextBaseline(value)
331 }
332
333 fn Direction(&self) -> CanvasDirection {
335 self.context.Direction()
336 }
337
338 fn SetDirection(&self, value: CanvasDirection) {
340 self.context.SetDirection(value)
341 }
342
343 fn LineWidth(&self) -> f64 {
345 self.context.LineWidth()
346 }
347
348 fn SetLineWidth(&self, width: f64) {
350 self.context.SetLineWidth(width)
351 }
352
353 fn LineCap(&self) -> CanvasLineCap {
355 self.context.LineCap()
356 }
357
358 fn SetLineCap(&self, cap: CanvasLineCap) {
360 self.context.SetLineCap(cap)
361 }
362
363 fn LineJoin(&self) -> CanvasLineJoin {
365 self.context.LineJoin()
366 }
367
368 fn SetLineJoin(&self, join: CanvasLineJoin) {
370 self.context.SetLineJoin(join)
371 }
372
373 fn MiterLimit(&self) -> f64 {
375 self.context.MiterLimit()
376 }
377
378 fn SetMiterLimit(&self, limit: f64) {
380 self.context.SetMiterLimit(limit)
381 }
382
383 fn SetLineDash(&self, segments: Vec<f64>) {
385 self.context.SetLineDash(segments)
386 }
387
388 fn GetLineDash(&self) -> Vec<f64> {
390 self.context.GetLineDash()
391 }
392
393 fn LineDashOffset(&self) -> f64 {
395 self.context.LineDashOffset()
396 }
397
398 fn SetLineDashOffset(&self, offset: f64) {
400 self.context.SetLineDashOffset(offset)
401 }
402
403 fn CreateImageData(
405 &self,
406 cx: &mut JSContext,
407 sw: i32,
408 sh: i32,
409 ) -> Fallible<DomRoot<ImageData>> {
410 self.context.CreateImageData(cx, sw, sh)
411 }
412
413 fn CreateImageData_(
415 &self,
416 cx: &mut JSContext,
417 imagedata: &ImageData,
418 ) -> Fallible<DomRoot<ImageData>> {
419 self.context.CreateImageData_(cx, imagedata)
420 }
421
422 fn GetImageData(
424 &self,
425 cx: &mut JSContext,
426 sx: i32,
427 sy: i32,
428 sw: i32,
429 sh: i32,
430 ) -> Fallible<DomRoot<ImageData>> {
431 self.context.GetImageData(cx, sx, sy, sw, sh)
432 }
433
434 fn PutImageData(&self, no_gc: &NoGC, imagedata: &ImageData, dx: i32, dy: i32) {
436 self.context.PutImageData(no_gc, imagedata, dx, dy)
437 }
438
439 fn PutImageData_(
441 &self,
442 no_gc: &NoGC,
443 imagedata: &ImageData,
444 dx: i32,
445 dy: i32,
446 dirty_x: i32,
447 dirty_y: i32,
448 dirty_width: i32,
449 dirty_height: i32,
450 ) {
451 self.context.PutImageData_(
452 no_gc,
453 imagedata,
454 dx,
455 dy,
456 dirty_x,
457 dirty_y,
458 dirty_width,
459 dirty_height,
460 )
461 }
462
463 fn DrawImage(&self, image: CanvasImageSource, dx: f64, dy: f64) -> ErrorResult {
465 self.context.DrawImage(image, dx, dy)
466 }
467
468 fn DrawImage_(
470 &self,
471 image: CanvasImageSource,
472 dx: f64,
473 dy: f64,
474 dw: f64,
475 dh: f64,
476 ) -> ErrorResult {
477 self.context.DrawImage_(image, dx, dy, dw, dh)
478 }
479
480 fn DrawImage__(
482 &self,
483 image: CanvasImageSource,
484 sx: f64,
485 sy: f64,
486 sw: f64,
487 sh: f64,
488 dx: f64,
489 dy: f64,
490 dw: f64,
491 dh: f64,
492 ) -> ErrorResult {
493 self.context
494 .DrawImage__(image, sx, sy, sw, sh, dx, dy, dw, dh)
495 }
496
497 fn BeginPath(&self) {
499 self.context.BeginPath()
500 }
501
502 fn Fill(&self, fill_rule: CanvasFillRule) {
504 self.context.Fill(fill_rule)
505 }
506
507 fn Fill_(&self, path: &Path2D, fill_rule: CanvasFillRule) {
509 self.context.Fill_(path, fill_rule)
510 }
511
512 fn Stroke(&self) {
514 self.context.Stroke()
515 }
516
517 fn Stroke_(&self, path: &Path2D) {
519 self.context.Stroke_(path)
520 }
521
522 fn Clip(&self, fill_rule: CanvasFillRule) {
524 self.context.Clip(fill_rule)
525 }
526
527 fn Clip_(&self, path: &Path2D, fill_rule: CanvasFillRule) {
529 self.context.Clip_(path, fill_rule)
530 }
531
532 fn IsPointInPath(&self, x: f64, y: f64, fill_rule: CanvasFillRule) -> bool {
534 self.context.IsPointInPath(x, y, fill_rule)
535 }
536
537 fn IsPointInPath_(&self, path: &Path2D, x: f64, y: f64, fill_rule: CanvasFillRule) -> bool {
539 self.context.IsPointInPath_(path, x, y, fill_rule)
540 }
541
542 fn Scale(&self, x: f64, y: f64) {
544 self.context.Scale(x, y)
545 }
546
547 fn Rotate(&self, angle: f64) {
549 self.context.Rotate(angle)
550 }
551
552 fn Translate(&self, x: f64, y: f64) {
554 self.context.Translate(x, y)
555 }
556
557 fn Transform(&self, a: f64, b: f64, c: f64, d: f64, e: f64, f: f64) {
559 self.context.Transform(a, b, c, d, e, f)
560 }
561
562 fn GetTransform(&self, cx: &mut JSContext) -> DomRoot<DOMMatrix> {
564 self.context.GetTransform(cx)
565 }
566
567 fn SetTransform(&self, a: f64, b: f64, c: f64, d: f64, e: f64, f: f64) -> ErrorResult {
569 self.context.SetTransform(a, b, c, d, e, f)
570 }
571
572 fn SetTransform_(&self, transform: &DOMMatrix2DInit) -> ErrorResult {
574 self.context.SetTransform_(transform)
575 }
576
577 fn ResetTransform(&self) {
579 self.context.ResetTransform()
580 }
581
582 fn ClosePath(&self) {
584 self.context.ClosePath()
585 }
586
587 fn MoveTo(&self, x: f64, y: f64) {
589 self.context.MoveTo(x, y)
590 }
591
592 fn LineTo(&self, x: f64, y: f64) {
594 self.context.LineTo(x, y)
595 }
596
597 fn Rect(&self, x: f64, y: f64, width: f64, height: f64) {
599 self.context.Rect(x, y, width, height)
600 }
601
602 fn RoundRect(
604 &self,
605 x: f64,
606 y: f64,
607 width: f64,
608 height: f64,
609 radii: UnrestrictedDoubleOrDOMPointInitOrUnrestrictedDoubleOrDOMPointInitSequence,
610 ) -> ErrorResult {
611 self.context.RoundRect(x, y, width, height, radii)
612 }
613
614 fn QuadraticCurveTo(&self, cpx: f64, cpy: f64, x: f64, y: f64) {
616 self.context.QuadraticCurveTo(cpx, cpy, x, y)
617 }
618
619 fn BezierCurveTo(&self, cp1x: f64, cp1y: f64, cp2x: f64, cp2y: f64, x: f64, y: f64) {
621 self.context.BezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)
622 }
623
624 fn Arc(&self, x: f64, y: f64, r: f64, start: f64, end: f64, ccw: bool) -> ErrorResult {
626 self.context.Arc(x, y, r, start, end, ccw)
627 }
628
629 fn ArcTo(&self, cp1x: f64, cp1y: f64, cp2x: f64, cp2y: f64, r: f64) -> ErrorResult {
631 self.context.ArcTo(cp1x, cp1y, cp2x, cp2y, r)
632 }
633
634 fn Ellipse(
636 &self,
637 x: f64,
638 y: f64,
639 rx: f64,
640 ry: f64,
641 rotation: f64,
642 start: f64,
643 end: f64,
644 ccw: bool,
645 ) -> ErrorResult {
646 self.context
647 .Ellipse(x, y, rx, ry, rotation, start, end, ccw)
648 }
649}