LibWeb: Generate CanvasRenderingContext2D bindings from IDL :^)

We're still missing optional argument support, so this implementation
doesn't support fill(), only fill(fill_rule).

Still it's really nice to get rid of so much hand-written wrapper code.
This commit is contained in:
Andreas Kling 2020-06-22 18:39:22 +02:00
parent f361d25ec8
commit 9ce25bbf1d
Notes: sideshowbarker 2024-07-19 05:26:51 +09:00
8 changed files with 84 additions and 505 deletions

View file

@ -143,12 +143,7 @@
/* LibWeb bindings */ \
M(BadArgCountOne, "%s() needs one argument") \
M(BadArgCountAtLeastOne, "%s() needs at least one argument") \
M(BadArgCountMany, "%s() needs %s arguments") \
M(DrawImageArgumentCount, "drawImage() needs three arguments") \
M(FillBadWindingRule, "fill() winding rule must be either 'nonzero' or 'evenodd'") \
M(FillNonString, "fill() called with non-string") \
M(ImageIsAn, "Image is not an HTMLImageElement, it's an %s") \
M(PutImageDataBadCall, "putImageData() called with non-ImageData") \
M(BadArgCountMany, "%s() needs %s arguments")
namespace JS {

View file

@ -1,413 +0,0 @@
/*
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <AK/FlyString.h>
#include <AK/Function.h>
#include <LibJS/Interpreter.h>
#include <LibJS/Runtime/Error.h>
#include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/PrimitiveString.h>
#include <LibJS/Runtime/Value.h>
#include <LibWeb/Bindings/CanvasRenderingContext2DWrapper.h>
#include <LibWeb/Bindings/HTMLImageElementWrapper.h>
#include <LibWeb/Bindings/ImageDataWrapper.h>
#include <LibWeb/Bindings/NodeWrapperFactory.h>
#include <LibWeb/DOM/CanvasRenderingContext2D.h>
#include <LibWeb/DOM/HTMLCanvasElement.h>
#include <LibWeb/DOM/HTMLImageElement.h>
#include <LibWeb/DOM/ImageData.h>
namespace Web {
namespace Bindings {
CanvasRenderingContext2DWrapper* wrap(JS::Heap& heap, CanvasRenderingContext2D& impl)
{
return static_cast<CanvasRenderingContext2DWrapper*>(wrap_impl(heap, impl));
}
CanvasRenderingContext2DWrapper::CanvasRenderingContext2DWrapper(JS::GlobalObject& global_object, CanvasRenderingContext2D& impl)
: Wrapper(*global_object.object_prototype())
, m_impl(impl)
{
}
void CanvasRenderingContext2DWrapper::initialize(JS::Interpreter& interpreter, JS::GlobalObject& global_object)
{
Wrapper::initialize(interpreter, global_object);
define_native_function("fillRect", fill_rect, 4);
define_native_function("scale", scale, 2);
define_native_function("translate", translate, 2);
define_native_function("strokeRect", stroke_rect, 4);
define_native_function("drawImage", draw_image, 3);
define_native_function("beginPath", begin_path, 0);
define_native_function("closePath", close_path, 0);
define_native_function("stroke", stroke, 0);
define_native_function("fill", fill, 0);
define_native_function("moveTo", move_to, 2);
define_native_function("lineTo", line_to, 2);
define_native_function("quadraticCurveTo", quadratic_curve_to, 4);
define_native_function("createImageData", create_image_data, 1);
define_native_function("putImageData", put_image_data, 3);
define_native_property("fillStyle", fill_style_getter, fill_style_setter);
define_native_property("strokeStyle", stroke_style_getter, stroke_style_setter);
define_native_property("lineWidth", line_width_getter, line_width_setter);
define_native_property("canvas", canvas_getter, nullptr);
}
CanvasRenderingContext2DWrapper::~CanvasRenderingContext2DWrapper()
{
}
static CanvasRenderingContext2D* impl_from(JS::Interpreter& interpreter, JS::GlobalObject& global_object)
{
auto* this_object = interpreter.this_value(global_object).to_object(interpreter, global_object);
if (!this_object)
return nullptr;
// FIXME: Verify that it's a CanvasRenderingContext2DWrapper somehow!
return &static_cast<CanvasRenderingContext2DWrapper*>(this_object)->impl();
}
JS_DEFINE_NATIVE_FUNCTION(CanvasRenderingContext2DWrapper::fill_rect)
{
auto* impl = impl_from(interpreter, global_object);
if (!impl)
return {};
if (interpreter.argument_count() >= 4) {
auto x = interpreter.argument(0).to_double(interpreter);
if (interpreter.exception())
return {};
auto y = interpreter.argument(1).to_double(interpreter);
if (interpreter.exception())
return {};
auto width = interpreter.argument(2).to_double(interpreter);
if (interpreter.exception())
return {};
auto height = interpreter.argument(3).to_double(interpreter);
if (interpreter.exception())
return {};
impl->fill_rect(x, y, width, height);
}
return JS::js_undefined();
}
JS_DEFINE_NATIVE_FUNCTION(CanvasRenderingContext2DWrapper::stroke_rect)
{
auto* impl = impl_from(interpreter, global_object);
if (!impl)
return {};
if (interpreter.argument_count() >= 4) {
auto x = interpreter.argument(0).to_double(interpreter);
if (interpreter.exception())
return {};
auto y = interpreter.argument(1).to_double(interpreter);
if (interpreter.exception())
return {};
auto width = interpreter.argument(2).to_double(interpreter);
if (interpreter.exception())
return {};
auto height = interpreter.argument(3).to_double(interpreter);
if (interpreter.exception())
return {};
impl->stroke_rect(x, y, width, height);
}
return JS::js_undefined();
}
JS_DEFINE_NATIVE_FUNCTION(CanvasRenderingContext2DWrapper::draw_image)
{
auto* impl = impl_from(interpreter, global_object);
if (!impl)
return {};
if (interpreter.argument_count() < 3)
return interpreter.throw_exception<JS::TypeError>(JS::ErrorType::DrawImageArgumentCount);
auto* image_argument = interpreter.argument(0).to_object(interpreter, global_object);
if (!image_argument)
return {};
if (StringView(image_argument->class_name()) != "HTMLImageElementWrapper")
return interpreter.throw_exception<JS::TypeError>(JS::ErrorType::ImageIsAn, image_argument->class_name());
auto x = interpreter.argument(1).to_double(interpreter);
if (interpreter.exception())
return {};
auto y = interpreter.argument(2).to_double(interpreter);
if (interpreter.exception())
return {};
impl->draw_image(static_cast<const HTMLImageElementWrapper&>(*image_argument).impl(), x, y);
return JS::js_undefined();
}
JS_DEFINE_NATIVE_FUNCTION(CanvasRenderingContext2DWrapper::scale)
{
auto* impl = impl_from(interpreter, global_object);
if (!impl)
return {};
if (interpreter.argument_count() >= 2) {
auto sx = interpreter.argument(0).to_number(interpreter);
if (interpreter.exception())
return {};
auto sy = interpreter.argument(1).to_number(interpreter);
if (interpreter.exception())
return {};
if (sx.is_finite_number() && sy.is_finite_number())
impl->scale(sx.as_double(), sy.as_double());
}
return JS::js_undefined();
}
JS_DEFINE_NATIVE_FUNCTION(CanvasRenderingContext2DWrapper::translate)
{
auto* impl = impl_from(interpreter, global_object);
if (!impl)
return {};
if (interpreter.argument_count() >= 2) {
auto tx = interpreter.argument(0).to_number(interpreter);
if (interpreter.exception())
return {};
auto ty = interpreter.argument(1).to_number(interpreter);
if (interpreter.exception())
return {};
if (tx.is_finite_number() && ty.is_finite_number())
impl->translate(tx.as_double(), ty.as_double());
}
return JS::js_undefined();
}
JS_DEFINE_NATIVE_GETTER(CanvasRenderingContext2DWrapper::fill_style_getter)
{
auto* impl = impl_from(interpreter, global_object);
if (!impl)
return {};
return JS::js_string(interpreter, impl->fill_style());
}
JS_DEFINE_NATIVE_SETTER(CanvasRenderingContext2DWrapper::fill_style_setter)
{
auto* impl = impl_from(interpreter, global_object);
if (!impl)
return;
auto string = value.to_string(interpreter);
if (interpreter.exception())
return;
impl->set_fill_style(string);
}
JS_DEFINE_NATIVE_GETTER(CanvasRenderingContext2DWrapper::stroke_style_getter)
{
auto* impl = impl_from(interpreter, global_object);
if (!impl)
return {};
return JS::js_string(interpreter, impl->stroke_style());
}
JS_DEFINE_NATIVE_SETTER(CanvasRenderingContext2DWrapper::stroke_style_setter)
{
auto* impl = impl_from(interpreter, global_object);
if (!impl)
return;
auto string = value.to_string(interpreter);
if (interpreter.exception())
return;
impl->set_stroke_style(string);
}
JS_DEFINE_NATIVE_GETTER(CanvasRenderingContext2DWrapper::line_width_getter)
{
auto* impl = impl_from(interpreter, global_object);
if (!impl)
return {};
return JS::Value(impl->line_width());
}
JS_DEFINE_NATIVE_SETTER(CanvasRenderingContext2DWrapper::line_width_setter)
{
auto* impl = impl_from(interpreter, global_object);
if (!impl)
return;
auto line_width = value.to_double(interpreter);
if (interpreter.exception())
return;
impl->set_line_width(line_width);
}
JS_DEFINE_NATIVE_FUNCTION(CanvasRenderingContext2DWrapper::begin_path)
{
auto* impl = impl_from(interpreter, global_object);
if (!impl)
return {};
impl->begin_path();
return JS::js_undefined();
}
JS_DEFINE_NATIVE_FUNCTION(CanvasRenderingContext2DWrapper::close_path)
{
auto* impl = impl_from(interpreter, global_object);
if (!impl)
return {};
impl->close_path();
return JS::js_undefined();
}
JS_DEFINE_NATIVE_FUNCTION(CanvasRenderingContext2DWrapper::stroke)
{
auto* impl = impl_from(interpreter, global_object);
if (!impl)
return {};
impl->stroke();
return JS::js_undefined();
}
JS_DEFINE_NATIVE_FUNCTION(CanvasRenderingContext2DWrapper::fill)
{
auto* impl = impl_from(interpreter, global_object);
if (!impl)
return {};
auto winding = Gfx::Painter::WindingRule::Nonzero;
if (interpreter.argument_count() == 1) {
auto arg0 = interpreter.argument(0);
if (arg0.is_string()) {
const auto& winding_name = arg0.as_string().string();
if (winding_name == "evenodd") {
winding = Gfx::Painter::WindingRule::EvenOdd;
} else if (winding_name != "nonzero") {
return interpreter.throw_exception<JS::TypeError>(JS::ErrorType::FillBadWindingRule);
}
} else {
return interpreter.throw_exception<JS::TypeError>(JS::ErrorType::FillNonString);
}
} else {
// FIXME: Path2D object
return JS::js_undefined();
}
impl->fill(winding);
return JS::js_undefined();
}
JS_DEFINE_NATIVE_FUNCTION(CanvasRenderingContext2DWrapper::move_to)
{
auto* impl = impl_from(interpreter, global_object);
if (!impl)
return {};
auto x = interpreter.argument(0).to_double(interpreter);
if (interpreter.exception())
return {};
auto y = interpreter.argument(1).to_double(interpreter);
if (interpreter.exception())
return {};
impl->move_to(x, y);
return JS::js_undefined();
}
JS_DEFINE_NATIVE_FUNCTION(CanvasRenderingContext2DWrapper::line_to)
{
auto* impl = impl_from(interpreter, global_object);
if (!impl)
return {};
auto x = interpreter.argument(0).to_double(interpreter);
if (interpreter.exception())
return {};
auto y = interpreter.argument(1).to_double(interpreter);
if (interpreter.exception())
return {};
impl->line_to(x, y);
return JS::js_undefined();
}
JS_DEFINE_NATIVE_FUNCTION(CanvasRenderingContext2DWrapper::quadratic_curve_to)
{
auto* impl = impl_from(interpreter, global_object);
if (!impl)
return {};
auto cx = interpreter.argument(0).to_double(interpreter);
if (interpreter.exception())
return {};
auto cy = interpreter.argument(1).to_double(interpreter);
if (interpreter.exception())
return {};
auto x = interpreter.argument(2).to_double(interpreter);
if (interpreter.exception())
return {};
auto y = interpreter.argument(3).to_double(interpreter);
if (interpreter.exception())
return {};
impl->quadratic_curve_to(cx, cy, x, y);
return JS::js_undefined();
}
JS_DEFINE_NATIVE_FUNCTION(CanvasRenderingContext2DWrapper::create_image_data)
{
auto* impl = impl_from(interpreter, global_object);
if (!impl)
return {};
auto width = interpreter.argument(0).to_i32(interpreter);
if (interpreter.exception())
return {};
auto height = interpreter.argument(1).to_i32(interpreter);
if (interpreter.exception())
return {};
auto image_data = impl->create_image_data(global_object, width, height);
return wrap(interpreter.heap(), *image_data);
}
JS_DEFINE_NATIVE_FUNCTION(CanvasRenderingContext2DWrapper::put_image_data)
{
auto* impl = impl_from(interpreter, global_object);
if (!impl)
return {};
auto* image_data_object = interpreter.argument(0).to_object(interpreter, global_object);
if (!image_data_object)
return {};
if (StringView(image_data_object->class_name()) != "ImageDataWrapper") {
return interpreter.throw_exception<JS::TypeError>(JS::ErrorType::PutImageDataBadCall);
}
auto& image_data = static_cast<ImageDataWrapper*>(image_data_object)->impl();
auto x = interpreter.argument(1).to_double(interpreter);
if (interpreter.exception())
return {};
auto y = interpreter.argument(2).to_double(interpreter);
if (interpreter.exception())
return {};
impl->put_image_data(image_data, x, y);
return JS::js_undefined();
}
JS_DEFINE_NATIVE_GETTER(CanvasRenderingContext2DWrapper::canvas_getter)
{
auto* impl = impl_from(interpreter, global_object);
if (!impl)
return {};
auto* element = impl->element();
if (!element)
return JS::js_null();
return wrap(interpreter.heap(), *element);
}
}
}

View file

@ -1,77 +0,0 @@
/*
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#include <LibWeb/Bindings/Wrapper.h>
namespace Web {
namespace Bindings {
class CanvasRenderingContext2DWrapper final : public Wrapper {
JS_OBJECT(CanvasRenderingContext2DWrapper, Wrapper);
public:
CanvasRenderingContext2DWrapper(JS::GlobalObject&, CanvasRenderingContext2D&);
virtual void initialize(JS::Interpreter&, JS::GlobalObject&) override;
virtual ~CanvasRenderingContext2DWrapper() override;
CanvasRenderingContext2D& impl() { return m_impl; }
const CanvasRenderingContext2D& impl() const { return m_impl; }
private:
JS_DECLARE_NATIVE_FUNCTION(fill_rect);
JS_DECLARE_NATIVE_FUNCTION(stroke_rect);
JS_DECLARE_NATIVE_FUNCTION(draw_image);
JS_DECLARE_NATIVE_FUNCTION(scale);
JS_DECLARE_NATIVE_FUNCTION(translate);
JS_DECLARE_NATIVE_FUNCTION(begin_path);
JS_DECLARE_NATIVE_FUNCTION(close_path);
JS_DECLARE_NATIVE_FUNCTION(stroke);
JS_DECLARE_NATIVE_FUNCTION(fill);
JS_DECLARE_NATIVE_FUNCTION(move_to);
JS_DECLARE_NATIVE_FUNCTION(line_to);
JS_DECLARE_NATIVE_FUNCTION(quadratic_curve_to);
JS_DECLARE_NATIVE_FUNCTION(create_image_data);
JS_DECLARE_NATIVE_FUNCTION(put_image_data);
JS_DECLARE_NATIVE_GETTER(fill_style_getter);
JS_DECLARE_NATIVE_SETTER(fill_style_setter);
JS_DECLARE_NATIVE_GETTER(stroke_style_getter);
JS_DECLARE_NATIVE_SETTER(stroke_style_setter);
JS_DECLARE_NATIVE_GETTER(line_width_getter);
JS_DECLARE_NATIVE_SETTER(line_width_setter);
JS_DECLARE_NATIVE_GETTER(canvas_getter);
NonnullRefPtr<CanvasRenderingContext2D> m_impl;
};
CanvasRenderingContext2DWrapper* wrap(JS::Heap&, CanvasRenderingContext2D&);
}
}

View file

@ -1,5 +1,4 @@
set(SOURCES
Bindings/CanvasRenderingContext2DWrapper.cpp
Bindings/EventListenerWrapper.cpp
Bindings/EventWrapperFactory.cpp
Bindings/LocationObject.cpp
@ -159,6 +158,7 @@ libweb_js_wrapper(HTMLCanvasElement)
libweb_js_wrapper(ImageData)
libweb_js_wrapper(Event)
libweb_js_wrapper(MouseEvent)
libweb_js_wrapper(CanvasRenderingContext2D)
get_property(WRAPPER_SOURCES GLOBAL PROPERTY wrapper_sources)
set(SOURCES ${SOURCES} ${WRAPPER_SOURCES})

View file

@ -214,6 +214,8 @@ OwnPtr<Interface> parse_interface(const StringView& input)
Vector<Parameter> parameters;
for (;;) {
if (consume_if(')'))
break;
auto type = parse_type();
consume_whitespace();
auto name = consume_while([](auto ch) { return !isspace(ch) && ch != ',' && ch != ')'; });
@ -327,6 +329,23 @@ static bool should_emit_wrapper_factory(const IDL::Interface& interface)
return true;
}
static bool is_wrappable_type(const IDL::Type& type)
{
if (type.name == "Node")
return true;
if (type.name == "Document")
return true;
if (type.name == "Text")
return true;
if (type.name == "DocumentType")
return true;
if (type.name.ends_with("Element"))
return true;
if (type.name == "ImageData")
return true;
return false;
}
static void generate_header(const IDL::Interface& interface)
{
auto& wrapper_class = interface.wrapper_class;
@ -404,6 +423,9 @@ void generate_implementation(const IDL::Interface& interface)
out() << "#include <LibWeb/DOM/Element.h>";
out() << "#include <LibWeb/DOM/HTMLElement.h>";
out() << "#include <LibWeb/DOM/EventListener.h>";
out() << "#include <LibWeb/Bindings/HTMLCanvasElementWrapper.h>";
out() << "#include <LibWeb/Bindings/HTMLImageElementWrapper.h>";
out() << "#include <LibWeb/Bindings/ImageDataWrapper.h>";
out() << "#include <LibWeb/Bindings/CanvasRenderingContext2DWrapper.h>";
out() << "namespace Web {";
@ -473,7 +495,7 @@ void generate_implementation(const IDL::Interface& interface)
generate_return();
out() << " }";
out() << " auto " << cpp_name << " = adopt(*new EventListener(JS::make_handle(&" << js_name << js_suffix << ".as_function())));";
} else if (parameter.type.name == "Node") {
} else if (is_wrappable_type(parameter.type)) {
out() << " auto " << cpp_name << "_object = " << js_name << js_suffix << ".to_object(interpreter, global_object);";
out() << " if (interpreter.exception())";
generate_return();
@ -482,6 +504,13 @@ void generate_implementation(const IDL::Interface& interface)
generate_return();
out() << " }";
out() << " auto& " << cpp_name << " = static_cast<" << parameter.type.name << "Wrapper*>(" << cpp_name << "_object)->impl();";
} else if (parameter.type.name == "double") {
out() << " auto " << cpp_name << " = " << js_name << js_suffix << ".to_double(interpreter);";
out() << " if (interpreter.exception())";
generate_return();
} else {
dbg() << "Unimplemented JS-to-C++ conversion: " << parameter.type.name;
ASSERT_NOT_REACHED();
}
};
@ -564,8 +593,10 @@ void generate_implementation(const IDL::Interface& interface)
out() << " auto* impl = impl_from(interpreter, global_object);";
out() << " if (!impl)";
out() << " return {};";
out() << " if (interpreter.argument_count() < " << function.length() << ")";
out() << " return interpreter.throw_exception<JS::TypeError>(JS::ErrorType::BadArgCountMany, \"" << function.name << "\", \"" << function.length() << "\");";
if (function.length() > 0) {
out() << " if (interpreter.argument_count() < " << function.length() << ")";
out() << " return interpreter.throw_exception<JS::TypeError>(JS::ErrorType::BadArgCountMany, \"" << function.name << "\", \"" << function.length() << "\");";
}
StringBuilder arguments_builder;
generate_arguments(function.parameters, arguments_builder);

View file

@ -26,6 +26,7 @@
#include <AK/OwnPtr.h>
#include <LibGfx/Painter.h>
#include <LibWeb/Bindings/CanvasRenderingContext2DWrapper.h>
#include <LibWeb/DOM/CanvasRenderingContext2D.h>
#include <LibWeb/DOM/HTMLCanvasElement.h>
#include <LibWeb/DOM/HTMLImageElement.h>
@ -190,9 +191,20 @@ void CanvasRenderingContext2D::fill(Gfx::Painter::WindingRule winding)
painter->fill_path(path, m_fill_style, winding);
}
RefPtr<ImageData> CanvasRenderingContext2D::create_image_data(JS::GlobalObject& global_object, int width, int height) const
void CanvasRenderingContext2D::fill(const String& fill_rule)
{
return ImageData::create_with_size(global_object, width, height);
if (fill_rule == "evenodd")
return fill(Gfx::Painter::WindingRule::EvenOdd);
return fill(Gfx::Painter::WindingRule::Nonzero);
}
RefPtr<ImageData> CanvasRenderingContext2D::create_image_data(int width, int height) const
{
if (!wrapper()) {
dbg() << "Hmm! Attempted to create ImageData for wrapper-less CRC2D.";
return nullptr;
}
return ImageData::create_with_size(wrapper()->global_object(), width, height);
}
void CanvasRenderingContext2D::put_image_data(const ImageData& image_data, float x, float y)

View file

@ -72,12 +72,15 @@ public:
void line_to(float x, float y);
void quadratic_curve_to(float cx, float cy, float x, float y);
void stroke();
void fill(Gfx::Painter::WindingRule);
RefPtr<ImageData> create_image_data(JS::GlobalObject&, int width, int height) const;
// FIXME: We should only have one fill(), really. Fix the wrapper generator!
void fill(Gfx::Painter::WindingRule);
void fill(const String& fill_rule);
RefPtr<ImageData> create_image_data(int width, int height) const;
void put_image_data(const ImageData&, float x, float y);
HTMLCanvasElement* element() { return m_element; }
HTMLCanvasElement* canvas() { return m_element; }
private:
explicit CanvasRenderingContext2D(HTMLCanvasElement&);

View file

@ -0,0 +1,28 @@
interface CanvasRenderingContext2D {
void fillRect(double x, double y, double w, double h);
void strokeRect(double x, double y, double w, double h);
void scale(double x, double y);
void translate(double x, double y);
void beginPath();
void closePath();
void fill(DOMString fillRule);
void stroke();
void moveTo(double x, double y);
void lineTo(double x, double y);
void quadraticCurveTo(double cpx, double cpy, double x, double y);
void drawImage(HTMLImageElement image, double dx, double dy);
attribute DOMString fillStyle;
attribute DOMString strokeStyle;
attribute double lineWidth;
ImageData createImageData(double sw, double sh);
void putImageData(ImageData imagedata, double dx, double dy);
readonly attribute HTMLCanvasElement canvas;
}