LibGfx: Add CanvasCommandList
Moving 2D canvas rasterization into the Compositor process needs a wire format for canvas mutations that does not depend on LibWeb state. Add CanvasCommandList as an apply-once log of drawing operations whose operands are Gfx value types and whose IPC encoders can be shared by WebContent and the compositor side.
This commit is contained in:
parent
956a2b96d5
commit
714cf827db
12 changed files with 747 additions and 0 deletions
|
|
@ -9,6 +9,8 @@
|
|||
#include <LibGfx/AffineTransform.h>
|
||||
#include <LibGfx/Quad.h>
|
||||
#include <LibGfx/Rect.h>
|
||||
#include <LibIPC/Decoder.h>
|
||||
#include <LibIPC/Encoder.h>
|
||||
|
||||
namespace Gfx {
|
||||
|
||||
|
|
@ -259,3 +261,31 @@ Matrix<4, float> AffineTransform::to_matrix() const
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
namespace IPC {
|
||||
|
||||
template<>
|
||||
ErrorOr<void> encode(Encoder& encoder, Gfx::AffineTransform const& transform)
|
||||
{
|
||||
TRY(encoder.encode(transform.a()));
|
||||
TRY(encoder.encode(transform.b()));
|
||||
TRY(encoder.encode(transform.c()));
|
||||
TRY(encoder.encode(transform.d()));
|
||||
TRY(encoder.encode(transform.e()));
|
||||
TRY(encoder.encode(transform.f()));
|
||||
return {};
|
||||
}
|
||||
|
||||
template<>
|
||||
ErrorOr<Gfx::AffineTransform> decode(Decoder& decoder)
|
||||
{
|
||||
auto a = TRY(decoder.decode<float>());
|
||||
auto b = TRY(decoder.decode<float>());
|
||||
auto c = TRY(decoder.decode<float>());
|
||||
auto d = TRY(decoder.decode<float>());
|
||||
auto e = TRY(decoder.decode<float>());
|
||||
auto f = TRY(decoder.decode<float>());
|
||||
return Gfx::AffineTransform { a, b, c, d, e, f };
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#include <AK/Forward.h>
|
||||
#include <LibGfx/Forward.h>
|
||||
#include <LibGfx/Matrix.h>
|
||||
#include <LibIPC/Forward.h>
|
||||
|
||||
namespace Gfx {
|
||||
|
||||
|
|
@ -99,3 +100,13 @@ struct AK::Formatter<Gfx::AffineTransform> : Formatter<FormatString> {
|
|||
return Formatter<FormatString>::format(builder, "[{} {} {} {} {} {}]"sv, value.a(), value.b(), value.c(), value.d(), value.e(), value.f());
|
||||
}
|
||||
};
|
||||
|
||||
namespace IPC {
|
||||
|
||||
template<>
|
||||
ErrorOr<void> encode(Encoder&, Gfx::AffineTransform const&);
|
||||
|
||||
template<>
|
||||
ErrorOr<Gfx::AffineTransform> decode(Decoder&);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ set(SOURCES
|
|||
BitmapExport.cpp
|
||||
BitmapSequence.cpp
|
||||
CMYKBitmap.cpp
|
||||
CanvasCommandList.cpp
|
||||
Color.cpp
|
||||
ColorConversion.cpp
|
||||
ColorSpace.cpp
|
||||
|
|
@ -21,7 +22,9 @@ set(SOURCES
|
|||
Font/WOFF2/Loader.cpp
|
||||
FontCascadeList.cpp
|
||||
GradientPainting.cpp
|
||||
Gradients.cpp
|
||||
Matrix4x4.cpp
|
||||
DecodedImageFrame.cpp
|
||||
ImageFormats/BMPWriter.cpp
|
||||
ImageFormats/JPEGWriter.cpp
|
||||
ImageFormats/PNGWriter.cpp
|
||||
|
|
|
|||
355
Libraries/LibGfx/CanvasCommandList.cpp
Normal file
355
Libraries/LibGfx/CanvasCommandList.cpp
Normal file
|
|
@ -0,0 +1,355 @@
|
|||
/*
|
||||
* Copyright (c) 2026, Aliaksandr Kalenik <kalenik.aliaksandr@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/TypeCasts.h>
|
||||
#include <LibGfx/CanvasCommandList.h>
|
||||
#include <LibIPC/Decoder.h>
|
||||
#include <LibIPC/Encoder.h>
|
||||
|
||||
namespace Gfx {
|
||||
|
||||
CanvasPaintStyle to_canvas_paint_style(PaintStyle const& paint_style)
|
||||
{
|
||||
if (auto const* solid_color = as_if<SolidColorPaintStyle>(paint_style))
|
||||
return solid_color->color();
|
||||
|
||||
if (auto const* linear_gradient = as_if<CanvasLinearGradientPaintStyle>(paint_style)) {
|
||||
return CanvasLinearGradient {
|
||||
.start_point = linear_gradient->start_point(),
|
||||
.end_point = linear_gradient->end_point(),
|
||||
.color_stops = Vector<ColorStop> { linear_gradient->color_stops() },
|
||||
.repeat_length = linear_gradient->repeat_length(),
|
||||
};
|
||||
}
|
||||
|
||||
if (auto const* radial_gradient = as_if<CanvasRadialGradientPaintStyle>(paint_style)) {
|
||||
return CanvasRadialGradient {
|
||||
.start_center = radial_gradient->start_center(),
|
||||
.start_radius = radial_gradient->start_radius(),
|
||||
.end_center = radial_gradient->end_center(),
|
||||
.end_radius = radial_gradient->end_radius(),
|
||||
.color_stops = Vector<ColorStop> { radial_gradient->color_stops() },
|
||||
.repeat_length = radial_gradient->repeat_length(),
|
||||
};
|
||||
}
|
||||
|
||||
if (auto const* conic_gradient = as_if<CanvasConicGradientPaintStyle>(paint_style)) {
|
||||
return CanvasConicGradient {
|
||||
.center = conic_gradient->center(),
|
||||
.start_angle = conic_gradient->start_angle(),
|
||||
.color_stops = Vector<ColorStop> { conic_gradient->color_stops() },
|
||||
.repeat_length = conic_gradient->repeat_length(),
|
||||
};
|
||||
}
|
||||
|
||||
if (auto const* pattern = as_if<CanvasPatternPaintStyle>(paint_style)) {
|
||||
return CanvasPatternStyle {
|
||||
.image = pattern->image(),
|
||||
.repetition = pattern->repetition(),
|
||||
.transform = pattern->transform(),
|
||||
};
|
||||
}
|
||||
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace IPC {
|
||||
|
||||
template<>
|
||||
ErrorOr<void> encode(Encoder& encoder, Gfx::CanvasLinearGradient const& gradient)
|
||||
{
|
||||
TRY(encoder.encode(gradient.start_point));
|
||||
TRY(encoder.encode(gradient.end_point));
|
||||
TRY(encoder.encode(gradient.color_stops));
|
||||
TRY(encoder.encode(gradient.repeat_length));
|
||||
return {};
|
||||
}
|
||||
|
||||
template<>
|
||||
ErrorOr<Gfx::CanvasLinearGradient> decode(Decoder& decoder)
|
||||
{
|
||||
return Gfx::CanvasLinearGradient {
|
||||
.start_point = TRY(decoder.decode<Gfx::FloatPoint>()),
|
||||
.end_point = TRY(decoder.decode<Gfx::FloatPoint>()),
|
||||
.color_stops = TRY(decoder.decode<Vector<Gfx::ColorStop>>()),
|
||||
.repeat_length = TRY(decoder.decode<Optional<float>>()),
|
||||
};
|
||||
}
|
||||
|
||||
template<>
|
||||
ErrorOr<void> encode(Encoder& encoder, Gfx::CanvasRadialGradient const& gradient)
|
||||
{
|
||||
TRY(encoder.encode(gradient.start_center));
|
||||
TRY(encoder.encode(gradient.start_radius));
|
||||
TRY(encoder.encode(gradient.end_center));
|
||||
TRY(encoder.encode(gradient.end_radius));
|
||||
TRY(encoder.encode(gradient.color_stops));
|
||||
TRY(encoder.encode(gradient.repeat_length));
|
||||
return {};
|
||||
}
|
||||
|
||||
template<>
|
||||
ErrorOr<Gfx::CanvasRadialGradient> decode(Decoder& decoder)
|
||||
{
|
||||
return Gfx::CanvasRadialGradient {
|
||||
.start_center = TRY(decoder.decode<Gfx::FloatPoint>()),
|
||||
.start_radius = TRY(decoder.decode<float>()),
|
||||
.end_center = TRY(decoder.decode<Gfx::FloatPoint>()),
|
||||
.end_radius = TRY(decoder.decode<float>()),
|
||||
.color_stops = TRY(decoder.decode<Vector<Gfx::ColorStop>>()),
|
||||
.repeat_length = TRY(decoder.decode<Optional<float>>()),
|
||||
};
|
||||
}
|
||||
|
||||
template<>
|
||||
ErrorOr<void> encode(Encoder& encoder, Gfx::CanvasConicGradient const& gradient)
|
||||
{
|
||||
TRY(encoder.encode(gradient.center));
|
||||
TRY(encoder.encode(gradient.start_angle));
|
||||
TRY(encoder.encode(gradient.color_stops));
|
||||
TRY(encoder.encode(gradient.repeat_length));
|
||||
return {};
|
||||
}
|
||||
|
||||
template<>
|
||||
ErrorOr<Gfx::CanvasConicGradient> decode(Decoder& decoder)
|
||||
{
|
||||
return Gfx::CanvasConicGradient {
|
||||
.center = TRY(decoder.decode<Gfx::FloatPoint>()),
|
||||
.start_angle = TRY(decoder.decode<float>()),
|
||||
.color_stops = TRY(decoder.decode<Vector<Gfx::ColorStop>>()),
|
||||
.repeat_length = TRY(decoder.decode<Optional<float>>()),
|
||||
};
|
||||
}
|
||||
|
||||
template<>
|
||||
ErrorOr<void> encode(Encoder& encoder, Gfx::CanvasPatternStyle const& pattern)
|
||||
{
|
||||
TRY(encoder.encode(pattern.image));
|
||||
TRY(encoder.encode(pattern.repetition));
|
||||
TRY(encoder.encode(pattern.transform));
|
||||
return {};
|
||||
}
|
||||
|
||||
template<>
|
||||
ErrorOr<Gfx::CanvasPatternStyle> decode(Decoder& decoder)
|
||||
{
|
||||
return Gfx::CanvasPatternStyle {
|
||||
.image = TRY(decoder.decode<Optional<Gfx::DecodedImageFrame>>()),
|
||||
.repetition = TRY(decoder.decode<Gfx::CanvasPatternPaintStyle::Repetition>()),
|
||||
.transform = TRY(decoder.decode<Optional<Gfx::AffineTransform>>()),
|
||||
};
|
||||
}
|
||||
|
||||
template<>
|
||||
ErrorOr<void> encode(Encoder& encoder, Gfx::CanvasCommands::ClearRect const& command)
|
||||
{
|
||||
TRY(encoder.encode(command.rect));
|
||||
TRY(encoder.encode(command.color));
|
||||
return {};
|
||||
}
|
||||
|
||||
template<>
|
||||
ErrorOr<Gfx::CanvasCommands::ClearRect> decode(Decoder& decoder)
|
||||
{
|
||||
return Gfx::CanvasCommands::ClearRect {
|
||||
.rect = TRY(decoder.decode<Gfx::FloatRect>()),
|
||||
.color = TRY(decoder.decode<Gfx::Color>()),
|
||||
};
|
||||
}
|
||||
|
||||
template<>
|
||||
ErrorOr<void> encode(Encoder& encoder, Gfx::CanvasCommands::FillRect const& command)
|
||||
{
|
||||
TRY(encoder.encode(command.rect));
|
||||
TRY(encoder.encode(command.color));
|
||||
return {};
|
||||
}
|
||||
|
||||
template<>
|
||||
ErrorOr<Gfx::CanvasCommands::FillRect> decode(Decoder& decoder)
|
||||
{
|
||||
return Gfx::CanvasCommands::FillRect {
|
||||
.rect = TRY(decoder.decode<Gfx::FloatRect>()),
|
||||
.color = TRY(decoder.decode<Gfx::Color>()),
|
||||
};
|
||||
}
|
||||
|
||||
template<>
|
||||
ErrorOr<void> encode(Encoder& encoder, Gfx::CanvasCommands::DrawBitmap const& command)
|
||||
{
|
||||
TRY(encoder.encode(command.frame));
|
||||
TRY(encoder.encode(command.dst_rect));
|
||||
TRY(encoder.encode(command.src_rect));
|
||||
TRY(encoder.encode(command.scaling_mode));
|
||||
TRY(encoder.encode(command.filter));
|
||||
TRY(encoder.encode(command.global_alpha));
|
||||
TRY(encoder.encode(command.compositing_and_blending_operator));
|
||||
return {};
|
||||
}
|
||||
|
||||
template<>
|
||||
ErrorOr<Gfx::CanvasCommands::DrawBitmap> decode(Decoder& decoder)
|
||||
{
|
||||
return Gfx::CanvasCommands::DrawBitmap {
|
||||
.frame = TRY(decoder.decode<Gfx::DecodedImageFrame>()),
|
||||
.dst_rect = TRY(decoder.decode<Gfx::FloatRect>()),
|
||||
.src_rect = TRY(decoder.decode<Gfx::IntRect>()),
|
||||
.scaling_mode = TRY(decoder.decode<Gfx::ScalingMode>()),
|
||||
.filter = TRY(decoder.decode<Optional<Gfx::Filter>>()),
|
||||
.global_alpha = TRY(decoder.decode<float>()),
|
||||
.compositing_and_blending_operator = TRY(decoder.decode<Gfx::CompositingAndBlendingOperator>()),
|
||||
};
|
||||
}
|
||||
|
||||
template<>
|
||||
ErrorOr<void> encode(Encoder& encoder, Gfx::CanvasCommands::FillPath const& command)
|
||||
{
|
||||
TRY(encoder.encode(command.path));
|
||||
TRY(encoder.encode(command.style));
|
||||
TRY(encoder.encode(command.winding_rule));
|
||||
TRY(encoder.encode(command.blur_radius));
|
||||
TRY(encoder.encode(command.filter));
|
||||
TRY(encoder.encode(command.global_alpha));
|
||||
TRY(encoder.encode(command.compositing_and_blending_operator));
|
||||
return {};
|
||||
}
|
||||
|
||||
template<>
|
||||
ErrorOr<Gfx::CanvasCommands::FillPath> decode(Decoder& decoder)
|
||||
{
|
||||
return Gfx::CanvasCommands::FillPath {
|
||||
.path = TRY(decoder.decode<Gfx::Path>()),
|
||||
.style = TRY(decoder.decode<Gfx::CanvasPaintStyle>()),
|
||||
.winding_rule = TRY(decoder.decode<Gfx::WindingRule>()),
|
||||
.blur_radius = TRY(decoder.decode<float>()),
|
||||
.filter = TRY(decoder.decode<Optional<Gfx::Filter>>()),
|
||||
.global_alpha = TRY(decoder.decode<float>()),
|
||||
.compositing_and_blending_operator = TRY(decoder.decode<Gfx::CompositingAndBlendingOperator>()),
|
||||
};
|
||||
}
|
||||
|
||||
template<>
|
||||
ErrorOr<void> encode(Encoder& encoder, Gfx::CanvasCommands::StrokePath const& command)
|
||||
{
|
||||
TRY(encoder.encode(command.path));
|
||||
TRY(encoder.encode(command.style));
|
||||
TRY(encoder.encode(command.thickness));
|
||||
TRY(encoder.encode(command.cap_style));
|
||||
TRY(encoder.encode(command.join_style));
|
||||
TRY(encoder.encode(command.miter_limit));
|
||||
TRY(encoder.encode(command.dash_array));
|
||||
TRY(encoder.encode(command.dash_offset));
|
||||
TRY(encoder.encode(command.blur_radius));
|
||||
TRY(encoder.encode(command.filter));
|
||||
TRY(encoder.encode(command.global_alpha));
|
||||
TRY(encoder.encode(command.compositing_and_blending_operator));
|
||||
return {};
|
||||
}
|
||||
|
||||
template<>
|
||||
ErrorOr<Gfx::CanvasCommands::StrokePath> decode(Decoder& decoder)
|
||||
{
|
||||
return Gfx::CanvasCommands::StrokePath {
|
||||
.path = TRY(decoder.decode<Gfx::Path>()),
|
||||
.style = TRY(decoder.decode<Gfx::CanvasPaintStyle>()),
|
||||
.thickness = TRY(decoder.decode<float>()),
|
||||
.cap_style = TRY(decoder.decode<Gfx::Path::CapStyle>()),
|
||||
.join_style = TRY(decoder.decode<Gfx::Path::JoinStyle>()),
|
||||
.miter_limit = TRY(decoder.decode<float>()),
|
||||
.dash_array = TRY(decoder.decode<Vector<float>>()),
|
||||
.dash_offset = TRY(decoder.decode<float>()),
|
||||
.blur_radius = TRY(decoder.decode<float>()),
|
||||
.filter = TRY(decoder.decode<Optional<Gfx::Filter>>()),
|
||||
.global_alpha = TRY(decoder.decode<float>()),
|
||||
.compositing_and_blending_operator = TRY(decoder.decode<Gfx::CompositingAndBlendingOperator>()),
|
||||
};
|
||||
}
|
||||
|
||||
template<>
|
||||
ErrorOr<void> encode(Encoder& encoder, Gfx::CanvasCommands::SetTransform const& command)
|
||||
{
|
||||
TRY(encoder.encode(command.transform));
|
||||
return {};
|
||||
}
|
||||
|
||||
template<>
|
||||
ErrorOr<Gfx::CanvasCommands::SetTransform> decode(Decoder& decoder)
|
||||
{
|
||||
return Gfx::CanvasCommands::SetTransform {
|
||||
.transform = TRY(decoder.decode<Gfx::AffineTransform>()),
|
||||
};
|
||||
}
|
||||
|
||||
template<>
|
||||
ErrorOr<void> encode(Encoder&, Gfx::CanvasCommands::Save const&)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
template<>
|
||||
ErrorOr<Gfx::CanvasCommands::Save> decode(Decoder&)
|
||||
{
|
||||
return Gfx::CanvasCommands::Save {};
|
||||
}
|
||||
|
||||
template<>
|
||||
ErrorOr<void> encode(Encoder&, Gfx::CanvasCommands::Restore const&)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
template<>
|
||||
ErrorOr<Gfx::CanvasCommands::Restore> decode(Decoder&)
|
||||
{
|
||||
return Gfx::CanvasCommands::Restore {};
|
||||
}
|
||||
|
||||
template<>
|
||||
ErrorOr<void> encode(Encoder& encoder, Gfx::CanvasCommands::ClipPath const& command)
|
||||
{
|
||||
TRY(encoder.encode(command.path));
|
||||
TRY(encoder.encode(command.winding_rule));
|
||||
return {};
|
||||
}
|
||||
|
||||
template<>
|
||||
ErrorOr<Gfx::CanvasCommands::ClipPath> decode(Decoder& decoder)
|
||||
{
|
||||
return Gfx::CanvasCommands::ClipPath {
|
||||
.path = TRY(decoder.decode<Gfx::Path>()),
|
||||
.winding_rule = TRY(decoder.decode<Gfx::WindingRule>()),
|
||||
};
|
||||
}
|
||||
|
||||
template<>
|
||||
ErrorOr<void> encode(Encoder&, Gfx::CanvasCommands::Reset const&)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
template<>
|
||||
ErrorOr<Gfx::CanvasCommands::Reset> decode(Decoder&)
|
||||
{
|
||||
return Gfx::CanvasCommands::Reset {};
|
||||
}
|
||||
|
||||
template<>
|
||||
ErrorOr<void> encode(Encoder& encoder, Gfx::CanvasCommandList const& command_list)
|
||||
{
|
||||
TRY(encoder.encode(command_list.commands()));
|
||||
return {};
|
||||
}
|
||||
|
||||
template<>
|
||||
ErrorOr<Gfx::CanvasCommandList> decode(Decoder& decoder)
|
||||
{
|
||||
return Gfx::CanvasCommandList { TRY(decoder.decode<Vector<Gfx::CanvasCommand>>()) };
|
||||
}
|
||||
|
||||
}
|
||||
237
Libraries/LibGfx/CanvasCommandList.h
Normal file
237
Libraries/LibGfx/CanvasCommandList.h
Normal file
|
|
@ -0,0 +1,237 @@
|
|||
/*
|
||||
* Copyright (c) 2026, Aliaksandr Kalenik <kalenik.aliaksandr@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/Optional.h>
|
||||
#include <AK/Variant.h>
|
||||
#include <AK/Vector.h>
|
||||
#include <LibGfx/AffineTransform.h>
|
||||
#include <LibGfx/Bitmap.h>
|
||||
#include <LibGfx/Color.h>
|
||||
#include <LibGfx/CompositingAndBlendingOperator.h>
|
||||
#include <LibGfx/DecodedImageFrame.h>
|
||||
#include <LibGfx/Filter.h>
|
||||
#include <LibGfx/Gradients.h>
|
||||
#include <LibGfx/PaintStyle.h>
|
||||
#include <LibGfx/Path.h>
|
||||
#include <LibGfx/Point.h>
|
||||
#include <LibGfx/Rect.h>
|
||||
#include <LibGfx/ScalingMode.h>
|
||||
#include <LibGfx/Size.h>
|
||||
#include <LibGfx/WindingRule.h>
|
||||
#include <LibIPC/Forward.h>
|
||||
|
||||
namespace Gfx {
|
||||
|
||||
struct CanvasLinearGradient {
|
||||
FloatPoint start_point;
|
||||
FloatPoint end_point;
|
||||
Vector<ColorStop> color_stops;
|
||||
Optional<float> repeat_length;
|
||||
};
|
||||
|
||||
struct CanvasRadialGradient {
|
||||
FloatPoint start_center;
|
||||
float start_radius { 0 };
|
||||
FloatPoint end_center;
|
||||
float end_radius { 0 };
|
||||
Vector<ColorStop> color_stops;
|
||||
Optional<float> repeat_length;
|
||||
};
|
||||
|
||||
struct CanvasConicGradient {
|
||||
FloatPoint center;
|
||||
float start_angle { 0 };
|
||||
Vector<ColorStop> color_stops;
|
||||
Optional<float> repeat_length;
|
||||
};
|
||||
|
||||
struct CanvasPatternStyle {
|
||||
Optional<DecodedImageFrame> image;
|
||||
CanvasPatternPaintStyle::Repetition repetition { CanvasPatternPaintStyle::Repetition::Repeat };
|
||||
Optional<AffineTransform> transform;
|
||||
};
|
||||
|
||||
using CanvasPaintStyle = Variant<Color, CanvasLinearGradient, CanvasRadialGradient, CanvasConicGradient, CanvasPatternStyle>;
|
||||
|
||||
namespace CanvasCommands {
|
||||
|
||||
struct ClearRect {
|
||||
FloatRect rect;
|
||||
Color color;
|
||||
};
|
||||
|
||||
struct FillRect {
|
||||
FloatRect rect;
|
||||
Color color;
|
||||
};
|
||||
|
||||
struct DrawBitmap {
|
||||
DecodedImageFrame frame;
|
||||
FloatRect dst_rect;
|
||||
IntRect src_rect;
|
||||
ScalingMode scaling_mode { ScalingMode::NearestNeighbor };
|
||||
Optional<Filter> filter;
|
||||
float global_alpha { 1 };
|
||||
CompositingAndBlendingOperator compositing_and_blending_operator { CompositingAndBlendingOperator::SourceOver };
|
||||
};
|
||||
|
||||
struct FillPath {
|
||||
Path path;
|
||||
CanvasPaintStyle style;
|
||||
WindingRule winding_rule { WindingRule::Nonzero };
|
||||
float blur_radius { 0 };
|
||||
Optional<Filter> filter;
|
||||
float global_alpha { 1 };
|
||||
CompositingAndBlendingOperator compositing_and_blending_operator { CompositingAndBlendingOperator::SourceOver };
|
||||
};
|
||||
|
||||
struct StrokePath {
|
||||
Path path;
|
||||
CanvasPaintStyle style;
|
||||
float thickness { 1 };
|
||||
Path::CapStyle cap_style { Path::CapStyle::Butt };
|
||||
Path::JoinStyle join_style { Path::JoinStyle::Miter };
|
||||
float miter_limit { 10 };
|
||||
Vector<float> dash_array;
|
||||
float dash_offset { 0 };
|
||||
float blur_radius { 0 };
|
||||
Optional<Filter> filter;
|
||||
float global_alpha { 1 };
|
||||
CompositingAndBlendingOperator compositing_and_blending_operator { CompositingAndBlendingOperator::SourceOver };
|
||||
};
|
||||
|
||||
struct SetTransform {
|
||||
AffineTransform transform;
|
||||
};
|
||||
|
||||
struct Save { };
|
||||
|
||||
struct Restore { };
|
||||
|
||||
struct ClipPath {
|
||||
Path path;
|
||||
WindingRule winding_rule { WindingRule::Nonzero };
|
||||
};
|
||||
|
||||
struct Reset { };
|
||||
|
||||
}
|
||||
|
||||
using CanvasCommand = Variant<
|
||||
CanvasCommands::ClearRect,
|
||||
CanvasCommands::FillRect,
|
||||
CanvasCommands::DrawBitmap,
|
||||
CanvasCommands::FillPath,
|
||||
CanvasCommands::StrokePath,
|
||||
CanvasCommands::SetTransform,
|
||||
CanvasCommands::Save,
|
||||
CanvasCommands::Restore,
|
||||
CanvasCommands::ClipPath,
|
||||
CanvasCommands::Reset>;
|
||||
|
||||
class CanvasCommandList {
|
||||
public:
|
||||
CanvasCommandList() = default;
|
||||
explicit CanvasCommandList(Vector<CanvasCommand> commands)
|
||||
: m_commands(move(commands))
|
||||
{
|
||||
}
|
||||
|
||||
void append(CanvasCommand&& command) { m_commands.append(move(command)); }
|
||||
|
||||
bool is_empty() const { return m_commands.is_empty(); }
|
||||
size_t size() const { return m_commands.size(); }
|
||||
|
||||
Vector<CanvasCommand> const& commands() const { return m_commands; }
|
||||
|
||||
private:
|
||||
Vector<CanvasCommand> m_commands;
|
||||
};
|
||||
|
||||
CanvasPaintStyle to_canvas_paint_style(PaintStyle const&);
|
||||
|
||||
}
|
||||
|
||||
namespace IPC {
|
||||
|
||||
template<>
|
||||
ErrorOr<void> encode(Encoder&, Gfx::CanvasLinearGradient const&);
|
||||
template<>
|
||||
ErrorOr<Gfx::CanvasLinearGradient> decode(Decoder&);
|
||||
|
||||
template<>
|
||||
ErrorOr<void> encode(Encoder&, Gfx::CanvasRadialGradient const&);
|
||||
template<>
|
||||
ErrorOr<Gfx::CanvasRadialGradient> decode(Decoder&);
|
||||
|
||||
template<>
|
||||
ErrorOr<void> encode(Encoder&, Gfx::CanvasConicGradient const&);
|
||||
template<>
|
||||
ErrorOr<Gfx::CanvasConicGradient> decode(Decoder&);
|
||||
|
||||
template<>
|
||||
ErrorOr<void> encode(Encoder&, Gfx::CanvasPatternStyle const&);
|
||||
template<>
|
||||
ErrorOr<Gfx::CanvasPatternStyle> decode(Decoder&);
|
||||
|
||||
template<>
|
||||
ErrorOr<void> encode(Encoder&, Gfx::CanvasCommands::ClearRect const&);
|
||||
template<>
|
||||
ErrorOr<Gfx::CanvasCommands::ClearRect> decode(Decoder&);
|
||||
|
||||
template<>
|
||||
ErrorOr<void> encode(Encoder&, Gfx::CanvasCommands::FillRect const&);
|
||||
template<>
|
||||
ErrorOr<Gfx::CanvasCommands::FillRect> decode(Decoder&);
|
||||
|
||||
template<>
|
||||
ErrorOr<void> encode(Encoder&, Gfx::CanvasCommands::DrawBitmap const&);
|
||||
template<>
|
||||
ErrorOr<Gfx::CanvasCommands::DrawBitmap> decode(Decoder&);
|
||||
|
||||
template<>
|
||||
ErrorOr<void> encode(Encoder&, Gfx::CanvasCommands::FillPath const&);
|
||||
template<>
|
||||
ErrorOr<Gfx::CanvasCommands::FillPath> decode(Decoder&);
|
||||
|
||||
template<>
|
||||
ErrorOr<void> encode(Encoder&, Gfx::CanvasCommands::StrokePath const&);
|
||||
template<>
|
||||
ErrorOr<Gfx::CanvasCommands::StrokePath> decode(Decoder&);
|
||||
|
||||
template<>
|
||||
ErrorOr<void> encode(Encoder&, Gfx::CanvasCommands::SetTransform const&);
|
||||
template<>
|
||||
ErrorOr<Gfx::CanvasCommands::SetTransform> decode(Decoder&);
|
||||
|
||||
template<>
|
||||
ErrorOr<void> encode(Encoder&, Gfx::CanvasCommands::Save const&);
|
||||
template<>
|
||||
ErrorOr<Gfx::CanvasCommands::Save> decode(Decoder&);
|
||||
|
||||
template<>
|
||||
ErrorOr<void> encode(Encoder&, Gfx::CanvasCommands::Restore const&);
|
||||
template<>
|
||||
ErrorOr<Gfx::CanvasCommands::Restore> decode(Decoder&);
|
||||
|
||||
template<>
|
||||
ErrorOr<void> encode(Encoder&, Gfx::CanvasCommands::ClipPath const&);
|
||||
template<>
|
||||
ErrorOr<Gfx::CanvasCommands::ClipPath> decode(Decoder&);
|
||||
|
||||
template<>
|
||||
ErrorOr<void> encode(Encoder&, Gfx::CanvasCommands::Reset const&);
|
||||
template<>
|
||||
ErrorOr<Gfx::CanvasCommands::Reset> decode(Decoder&);
|
||||
|
||||
template<>
|
||||
ErrorOr<void> encode(Encoder&, Gfx::CanvasCommandList const&);
|
||||
template<>
|
||||
ErrorOr<Gfx::CanvasCommandList> decode(Decoder&);
|
||||
|
||||
}
|
||||
31
Libraries/LibGfx/DecodedImageFrame.cpp
Normal file
31
Libraries/LibGfx/DecodedImageFrame.cpp
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Copyright (c) 2026, Aliaksandr Kalenik <kalenik.aliaksandr@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <LibGfx/DecodedImageFrame.h>
|
||||
#include <LibGfx/ShareableBitmap.h>
|
||||
#include <LibIPC/Decoder.h>
|
||||
#include <LibIPC/Encoder.h>
|
||||
|
||||
namespace IPC {
|
||||
|
||||
template<>
|
||||
ErrorOr<void> encode(Encoder& encoder, Gfx::DecodedImageFrame const& frame)
|
||||
{
|
||||
auto bitmap = frame.bitmap().to_shareable_bitmap();
|
||||
TRY(encoder.encode(bitmap));
|
||||
TRY(encoder.encode(frame.color_space()));
|
||||
return {};
|
||||
}
|
||||
|
||||
template<>
|
||||
ErrorOr<Gfx::DecodedImageFrame> decode(Decoder& decoder)
|
||||
{
|
||||
auto bitmap = TRY(decoder.decode<Gfx::ShareableBitmap>());
|
||||
auto color_space = TRY(decoder.decode<Gfx::ColorSpace>());
|
||||
return Gfx::DecodedImageFrame { *bitmap.bitmap(), move(color_space) };
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -13,6 +13,7 @@
|
|||
#include <LibGfx/ColorSpace.h>
|
||||
#include <LibGfx/Forward.h>
|
||||
#include <LibGfx/Rect.h>
|
||||
#include <LibIPC/Forward.h>
|
||||
|
||||
namespace Gfx {
|
||||
|
||||
|
|
@ -67,3 +68,13 @@ private:
|
|||
};
|
||||
|
||||
}
|
||||
|
||||
namespace IPC {
|
||||
|
||||
template<>
|
||||
ErrorOr<void> encode(Encoder&, Gfx::DecodedImageFrame const&);
|
||||
|
||||
template<>
|
||||
ErrorOr<Gfx::DecodedImageFrame> decode(Decoder&);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ namespace Gfx {
|
|||
|
||||
class Bitmap;
|
||||
class CMYKBitmap;
|
||||
class CanvasCommandList;
|
||||
class ColorSpace;
|
||||
class DecodedImageFrame;
|
||||
class Color;
|
||||
|
|
|
|||
31
Libraries/LibGfx/Gradients.cpp
Normal file
31
Libraries/LibGfx/Gradients.cpp
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Copyright (c) 2026, Aliaksandr Kalenik <kalenik.aliaksandr@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <LibGfx/Gradients.h>
|
||||
#include <LibIPC/Decoder.h>
|
||||
#include <LibIPC/Encoder.h>
|
||||
|
||||
namespace IPC {
|
||||
|
||||
template<>
|
||||
ErrorOr<void> encode(Encoder& encoder, Gfx::ColorStop const& color_stop)
|
||||
{
|
||||
TRY(encoder.encode(color_stop.color));
|
||||
TRY(encoder.encode(color_stop.position));
|
||||
TRY(encoder.encode(color_stop.transition_hint));
|
||||
return {};
|
||||
}
|
||||
|
||||
template<>
|
||||
ErrorOr<Gfx::ColorStop> decode(Decoder& decoder)
|
||||
{
|
||||
auto color = TRY(decoder.decode<Gfx::Color>());
|
||||
auto position = TRY(decoder.decode<float>());
|
||||
auto transition_hint = TRY(decoder.decode<Optional<float>>());
|
||||
return Gfx::ColorStop { color, position, transition_hint };
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -9,6 +9,7 @@
|
|||
#include <AK/Math.h>
|
||||
#include <LibGfx/Color.h>
|
||||
#include <LibGfx/Size.h>
|
||||
#include <LibIPC/Forward.h>
|
||||
|
||||
namespace Gfx {
|
||||
|
||||
|
|
@ -45,3 +46,13 @@ inline float calculate_gradient_length(Size<T> gradient_size, float gradient_ang
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
namespace IPC {
|
||||
|
||||
template<>
|
||||
ErrorOr<void> encode(Encoder&, Gfx::ColorStop const&);
|
||||
|
||||
template<>
|
||||
ErrorOr<Gfx::ColorStop> decode(Decoder&);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,6 +43,26 @@ ErrorOr<Gfx::IntRect> decode(Decoder& decoder)
|
|||
return Gfx::IntRect { point, size };
|
||||
}
|
||||
|
||||
template<>
|
||||
ErrorOr<void> encode(Encoder& encoder, Gfx::FloatRect const& rect)
|
||||
{
|
||||
TRY(encoder.encode(rect.x()));
|
||||
TRY(encoder.encode(rect.y()));
|
||||
TRY(encoder.encode(rect.width()));
|
||||
TRY(encoder.encode(rect.height()));
|
||||
return {};
|
||||
}
|
||||
|
||||
template<>
|
||||
ErrorOr<Gfx::FloatRect> decode(Decoder& decoder)
|
||||
{
|
||||
auto x = TRY(decoder.decode<float>());
|
||||
auto y = TRY(decoder.decode<float>());
|
||||
auto width = TRY(decoder.decode<float>());
|
||||
auto height = TRY(decoder.decode<float>());
|
||||
return Gfx::FloatRect { x, y, width, height };
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template class Gfx::Rect<int>;
|
||||
|
|
|
|||
|
|
@ -620,4 +620,10 @@ ErrorOr<void> encode(Encoder&, Gfx::IntRect const&);
|
|||
template<>
|
||||
ErrorOr<Gfx::IntRect> decode(Decoder&);
|
||||
|
||||
template<>
|
||||
ErrorOr<void> encode(Encoder&, Gfx::FloatRect const&);
|
||||
|
||||
template<>
|
||||
ErrorOr<Gfx::FloatRect> decode(Decoder&);
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue