[pango/lines: 2/2] Add dashed and dotted lines




commit 5ce5b8f5b7dc4616d0d88454a23dd3bd89902265
Author: Matthias Clasen <mclasen redhat com>
Date:   Tue Mar 30 20:08:29 2021 -0400

    Add dashed and dotted lines
    
    Extend the PangoUnderline and PangoOverline enumerations to
    cover dashed and dotted variants of the various lines, add
    api to PangoRenderer to render such lines, and implement it
    in the cairo renderer.

 pango/pango-attributes.h  |  36 ++++++++++++-
 pango/pango-layout.c      |  12 +++++
 pango/pango-renderer.c    | 128 ++++++++++++++++++++++++++++++++++++++++++++++
 pango/pango-renderer.h    |  34 +++++++++++-
 pango/pangocairo-render.c |  84 ++++++++++++++++++++++++++++++
 5 files changed, 291 insertions(+), 3 deletions(-)
---
diff --git a/pango/pango-attributes.h b/pango/pango-attributes.h
index e20b6413..fdc1e86a 100644
--- a/pango/pango-attributes.h
+++ b/pango/pango-attributes.h
@@ -228,6 +228,22 @@ typedef enum
  * @PANGO_UNDERLINE_ERROR_LINE: Like @PANGO_UNDERLINE_ERROR, but
  *     drawn continuously across multiple runs. This type
  *     of underlining is available since Pango 1.46.
+ * @PANGO_UNDERLINE_SINGLE_DOTTED: a single, dotted underline. Since Pango 1.50.
+ * @PANGO_UNDERLINE_DOUBLE_DOTTED: a double, dotted underline. Since Pango 1.50.
+ * @PANGO_UNDERLINE_LOW_DOTTED: a single, dotted underline in the same
+ *     position as for @PANGO_UNDERLINE_LOW. Since Pango 1.50.
+ * @PANGO_UNDERLINE_SINGLE_LINE_DOTTED: a single, dotted underline, drawn
+ *     continuously across multiple runs. Since Pango 1.50.
+ * @PANGO_UNDERLINE_DOUBLE_LINE_DOTTED: a double, dotted underline, drawn
+ *     continuously across multiple runs. Since Pango 1.50.
+ * @PANGO_UNDERLINE_SINGLE_DASHED: a single, dashed underline. Since Pango 1.50.
+ * @PANGO_UNDERLINE_DOUBLE_DASHED: a double, dashed underline. Since Pango 1.50.
+ * @PANGO_UNDERLINE_LOW_DASHED: a single, dashed underline in the same
+ *     position as for @PANGO_UNDERLINE_LOW. Since Pango 1.50.
+ * @PANGO_UNDERLINE_SINGLE_LINE_DASHED: a single, dashed underline, drawn
+ *     continuously across multiple runs. Since Pango 1.50.
+ * @PANGO_UNDERLINE_DOUBLE_LINE_DASHED: a double, dashed underline, drawn
+ *     continuously across multiple runs. Since Pango 1.50.
  *
  * The `PangoUnderline` enumeration is used to specify whether text
  * should be underlined, and if so, the type of underlining.
@@ -240,7 +256,19 @@ typedef enum {
   PANGO_UNDERLINE_ERROR,
   PANGO_UNDERLINE_SINGLE_LINE,
   PANGO_UNDERLINE_DOUBLE_LINE,
-  PANGO_UNDERLINE_ERROR_LINE
+  PANGO_UNDERLINE_ERROR_LINE,
+
+  PANGO_UNDERLINE_SINGLE_DOTTED,
+  PANGO_UNDERLINE_DOUBLE_DOTTED,
+  PANGO_UNDERLINE_LOW_DOTTED,
+  PANGO_UNDERLINE_SINGLE_LINE_DOTTED,
+  PANGO_UNDERLINE_DOUBLE_LINE_DOTTED,
+
+  PANGO_UNDERLINE_SINGLE_DASHED,
+  PANGO_UNDERLINE_DOUBLE_DASHED,
+  PANGO_UNDERLINE_LOW_DASHED,
+  PANGO_UNDERLINE_SINGLE_LINE_DASHED,
+  PANGO_UNDERLINE_DOUBLE_LINE_DASHED,
 } PangoUnderline;
 
 
