From f90e9b26f8d0b9de50fa1a8e86ed3e26706827c3 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Mon, 23 Aug 2021 17:39:04 -0400 Subject: [PATCH 1/2] Implement sloped caret drawing Prepare for Pango to return slope information for carets. While we are at it, improve the shape of our carets a bit. --- gtk/gtkstylecontext.c | 111 +++++++++++++++++++++--------------------- 1 file changed, 56 insertions(+), 55 deletions(-) diff --git a/gtk/gtkstylecontext.c b/gtk/gtkstylecontext.c index 4ded60230c..2642106bf0 100644 --- a/gtk/gtkstylecontext.c +++ b/gtk/gtkstylecontext.c @@ -972,6 +972,7 @@ draw_insertion_cursor (GtkStyleContext *context, cairo_t *cr, double x, double y, + double width, double height, double aspect_ratio, gboolean is_primary, @@ -981,7 +982,8 @@ draw_insertion_cursor (GtkStyleContext *context, GdkRGBA primary_color; GdkRGBA secondary_color; int stem_width; - int offset; + double angle; + double dx, dy; cairo_save (cr); cairo_new_path (cr); @@ -990,107 +992,104 @@ draw_insertion_cursor (GtkStyleContext *context, gdk_cairo_set_source_rgba (cr, is_primary ? &primary_color : &secondary_color); stem_width = height * aspect_ratio + 1; + if (width < 0) + stem_width = - stem_width; - /* put (stem_width % 2) on the proper side of the cursor */ - if (direction == PANGO_DIRECTION_LTR) - offset = stem_width / 2; - else - offset = stem_width - stem_width / 2; + angle = atan (height / width); - cairo_rectangle (cr, x - offset, y, stem_width, height); - cairo_fill (cr); + dx = (stem_width/2.0) * cos (M_PI/2 - angle); + dy = (stem_width/2.0) * sin (M_PI/2 - angle); if (draw_arrow) { - int arrow_width; - int ax, ay; - - arrow_width = stem_width + 1; - if (direction == PANGO_DIRECTION_RTL) { - ax = x - offset - 1; - ay = y + height - arrow_width * 2 - arrow_width + 1; + double x0, y0, x1, y1, x2, y2; - cairo_move_to (cr, ax, ay + 1); - cairo_line_to (cr, ax - arrow_width, ay + arrow_width); - cairo_line_to (cr, ax, ay + 2 * arrow_width); - cairo_fill (cr); + x0 = x - dx + 2 * dy; + y0 = y + height - dy - 2 * dx; + + x1 = x0 + 4 * dy; + y1 = y0 - 4 * dx; + x2 = x0 + 2 * dy - 3 * dx; + y2 = y0 - 2 * dx - 3 * dy; + + cairo_move_to (cr, x + width + dx, y + dy); + cairo_line_to (cr, x + dx, y + height + dy); + cairo_line_to (cr, x2, y2); + cairo_line_to (cr, x1, y1); + cairo_line_to (cr, x + width - dx, y - dy); } else if (direction == PANGO_DIRECTION_LTR) { - ax = x + stem_width - offset; - ay = y + height - arrow_width * 2 - arrow_width + 1; + double x0, y0, x1, y1, x2, y2; - cairo_move_to (cr, ax, ay + 1); - cairo_line_to (cr, ax + arrow_width, ay + arrow_width); - cairo_line_to (cr, ax, ay + 2 * arrow_width); - cairo_fill (cr); + x0 = x + dx + 2 * dy; + y0 = y + height + dy - 2 * dx; + + x1 = x0 + 4 * dy; + y1 = y0 - 4 * dx; + x2 = x0 + 2 * dy + 3 * dx; + y2 = y0 - 2 * dx + 3 * dy; + + cairo_move_to (cr, x + width - dx, y - dy); + cairo_line_to (cr, x - dx, y + height - dy); + cairo_line_to (cr, x2, y2); + cairo_line_to (cr, x1, y1); + cairo_line_to (cr, x + width + dx, y + dy); } else g_assert_not_reached(); } + else + { + cairo_move_to (cr, x + width + dx, y + dy); + cairo_line_to (cr, x + dx, y + height + dy); + cairo_line_to (cr, x - dx, y + height - dy); + cairo_line_to (cr, x + width - dx, y - dy); + } + + cairo_fill (cr); cairo_restore (cr); } static void -get_insertion_cursor_bounds (double height, +get_insertion_cursor_bounds (double width, + double height, double aspect_ratio, PangoDirection direction, gboolean draw_arrow, graphene_rect_t *bounds) { int stem_width; - int offset; stem_width = height * aspect_ratio + 1; - if (direction == PANGO_DIRECTION_LTR) - offset = stem_width / 2; - else - offset = stem_width - stem_width / 2; - if (draw_arrow) - { - if (direction == PANGO_DIRECTION_LTR) - { - graphene_rect_init (bounds, - - offset, 0, - 2 * stem_width + 1, height); - } - else - { - graphene_rect_init (bounds, - - offset - stem_width - 2, 0, - 2 * stem_width + 2, height); - } - } - else - { - graphene_rect_init (bounds, - - offset, 0, - stem_width, height); - } + graphene_rect_init (bounds, + - 2 * stem_width, - stem_width, + width + 4 * stem_width, height + 2 * stem_width); } static void snapshot_insertion_cursor (GtkSnapshot *snapshot, GtkStyleContext *context, + double width, double height, double aspect_ratio, gboolean is_primary, PangoDirection direction, gboolean draw_arrow) { - if (draw_arrow) + if (width != 0 || draw_arrow) { cairo_t *cr; graphene_rect_t bounds; - get_insertion_cursor_bounds (height, aspect_ratio, direction, draw_arrow, &bounds); + get_insertion_cursor_bounds (width, height, aspect_ratio, direction, draw_arrow, &bounds); cr = gtk_snapshot_append_cairo (snapshot, &bounds); - draw_insertion_cursor (context, cr, 0, 0, height, aspect_ratio, is_primary, direction, draw_arrow); + draw_insertion_cursor (context, cr, 0, 0, width, height, aspect_ratio, is_primary, direction, draw_arrow); cairo_destroy (cr); } @@ -1193,6 +1192,7 @@ gtk_snapshot_render_insertion_cursor (GtkSnapshot *snapshot, gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (x + PANGO_PIXELS (cursor1->x), y + PANGO_PIXELS (cursor1->y))); snapshot_insertion_cursor (snapshot, context, + PANGO_PIXELS (cursor1->width), PANGO_PIXELS (cursor1->height), aspect_ratio, TRUE, @@ -1206,6 +1206,7 @@ gtk_snapshot_render_insertion_cursor (GtkSnapshot *snapshot, gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (x + PANGO_PIXELS (cursor2->x), y + PANGO_PIXELS (cursor2->y))); snapshot_insertion_cursor (snapshot, context, + PANGO_PIXELS (cursor2->width), PANGO_PIXELS (cursor2->height), aspect_ratio, FALSE, From 2f1db4b77c0009d4dab81a88e78892fec20954bc Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Tue, 24 Aug 2021 16:49:30 -0400 Subject: [PATCH 2/2] Use pango_layout_get_caret_pos This new api returns rectangles for sloped carets, in contrast to pango_layout_get_cursor_pos, which always returns a rectangle with a width of zero. --- gtk/gtkstylecontext.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gtk/gtkstylecontext.c b/gtk/gtkstylecontext.c index 2642106bf0..864ee19da1 100644 --- a/gtk/gtkstylecontext.c +++ b/gtk/gtkstylecontext.c @@ -1166,7 +1166,7 @@ gtk_snapshot_render_insertion_cursor (GtkSnapshot *snapshot, keyboard_direction = gdk_device_get_direction (keyboard); } - pango_layout_get_cursor_pos (layout, index, &strong_pos, &weak_pos); + pango_layout_get_caret_pos (layout, index, &strong_pos, &weak_pos); direction2 = PANGO_DIRECTION_NEUTRAL;