summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthias Clasen <mclasen@redhat.com>2022-01-23 18:39:08 -0500
committerMatthias Clasen <mclasen@redhat.com>2022-01-24 07:46:42 -0500
commit026bbb125b3302403c6067b22320c4862eb9009f (patch)
tree0e198d713bbc2d1eeed527e0ab2d24c8c3dca5d0
parent04aff39ebcbf43ed4e89d0e00c4b42669dcda0af (diff)
downloadpango-026bbb125b3302403c6067b22320c4862eb9009f.tar.gz
Add PangoLayoutRun
Make this a separate type from PangoGlyphItem, and give it some minimal api.
-rw-r--r--pango/meson.build2
-rw-r--r--pango/pango-layout-run-private.h14
-rw-r--r--pango/pango-layout-run.c175
-rw-r--r--pango/pango-layout-run.h20
-rw-r--r--pango/pango.h1
5 files changed, 212 insertions, 0 deletions
diff --git a/pango/meson.build b/pango/meson.build
index 9f4c49be..63a772ea 100644
--- a/pango/meson.build
+++ b/pango/meson.build
@@ -31,6 +31,7 @@ pango_sources = [
'serializer.c',
'json/gtkjsonparser.c',
'json/gtkjsonprinter.c',
+ 'pango-layout-run.c',
]
pango_headers = [
@@ -52,6 +53,7 @@ pango_headers = [
'pango-gravity.h',
'pango-item.h',
'pango-language.h',
+ 'pango-layout-run.h',
'pango-layout.h',
'pango-matrix.h',
'pango-markup.h',
diff --git a/pango/pango-layout-run-private.h b/pango/pango-layout-run-private.h
new file mode 100644
index 00000000..4d315da7
--- /dev/null
+++ b/pango/pango-layout-run-private.h
@@ -0,0 +1,14 @@
+#pragma once
+
+#include "config.h"
+
+#include "pango-layout-run.h"
+#include "pango-glyph-item.h"
+#include "pango-item-private.h"
+
+
+static inline PangoGlyphItem *
+pango_layout_run_get_glyph_item (PangoLayoutRun *run)
+{
+ return (PangoGlyphItem *)run;
+}
diff --git a/pango/pango-layout-run.c b/pango/pango-layout-run.c
new file mode 100644
index 00000000..63965842
--- /dev/null
+++ b/pango/pango-layout-run.c
@@ -0,0 +1,175 @@
+#include "config.h"
+
+#include "pango-layout-run-private.h"
+#include "pango-item-private.h"
+#include "pango-impl-utils.h"
+
+#include <math.h>
+
+PangoItem *
+pango_layout_run_get_item (PangoLayoutRun *run)
+{
+ return run->item;
+}
+
+PangoGlyphString *
+pango_layout_run_get_glyphs (PangoLayoutRun *run)
+{
+ return run->glyphs;
+}
+
+/**
+ * pango_layout_run_get_extents:
+ * @run: a `PangoLayoutRun`
+ * @trim: `PangoLeadingTrim` flags
+ * @ink_rect: (out caller-allocates) (optional): return location
+ * for the ink extents
+ * @logical_rect: (out caller-allocates) (optional): return location
+ * for the logical extents
+ *
+ * Gets the extents of a `PangoLayoutRun`.
+ *
+ * The @trim flags specify if line-height attributes are taken
+ * into consideration for determining the logical height. See the
+ * [CSS inline layout](https://www.w3.org/TR/css-inline-3/#inline-height)
+ * specification for details.
+ */
+void
+pango_layout_run_get_extents (PangoLayoutRun *run,
+ PangoLeadingTrim trim,
+ PangoRectangle *ink_rect,
+ PangoRectangle *logical_rect)
+{
+ PangoGlyphItem *glyph_item = run;
+ ItemProperties properties;
+ gboolean has_underline;
+ gboolean has_overline;
+ PangoRectangle logical;
+ PangoFontMetrics *metrics = NULL;
+ int y_offset;
+
+ pango_item_get_properties (glyph_item->item, &properties);
+
+ has_underline = properties.uline_single || properties.uline_double ||
+ properties.uline_low || properties.uline_error;
+ has_overline = properties.oline_single;
+
+ if (!logical_rect && (glyph_item->item->analysis.flags & PANGO_ANALYSIS_FLAG_CENTERED_BASELINE))
+ logical_rect = &logical;
+
+ if (!logical_rect && (has_underline || has_overline || properties.strikethrough))
+ logical_rect = &logical;
+
+ if (properties.shape_set)
+ _pango_shape_get_extents (glyph_item->item->num_chars,
+ properties.shape_ink_rect, properties.shape_logical_rect,
+ 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 || properties.strikethrough))
+ {
+ int underline_thickness;
+ int underline_position;
+ int strikethrough_thickness;
+ int strikethrough_position;
+ int new_pos;
+
+ if (!metrics)
+ metrics = pango_font_get_metrics (glyph_item->item->analysis.font,
+ glyph_item->item->analysis.language);
+
+ underline_thickness = pango_font_metrics_get_underline_thickness (metrics);
+ underline_position = pango_font_metrics_get_underline_position (metrics);
+ strikethrough_thickness = pango_font_metrics_get_strikethrough_thickness (metrics);
+ strikethrough_position = pango_font_metrics_get_strikethrough_position (metrics);
+
+ /* the underline/strikethrough takes x, width of logical_rect.
+ * Reflect that into ink_rect.
+ */
+ new_pos = MIN (ink_rect->x, logical_rect->x);
+ ink_rect->width = MAX (ink_rect->x + ink_rect->width, logical_rect->x + logical_rect->width) - new_pos;
+ ink_rect->x = new_pos;
+
+ /* We should better handle the case of height==0 in the following cases.
+ * If ink_rect->height == 0, we should adjust ink_rect->y appropriately.
+ */
+
+ if (properties.strikethrough)
+ {
+ if (ink_rect->height == 0)
+ {
+ ink_rect->height = strikethrough_thickness;
+ ink_rect->y = -strikethrough_position;
+ }
+ }
+
+ if (properties.oline_single)
+ {
+ ink_rect->y -= underline_thickness;
+ ink_rect->height += underline_thickness;
+ }
+
+ if (properties.uline_low)
+ ink_rect->height += 2 * underline_thickness;
+ if (properties.uline_single)
+ ink_rect->height = MAX (ink_rect->height,
+ underline_thickness - underline_position - ink_rect->y);
+ if (properties.uline_double)
+ ink_rect->height = MAX (ink_rect->height,
+ 3 * underline_thickness - underline_position - ink_rect->y);
+ if (properties.uline_error)
+ ink_rect->height = MAX (ink_rect->height,
+ 3 * underline_thickness - underline_position - ink_rect->y);
+ }
+
+ y_offset = glyph_item->y_offset;
+
+ if (glyph_item->item->analysis.flags & PANGO_ANALYSIS_FLAG_CENTERED_BASELINE)
+ {
+ gboolean is_hinted = (logical_rect->y & logical_rect->height & (PANGO_SCALE - 1)) == 0;
+ int adjustment = logical_rect->y + logical_rect->height / 2;
+
+ if (is_hinted)
+ adjustment = PANGO_UNITS_ROUND (adjustment);
+
+ y_offset += adjustment;
+ }
+
+ if (ink_rect)
+ ink_rect->y -= y_offset;
+
+ if (logical_rect)
+ logical_rect->y -= y_offset;
+
+ if (logical_rect && trim != PANGO_LEADING_TRIM_BOTH)
+ {
+ int leading;
+
+ if (properties.absolute_line_height != 0 || properties.line_height != 0.0)
+ {
+ int line_height;
+
+ line_height = MAX (properties.absolute_line_height, ceilf (properties.line_height * logical_rect->height));
+ leading = (line_height - logical_rect->height);
+ }
+ else
+ {
+ /* line-height 'normal' in the CSS inline layout spec */
+ if (!metrics)
+ metrics = pango_font_get_metrics (glyph_item->item->analysis.font,
+ glyph_item->item->analysis.language);
+ leading = MAX (metrics->height - (metrics->ascent + metrics->descent), 0);
+ }
+ if ((trim & PANGO_LEADING_TRIM_START) == 0)
+ logical_rect->y -= leading / 2;
+ if (trim == PANGO_LEADING_TRIM_NONE)
+ logical_rect->height += leading;
+ else
+ logical_rect->height += (leading - leading / 2);
+ }
+
+ if (metrics)
+ pango_font_metrics_unref (metrics);
+}
diff --git a/pango/pango-layout-run.h b/pango/pango-layout-run.h
new file mode 100644
index 00000000..b9201071
--- /dev/null
+++ b/pango/pango-layout-run.h
@@ -0,0 +1,20 @@
+#pragma once
+
+#include <glib-object.h>
+#include <pango/pango-types.h>
+#include <pango/pango-item.h>
+#include <pango/pango-glyph.h>
+#include <pango/pango-layout.h>
+
+
+PANGO_AVAILABLE_IN_ALL
+PangoItem * pango_layout_run_get_item (PangoLayoutRun *run);
+
+PANGO_AVAILABLE_IN_ALL
+PangoGlyphString * pango_layout_run_get_glyphs (PangoLayoutRun *run);
+
+PANGO_AVAILABLE_IN_ALL
+void pango_layout_run_get_extents (PangoLayoutRun *run,
+ PangoLeadingTrim trim,
+ PangoRectangle *ink_rect,
+ PangoRectangle *logical_rect);
diff --git a/pango/pango.h b/pango/pango.h
index eca66265..1809296d 100644
--- a/pango/pango.h
+++ b/pango/pango.h
@@ -42,6 +42,7 @@
#include <pango/pango-item.h>
#include <pango/pango-language.h>
#include <pango/pango-layout.h>
+#include <pango/pango-layout-run.h>
#include <pango/pango-matrix.h>
#include <pango/pango-markup.h>
#include <pango/pango-renderer.h>