1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 00:27:45 +00:00

LibWeb: Make DOMException GC-allocated

This commit is contained in:
Andreas Kling 2022-09-04 16:56:15 +02:00
parent 0e47754ac8
commit 497ead37bc
58 changed files with 307 additions and 278 deletions

View file

@ -7,6 +7,7 @@
#include <AK/ExtraMathConstants.h>
#include <LibWeb/HTML/Canvas/CanvasPath.h>
#include <LibWeb/HTML/Window.h>
namespace Web::HTML {
@ -38,17 +39,17 @@ void CanvasPath::bezier_curve_to(double cp1x, double cp1y, double cp2x, double c
DOM::ExceptionOr<void> CanvasPath::arc(float x, float y, float radius, float start_angle, float end_angle, bool counter_clockwise)
{
if (radius < 0)
return DOM::IndexSizeError::create(String::formatted("The radius provided ({}) is negative.", radius));
return DOM::IndexSizeError::create(m_self.global_object(), String::formatted("The radius provided ({}) is negative.", radius));
return ellipse(x, y, radius, radius, 0, start_angle, end_angle, counter_clockwise);
}
DOM::ExceptionOr<void> CanvasPath::ellipse(float x, float y, float radius_x, float radius_y, float rotation, float start_angle, float end_angle, bool counter_clockwise)
{
if (radius_x < 0)
return DOM::IndexSizeError::create(String::formatted("The major-axis radius provided ({}) is negative.", radius_x));
return DOM::IndexSizeError::create(m_self.global_object(), String::formatted("The major-axis radius provided ({}) is negative.", radius_x));
if (radius_y < 0)
return DOM::IndexSizeError::create(String::formatted("The minor-axis radius provided ({}) is negative.", radius_y));
return DOM::IndexSizeError::create(m_self.global_object(), String::formatted("The minor-axis radius provided ({}) is negative.", radius_y));
if (constexpr float tau = M_TAU; (!counter_clockwise && (end_angle - start_angle) >= tau)
|| (counter_clockwise && (start_angle - end_angle) >= tau)) {

View file

@ -30,9 +30,13 @@ public:
Gfx::Path const& path() const { return m_path; }
protected:
CanvasPath() = default;
explicit CanvasPath(Bindings::PlatformObject& self)
: m_self(self)
{
}
private:
Bindings::PlatformObject& m_self;
Gfx::Path m_path;
};

View file

@ -53,14 +53,14 @@ DOM::ExceptionOr<void> CanvasGradient::add_color_stop(double offset, String cons
{
// 1. If the offset is less than 0 or greater than 1, then throw an "IndexSizeError" DOMException.
if (offset < 0 || offset > 1)
return DOM::IndexSizeError::create("CanvasGradient color stop offset out of bounds");
return DOM::IndexSizeError::create(global_object(), "CanvasGradient color stop offset out of bounds");
// 2. Let parsed color be the result of parsing color.
auto parsed_color = Color::from_string(color);
// 3. If parsed color is failure, throw a "SyntaxError" DOMException.
if (!parsed_color.has_value())
return DOM::SyntaxError::create("Could not parse color for CanvasGradient");
return DOM::SyntaxError::create(global_object(), "Could not parse color for CanvasGradient");
// 4. Place a new stop on the gradient, at offset offset relative to the whole gradient, and with the color parsed color.
m_color_stops.append(ColorStop { offset, parsed_color.value() });

View file

@ -29,6 +29,7 @@ JS::NonnullGCPtr<CanvasRenderingContext2D> CanvasRenderingContext2D::create(HTML
CanvasRenderingContext2D::CanvasRenderingContext2D(HTML::Window& window, HTMLCanvasElement& element)
: PlatformObject(window.realm())
, CanvasPath(static_cast<Bindings::PlatformObject&>(*this))
, m_element(element)
{
set_prototype(&window.cached_web_prototype("CanvasRenderingContext2D"));
@ -326,11 +327,11 @@ DOM::ExceptionOr<JS::GCPtr<ImageData>> CanvasRenderingContext2D::get_image_data(
{
// 1. If either the sw or sh arguments are zero, then throw an "IndexSizeError" DOMException.
if (width == 0 || height == 0)
return DOM::IndexSizeError::create("Width and height must not be zero");
return DOM::IndexSizeError::create(global_object(), "Width and height must not be zero");
// 2. If the CanvasRenderingContext2D's origin-clean flag is set to false, then throw a "SecurityError" DOMException.
if (!m_origin_clean)
return DOM::SecurityError::create("CanvasRenderingContext2D is not origin-clean");
return DOM::SecurityError::create(global_object(), "CanvasRenderingContext2D is not origin-clean");
// 3. Let imageData be a new ImageData object.
// 4. Initialize imageData given sw, sh, settings set to settings, and defaultColorSpace set to this's color space.
@ -548,7 +549,7 @@ DOM::ExceptionOr<CanvasImageSourceUsability> check_usability_of_image(CanvasImag
[](JS::Handle<HTMLCanvasElement> const& canvas_element) -> DOM::ExceptionOr<Optional<CanvasImageSourceUsability>> {
// If image has either a horizontal dimension or a vertical dimension equal to zero, then throw an "InvalidStateError" DOMException.
if (canvas_element->width() == 0 || canvas_element->height() == 0)
return DOM::InvalidStateError::create("Canvas width or height is zero");
return DOM::InvalidStateError::create(canvas_element->global_object(), "Canvas width or height is zero");
return Optional<CanvasImageSourceUsability> {};
}));
if (usability.has_value())

View file

@ -126,7 +126,7 @@ DOM::ExceptionOr<void> DOMStringMap::set_value_of_new_named_property(String cons
if (current_character == '-' && character_index + 1 < name.length()) {
auto next_character = name[character_index + 1];
if (is_ascii_lower_alpha(next_character))
return DOM::SyntaxError::create("Name cannot contain a '-' followed by a lowercase character.");
return DOM::SyntaxError::create(global_object(), "Name cannot contain a '-' followed by a lowercase character.");
}
// 2. For each ASCII upper alpha in name, insert a U+002D HYPHEN-MINUS character (-) before the character and replace the character with the same character converted to ASCII lowercase.

View file

@ -104,7 +104,7 @@ DOM::ExceptionOr<void> HTMLElement::set_content_editable(String const& content_e
set_attribute(HTML::AttributeNames::contenteditable, "false");
return {};
}
return DOM::SyntaxError::create("Invalid contentEditable value, must be 'true', 'false', or 'inherit'");
return DOM::SyntaxError::create(global_object(), "Invalid contentEditable value, must be 'true', 'false', or 'inherit'");
}
void HTMLElement::set_inner_text(StringView text)

View file

@ -40,11 +40,11 @@ DOM::ExceptionOr<void> HTMLOptionsCollection::add(HTMLOptionOrOptGroupElement el
// 1. If element is an ancestor of the select element on which the HTMLOptionsCollection is rooted, then throw a "HierarchyRequestError" DOMException.
if (resolved_element->is_ancestor_of(root()))
return DOM::HierarchyRequestError::create("The provided element is an ancestor of the root select element.");
return DOM::HierarchyRequestError::create(global_object(), "The provided element is an ancestor of the root select element.");
// 2. If before is an element, but that element isn't a descendant of the select element on which the HTMLOptionsCollection is rooted, then throw a "NotFoundError" DOMException.
if (before_element && !before_element->is_descendant_of(root()))
return DOM::NotFoundError::create("The 'before' element is not a descendant of the root select element.");
return DOM::NotFoundError::create(global_object(), "The 'before' element is not a descendant of the root select element.");
// 3. If element and before are the same element, then return.
if (before_element && (resolved_element.ptr() == before_element.ptr()))

View file

@ -103,7 +103,7 @@ DOM::ExceptionOr<void> HTMLTableElement::set_t_head(HTMLTableSectionElement* the
VERIFY(thead);
if (thead->local_name() != TagNames::thead)
return DOM::HierarchyRequestError::create("Element is not thead");
return DOM::HierarchyRequestError::create(global_object(), "Element is not thead");
// FIXME: The spec requires deleting the current thead if thead is null
// Currently the wrapper generator doesn't send us a nullable value
@ -190,7 +190,7 @@ DOM::ExceptionOr<void> HTMLTableElement::set_t_foot(HTMLTableSectionElement* tfo
VERIFY(tfoot);
if (tfoot->local_name() != TagNames::tfoot)
return DOM::HierarchyRequestError::create("Element is not tfoot");
return DOM::HierarchyRequestError::create(global_object(), "Element is not tfoot");
// FIXME: The spec requires deleting the current tfoot if tfoot is null
// Currently the wrapper generator doesn't send us a nullable value
@ -286,7 +286,7 @@ DOM::ExceptionOr<JS::NonnullGCPtr<HTMLTableRowElement>> HTMLTableElement::insert
auto rows_length = rows->length();
if (index < -1 || index > (long)rows_length) {
return DOM::IndexSizeError::create("Index is negative or greater than the number of rows");
return DOM::IndexSizeError::create(global_object(), "Index is negative or greater than the number of rows");
}
auto& tr = static_cast<HTMLTableRowElement&>(*DOM::create_element(document(), TagNames::tr, Namespace::HTML));
if (rows_length == 0 && !has_child_of_type<HTMLTableRowElement>()) {
@ -313,7 +313,7 @@ DOM::ExceptionOr<void> HTMLTableElement::delete_row(long index)
// 1. If index is less than 1 or greater than or equal to the number of elements in the rows collection, then throw an "IndexSizeError" DOMException.
if (index < -1 || index >= (long)rows_length)
return DOM::IndexSizeError::create("Index is negative or greater than or equal to the number of rows");
return DOM::IndexSizeError::create(global_object(), "Index is negative or greater than or equal to the number of rows");
// 2. If index is 1, then remove the last element in the rows collection from its parent, or do nothing if the rows collection is empty.
if (index == -1) {

View file

@ -43,7 +43,7 @@ DOM::ExceptionOr<JS::NonnullGCPtr<HTMLTableRowElement>> HTMLTableSectionElement:
// 1. If index is less than 1 or greater than the number of elements in the rows collection, throw an "IndexSizeError" DOMException.
if (index < -1 || index > rows_collection_size)
return DOM::IndexSizeError::create("Index is negative or greater than the number of rows");
return DOM::IndexSizeError::create(global_object(), "Index is negative or greater than the number of rows");
// 2. Let table row be the result of creating an element given this element's node document, tr, and the HTML namespace.
auto& table_row = static_cast<HTMLTableRowElement&>(*DOM::create_element(document(), TagNames::tr, Namespace::HTML));
@ -67,7 +67,7 @@ DOM::ExceptionOr<void> HTMLTableSectionElement::delete_row(long index)
// 1. If index is less than 1 or greater than or equal to the number of elements in the rows collection, then throw an "IndexSizeError" DOMException.
if (index < -1 || index >= rows_collection_size)
return DOM::IndexSizeError::create("Index is negative or greater than or equal to the number of rows");
return DOM::IndexSizeError::create(global_object(), "Index is negative or greater than or equal to the number of rows");
// 2. If index is 1, then remove the last element in the rows collection from this element, or do nothing if the rows collection is empty.
if (index == -1) {

View file

@ -50,7 +50,7 @@ DOM::ExceptionOr<void> History::shared_history_push_replace_state(JS::Value, Str
// 2. If document is not fully active, then throw a "SecurityError" DOMException.
if (!m_associated_document->is_fully_active())
return DOM::SecurityError::create("Cannot perform pushState or replaceState on a document that isn't fully active.");
return DOM::SecurityError::create(global_object(), "Cannot perform pushState or replaceState on a document that isn't fully active.");
// 3. Optionally, return. (For example, the user agent might disallow calls to these methods that are invoked on a timer,
// or from event listeners that are not triggered in response to a clear user action, or that are invoked in rapid succession.)

View file

@ -17,6 +17,7 @@ JS::NonnullGCPtr<Path2D> Path2D::create_with_global_object(HTML::Window& window,
// https://html.spec.whatwg.org/multipage/canvas.html#dom-path2d
Path2D::Path2D(HTML::Window& window, Optional<Variant<JS::Handle<Path2D>, String>> const& path)
: PlatformObject(window.realm())
, CanvasPath(static_cast<Bindings::PlatformObject&>(*this))
{
set_prototype(&window.cached_web_prototype("Path2D"));

View file

@ -109,6 +109,7 @@ JS::Completion ClassicScript::run(RethrowErrors rethrow_errors)
// 1. Clean up after running script with settings.
settings.clean_up_after_running_script();
dbgln("rethrow");
// 2. Rethrow evaluationStatus.[[Value]].
return JS::throw_completion(*evaluation_status.value());
}
@ -118,15 +119,17 @@ JS::Completion ClassicScript::run(RethrowErrors rethrow_errors)
// 1. Clean up after running script with settings.
settings.clean_up_after_running_script();
dbgln("network error");
// 2. Throw a "NetworkError" DOMException.
return Bindings::throw_dom_exception_if_needed(vm, [] {
return DOM::NetworkError::create("Script error.");
}).release_error();
return throw_completion(DOM::NetworkError::create(settings.global_object(), "Script error."));
}
// 3. Otherwise, rethrow errors is false. Perform the following steps:
VERIFY(rethrow_errors == RethrowErrors::No);
dbgln("no rethrow, stat: {}", evaluation_status.value().value().to_string_without_side_effects());
// 1. Report the exception given by evaluationStatus.[[Value]] for script.
report_exception(evaluation_status);

View file

@ -1067,11 +1067,8 @@ JS_DEFINE_NATIVE_FUNCTION(Window::btoa)
Vector<u8> byte_string;
byte_string.ensure_capacity(string.length());
for (u32 code_point : Utf8View(string)) {
if (code_point > 0xff) {
return Bindings::throw_dom_exception_if_needed(vm, [] {
return DOM::InvalidCharacterError::create("Data contains characters outside the range U+0000 and U+00FF");
}).release_error();
}
if (code_point > 0xff)
return throw_completion(DOM::InvalidCharacterError::create(vm.current_realm()->global_object(), "Data contains characters outside the range U+0000 and U+00FF"));
byte_string.append(code_point);
}

View file

@ -65,7 +65,7 @@ DOM::ExceptionOr<JS::NonnullGCPtr<Worker>> Worker::create(FlyString const& scrip
// 4. If this fails, throw a "SyntaxError" DOMException.
if (!url.is_valid()) {
dbgln_if(WEB_WORKER_DEBUG, "WebWorker: Invalid URL loaded '{}'.", script_url);
return DOM::SyntaxError::create("url is not valid");
return DOM::SyntaxError::create(document.global_object(), "url is not valid");
}
// 5. Let worker URL be the resulting URL record.

View file

@ -14,6 +14,7 @@
#include <LibWeb/Forward.h>
#include <LibWeb/HTML/EventHandler.h>
#include <LibWeb/HTML/EventNames.h>
#include <LibWeb/HTML/Window.h>
#include <LibWeb/HTML/WorkerGlobalScope.h>
#include <LibWeb/HTML/WorkerLocation.h>
#include <LibWeb/HTML/WorkerNavigator.h>
@ -129,7 +130,7 @@ DOM::ExceptionOr<String> WorkerGlobalScope::btoa(String const& data) const
byte_string.ensure_capacity(data.length());
for (u32 code_point : Utf8View(data)) {
if (code_point > 0xff)
return DOM::InvalidCharacterError::create("Data contains characters outside the range U+0000 and U+00FF");
return DOM::InvalidCharacterError::create(global_object(), "Data contains characters outside the range U+0000 and U+00FF");
byte_string.append(code_point);
}
@ -149,7 +150,7 @@ DOM::ExceptionOr<String> WorkerGlobalScope::atob(String const& data) const
// 2. If decodedData is failure, then throw an "InvalidCharacterError" DOMException.
if (decoded_data.is_error())
return DOM::InvalidCharacterError::create("Input string is not valid base64 data");
return DOM::InvalidCharacterError::create(global_object(), "Input string is not valid base64 data");
// 3. Return decodedData.
// decode_base64() returns a byte string. LibJS uses UTF-8 for strings. Use Latin1Decoder to convert bytes 128-255 to UTF-8.