diff options
author | Matthias Clasen <mclasen@redhat.com> | 2022-01-14 22:11:15 -0500 |
---|---|---|
committer | Matthias Clasen <mclasen@redhat.com> | 2022-01-24 10:58:17 -0500 |
commit | 65bf6b818579ff3d5c072814d10260a324ffd01e (patch) | |
tree | 5f1f5c50bac8eca5b267641d1a5c259e20c452ed /pango | |
parent | 1f655e6b71096ff32a9e479bdcc702ed24131923 (diff) | |
download | pango-65bf6b818579ff3d5c072814d10260a324ffd01e.tar.gz |
Implement rendering for PangoLine
Diffstat (limited to 'pango')
-rw-r--r-- | pango/pango-renderer.c | 260 | ||||
-rw-r--r-- | pango/pango-renderer.h | 15 | ||||
-rw-r--r-- | pango/pangocairo-context.c | 27 | ||||
-rw-r--r-- | pango/pangocairo-render.c | 139 | ||||
-rw-r--r-- | pango/pangocairo.h | 18 |
5 files changed, 375 insertions, 84 deletions
diff --git a/pango/pango-renderer.c b/pango/pango-renderer.c index 311c28cd..afb9b360 100644 --- a/pango/pango-renderer.c +++ b/pango/pango-renderer.c @@ -25,6 +25,8 @@ #include "pango-renderer.h" #include "pango-impl-utils.h" #include "pango-layout-private.h" +#include "pango-line-private.h" +#include "pango-layout-run-private.h" #define N_RENDER_PARTS 5 @@ -56,6 +58,8 @@ struct _LineState struct _PangoRendererPrivate { + PangoContext *context; + PangoColor color[N_RENDER_PARTS]; gboolean color_set[N_RENDER_PARTS]; guint16 alpha[N_RENDER_PARTS]; @@ -146,6 +150,20 @@ pango_renderer_finalize (GObject *gobject) G_OBJECT_CLASS (pango_renderer_parent_class)->finalize (gobject); } +static void +pango_renderer_activate_with_context (PangoRenderer *renderer, + PangoContext *context) +{ + /* We only change the matrix if the renderer isn't already active. */ + if (!renderer->active_count) + { + pango_renderer_set_matrix (renderer, context ? pango_context_get_matrix (context) : NULL); + renderer->priv->context = context; + } + + pango_renderer_activate (renderer); +} + /** * pango_renderer_draw_layout: * @renderer: a `PangoRenderer` @@ -173,17 +191,7 @@ pango_renderer_draw_layout (PangoRenderer *renderer, g_return_if_fail (PANGO_IS_RENDERER (renderer)); g_return_if_fail (PANGO_IS_LAYOUT (layout)); - /* We only change the matrix if the renderer isn't already - * active. - */ - if (!renderer->active_count) - { - PangoContext *context = pango_layout_get_context (layout); - pango_renderer_set_matrix (renderer, - pango_context_get_matrix (context)); - } - - pango_renderer_activate (renderer); + pango_renderer_activate_with_context (renderer, pango_layout_get_context (layout)); _pango_layout_get_iter (layout, &iter); @@ -549,6 +557,11 @@ draw_shaped_glyphs (PangoRenderer *renderer, } } +static void pango_renderer_draw_runs (PangoRenderer *renderer, + GSList *runs, + const char *text, + int x, + int y); /** * pango_renderer_draw_layout_line: @@ -573,27 +586,13 @@ pango_renderer_draw_layout_line (PangoRenderer *renderer, int x, int y) { - int x_off = 0; - int glyph_string_width; LineState state = { 0, }; - GSList *l; - gboolean got_overall = FALSE; - PangoRectangle overall_rect; const char *text; g_return_if_fail (PANGO_IS_RENDERER_FAST (renderer)); - /* We only change the matrix if the renderer isn't already - * active. - */ - if (!renderer->active_count) - pango_renderer_set_matrix (renderer, - G_LIKELY (line->layout) ? - pango_context_get_matrix - (pango_layout_get_context (line->layout)) : - NULL); - - pango_renderer_activate (renderer); + pango_renderer_activate_with_context (renderer, + line->layout ? pango_layout_get_context (line->layout) : NULL); renderer->priv->line = line; renderer->priv->line_state = &state; @@ -604,27 +603,143 @@ pango_renderer_draw_layout_line (PangoRenderer *renderer, text = G_LIKELY (line->layout) ? pango_layout_get_text (line->layout) : NULL; - for (l = line->runs; l; l = l->next) + pango_renderer_draw_runs (renderer, line->runs, text, x, y); + + /* Finish off any remaining underlines */ + draw_underline (renderer, &state); + draw_overline (renderer, &state); + draw_strikethrough (renderer, &state); + + renderer->priv->line_state = NULL; + renderer->priv->line = NULL; + + pango_renderer_deactivate (renderer); +} + +/** + * pango_renderer_draw_line: + * @renderer: a `PangoRenderer` + * @line: a `PangoLine` + * @x: X position of left edge of baseline, in user space coordinates + * in Pango units. + * @y: Y position of left edge of baseline, in user space coordinates + * in Pango units. + * + * Draws @line with the specified `PangoRenderer`. + * + * This draws the glyph items that make up the line, as well as + * shapes, backgrounds and lines that are specified by the attributes + * of those items. + */ +void +pango_renderer_draw_line (PangoRenderer *renderer, + PangoLine *line, + int x, + int y) +{ + LineState state = { 0, }; + + g_return_if_fail (PANGO_IS_RENDERER_FAST (renderer)); + + pango_renderer_activate_with_context (renderer, line->context); + + renderer->priv->line = NULL; + renderer->priv->line_state = &state; + + state.underline = PANGO_UNDERLINE_NONE; + state.overline = PANGO_OVERLINE_NONE; + state.strikethrough = FALSE; + + pango_renderer_draw_runs (renderer, line->runs, line->data->text, x, y); + + /* Finish off any remaining underlines */ + draw_underline (renderer, &state); + draw_overline (renderer, &state); + draw_strikethrough (renderer, &state); + + renderer->priv->line_state = NULL; + renderer->priv->line = NULL; + + pango_renderer_deactivate (renderer); +} + +/** + * pango_renderer_draw_lines: + * @renderer: a `PangoRenderer` + * @lines: a `PangoLines` object + * @x: X position of left edge of baseline, in user space coordinates + * in Pango units. + * @y: Y position of left edge of baseline, in user space coordinates + * in Pango units. + * + * Draws @lines with the specified `PangoRenderer`. + */ +void +pango_renderer_draw_lines (PangoRenderer *renderer, + PangoLines *lines, + int x, + int y) +{ + int n; + PangoLine *line; + int line_x, line_y; + + g_return_if_fail (PANGO_IS_RENDERER_FAST (renderer)); + + renderer->priv->lines = lines; + + n = 0; + while ((line = pango_lines_get_line (lines, n, &line_x, &line_y)) != NULL) + { + if (n == 0) + pango_renderer_activate_with_context (renderer, line->context); + + pango_renderer_draw_line (renderer, line, x + line_x, y + line_y); + + n++; + } + + if (n > 0) + pango_renderer_deactivate (renderer); +} + +static void +pango_renderer_draw_runs (PangoRenderer *renderer, + GSList *runs, + const char *text, + int x, + int y) +{ + GSList *l; + int x_off = 0; + int glyph_string_width; + gboolean got_overall = FALSE; + PangoRectangle overall_rect; + + for (l = runs; l; l = l->next) { PangoFontMetrics *metrics; PangoLayoutRun *run = l->data; + PangoGlyphItem *glyph_item = l->data; + PangoItem *item = glyph_item->item; + PangoGlyphString *glyphs = glyph_item->glyphs; PangoAttrShape *shape_attr; PangoRectangle ink_rect, *ink = NULL; PangoRectangle logical_rect, *logical = NULL; int y_off; - if (run->item->analysis.flags & PANGO_ANALYSIS_FLAG_CENTERED_BASELINE) + if (glyph_item->item->analysis.flags & PANGO_ANALYSIS_FLAG_CENTERED_BASELINE) logical = &logical_rect; pango_renderer_prepare_run (renderer, run); - get_item_properties (run->item, &shape_attr); + get_item_properties (item, &shape_attr); if (shape_attr) { ink = &ink_rect; logical = &logical_rect; - _pango_shape_get_extents (run->glyphs->num_glyphs, + _pango_shape_get_extents (glyphs->num_glyphs, &shape_attr->ink_rect, &shape_attr->logical_rect, ink, @@ -641,20 +756,19 @@ pango_renderer_draw_layout_line (PangoRenderer *renderer, logical = &logical_rect; } if (G_UNLIKELY (ink || logical)) - pango_glyph_string_extents (run->glyphs, run->item->analysis.font, - 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 (run->glyphs); + glyph_string_width = pango_glyph_string_get_width (glyphs); } - state.logical_rect_end = x + x_off + glyph_string_width; + renderer->priv->line_state->logical_rect_end = x + x_off + glyph_string_width; - x_off += run->start_x_offset; - y_off = run->y_offset; + x_off += glyph_item->start_x_offset; + y_off = glyph_item->y_offset; - if (run->item->analysis.flags & PANGO_ANALYSIS_FLAG_CENTERED_BASELINE) + if (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; @@ -665,12 +779,13 @@ pango_renderer_draw_layout_line (PangoRenderer *renderer, y_off += adjustment; } - if (renderer->priv->color_set[PANGO_RENDER_PART_BACKGROUND]) { if (!got_overall) { +#ifdef EXTENTS pango_layout_line_get_extents (line, NULL, &overall_rect); +#endif got_overall = TRUE; } @@ -683,67 +798,49 @@ pango_renderer_draw_layout_line (PangoRenderer *renderer, } if (shape_attr) - { - draw_shaped_glyphs (renderer, run->glyphs, shape_attr, x + x_off, y - y_off); - } + draw_shaped_glyphs (renderer, glyphs, shape_attr, x + x_off, y - y_off); else - { - pango_renderer_draw_glyph_item (renderer, - text, - run, - x + x_off, y - y_off); - } + pango_renderer_draw_glyph_item (renderer, text, glyph_item, x + x_off, y - y_off); if (renderer->underline != PANGO_UNDERLINE_NONE || renderer->priv->overline != PANGO_OVERLINE_NONE || renderer->strikethrough) { - metrics = pango_font_get_metrics (run->item->analysis.font, - run->item->analysis.language); + metrics = pango_font_get_metrics (item->analysis.font, + item->analysis.language); if (renderer->underline != PANGO_UNDERLINE_NONE) - add_underline (renderer, &state,metrics, + add_underline (renderer, renderer->priv->line_state, metrics, x + x_off, y - y_off, ink, logical); if (renderer->priv->overline != PANGO_OVERLINE_NONE) - add_overline (renderer, &state,metrics, + add_overline (renderer, renderer->priv->line_state, metrics, x + x_off, y - y_off, ink, logical); if (renderer->strikethrough) - add_strikethrough (renderer, &state, metrics, + add_strikethrough (renderer, renderer->priv->line_state, metrics, x + x_off, y - y_off, - ink, logical, run->glyphs->num_glyphs); + ink, logical, glyphs->num_glyphs); pango_font_metrics_unref (metrics); } if (renderer->underline == PANGO_UNDERLINE_NONE && - state.underline != PANGO_UNDERLINE_NONE) - draw_underline (renderer, &state); + renderer->priv->line_state->underline != PANGO_UNDERLINE_NONE) + draw_underline (renderer, renderer->priv->line_state); if (renderer->priv->overline == PANGO_OVERLINE_NONE && - state.overline != PANGO_OVERLINE_NONE) - draw_overline (renderer, &state); + renderer->priv->line_state->overline != PANGO_OVERLINE_NONE) + draw_overline (renderer, renderer->priv->line_state); - if (!renderer->strikethrough && state.strikethrough) - draw_strikethrough (renderer, &state); + if (!renderer->strikethrough && renderer->priv->line_state->strikethrough) + draw_strikethrough (renderer, renderer->priv->line_state); x_off += glyph_string_width; - x_off += run->end_x_offset; + x_off += glyph_item->end_x_offset; } - - /* Finish off any remaining underlines - */ - draw_underline (renderer, &state); - draw_overline (renderer, &state); - draw_strikethrough (renderer, &state); - - renderer->priv->line_state = NULL; - renderer->priv->line = NULL; - - pango_renderer_deactivate (renderer); } /** @@ -1476,12 +1573,15 @@ pango_renderer_default_prepare_run (PangoRenderer *renderer, guint16 fg_alpha = 0; guint16 bg_alpha = 0; GSList *l; + PangoGlyphItem *glyph_item; + + glyph_item = pango_layout_run_get_glyph_item (run); renderer->underline = PANGO_UNDERLINE_NONE; renderer->priv->overline = PANGO_OVERLINE_NONE; renderer->strikethrough = FALSE; - for (l = run->item->analysis.extra_attrs; l; l = l->next) + for (l = glyph_item->item->analysis.extra_attrs; l; l = l->next) { PangoAttribute *attr = l->data; @@ -1645,3 +1745,17 @@ pango_renderer_get_layout_line (PangoRenderer *renderer) { return renderer->priv->line; } + +/** + * pango_renderer_get_context: + * @renderer: a `PangoRenderer` + * + * Gets the current context in which @renderer operates. + * + * Returns: (nullable) (transfer none): the `PangoContext` + */ +PangoContext * +pango_renderer_get_context (PangoRenderer *renderer) +{ + return renderer->priv->context; +} diff --git a/pango/pango-renderer.h b/pango/pango-renderer.h index 16a1bbd4..61f18a72 100644 --- a/pango/pango-renderer.h +++ b/pango/pango-renderer.h @@ -22,6 +22,8 @@ #define __PANGO_RENDERER_H_ #include <pango/pango-layout.h> +#include <pango/pango-line.h> +#include <pango/pango-lines.h> G_BEGIN_DECLS @@ -207,6 +209,16 @@ void pango_renderer_draw_layout_line (PangoRenderer *renderer, PangoLayoutLine *line, int x, int y); +PANGO_AVAILABLE_IN_ALL +void pango_renderer_draw_line (PangoRenderer *renderer, + PangoLine *line, + int x, + int y); +PANGO_AVAILABLE_IN_ALL +void pango_renderer_draw_lines (PangoRenderer *renderer, + PangoLines *lines, + int x, + int y); PANGO_AVAILABLE_IN_1_8 void pango_renderer_draw_glyphs (PangoRenderer *renderer, PangoFont *font, @@ -284,6 +296,9 @@ PangoLayout *pango_renderer_get_layout (PangoRenderer *renderer); PANGO_AVAILABLE_IN_1_20 PangoLayoutLine *pango_renderer_get_layout_line (PangoRenderer *renderer); +PANGO_AVAILABLE_IN_ALL +PangoContext * pango_renderer_get_context (PangoRenderer *renderer); + G_END_DECLS #endif /* __PANGO_RENDERER_H_ */ diff --git a/pango/pangocairo-context.c b/pango/pangocairo-context.c index 08a90678..0ea8332a 100644 --- a/pango/pangocairo-context.c +++ b/pango/pangocairo-context.c @@ -491,6 +491,21 @@ pango_cairo_create_layout (cairo_t *cr) return layout; } +PangoSimpleLayout * +pango_cairo_create_simple_layout (cairo_t *cr) +{ + PangoContext *context; + PangoSimpleLayout *layout; + + g_return_val_if_fail (cr != NULL, NULL); + + context = pango_cairo_create_context (cr); + layout = pango_simple_layout_new (context); + g_object_unref (context); + + return layout; +} + /** * pango_cairo_update_layout: * @cr: a Cairo context @@ -504,7 +519,7 @@ pango_cairo_create_layout (cairo_t *cr) */ void pango_cairo_update_layout (cairo_t *cr, - PangoLayout *layout) + PangoLayout *layout) { g_return_if_fail (cr != NULL); g_return_if_fail (PANGO_IS_LAYOUT (layout)); @@ -512,3 +527,13 @@ pango_cairo_update_layout (cairo_t *cr, _pango_cairo_update_context (cr, pango_layout_get_context (layout)); } +void +pango_cairo_update_simple_layout (cairo_t *cr, + PangoSimpleLayout *layout) +{ + g_return_if_fail (cr != NULL); + g_return_if_fail (PANGO_IS_SIMPLE_LAYOUT (layout)); + + _pango_cairo_update_context (cr, pango_simple_layout_get_context (layout)); +} + diff --git a/pango/pangocairo-render.c b/pango/pangocairo-render.c index 2c552ba1..21f32c58 100644 --- a/pango/pangocairo-render.c +++ b/pango/pangocairo-render.c @@ -772,24 +772,23 @@ pango_cairo_renderer_draw_error_underline (PangoRenderer *renderer, static void pango_cairo_renderer_draw_shape (PangoRenderer *renderer, - PangoAttrShape *attr, - int x, - int y) + PangoAttrShape *attr, + int x, + int y) { PangoCairoRenderer *crenderer = (PangoCairoRenderer *) (renderer); cairo_t *cr = crenderer->cr; - PangoLayout *layout; + PangoContext *context; PangoCairoShapeRendererFunc shape_renderer; - gpointer shape_renderer_data; + gpointer shape_renderer_data; double base_x, base_y; - layout = pango_renderer_get_layout (renderer); + context = pango_renderer_get_context (renderer); - if (!layout) - return; + if (!context) + return; - shape_renderer = pango_cairo_context_get_shape_renderer (pango_layout_get_context (layout), - &shape_renderer_data); + shape_renderer = pango_cairo_context_get_shape_renderer (context, &shape_renderer_data); if (!shape_renderer) return; @@ -993,6 +992,44 @@ _pango_cairo_do_layout_line (cairo_t *cr, } static void +_pango_cairo_do_line (cairo_t *cr, + PangoLine *line, + gboolean do_path) +{ + PangoCairoRenderer *crenderer = acquire_renderer (); + PangoRenderer *renderer = (PangoRenderer *) crenderer; + + crenderer->cr = cr; + crenderer->do_path = do_path; + save_current_point (crenderer); + + pango_renderer_draw_line (renderer, line, 0, 0); + + restore_current_point (crenderer); + + release_renderer (crenderer); +} + +static void +_pango_cairo_do_lines (cairo_t *cr, + PangoLines *lines, + gboolean do_path) +{ + PangoCairoRenderer *crenderer = acquire_renderer (); + PangoRenderer *renderer = (PangoRenderer *) crenderer; + + crenderer->cr = cr; + crenderer->do_path = do_path; + save_current_point (crenderer); + + pango_renderer_draw_lines (renderer, lines, 0, 0); + + restore_current_point (crenderer); + + release_renderer (crenderer); +} + +static void _pango_cairo_do_layout (cairo_t *cr, PangoLayout *layout, gboolean do_path) @@ -1118,6 +1155,46 @@ pango_cairo_show_layout_line (cairo_t *cr, } /** + * pango_cairo_show_line: + * @cr: a Cairo context + * @line: a `PangoLine` + * + * Draws a `PangoLine` in the specified cairo context. + * + * The origin of the glyphs (the left edge of the line) will + * be drawn at the current point of the cairo context. + */ +void +pango_cairo_show_line (cairo_t *cr, + PangoLine *line) +{ + g_return_if_fail (cr != NULL); + g_return_if_fail (line != NULL); + + _pango_cairo_do_line (cr, line, FALSE); +} + +/** + * pango_cairo_show_lines: + * @cr: a Cairo context + * @lines: a `PangoLines` object + * + * Draws a `PangoLines` object in the specified cairo context. + * + * The top-left corner of the `PangoLines` will be drawn + * at the current point of the cairo context. + */ +void +pango_cairo_show_lines (cairo_t *cr, + PangoLines *lines) +{ + g_return_if_fail (cr != NULL); + g_return_if_fail (lines != NULL); + + _pango_cairo_do_lines (cr, lines, FALSE); +} + +/** * pango_cairo_show_layout: * @cr: a Cairo context * @layout: a Pango layout @@ -1219,6 +1296,27 @@ pango_cairo_layout_line_path (cairo_t *cr, } /** + * pango_cairo_line_path: + * @cr: a Cairo context + * @line: a `PangoLayoutLine` + * + * Adds the text in `PangoLine` to the current path in the + * specified cairo context. + * + * The origin of the glyphs (the left edge of the line) will be + * at the current point of the cairo context. + */ +void +pango_cairo_line_path (cairo_t *cr, + PangoLine *line) +{ + g_return_if_fail (cr != NULL); + g_return_if_fail (PANGO_IS_LINE (line)); + + _pango_cairo_do_line (cr, line, TRUE); +} + +/** * pango_cairo_layout_path: * @cr: a Cairo context * @layout: a Pango layout @@ -1242,6 +1340,27 @@ pango_cairo_layout_path (cairo_t *cr, } /** + * pango_cairo_lines_path: + * @cr: a Cairo context + * @lines: a `PangoLines` object + * + * Adds the text in a `PangoLines` to the current path in the + * specified cairo context. + * + * The top-left corner of the `PangoLayout` will be at the + * current point of the cairo context. + */ +void +pango_cairo_lines_path (cairo_t *cr, + PangoLines *lines) +{ + g_return_if_fail (cr != NULL); + g_return_if_fail (PANGO_IS_LINES (lines)); + + _pango_cairo_do_lines (cr, lines, TRUE); +} + +/** * pango_cairo_error_underline_path: * @cr: a Cairo context * @x: The X coordinate of one corner of the rectangle diff --git a/pango/pangocairo.h b/pango/pangocairo.h index 7e860554..60d9d9d6 100644 --- a/pango/pangocairo.h +++ b/pango/pangocairo.h @@ -169,6 +169,11 @@ PANGO_AVAILABLE_IN_1_10 void pango_cairo_update_layout (cairo_t *cr, PangoLayout *layout); +PANGO_AVAILABLE_IN_ALL +PangoSimpleLayout *pango_cairo_create_simple_layout (cairo_t *cr); +PANGO_AVAILABLE_IN_ALL +void pango_cairo_update_simple_layout (cairo_t *cr, + PangoSimpleLayout *layout); /* * Rendering */ @@ -183,6 +188,12 @@ void pango_cairo_show_glyph_item (cairo_t *cr, PANGO_AVAILABLE_IN_1_10 void pango_cairo_show_layout_line (cairo_t *cr, PangoLayoutLine *line); +PANGO_AVAILABLE_IN_ALL +void pango_cairo_show_line (cairo_t *cr, + PangoLine *line); +PANGO_AVAILABLE_IN_ALL +void pango_cairo_show_lines (cairo_t *cr, + PangoLines *lines); PANGO_AVAILABLE_IN_1_10 void pango_cairo_show_layout (cairo_t *cr, PangoLayout *layout); @@ -194,6 +205,7 @@ void pango_cairo_show_error_underline (cairo_t *cr, double width, double height); + /* * Rendering to a path */ @@ -207,6 +219,12 @@ void pango_cairo_layout_line_path (cairo_t *cr, PANGO_AVAILABLE_IN_1_10 void pango_cairo_layout_path (cairo_t *cr, PangoLayout *layout); +PANGO_AVAILABLE_IN_ALL +void pango_cairo_line_path (cairo_t *cr, + PangoLine *line); +PANGO_AVAILABLE_IN_ALL +void pango_cairo_lines_path (cairo_t *cr, + PangoLines *lines); PANGO_AVAILABLE_IN_1_14 void pango_cairo_error_underline_path (cairo_t *cr, |