mirror of
https://github.com/RGBCube/serenity
synced 2025-07-24 14:57:35 +00:00
LibWeb: Encapsulate canvas drawing state in a struct
This will allow us to easily add copies of the relevant canvas drawing state to a stack, and likewise replace the current drawing state with an entry from that stack.
This commit is contained in:
parent
b32893eb54
commit
6d50ff71de
2 changed files with 35 additions and 30 deletions
|
@ -26,12 +26,12 @@ CanvasRenderingContext2D::~CanvasRenderingContext2D()
|
||||||
|
|
||||||
void CanvasRenderingContext2D::set_fill_style(String style)
|
void CanvasRenderingContext2D::set_fill_style(String style)
|
||||||
{
|
{
|
||||||
m_fill_style = Gfx::Color::from_string(style).value_or(Color::Black);
|
m_drawing_state.fill_style = Gfx::Color::from_string(style).value_or(Color::Black);
|
||||||
}
|
}
|
||||||
|
|
||||||
String CanvasRenderingContext2D::fill_style() const
|
String CanvasRenderingContext2D::fill_style() const
|
||||||
{
|
{
|
||||||
return m_fill_style.to_string();
|
return m_drawing_state.fill_style.to_string();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CanvasRenderingContext2D::fill_rect(float x, float y, float width, float height)
|
void CanvasRenderingContext2D::fill_rect(float x, float y, float width, float height)
|
||||||
|
@ -40,8 +40,8 @@ void CanvasRenderingContext2D::fill_rect(float x, float y, float width, float he
|
||||||
if (!painter)
|
if (!painter)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto rect = m_transform.map(Gfx::FloatRect(x, y, width, height));
|
auto rect = m_drawing_state.transform.map(Gfx::FloatRect(x, y, width, height));
|
||||||
painter->fill_rect(enclosing_int_rect(rect), m_fill_style);
|
painter->fill_rect(enclosing_int_rect(rect), m_drawing_state.fill_style);
|
||||||
did_draw(rect);
|
did_draw(rect);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,19 +51,19 @@ void CanvasRenderingContext2D::clear_rect(float x, float y, float width, float h
|
||||||
if (!painter)
|
if (!painter)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto rect = m_transform.map(Gfx::FloatRect(x, y, width, height));
|
auto rect = m_drawing_state.transform.map(Gfx::FloatRect(x, y, width, height));
|
||||||
painter->clear_rect(enclosing_int_rect(rect), Color());
|
painter->clear_rect(enclosing_int_rect(rect), Color());
|
||||||
did_draw(rect);
|
did_draw(rect);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CanvasRenderingContext2D::set_stroke_style(String style)
|
void CanvasRenderingContext2D::set_stroke_style(String style)
|
||||||
{
|
{
|
||||||
m_stroke_style = Gfx::Color::from_string(style).value_or(Color::Black);
|
m_drawing_state.stroke_style = Gfx::Color::from_string(style).value_or(Color::Black);
|
||||||
}
|
}
|
||||||
|
|
||||||
String CanvasRenderingContext2D::stroke_style() const
|
String CanvasRenderingContext2D::stroke_style() const
|
||||||
{
|
{
|
||||||
return m_stroke_style.to_string();
|
return m_drawing_state.stroke_style.to_string();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CanvasRenderingContext2D::stroke_rect(float x, float y, float width, float height)
|
void CanvasRenderingContext2D::stroke_rect(float x, float y, float width, float height)
|
||||||
|
@ -72,17 +72,17 @@ void CanvasRenderingContext2D::stroke_rect(float x, float y, float width, float
|
||||||
if (!painter)
|
if (!painter)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto rect = m_transform.map(Gfx::FloatRect(x, y, width, height));
|
auto rect = m_drawing_state.transform.map(Gfx::FloatRect(x, y, width, height));
|
||||||
|
|
||||||
auto top_left = m_transform.map(Gfx::FloatPoint(x, y)).to_type<int>();
|
auto top_left = m_drawing_state.transform.map(Gfx::FloatPoint(x, y)).to_type<int>();
|
||||||
auto top_right = m_transform.map(Gfx::FloatPoint(x + width - 1, y)).to_type<int>();
|
auto top_right = m_drawing_state.transform.map(Gfx::FloatPoint(x + width - 1, y)).to_type<int>();
|
||||||
auto bottom_left = m_transform.map(Gfx::FloatPoint(x, y + height - 1)).to_type<int>();
|
auto bottom_left = m_drawing_state.transform.map(Gfx::FloatPoint(x, y + height - 1)).to_type<int>();
|
||||||
auto bottom_right = m_transform.map(Gfx::FloatPoint(x + width - 1, y + height - 1)).to_type<int>();
|
auto bottom_right = m_drawing_state.transform.map(Gfx::FloatPoint(x + width - 1, y + height - 1)).to_type<int>();
|
||||||
|
|
||||||
painter->draw_line(top_left, top_right, m_stroke_style, m_line_width);
|
painter->draw_line(top_left, top_right, m_drawing_state.stroke_style, m_drawing_state.line_width);
|
||||||
painter->draw_line(top_right, bottom_right, m_stroke_style, m_line_width);
|
painter->draw_line(top_right, bottom_right, m_drawing_state.stroke_style, m_drawing_state.line_width);
|
||||||
painter->draw_line(bottom_right, bottom_left, m_stroke_style, m_line_width);
|
painter->draw_line(bottom_right, bottom_left, m_drawing_state.stroke_style, m_drawing_state.line_width);
|
||||||
painter->draw_line(bottom_left, top_left, m_stroke_style, m_line_width);
|
painter->draw_line(bottom_left, top_left, m_drawing_state.stroke_style, m_drawing_state.line_width);
|
||||||
|
|
||||||
did_draw(rect);
|
did_draw(rect);
|
||||||
}
|
}
|
||||||
|
@ -98,7 +98,7 @@ void CanvasRenderingContext2D::draw_image(const HTMLImageElement& image_element,
|
||||||
|
|
||||||
auto src_rect = image_element.bitmap()->rect();
|
auto src_rect = image_element.bitmap()->rect();
|
||||||
Gfx::FloatRect dst_rect = { x, y, (float)image_element.bitmap()->width(), (float)image_element.bitmap()->height() };
|
Gfx::FloatRect dst_rect = { x, y, (float)image_element.bitmap()->width(), (float)image_element.bitmap()->height() };
|
||||||
auto rect = m_transform.map(dst_rect);
|
auto rect = m_drawing_state.transform.map(dst_rect);
|
||||||
|
|
||||||
painter->draw_scaled_bitmap(rounded_int_rect(rect), *image_element.bitmap(), src_rect, 1.0f, Gfx::Painter::ScalingMode::BilinearBlend);
|
painter->draw_scaled_bitmap(rounded_int_rect(rect), *image_element.bitmap(), src_rect, 1.0f, Gfx::Painter::ScalingMode::BilinearBlend);
|
||||||
}
|
}
|
||||||
|
@ -106,19 +106,19 @@ void CanvasRenderingContext2D::draw_image(const HTMLImageElement& image_element,
|
||||||
void CanvasRenderingContext2D::scale(float sx, float sy)
|
void CanvasRenderingContext2D::scale(float sx, float sy)
|
||||||
{
|
{
|
||||||
dbgln("CanvasRenderingContext2D::scale({}, {})", sx, sy);
|
dbgln("CanvasRenderingContext2D::scale({}, {})", sx, sy);
|
||||||
m_transform.scale(sx, sy);
|
m_drawing_state.transform.scale(sx, sy);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CanvasRenderingContext2D::translate(float tx, float ty)
|
void CanvasRenderingContext2D::translate(float tx, float ty)
|
||||||
{
|
{
|
||||||
dbgln("CanvasRenderingContext2D::translate({}, {})", tx, ty);
|
dbgln("CanvasRenderingContext2D::translate({}, {})", tx, ty);
|
||||||
m_transform.translate(tx, ty);
|
m_drawing_state.transform.translate(tx, ty);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CanvasRenderingContext2D::rotate(float radians)
|
void CanvasRenderingContext2D::rotate(float radians)
|
||||||
{
|
{
|
||||||
dbgln("CanvasRenderingContext2D::rotate({})", radians);
|
dbgln("CanvasRenderingContext2D::rotate({})", radians);
|
||||||
m_transform.rotate_radians(radians);
|
m_drawing_state.transform.rotate_radians(radians);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CanvasRenderingContext2D::did_draw(const Gfx::FloatRect&)
|
void CanvasRenderingContext2D::did_draw(const Gfx::FloatRect&)
|
||||||
|
@ -155,8 +155,8 @@ void CanvasRenderingContext2D::fill_text(const String& text, float x, float y, O
|
||||||
|
|
||||||
// FIXME: painter only supports integer rects for text right now, so this effectively chops off any fractional position
|
// FIXME: painter only supports integer rects for text right now, so this effectively chops off any fractional position
|
||||||
auto text_rect = Gfx::IntRect(x, y, max_width.has_value() ? max_width.value() : painter->font().width(text), painter->font().glyph_height());
|
auto text_rect = Gfx::IntRect(x, y, max_width.has_value() ? max_width.value() : painter->font().width(text), painter->font().glyph_height());
|
||||||
auto transformed_rect = m_transform.map(text_rect);
|
auto transformed_rect = m_drawing_state.transform.map(text_rect);
|
||||||
painter->draw_text(transformed_rect, text, Gfx::TextAlignment::TopLeft, m_fill_style);
|
painter->draw_text(transformed_rect, text, Gfx::TextAlignment::TopLeft, m_drawing_state.fill_style);
|
||||||
did_draw(transformed_rect.to_type<float>());
|
did_draw(transformed_rect.to_type<float>());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -270,7 +270,7 @@ void CanvasRenderingContext2D::stroke()
|
||||||
if (!painter)
|
if (!painter)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
painter->stroke_path(m_path, m_stroke_style, m_line_width);
|
painter->stroke_path(m_path, m_drawing_state.stroke_style, m_drawing_state.line_width);
|
||||||
did_draw(m_path.bounding_box());
|
did_draw(m_path.bounding_box());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -282,7 +282,7 @@ void CanvasRenderingContext2D::fill(Gfx::Painter::WindingRule winding)
|
||||||
|
|
||||||
auto path = m_path;
|
auto path = m_path;
|
||||||
path.close_all_subpaths();
|
path.close_all_subpaths();
|
||||||
painter->fill_path(path, m_fill_style, winding);
|
painter->fill_path(path, m_drawing_state.fill_style, winding);
|
||||||
did_draw(m_path.bounding_box());
|
did_draw(m_path.bounding_box());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -46,8 +46,8 @@ public:
|
||||||
void translate(float x, float y);
|
void translate(float x, float y);
|
||||||
void rotate(float degrees);
|
void rotate(float degrees);
|
||||||
|
|
||||||
void set_line_width(float line_width) { m_line_width = line_width; }
|
void set_line_width(float line_width) { m_drawing_state.line_width = line_width; }
|
||||||
float line_width() const { return m_line_width; }
|
float line_width() const { return m_drawing_state.line_width; }
|
||||||
|
|
||||||
void begin_path();
|
void begin_path();
|
||||||
void close_path();
|
void close_path();
|
||||||
|
@ -80,10 +80,15 @@ private:
|
||||||
|
|
||||||
WeakPtr<HTMLCanvasElement> m_element;
|
WeakPtr<HTMLCanvasElement> m_element;
|
||||||
|
|
||||||
Gfx::AffineTransform m_transform;
|
// https://html.spec.whatwg.org/multipage/canvas.html#drawing-state
|
||||||
Gfx::Color m_fill_style { Gfx::Color::Black };
|
struct DrawingState {
|
||||||
Gfx::Color m_stroke_style { Gfx::Color::Black };
|
Gfx::AffineTransform transform;
|
||||||
float m_line_width { 1 };
|
Gfx::Color fill_style { Gfx::Color::Black };
|
||||||
|
Gfx::Color stroke_style { Gfx::Color::Black };
|
||||||
|
float line_width { 1 };
|
||||||
|
};
|
||||||
|
|
||||||
|
DrawingState m_drawing_state;
|
||||||
|
|
||||||
Gfx::Path m_path;
|
Gfx::Path m_path;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue