summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthias Clasen <mclasen@redhat.com>2022-06-20 06:29:30 -0700
committerMatthias Clasen <mclasen@redhat.com>2022-07-04 11:17:20 -0400
commit366cbe701c398782c4543313625187e7fa297135 (patch)
tree359ce90abb82e43de08dee03c28b47c0156bc161
parent3721547fb4dc2a6c16686fafc3b2e7dff747226f (diff)
downloadpango-366cbe701c398782c4543313625187e7fa297135.tar.gz
Bring back shape attributes
It turns out that using user fonts for embedding is a bit too involved, so lets keep the shape attribute machinery around.
-rw-r--r--pango/pango-attr-list.c1
-rw-r--r--pango/pango-attr.c93
-rw-r--r--pango/pango-attributes-private.h9
-rw-r--r--pango/pango-attributes.c44
-rw-r--r--pango/pango-attributes.h8
-rw-r--r--pango/pango-item-private.h1
-rw-r--r--pango/pango-item.c5
-rw-r--r--pango/pango-line-breaker.c37
-rw-r--r--pango/pango-renderer.c105
-rw-r--r--pango/pango-renderer.h12
-rw-r--r--pango/pango-run.c57
-rw-r--r--pango/serializer.c1
12 files changed, 315 insertions, 58 deletions
diff --git a/pango/pango-attr-list.c b/pango/pango-attr-list.c
index 0cf381b1..3f5c00f8 100644
--- a/pango/pango-attr-list.c
+++ b/pango/pango-attr-list.c
@@ -1253,6 +1253,7 @@ pango_attr_list_from_string (const char *text)
INT_ATTR(line_spacing, int);
break;
+ case PANGO_ATTR_SHAPE:
default:
g_assert_not_reached ();
}
diff --git a/pango/pango-attr.c b/pango/pango-attr.c
index 9640e009..211d8232 100644
--- a/pango/pango-attr.c
+++ b/pango/pango-attr.c
@@ -23,6 +23,7 @@
#include <string.h>
#include "pango-attr-private.h"
+#include "pango-attributes-private.h"
#include "pango-impl-utils.h"
@@ -98,6 +99,7 @@ is_valid_attr_type (guint type)
case PANGO_ATTR_SENTENCE:
case PANGO_ATTR_BASELINE_SHIFT:
case PANGO_ATTR_FONT_SCALE:
+ case PANGO_ATTR_SHAPE:
return TRUE;
default:
if (!attr_type)
@@ -265,28 +267,39 @@ pango_attribute_copy (const PangoAttribute *attr)
break;
case PANGO_ATTR_VALUE_POINTER:
- {
- PangoAttrDataCopyFunc copy = NULL;
+ if (attr->type == PANGO_ATTR_SHAPE)
+ {
+ ShapeData *shape_data;
- G_LOCK (attr_type);
+ shape_data = g_memdup2 (attr->pointer_value, sizeof (ShapeData));
+ if (shape_data->copy)
+ shape_data->data = shape_data->copy (shape_data->data);
- g_assert (attr_type != NULL);
+ result->pointer_value = shape_data;
+ }
+ else
+ {
+ PangoAttrDataCopyFunc copy = NULL;
- for (int i = 0; i < attr_type->len; i++)
- {
- PangoAttrClass *class = &g_array_index (attr_type, PangoAttrClass, i);
- if (class->type == attr->type)
- {
- copy = class->copy;
- break;
- }
- }
+ G_LOCK (attr_type);
- G_UNLOCK (attr_type);
+ g_assert (attr_type != NULL);
- if (copy)
- result->pointer_value = copy (attr->pointer_value);
- }
+ for (int i = 0; i < attr_type->len; i++)
+ {
+ PangoAttrClass *class = &g_array_index (attr_type, PangoAttrClass, i);
+ if (class->type == attr->type)
+ {
+ copy = class->copy;
+ break;
+ }
+ }
+
+ G_UNLOCK (attr_type);
+
+ if (copy)
+ result->pointer_value = copy (attr->pointer_value);
+ }
break;
case PANGO_ATTR_VALUE_INT:
@@ -322,28 +335,38 @@ pango_attribute_destroy (PangoAttribute *attr)
break;
case PANGO_ATTR_VALUE_POINTER:
- {
- GDestroyNotify destroy = NULL;
+ if (attr->type == PANGO_ATTR_SHAPE)
+ {
+ ShapeData *shape_data = attr->pointer_value;
- G_LOCK (attr_type);
+ if (shape_data->destroy)
+ shape_data->destroy (shape_data->data);
- g_assert (attr_type != NULL);
+ g_free (shape_data);
+ }
+ else
+ {
+ GDestroyNotify destroy = NULL;
- for (int i = 0; i < attr_type->len; i++)
- {
- PangoAttrClass *class = &g_array_index (attr_type, PangoAttrClass, i);
- if (class->type == attr->type)
- {
- destroy = class->destroy;
- break;
- }
- }
+ G_LOCK (attr_type);
- G_UNLOCK (attr_type);
+ g_assert (attr_type != NULL);
- if (destroy)
- destroy (attr->pointer_value);
- }
+ for (int i = 0; i < attr_type->len; i++)
+ {
+ PangoAttrClass *class = &g_array_index (attr_type, PangoAttrClass, i);
+ if (class->type == attr->type)
+ {
+ destroy = class->destroy;
+ break;
+ }
+ }
+
+ G_UNLOCK (attr_type);
+
+ if (destroy)
+ destroy (attr->pointer_value);
+ }
break;
case PANGO_ATTR_VALUE_INT:
@@ -427,8 +450,6 @@ pango_attribute_equal (const PangoAttribute *attr1,
G_UNLOCK (attr_type);
- g_assert (equal != NULL);
-
if (equal)
return equal (attr1->pointer_value, attr2->pointer_value);
diff --git a/pango/pango-attributes-private.h b/pango/pango-attributes-private.h
index 3ff30529..181fe98d 100644
--- a/pango/pango-attributes-private.h
+++ b/pango/pango-attributes-private.h
@@ -25,3 +25,12 @@ gboolean pango_attribute_affects_itemization (PangoAttribute *attr,
gpointer data);
gboolean pango_attribute_affects_break_or_shape (PangoAttribute *attr,
gpointer data);
+
+typedef struct {
+ PangoRectangle ink_rect;
+ PangoRectangle logical_rect;
+ gpointer data;
+ PangoAttrDataCopyFunc copy;
+ GDestroyNotify destroy;
+} ShapeData;
+
diff --git a/pango/pango-attributes.c b/pango/pango-attributes.c
index 253feca9..c1dc26d2 100644
--- a/pango/pango-attributes.c
+++ b/pango/pango-attributes.c
@@ -799,6 +799,50 @@ pango_attr_text_transform_new (PangoTextTransform transform)
return pango_attr_int_new (PANGO_ATTR_TEXT_TRANSFORM, transform);
}
+/**
+ * pango_attr_shape_new:
+ * @ink_rect: ink rectangle to use for each character
+ * @logical_rect: logical rectangle to use for each character
+ * @data: user data
+ * @copy: (nullable): function to copy @data when the attribute
+ * is copied
+ * @destroy: (nullable): function to free @data when the attribute
+ * is freed
+ *
+ * Creates a new shape attribute.
+ *
+ * Shape attributes override the extents for a glyph and can
+ * trigger custom rendering in a `PangoRenderer`. This might
+ * be used, for instance, for embedding a picture or a widget
+ * inside a `PangoLayout`.
+ *
+ * Return value: (transfer full): the newly allocated
+ * `PangoAttribute`, which should be freed with
+ * [method@Pango.Attribute.destroy]
+ */
+PangoAttribute *
+pango_attr_shape_new (PangoRectangle *ink_rect,
+ PangoRectangle *logical_rect,
+ gpointer data,
+ PangoAttrDataCopyFunc copy,
+ GDestroyNotify destroy)
+{
+ PangoAttribute *attr;
+ ShapeData *shape_data;
+
+ shape_data = g_new0 (ShapeData, 1);
+ shape_data->ink_rect = *ink_rect;
+ shape_data->logical_rect = *logical_rect;
+ shape_data->data = data;
+ shape_data->copy = copy;
+ shape_data->destroy = destroy;
+
+ attr = pango_attr_init (PANGO_ATTR_SHAPE);
+ attr->pointer_value = shape_data;
+
+ return attr;
+}
+
/* }}} */
/* {{{ Private API */
diff --git a/pango/pango-attributes.h b/pango/pango-attributes.h
index a92350a8..ffb3d07f 100644
--- a/pango/pango-attributes.h
+++ b/pango/pango-attributes.h
@@ -118,11 +118,11 @@ typedef enum
PANGO_ATTR_BASELINE_SHIFT = PANGO_ATTR_TYPE (INT, ITEMIZATION, ACCUMULATES),
PANGO_ATTR_FONT_SCALE = PANGO_ATTR_TYPE (INT, ITEMIZATION, ACCUMULATES),
PANGO_ATTR_LINE_SPACING = PANGO_ATTR_TYPE (INT, ITEMIZATION, OVERRIDES),
+ PANGO_ATTR_SHAPE = PANGO_ATTR_TYPE (POINTER, ITEMIZATION, OVERRIDES),
} PangoAttrType;
#undef PANGO_ATTR_TYPE
-
PANGO_AVAILABLE_IN_ALL
PangoAttribute * pango_attr_language_new (PangoLanguage *language);
PANGO_AVAILABLE_IN_ALL
@@ -301,5 +301,11 @@ typedef enum {
PANGO_AVAILABLE_IN_ALL
PangoAttribute * pango_attr_text_transform_new (PangoTextTransform transform);
+PANGO_AVAILABLE_IN_ALL
+PangoAttribute * pango_attr_shape_new (PangoRectangle *ink_rect,
+ PangoRectangle *logical_rect,
+ gpointer data,
+ PangoAttrDataCopyFunc copy,
+ GDestroyNotify destroy);
G_END_DECLS
diff --git a/pango/pango-item-private.h b/pango/pango-item-private.h
index 541eb017..3c8b18d7 100644
--- a/pango/pango-item-private.h
+++ b/pango/pango-item-private.h
@@ -116,6 +116,7 @@ struct _ItemProperties
int line_spacing;
int absolute_line_height;
double line_height;
+ PangoAttribute *shape;
};
void pango_item_get_properties (PangoItem *item,
diff --git a/pango/pango-item.c b/pango/pango-item.c
index 079f5796..952cab05 100644
--- a/pango/pango-item.c
+++ b/pango/pango-item.c
@@ -401,6 +401,7 @@ pango_item_get_properties (PangoItem *item,
properties->line_height = 0.0;
properties->absolute_line_height = 0;
properties->line_spacing = 0;
+ properties->shape = NULL;
while (tmp_list)
{
@@ -448,6 +449,10 @@ pango_item_get_properties (PangoItem *item,
properties->no_paragraph_break = TRUE;
break;
+ case PANGO_ATTR_SHAPE:
+ properties->shape = attr;
+ break;
+
default:
break;
}
diff --git a/pango/pango-line-breaker.c b/pango/pango-line-breaker.c
index 55eb9f4f..6fe52dc3 100644
--- a/pango/pango-line-breaker.c
+++ b/pango/pango-line-breaker.c
@@ -849,6 +849,28 @@ distribute_letter_spacing (int letter_spacing,
*space_right = letter_spacing - *space_left;
}
+static void
+pango_shape_shape (const char *text,
+ unsigned int n_chars,
+ ShapeData *shape,
+ PangoGlyphString *glyphs)
+{
+ unsigned int i;
+ const char *p;
+
+ pango_glyph_string_set_size (glyphs, n_chars);
+
+ for (i = 0, p = text; i < n_chars; i++, p = g_utf8_next_char (p))
+ {
+ glyphs->glyphs[i].glyph = PANGO_GLYPH_EMPTY;
+ glyphs->glyphs[i].geometry.x_offset = 0;
+ glyphs->glyphs[i].geometry.y_offset = 0;
+ glyphs->glyphs[i].geometry.width = shape->logical_rect.width;
+ glyphs->glyphs[i].attr.is_cluster_start = 1;
+
+ glyphs->log_clusters[i] = p - text;
+ }
+}
static PangoGlyphString *
shape_run (PangoLineBreaker *self,
@@ -866,11 +888,16 @@ shape_run (PangoLineBreaker *self,
if (pango_context_get_round_glyph_positions (self->context))
shape_flags |= PANGO_SHAPE_ROUND_POSITIONS;
- pango_shape_item (item,
- self->data->text, self->data->length,
- self->data->log_attrs + self->start_offset,
- glyphs,
- shape_flags);
+ if (self->properties.shape)
+ pango_shape_shape (self->data->text + item->offset, item->num_chars,
+ (ShapeData *)self->properties.shape->pointer_value,
+ glyphs);
+ else
+ pango_shape_item (item,
+ self->data->text, self->data->length,
+ self->data->log_attrs + self->start_offset,
+ glyphs,
+ shape_flags);
if (self->properties.letter_spacing)
{
diff --git a/pango/pango-renderer.c b/pango/pango-renderer.c
index 5c94be74..adaeb70f 100644
--- a/pango/pango-renderer.c
+++ b/pango/pango-renderer.c
@@ -27,6 +27,7 @@
#include "pango-layout.h"
#include "pango-run-private.h"
#include "pango-line-private.h"
+#include "pango-attributes-private.h"
#define N_RENDER_PARTS 5
@@ -505,6 +506,34 @@ static void pango_renderer_draw_runs (PangoRenderer *renderer,
int x,
int y);
+static void
+draw_shaped_glyphs (PangoRenderer *renderer,
+ PangoGlyphString *glyphs,
+ PangoAttribute *attr,
+ int x,
+ int y)
+{
+ PangoRendererClass *class = PANGO_RENDERER_GET_CLASS (renderer);
+ int i;
+
+ if (!class->draw_shape)
+ return;
+
+ for (i = 0; i < glyphs->num_glyphs; i++)
+ {
+ PangoGlyphInfo *gi = &glyphs->glyphs[i];
+ ShapeData *data = (ShapeData *)attr->pointer_value;
+
+ class->draw_shape (renderer,
+ &data->ink_rect,
+ &data->logical_rect,
+ data->data,
+ x, y);
+
+ x += gi->geometry.width;
+ }
+}
+
/**
* pango_renderer_draw_line:
* @renderer: a `PangoRenderer`
@@ -599,6 +628,41 @@ pango_renderer_draw_lines (PangoRenderer *renderer,
}
static void
+pango_shape_get_extents (int n_chars,
+ PangoRectangle *shape_ink,
+ PangoRectangle *shape_logical,
+ PangoRectangle *ink_rect,
+ PangoRectangle *logical_rect)
+{
+ if (n_chars > 0)
+ {
+ ink_rect->x = MIN (shape_ink->x, shape_ink->x + shape_logical->width * (n_chars - 1));
+ ink_rect->width = MAX (shape_ink->width, shape_ink->width + shape_logical->width * (n_chars - 1));
+ ink_rect->y = shape_ink->y;
+ ink_rect->height = shape_ink->height;
+
+ logical_rect->x = MIN (shape_logical->x, shape_logical->x + shape_logical->width * (n_chars - 1));
+ logical_rect->width = MAX (shape_logical->width, shape_logical->width + shape_logical->width * (n_chars - 1));
+ logical_rect->y = shape_logical->y;
+ logical_rect->height = shape_logical->height;
+ }
+ else
+ {
+ ink_rect->x = 0;
+ ink_rect->y = 0;
+ ink_rect->width = 0;
+ ink_rect->height = 0;
+
+ logical_rect->x = 0;
+ logical_rect->y = 0;
+ logical_rect->width = 0;
+ logical_rect->height = 0;
+ }
+}
+
+
+
+static void
pango_renderer_draw_runs (PangoRenderer *renderer,
PangoLine *line,
GSList *runs,
@@ -621,6 +685,7 @@ pango_renderer_draw_runs (PangoRenderer *renderer,
PangoGlyphString *glyphs = glyph_item->glyphs;
PangoRectangle ink_rect, *ink = NULL;
PangoRectangle logical_rect, *logical = NULL;
+ ItemProperties properties;
int y_off;
if (glyph_item->item->analysis.flags & PANGO_ANALYSIS_FLAG_CENTERED_BASELINE)
@@ -628,19 +693,38 @@ pango_renderer_draw_runs (PangoRenderer *renderer,
pango_renderer_prepare_run (renderer, run);
- if (renderer->underline != PANGO_LINE_STYLE_NONE ||
- renderer->overline != PANGO_LINE_STYLE_NONE ||
- renderer->strikethrough != PANGO_LINE_STYLE_NONE)
+ pango_item_get_properties (item, &properties);
+
+ if (properties.shape)
{
+ ShapeData *data = (ShapeData *)properties.shape->pointer_value;
+
ink = &ink_rect;
logical = &logical_rect;
+ pango_shape_get_extents (glyphs->num_glyphs,
+ &data->ink_rect,
+ &data->logical_rect,
+ ink,
+ logical);
+
+ glyph_string_width = logical->width;
}
- if (G_UNLIKELY (ink || logical))
- pango_glyph_string_extents (glyphs, item->analysis.font, ink, logical);
- if (logical)
- glyph_string_width = logical_rect.width;
else
- glyph_string_width = pango_glyph_string_get_width (glyphs);
+ {
+ if (renderer->underline != PANGO_LINE_STYLE_NONE ||
+ renderer->overline != PANGO_LINE_STYLE_NONE ||
+ renderer->strikethrough != PANGO_LINE_STYLE_NONE)
+ {
+ ink = &ink_rect;
+ logical = &logical_rect;
+ }
+ if (G_UNLIKELY (ink || logical))
+ pango_glyph_string_extents (glyphs, item->analysis.font, ink, logical);
+ if (logical)
+ glyph_string_width = logical_rect.width;
+ else
+ glyph_string_width = pango_glyph_string_get_width (glyphs);
+ }
renderer->priv->line_state->logical_rect_end = x + x_off + glyph_string_width;
@@ -674,7 +758,10 @@ pango_renderer_draw_runs (PangoRenderer *renderer,
overall_rect.height);
}
- pango_renderer_draw_glyph_item (renderer, text, glyph_item, x + x_off, y - y_off);
+ if (properties.shape)
+ draw_shaped_glyphs (renderer, glyphs, properties.shape, x + x_off, y - y_off);
+ else
+ pango_renderer_draw_glyph_item (renderer, text, glyph_item, x + x_off, y - y_off);
if (renderer->underline != PANGO_LINE_STYLE_NONE ||
renderer->overline != PANGO_LINE_STYLE_NONE ||
diff --git a/pango/pango-renderer.h b/pango/pango-renderer.h
index 954ffea8..ab70f183 100644
--- a/pango/pango-renderer.h
+++ b/pango/pango-renderer.h
@@ -127,7 +127,6 @@ struct _PangoRendererClass
/*< private >*/
GObjectClass parent_class;
- /* vtable - not signals */
/*< public >*/
void (*draw_glyphs) (PangoRenderer *renderer,
@@ -146,7 +145,12 @@ struct _PangoRendererClass
int y,
int width,
int height);
-
+ void (*draw_shape) (PangoRenderer *renderer,
+ PangoRectangle *ink_rect,
+ PangoRectangle *logical_rect,
+ gpointer data,
+ int x,
+ int y);
void (*draw_trapezoid) (PangoRenderer *renderer,
PangoRenderPart part,
double y1_,
@@ -179,9 +183,7 @@ struct _PangoRendererClass
/*< private >*/
/* Padding for future expansion */
- void (*_pango_reserved2) (void);
- void (*_pango_reserved3) (void);
- void (*_pango_reserved4) (void);
+ gpointer _pango_reserved[8];
};
PANGO_AVAILABLE_IN_ALL
diff --git a/pango/pango-run.c b/pango/pango-run.c
index 23f495aa..d3138cb6 100644
--- a/pango/pango-run.c
+++ b/pango/pango-run.c
@@ -4,6 +4,7 @@
#include "pango-item-private.h"
#include "pango-impl-utils.h"
#include "pango-font-metrics-private.h"
+#include "pango-attributes-private.h"
#include <math.h>
@@ -48,6 +49,54 @@ pango_run_get_glyphs (PangoRun *run)
return run->glyph_item.glyphs;
}
+static void
+pango_shape_get_extents (int n_chars,
+ PangoAttribute *attr,
+ PangoRectangle *ink_rect,
+ PangoRectangle *logical_rect)
+{
+ if (n_chars > 0)
+ {
+ ShapeData *data = (ShapeData *)attr->pointer_value;
+ PangoRectangle *shape_ink = &data->ink_rect;
+ PangoRectangle *shape_logical = &data->logical_rect;
+
+ if (ink_rect)
+ {
+ ink_rect->x = MIN (shape_ink->x, shape_ink->x + shape_logical->width * (n_chars - 1));
+ ink_rect->width = MAX (shape_ink->width, shape_ink->width + shape_logical->width * (n_chars - 1));
+ ink_rect->y = shape_ink->y;
+ ink_rect->height = shape_ink->height;
+ }
+
+ if (logical_rect)
+ {
+ logical_rect->x = MIN (shape_logical->x, shape_logical->x + shape_logical->width * (n_chars - 1));
+ logical_rect->width = MAX (shape_logical->width, shape_logical->width + shape_logical->width * (n_chars - 1));
+ logical_rect->y = shape_logical->y;
+ logical_rect->height = shape_logical->height;
+ }
+ }
+ else
+ {
+ if (ink_rect)
+ {
+ ink_rect->x = 0;
+ ink_rect->y = 0;
+ ink_rect->width = 0;
+ ink_rect->height = 0;
+ }
+
+ if (logical_rect)
+ {
+ logical_rect->x = 0;
+ logical_rect->y = 0;
+ logical_rect->width = 0;
+ logical_rect->height = 0;
+ }
+ }
+}
+
/**
* pango_run_get_extents:
* @run: a `PangoRun`
@@ -91,8 +140,12 @@ pango_run_get_extents (PangoRun *run,
if (!logical_rect && (has_underline || has_overline || has_strikethrough))
logical_rect = &logical;
- pango_glyph_string_extents (glyph_item->glyphs, glyph_item->item->analysis.font,
- ink_rect, logical_rect);
+ if (properties.shape)
+ pango_shape_get_extents (glyph_item->item->num_chars, properties.shape,
+ ink_rect, logical_rect);
+ else
+ pango_glyph_string_extents (glyph_item->glyphs, glyph_item->item->analysis.font,
+ ink_rect, logical_rect);
if (ink_rect && (has_underline || has_overline || has_strikethrough))
{
diff --git a/pango/serializer.c b/pango/serializer.c
index 6298f48c..f9941faa 100644
--- a/pango/serializer.c
+++ b/pango/serializer.c
@@ -936,6 +936,7 @@ attr_for_type (GtkJsonParser *parser,
switch (type)
{
+ case PANGO_ATTR_SHAPE:
default:
g_assert_not_reached ();