@@ -734,9 +734,65 @@ void paint_cursor_if_needed(DisplayListRecordingContext& context, TextPaintable
734734 context.display_list_recorder ().fill_rect (cursor_device_rect, caret_color);
735735}
736736
737+ static Gfx::Path build_triangle_wave_path (Gfx::IntPoint from, Gfx::IntPoint to, float amplitude)
738+ {
739+ Gfx::Path path;
740+ if (from.y () != to.y ()) {
741+ dbgln (" FIXME: Support more than horizontal waves" );
742+ return path;
743+ }
744+
745+ path.move_to (from.to_type <float >());
746+
747+ float const wavelength = amplitude * 2 .0f ;
748+ float const half_wavelength = amplitude;
749+ float const quarter_wavelength = amplitude / 2 .0f ;
750+
751+ auto position = from.to_type <float >();
752+ auto remaining = abs (to.x () - position.x ());
753+ while (remaining > wavelength) {
754+ // Draw a whole wave
755+ path.line_to ({ position.x () + quarter_wavelength, position.y () - quarter_wavelength });
756+ path.line_to ({ position.x () + quarter_wavelength + half_wavelength, position.y () + quarter_wavelength });
757+ path.line_to ({ position.x () + wavelength, (float )position.y () });
758+ position.translate_by ({ wavelength, 0 });
759+ remaining = abs (to.x () - position.x ());
760+ }
761+
762+ // Up
763+ if (remaining > quarter_wavelength) {
764+ path.line_to ({ position.x () + quarter_wavelength, position.y () - quarter_wavelength });
765+ position.translate_by ({ quarter_wavelength, 0 });
766+ remaining = abs (to.x () - position.x ());
767+ } else if (remaining >= 1 ) {
768+ auto fraction = remaining / quarter_wavelength;
769+ path.line_to ({ position.x () + (fraction * quarter_wavelength), position.y () - (fraction * quarter_wavelength) });
770+ remaining = 0 ;
771+ }
772+
773+ // Down
774+ if (remaining > half_wavelength) {
775+ path.line_to ({ position.x () + half_wavelength, position.y () + quarter_wavelength });
776+ position.translate_by (half_wavelength, 0 );
777+ remaining = abs (to.x () - position.x ());
778+ } else if (remaining >= 1 ) {
779+ auto fraction = remaining / half_wavelength;
780+ path.line_to ({ position.x () + (fraction * half_wavelength), position.y () - quarter_wavelength + (fraction * half_wavelength) });
781+ remaining = 0 ;
782+ }
783+
784+ // Back to middle
785+ if (remaining >= 1 ) {
786+ auto fraction = remaining / quarter_wavelength;
787+ path.line_to ({ position.x () + (fraction * quarter_wavelength), position.y () + ((1 - fraction) * quarter_wavelength) });
788+ }
789+
790+ return path;
791+ }
792+
737793void paint_text_decoration (DisplayListRecordingContext& context, TextPaintable const & paintable, PaintableFragment const & fragment)
738794{
739- auto & painter = context.display_list_recorder ();
795+ auto & recorder = context.display_list_recorder ();
740796 auto & font = fragment.layout_node ().first_available_font ();
741797 auto fragment_box = fragment.absolute_rect ();
742798 CSSPixels glyph_height = CSSPixels::nearest_value_for (font.pixel_size ());
@@ -796,7 +852,7 @@ void paint_text_decoration(DisplayListRecordingContext& context, TextPaintable c
796852
797853 switch (line_style) {
798854 case CSS::TextDecorationStyle::Solid:
799- painter .draw_line (line_start_point.to_type <int >(), line_end_point.to_type <int >(), line_color, device_line_thickness.value (), Gfx::LineStyle::Solid);
855+ recorder .draw_line (line_start_point.to_type <int >(), line_end_point.to_type <int >(), line_color, device_line_thickness.value (), Gfx::LineStyle::Solid);
800856 break ;
801857 case CSS::TextDecorationStyle::Double:
802858 switch (line) {
@@ -814,14 +870,14 @@ void paint_text_decoration(DisplayListRecordingContext& context, TextPaintable c
814870 VERIFY_NOT_REACHED ();
815871 }
816872
817- painter .draw_line (line_start_point.to_type <int >(), line_end_point.to_type <int >(), line_color, device_line_thickness.value ());
818- painter .draw_line (line_start_point.translated (0 , device_line_thickness + 1 ).to_type <int >(), line_end_point.translated (0 , device_line_thickness + 1 ).to_type <int >(), line_color, device_line_thickness.value ());
873+ recorder .draw_line (line_start_point.to_type <int >(), line_end_point.to_type <int >(), line_color, device_line_thickness.value ());
874+ recorder .draw_line (line_start_point.translated (0 , device_line_thickness + 1 ).to_type <int >(), line_end_point.translated (0 , device_line_thickness + 1 ).to_type <int >(), line_color, device_line_thickness.value ());
819875 break ;
820876 case CSS::TextDecorationStyle::Dashed:
821- painter .draw_line (line_start_point.to_type <int >(), line_end_point.to_type <int >(), line_color, device_line_thickness.value (), Gfx::LineStyle::Dashed);
877+ recorder .draw_line (line_start_point.to_type <int >(), line_end_point.to_type <int >(), line_color, device_line_thickness.value (), Gfx::LineStyle::Dashed);
822878 break ;
823879 case CSS::TextDecorationStyle::Dotted:
824- painter .draw_line (line_start_point.to_type <int >(), line_end_point.to_type <int >(), line_color, device_line_thickness.value (), Gfx::LineStyle::Dotted);
880+ recorder .draw_line (line_start_point.to_type <int >(), line_end_point.to_type <int >(), line_color, device_line_thickness.value (), Gfx::LineStyle::Dotted);
825881 break ;
826882 case CSS::TextDecorationStyle::Wavy:
827883 auto amplitude = device_line_thickness.value () * 3 ;
@@ -841,7 +897,16 @@ void paint_text_decoration(DisplayListRecordingContext& context, TextPaintable c
841897 default :
842898 VERIFY_NOT_REACHED ();
843899 }
844- painter.draw_triangle_wave (line_start_point.to_type <int >(), line_end_point.to_type <int >(), line_color, amplitude, device_line_thickness.value ());
900+ recorder.stroke_path ({
901+ .cap_style = Gfx::Path::CapStyle::Round,
902+ .join_style = Gfx::Path::JoinStyle::Round,
903+ .miter_limit = 0 ,
904+ .dash_array = {},
905+ .dash_offset = 0 ,
906+ .path = build_triangle_wave_path (line_start_point.to_type <int >(), line_end_point.to_type <int >(), amplitude),
907+ .color = line_color,
908+ .thickness = static_cast <float >(device_line_thickness.value ()),
909+ });
845910 break ;
846911 }
847912 }
0 commit comments