/src/serenity/Userland/Libraries/LibWeb/HTML/CanvasGradient.cpp
Line | Count | Source |
1 | | /* |
2 | | * Copyright (c) 2022, Andreas Kling <kling@serenityos.org> |
3 | | * Copyright (c) 2023, MacDue <macdue@dueutil.tech> |
4 | | * |
5 | | * SPDX-License-Identifier: BSD-2-Clause |
6 | | */ |
7 | | |
8 | | #include <AK/QuickSort.h> |
9 | | #include <LibWeb/Bindings/CanvasGradientPrototype.h> |
10 | | #include <LibWeb/Bindings/Intrinsics.h> |
11 | | #include <LibWeb/HTML/CanvasGradient.h> |
12 | | #include <LibWeb/WebIDL/ExceptionOr.h> |
13 | | |
14 | | namespace Web::HTML { |
15 | | |
16 | | JS_DEFINE_ALLOCATOR(CanvasGradient); |
17 | | |
18 | | // https://html.spec.whatwg.org/multipage/canvas.html#dom-context-2d-createradialgradient |
19 | | WebIDL::ExceptionOr<JS::NonnullGCPtr<CanvasGradient>> CanvasGradient::create_radial(JS::Realm& realm, double x0, double y0, double r0, double x1, double y1, double r1) |
20 | 0 | { |
21 | | // If either of r0 or r1 are negative, then an "IndexSizeError" DOMException must be thrown. |
22 | 0 | if (r0 < 0) |
23 | 0 | return WebIDL::IndexSizeError::create(realm, "The r0 passed is less than 0"_string); |
24 | 0 | if (r1 < 0) |
25 | 0 | return WebIDL::IndexSizeError::create(realm, "The r1 passed is less than 0"_string); |
26 | | |
27 | 0 | auto radial_gradient = TRY_OR_THROW_OOM(realm.vm(), Gfx::CanvasRadialGradientPaintStyle::create(Gfx::FloatPoint { x0, y0 }, r0, Gfx::FloatPoint { x1, y1 }, r1)); |
28 | 0 | return realm.heap().allocate<CanvasGradient>(realm, realm, *radial_gradient); |
29 | 0 | } |
30 | | |
31 | | // https://html.spec.whatwg.org/multipage/canvas.html#dom-context-2d-createlineargradient |
32 | | WebIDL::ExceptionOr<JS::NonnullGCPtr<CanvasGradient>> CanvasGradient::create_linear(JS::Realm& realm, double x0, double y0, double x1, double y1) |
33 | 0 | { |
34 | 0 | auto linear_gradient = TRY_OR_THROW_OOM(realm.vm(), Gfx::CanvasLinearGradientPaintStyle::create(Gfx::FloatPoint { x0, y0 }, Gfx::FloatPoint { x1, y1 })); |
35 | 0 | return realm.heap().allocate<CanvasGradient>(realm, realm, *linear_gradient); |
36 | 0 | } |
37 | | |
38 | | // https://html.spec.whatwg.org/multipage/canvas.html#dom-context-2d-createconicgradient |
39 | | WebIDL::ExceptionOr<JS::NonnullGCPtr<CanvasGradient>> CanvasGradient::create_conic(JS::Realm& realm, double start_angle, double x, double y) |
40 | 0 | { |
41 | 0 | auto conic_gradient = TRY_OR_THROW_OOM(realm.vm(), Gfx::CanvasConicGradientPaintStyle::create(Gfx::FloatPoint { x, y }, start_angle)); |
42 | 0 | return realm.heap().allocate<CanvasGradient>(realm, realm, *conic_gradient); |
43 | 0 | } |
44 | | |
45 | | CanvasGradient::CanvasGradient(JS::Realm& realm, Gfx::GradientPaintStyle& gradient) |
46 | 0 | : PlatformObject(realm) |
47 | 0 | , m_gradient(gradient) |
48 | 0 | { |
49 | 0 | } |
50 | | |
51 | 0 | CanvasGradient::~CanvasGradient() = default; |
52 | | |
53 | | void CanvasGradient::initialize(JS::Realm& realm) |
54 | 0 | { |
55 | 0 | Base::initialize(realm); |
56 | 0 | WEB_SET_PROTOTYPE_FOR_INTERFACE(CanvasGradient); |
57 | 0 | } |
58 | | |
59 | | // https://html.spec.whatwg.org/multipage/canvas.html#dom-canvasgradient-addcolorstop |
60 | | WebIDL::ExceptionOr<void> CanvasGradient::add_color_stop(double offset, StringView color) |
61 | 0 | { |
62 | | // 1. If the offset is less than 0 or greater than 1, then throw an "IndexSizeError" DOMException. |
63 | 0 | if (offset < 0 || offset > 1) |
64 | 0 | return WebIDL::IndexSizeError::create(realm(), "CanvasGradient color stop offset out of bounds"_string); |
65 | | |
66 | | // 2. Let parsed color be the result of parsing color. |
67 | 0 | auto parsed_color = Color::from_string(color); |
68 | | |
69 | | // 3. If parsed color is failure, throw a "SyntaxError" DOMException. |
70 | 0 | if (!parsed_color.has_value()) |
71 | 0 | return WebIDL::SyntaxError::create(realm(), "Could not parse color for CanvasGradient"_string); |
72 | | |
73 | | // 4. Place a new stop on the gradient, at offset offset relative to the whole gradient, and with the color parsed color. |
74 | 0 | TRY_OR_THROW_OOM(realm().vm(), m_gradient->add_color_stop(offset, parsed_color.value())); |
75 | | |
76 | | // FIXME: If multiple stops are added at the same offset on a gradient, then they must be placed in the order added, |
77 | | // with the first one closest to the start of the gradient, and each subsequent one infinitesimally further along |
78 | | // towards the end point (in effect causing all but the first and last stop added at each point to be ignored). |
79 | |
|
80 | 0 | return {}; |
81 | 0 | } |
82 | | |
83 | | } |