@@ -249,6 +277,8 @@ typedef enum {
  * @PANGO_OVERLINE_NONE: no overline should be drawn
  * @PANGO_OVERLINE_SINGLE: Draw a single line above the ink
  *     extents of the text being underlined.
+ * @PANGO_OVERLINE_SINGLE_DOTTED: A single, dotted line. Since Pango 1.50
+ * @PANGO_OVERLINE_SINGLE_DASHED: A single, dashed line. Since Pango 1.50
  *
  * The `PangoOverline` enumeration is used to specify whether text
  * should be overlined, and if so, the type of line.
@@ -257,7 +287,9 @@ typedef enum {
  */
 typedef enum {
   PANGO_OVERLINE_NONE,
-  PANGO_OVERLINE_SINGLE
+  PANGO_OVERLINE_SINGLE,
+  PANGO_OVERLINE_SINGLE_DOTTED,
+  PANGO_OVERLINE_SINGLE_DASHED
 } PangoOverline;
 
 /**
diff --git a/pango/pango-layout.c b/pango/pango-layout.c
index 1f86150e..22924f88 100644
--- a/pango/pango-layout.c
+++ b/pango/pango-layout.c
@@ -5953,13 +5953,23 @@ pango_layout_get_item_properties (PangoItem      *item,
               break;
             case PANGO_UNDERLINE_SINGLE:
             case PANGO_UNDERLINE_SINGLE_LINE:
+            case PANGO_UNDERLINE_SINGLE_DOTTED:
+            case PANGO_UNDERLINE_SINGLE_LINE_DOTTED:
+            case PANGO_UNDERLINE_SINGLE_DASHED:
+            case PANGO_UNDERLINE_SINGLE_LINE_DASHED:
               properties->uline_single = TRUE;
               break;
             case PANGO_UNDERLINE_DOUBLE:
             case PANGO_UNDERLINE_DOUBLE_LINE:
+            case PANGO_UNDERLINE_DOUBLE_DOTTED:
+            case PANGO_UNDERLINE_DOUBLE_LINE_DOTTED:
+            case PANGO_UNDERLINE_DOUBLE_DASHED:
+            case PANGO_UNDERLINE_DOUBLE_LINE_DASHED:
               properties->uline_double = TRUE;
               break;
             case PANGO_UNDERLINE_LOW:
+            case PANGO_UNDERLINE_LOW_DOTTED:
+            case PANGO_UNDERLINE_LOW_DASHED:
               properties->uline_low = TRUE;
               break;
             case PANGO_UNDERLINE_ERROR:
@@ -5976,6 +5986,8 @@ pango_layout_get_item_properties (PangoItem      *item,
           switch (((PangoAttrInt *)attr)->value)
             {
             case PANGO_OVERLINE_SINGLE:
+            case PANGO_OVERLINE_SINGLE_DASHED:
+            case PANGO_OVERLINE_SINGLE_DOTTED:
               properties->oline_single = TRUE;
               break;
             default:
diff --git a/pango/pango-renderer.c b/pango/pango-renderer.c
index 2d676782..52d44061 100644
--- a/pango/pango-renderer.c
+++ b/pango/pango-renderer.c
@@ -87,6 +87,13 @@ static void pango_renderer_default_draw_error_underline (PangoRenderer    *rende
                                                          int               y,
                                                          int               width,
                                                          int               height);
+static void pango_renderer_default_draw_line            (PangoRenderer    *renderer,
+                                                         PangoRenderPart   part,
+                                                         PangoRenderLineStyle style,
+                                                         int               x,
+                                                         int               y,
+                                                         int               width,
+                                                         int               height);
 static void pango_renderer_default_prepare_run          (PangoRenderer    *renderer,
                                                          PangoLayoutRun   *run);
 
@@ -123,6 +130,7 @@ pango_renderer_class_init (PangoRendererClass *klass)
   klass->draw_glyph_item = pango_renderer_default_draw_glyph_item;
   klass->draw_rectangle = pango_renderer_default_draw_rectangle;
   klass->draw_error_underline = pango_renderer_default_draw_error_underline;
+  klass->draw_line = pango_renderer_default_draw_line;
   klass->prepare_run = pango_renderer_default_prepare_run;
 
   gobject_class->finalize = pango_renderer_finalize;
@@ -239,6 +247,48 @@ draw_underline (PangoRenderer *renderer,
                                      rect->width,
                                      rect->height);
       break;
+    case PANGO_UNDERLINE_DOUBLE_DASHED:
+    case PANGO_UNDERLINE_DOUBLE_LINE_DASHED:
+      pango_renderer_draw_line (renderer,
+                                PANGO_RENDER_PART_UNDERLINE,
+                                PANGO_RENDER_LINE_DASHED,
+                                rect->x,
+                                rect->y + 2 * rect->height,
+                                rect->width,
+                                rect->height);
+      G_GNUC_FALLTHROUGH;
+    case PANGO_UNDERLINE_SINGLE_DASHED:
+    case PANGO_UNDERLINE_LOW_DASHED:
+    case PANGO_UNDERLINE_SINGLE_LINE_DASHED:
+      pango_renderer_draw_line (renderer,
+                                PANGO_RENDER_PART_UNDERLINE,
+                                PANGO_RENDER_LINE_DASHED,
+                                rect->x,
+                                rect->y,
+                                rect->width,
+                                rect->height);
+      break;
+    case PANGO_UNDERLINE_DOUBLE_DOTTED:
+    case PANGO_UNDERLINE_DOUBLE_LINE_DOTTED:
+      pango_renderer_draw_line (renderer,
+                                PANGO_RENDER_PART_UNDERLINE,
+                                PANGO_RENDER_LINE_DOTTED,
+                                rect->x,
+                                rect->y + 2 * rect->height,
+                                rect->width,
+                                rect->height);
+      G_GNUC_FALLTHROUGH;
+    case PANGO_UNDERLINE_SINGLE_DOTTED:
+    case PANGO_UNDERLINE_LOW_DOTTED:
+    case PANGO_UNDERLINE_SINGLE_LINE_DOTTED:
+      pango_renderer_draw_line (renderer,
+                                PANGO_RENDER_PART_UNDERLINE,
+                                PANGO_RENDER_LINE_DOTTED,
+                                rect->x,
+                                rect->y,
+                                rect->width,
+                                rect->height);
+      break;
     case PANGO_UNDERLINE_ERROR:
     case PANGO_UNDERLINE_ERROR_LINE:
       pango_renderer_draw_error_underline (renderer,
@@ -271,6 +321,24 @@ draw_overline (PangoRenderer *renderer,
                                      rect->width,
                                      rect->height);
       break;
+    case PANGO_OVERLINE_SINGLE_DASHED:
+      pango_renderer_draw_line (renderer,
+                                PANGO_RENDER_PART_OVERLINE,
+                                PANGO_RENDER_LINE_DASHED,
+                                rect->x,
+                                rect->y,
+                                rect->width,
+                                rect->height);
+      break;
+    case PANGO_OVERLINE_SINGLE_DOTTED:
+      pango_renderer_draw_line (renderer,
+                                PANGO_RENDER_PART_OVERLINE,
+                                PANGO_RENDER_LINE_DOTTED,
+                                rect->x,
+                                rect->y,
+                                rect->width,
+                                rect->height);
+      break;
     }
 }
 
@@ -364,15 +432,25 @@ add_underline (PangoRenderer    *renderer,
       g_assert_not_reached ();
       break;
     case PANGO_UNDERLINE_SINGLE:
+    case PANGO_UNDERLINE_SINGLE_DASHED:
+    case PANGO_UNDERLINE_SINGLE_DOTTED:
     case PANGO_UNDERLINE_DOUBLE:
+    case PANGO_UNDERLINE_DOUBLE_DASHED:
+    case PANGO_UNDERLINE_DOUBLE_DOTTED:
     case PANGO_UNDERLINE_ERROR:
       new_rect.y -= underline_position;
       break;
     case PANGO_UNDERLINE_LOW:
+    case PANGO_UNDERLINE_LOW_DASHED:
+    case PANGO_UNDERLINE_LOW_DOTTED:
       new_rect.y += ink_rect->y + ink_rect->height + underline_thickness;
       break;
     case PANGO_UNDERLINE_SINGLE_LINE:
+    case PANGO_UNDERLINE_SINGLE_LINE_DASHED:
+    case PANGO_UNDERLINE_SINGLE_LINE_DOTTED:
     case PANGO_UNDERLINE_DOUBLE_LINE:
+    case PANGO_UNDERLINE_DOUBLE_LINE_DASHED:
+    case PANGO_UNDERLINE_DOUBLE_LINE_DOTTED:
     case PANGO_UNDERLINE_ERROR_LINE:
       new_rect.y -= underline_position;
       if (state->underline == renderer->underline)
@@ -425,6 +503,8 @@ add_overline (PangoRenderer    *renderer,
       g_assert_not_reached ();
       break;
     case PANGO_OVERLINE_SINGLE:
+    case PANGO_OVERLINE_SINGLE_DASHED:
+    case PANGO_OVERLINE_SINGLE_DOTTED:
       new_rect.y -= ascent;
       if (state->overline == renderer->priv->overline)
         {
@@ -889,6 +969,42 @@ pango_renderer_draw_rectangle (PangoRenderer   *renderer,
   PANGO_RENDERER_GET_CLASS (renderer)->draw_rectangle (renderer, part, x, y, width, height);
 }
 
+/**
+ * pango_renderer_draw_line:
+ * @renderer: a `PangoRenderer`
+ * @part: type of object this rectangle is part of
+ * @style: the style of line to draw
+ * @x: X position of upper left corner, in user space coordinates
+ *   in Pango units
+ * @y: Y position of upper left corner, in user space coordinates
+ *   in Pango units
+ * @width: width of line in Pango units
+ * @height: height of line in Pango units
+ *
+ * Draws a line with the given style into an axis-aligned rectangle
+ * in user space coordinates with the specified `PangoRenderer`.
+ *
+ * This should be called while @renderer is already active.
+ * Use [method@Pango.Renderer.activate] to activate a renderer.
+ *
+ * Since: 1.50
+ */
+void
+pango_renderer_draw_line (PangoRenderer        *renderer,
+                          PangoRenderPart       part,
+                          PangoRenderLineStyle  style,
+                          int                   x,
+                          int                   y,
+                          int                   width,
+                          int                   height)
+{
+  g_return_if_fail (PANGO_IS_RENDERER_FAST (renderer));
+  g_return_if_fail (IS_VALID_PART (part));
+  g_return_if_fail (renderer->active_count > 0);
+
+  PANGO_RENDERER_GET_CLASS (renderer)->draw_line (renderer, part, style, x, y, width, height);
+}
+
 static int
 compare_points (const void *a,
                 const void *b)
@@ -996,6 +1112,18 @@ pango_renderer_default_draw_rectangle (PangoRenderer  *renderer,
   draw_rectangle (renderer, renderer->matrix, part, x, y, width, height);
 }
 
+static void
+pango_renderer_default_draw_line (PangoRenderer        *renderer,
+                                  PangoRenderPart       part,
+                                  PangoRenderLineStyle  style,
+                                  int                   x,
+                                  int                   y,
+                                  int                   width,
+                                  int                   height)
+{
+  draw_rectangle (renderer, renderer->matrix, part, x, y, width, height);
+}
+
 /**
  * pango_renderer_draw_error_underline:
  * @renderer: a `PangoRenderer`
diff --git a/pango/pango-renderer.h b/pango/pango-renderer.h
index 98c4cfb0..1b1e744e 100644
--- a/pango/pango-renderer.h
+++ b/pango/pango-renderer.h
@@ -59,6 +59,21 @@ typedef enum
   PANGO_RENDER_PART_OVERLINE
 } PangoRenderPart;
 
+/**
+ * PangoRenderLineStyle:
+ * @PANGO_RENDER_LINE_SOLID: A solid line
+ * @PANGO_RENDER_LINE_DASHED: A dashed line
+ * @PANGO_RENDER_LINE_DOTTED: A dotted line
+ *
+ * The line style passed to the draw_line() vfunc.
+ */
+typedef enum
+{
+  PANGO_RENDER_LINE_SOLID,
+  PANGO_RENDER_LINE_DASHED,
+  PANGO_RENDER_LINE_DOTTED
+} PangoRenderLineStyle;
+
 /**
  * PangoRenderer:
  * @matrix: (nullable): the current transformation matrix for
@@ -108,6 +123,7 @@ struct _PangoRenderer
  * @end: Do renderer-specific cleanup after drawing
  * @prepare_run: updates the renderer for a new run
  * @draw_glyph_item: draws a #PangoGlyphItem
+ * @draw_line: draws a line. Available since Pango 1.50
  *
  * Class structure for #PangoRenderer.
  *
@@ -186,10 +202,17 @@ struct _PangoRendererClass
                                 int               x,
                                 int               y);
 
+  void (*draw_line)            (PangoRenderer        *renderer,
+                                PangoRenderPart       part,
+                                PangoRenderLineStyle  style,
+                                int                   x,
+                                int                   y,
+                                int                   width,
+                                int                   height);
+
   /*< private >*/
 
   /* Padding for future expansion */
-  void (*_pango_reserved2) (void);
   void (*_pango_reserved3) (void);
   void (*_pango_reserved4) (void);
 };
@@ -248,6 +271,15 @@ void pango_renderer_draw_glyph           (PangoRenderer    *renderer,
                                           double            x,
                                           double            y);
 
+PANGO_AVAILABLE_IN_1_50
+void pango_renderer_draw_line            (PangoRenderer        *renderer,
+                                          PangoRenderPart       part,
+                                          PangoRenderLineStyle  style,
+                                          int                   x,
+                                          int                   y,
+                                          int                   width,
+                                          int                   height);
+
 PANGO_AVAILABLE_IN_1_8
 void pango_renderer_activate             (PangoRenderer    *renderer);
 PANGO_AVAILABLE_IN_1_8
diff --git a/pango/pangocairo-render.c b/pango/pangocairo-render.c
index 9e3cfab8..c5ca74e3 100644
--- a/pango/pangocairo-render.c
+++ b/pango/pangocairo-render.c
@@ -808,6 +808,89 @@ pango_cairo_renderer_draw_shape (PangoRenderer  *renderer,
   cairo_restore (cr);
 }
 
+static void
+pango_cairo_renderer_draw_line (PangoRenderer        *renderer,
+                                PangoRenderPart       part,
+                                PangoRenderLineStyle  style,
+                                int                   x,
+                                int                   y,
+                                int                   width,
+                                int                   height)
+{
+  PangoCairoRenderer *crenderer = (PangoCairoRenderer *) (renderer);
+
+  if (!crenderer->do_path)
+    {
+      cairo_save (crenderer->cr);
+
+      set_color (crenderer, part);
+    }
+
+  switch (style)
+    {
+    case PANGO_RENDER_LINE_SOLID:
+      cairo_rectangle (crenderer->cr,
+                       crenderer->x_offset + (double)x / PANGO_SCALE,
+                       crenderer->y_offset + (double)y / PANGO_SCALE,
+                       (double)width / PANGO_SCALE,
+                       (double)height / PANGO_SCALE);
+      break;
+
+    case PANGO_RENDER_LINE_DOTTED:
+      {
+        double radius;
+        double xc, yc;
+        double xend;
+
+        radius = MIN (width, height) / (2.0 * PANGO_SCALE);
+        xc = crenderer->x_offset + (double)x / PANGO_SCALE + radius;
+        yc = crenderer->y_offset + (double)y / PANGO_SCALE + radius;
+        xend = xc + (double)width / PANGO_SCALE;
+
+        while (xc + radius <= xend)
+          {
+            cairo_new_sub_path (crenderer->cr);
+            cairo_arc (crenderer->cr, xc, yc, radius, 0, 2 * M_PI);
+            cairo_close_path (crenderer->cr);
+            xc += 3 * radius;
+          }
+      }
+      break;
+
+    case PANGO_RENDER_LINE_DASHED:
+      {
+        double xr, yr;
+        double w, h;
+        double d;
+        double xend;
+
+        xr = crenderer->x_offset + (double)x / PANGO_SCALE;
+        yr = crenderer->y_offset + (double)y / PANGO_SCALE;
+        xend = xr + (double)width / PANGO_SCALE;
+
+        h = MIN (width, height) / (double) PANGO_SCALE;
+        w = 5 * h;
+        d = 9 * h;
+
+        while (xr <= xend)
+          {
+            cairo_rectangle (crenderer->cr, xr, yr, MIN (w, xend - xr), h);
+            xr += d;
+          }
+      }
+      break;
+
+    default:
+      g_assert_not_reached ();
+    }
+
+  if (!crenderer->do_path)
+    {
+      cairo_fill (crenderer->cr);
+      cairo_restore (crenderer->cr);
+    }
+}
+
 static void
 pango_cairo_renderer_init (PangoCairoRenderer *renderer G_GNUC_UNUSED)
 {
@@ -824,6 +907,7 @@ pango_cairo_renderer_class_init (PangoCairoRendererClass *klass)
   renderer_class->draw_trapezoid = pango_cairo_renderer_draw_trapezoid;
   renderer_class->draw_error_underline = pango_cairo_renderer_draw_error_underline;
   renderer_class->draw_shape = pango_cairo_renderer_draw_shape;
+  renderer_class->draw_line = pango_cairo_renderer_draw_line;
 }
 
 static PangoCairoRenderer *cached_renderer = NULL; /* MT-safe */


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]