diff --git a/Libraries/LibGfx/Path.h b/Libraries/LibGfx/Path.h index 9dd7453b9a2..c36deb087e3 100644 --- a/Libraries/LibGfx/Path.h +++ b/Libraries/LibGfx/Path.h @@ -72,6 +72,19 @@ public: void line_to(Gfx::FloatPoint const& point) { impl().line_to(point); } void close_all_subpaths() { impl().close_all_subpaths(); } void close() { impl().close(); } + + enum class CapStyle { + Butt, + Round, + Square, + }; + + enum class JoinStyle { + Miter, + Round, + Bevel, + }; + void elliptical_arc_to(FloatPoint point, FloatSize radii, float x_axis_rotation, bool large_arc, bool sweep) { impl().elliptical_arc_to(point, radii, x_axis_rotation, large_arc, sweep); } void arc_to(FloatPoint point, float radius, bool large_arc, bool sweep) { impl().arc_to(point, radius, large_arc, sweep); } void quadratic_bezier_curve_to(FloatPoint through, FloatPoint point) { impl().quadratic_bezier_curve_to(through, point); } diff --git a/Libraries/LibWeb/Painting/Command.h b/Libraries/LibWeb/Painting/Command.h index e564e99ef86..47c643e052c 100644 --- a/Libraries/LibWeb/Painting/Command.h +++ b/Libraries/LibWeb/Painting/Command.h @@ -216,6 +216,11 @@ struct FillPathUsingPaintStyle { }; struct StrokePathUsingColor { + Gfx::Path::CapStyle cap_style; + Gfx::Path::JoinStyle join_style; + float miter_limit; + Vector dash_array; + float dash_offset; Gfx::IntRect path_bounding_rect; Gfx::Path path; Color color; @@ -232,6 +237,11 @@ struct StrokePathUsingColor { }; struct StrokePathUsingPaintStyle { + Gfx::Path::CapStyle cap_style; + Gfx::Path::JoinStyle join_style; + float miter_limit; + Vector dash_array; + float dash_offset; Gfx::IntRect path_bounding_rect; Gfx::Path path; PaintStyle paint_style; diff --git a/Libraries/LibWeb/Painting/DisplayListPlayerSkia.cpp b/Libraries/LibWeb/Painting/DisplayListPlayerSkia.cpp index f1eff706d31..b72a2b3b9d9 100644 --- a/Libraries/LibWeb/Painting/DisplayListPlayerSkia.cpp +++ b/Libraries/LibWeb/Painting/DisplayListPlayerSkia.cpp @@ -817,6 +817,7 @@ void DisplayListPlayerSkia::stroke_path_using_color(StrokePathUsingColor const& if (!command.thickness) return; + // FIXME: Use .cap_style, .join_style, .miter_limit, .dash_array, .dash_offset. auto& canvas = surface().canvas(); SkPaint paint; paint.setAntiAlias(true); @@ -834,6 +835,7 @@ void DisplayListPlayerSkia::stroke_path_using_paint_style(StrokePathUsingPaintSt if (!command.thickness) return; + // FIXME: Use .cap_style, .join_style, .miter_limit, .dash_array, .dash_offset. auto path = to_skia_path(command.path); path.offset(command.aa_translation.x(), command.aa_translation.y()); auto paint = paint_style_to_skia_paint(*command.paint_style, command.bounding_rect().to_type()); diff --git a/Libraries/LibWeb/Painting/DisplayListRecorder.cpp b/Libraries/LibWeb/Painting/DisplayListRecorder.cpp index 44385334af5..2b1584cee64 100644 --- a/Libraries/LibWeb/Painting/DisplayListRecorder.cpp +++ b/Libraries/LibWeb/Painting/DisplayListRecorder.cpp @@ -86,6 +86,11 @@ void DisplayListRecorder::stroke_path(StrokePathUsingColorParams params) if (path_bounding_rect.is_empty()) return; append(StrokePathUsingColor { + .cap_style = params.cap_style, + .join_style = params.join_style, + .miter_limit = params.miter_limit, + .dash_array = move(params.dash_array), + .dash_offset = params.dash_offset, .path_bounding_rect = path_bounding_rect, .path = move(params.path), .color = params.color, @@ -103,6 +108,11 @@ void DisplayListRecorder::stroke_path(StrokePathUsingPaintStyleParams params) if (path_bounding_rect.is_empty()) return; append(StrokePathUsingPaintStyle { + .cap_style = params.cap_style, + .join_style = params.join_style, + .miter_limit = params.miter_limit, + .dash_array = move(params.dash_array), + .dash_offset = params.dash_offset, .path_bounding_rect = path_bounding_rect, .path = move(params.path), .paint_style = params.paint_style, diff --git a/Libraries/LibWeb/Painting/DisplayListRecorder.h b/Libraries/LibWeb/Painting/DisplayListRecorder.h index 0883408220f..581622c1cc0 100644 --- a/Libraries/LibWeb/Painting/DisplayListRecorder.h +++ b/Libraries/LibWeb/Painting/DisplayListRecorder.h @@ -61,6 +61,11 @@ public: void fill_path(FillPathUsingPaintStyleParams params); struct StrokePathUsingColorParams { + Gfx::Path::CapStyle cap_style; + Gfx::Path::JoinStyle join_style; + float miter_limit; + Vector dash_array; + float dash_offset; Gfx::Path path; Gfx::Color color; float thickness; @@ -69,6 +74,11 @@ public: void stroke_path(StrokePathUsingColorParams params); struct StrokePathUsingPaintStyleParams { + Gfx::Path::CapStyle cap_style; + Gfx::Path::JoinStyle join_style; + float miter_limit; + Vector dash_array; + float dash_offset; Gfx::Path path; PaintStyle paint_style; float thickness; diff --git a/Libraries/LibWeb/Painting/MediaPaintable.cpp b/Libraries/LibWeb/Painting/MediaPaintable.cpp index 5ad7fec75c6..7788dafb5d2 100644 --- a/Libraries/LibWeb/Painting/MediaPaintable.cpp +++ b/Libraries/LibWeb/Painting/MediaPaintable.cpp @@ -234,7 +234,16 @@ void MediaPaintable::paint_control_bar_speaker(PaintContext& context, HTML::HTML path.quadratic_bezier_curve_to(device_point(16, 7.5), device_point(13, 12)); path.move_to(device_point(14, 0)); path.quadratic_bezier_curve_to(device_point(20, 7.5), device_point(14, 15)); - context.display_list_recorder().stroke_path({ .path = path, .color = speaker_button_color, .thickness = 1 }); + context.display_list_recorder().stroke_path({ + .cap_style = Gfx::Path::CapStyle::Round, + .join_style = Gfx::Path::JoinStyle::Round, + .miter_limit = 4, + .dash_array = {}, + .dash_offset = 0, + .path = path, + .color = speaker_button_color, + .thickness = 1, + }); if (media_element.muted()) { context.display_list_recorder().draw_line(device_point(0, 0).to_type(), device_point(20, 15).to_type(), Color::Red, 2); diff --git a/Libraries/LibWeb/Painting/SVGPathPaintable.cpp b/Libraries/LibWeb/Painting/SVGPathPaintable.cpp index dcb8bc81cf8..18a031c3396 100644 --- a/Libraries/LibWeb/Painting/SVGPathPaintable.cpp +++ b/Libraries/LibWeb/Painting/SVGPathPaintable.cpp @@ -129,17 +129,51 @@ void SVGPathPaintable::paint(PaintContext& context, PaintPhase phase) const }); } - auto stroke_linecap = graphics_element.stroke_linecap().value_or(CSS::StrokeLinecap::Butt); - (void)stroke_linecap; // FIXME: Use + Gfx::Path::CapStyle cap_style; + switch (graphics_element.stroke_linecap().value_or(CSS::InitialValues::stroke_linecap())) { + case CSS::StrokeLinecap::Butt: + cap_style = Gfx::Path::CapStyle::Butt; + break; + case CSS::StrokeLinecap::Round: + cap_style = Gfx::Path::CapStyle::Round; + break; + case CSS::StrokeLinecap::Square: + cap_style = Gfx::Path::CapStyle::Square; + break; + } + + Gfx::Path::JoinStyle join_style; + switch (graphics_element.stroke_linejoin().value_or(CSS::InitialValues::stroke_linejoin())) { + case CSS::StrokeLinejoin::Miter: + join_style = Gfx::Path::JoinStyle::Miter; + break; + case CSS::StrokeLinejoin::Round: + join_style = Gfx::Path::JoinStyle::Round; + break; + case CSS::StrokeLinejoin::Bevel: + join_style = Gfx::Path::JoinStyle::Bevel; + break; + } + + auto miter_limit = graphics_element.stroke_miterlimit().value_or(CSS::InitialValues::stroke_miterlimit()).resolved(layout_node()); auto stroke_opacity = graphics_element.stroke_opacity().value_or(1); // Note: This is assuming .x_scale() == .y_scale() (which it does currently). auto viewbox_scale = paint_transform.x_scale(); float stroke_thickness = graphics_element.stroke_width().value_or(1) * viewbox_scale; + auto stroke_dasharray = graphics_element.stroke_dasharray(); + for (auto& value : stroke_dasharray) + value *= viewbox_scale; + float stroke_dashoffset = graphics_element.stroke_dashoffset().value_or(0) * viewbox_scale; if (auto paint_style = graphics_element.stroke_paint_style(paint_context); paint_style.has_value()) { context.display_list_recorder().stroke_path({ + .cap_style = cap_style, + .join_style = join_style, + .miter_limit = static_cast(miter_limit), + .dash_array = stroke_dasharray, + .dash_offset = stroke_dashoffset, .path = path, .paint_style = *paint_style, .thickness = stroke_thickness, @@ -148,6 +182,11 @@ void SVGPathPaintable::paint(PaintContext& context, PaintPhase phase) const }); } else if (auto stroke_color = graphics_element.stroke_color(); stroke_color.has_value()) { context.display_list_recorder().stroke_path({ + .cap_style = cap_style, + .join_style = join_style, + .miter_limit = static_cast(miter_limit), + .dash_array = stroke_dasharray, + .dash_offset = stroke_dashoffset, .path = path, .color = stroke_color->with_opacity(stroke_opacity), .thickness = stroke_thickness,