summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthias Clasen <mclasen@redhat.com>2021-03-30 20:08:29 -0400
committerMatthias Clasen <mclasen@redhat.com>2021-03-31 17:12:36 -0400
commit6309c75a09cbfd92a69586c4577dd354b67acf01 (patch)
tree41fc2943525b664e24b3e1479b5564fd2d7070f3
parent7e753e880aa20d568778099ce6b3050d15d10c33 (diff)
downloadpango-dashed-lines.tar.gz
Add dashed and dotted linesdashed-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.
-rw-r--r--pango/pango-attributes.h36
-rw-r--r--pango/pango-layout.c12
-rw-r--r--pango/pango-renderer.c128
-rw-r--r--pango/pango-renderer.h34
-rw-r--r--pango/pangocairo-render.c84
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
@@ -60,6 +60,21 @@ typedef enum
} 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
* the Renderer; may be %NULL, which should be treated the
@@ -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
@@ -809,6 +809,89 @@ pango_cairo_renderer_draw_shape (PangoRenderer *renderer,
}
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 */