diff options
Diffstat (limited to 'pango/pango-layout.c')
-rw-r--r-- | pango/pango-layout.c | 201 |
1 files changed, 172 insertions, 29 deletions
diff --git a/pango/pango-layout.c b/pango/pango-layout.c index d3d93e60..098e3a3e 100644 --- a/pango/pango-layout.c +++ b/pango/pango-layout.c @@ -92,7 +92,7 @@ typedef struct _ItemProperties ItemProperties; typedef struct _ParaBreakState ParaBreakState; -/* Note that rise, letter_spacing, shape are constant across items, +/* Note that letter_spacing and shape are constant across items, * since we pass them into itemization. * * uline and strikethrough can vary across an item, so we collect @@ -108,7 +108,6 @@ struct _ItemProperties guint uline_error : 1; guint strikethrough : 1; guint oline_single : 1; - gint rise; gint letter_spacing; gboolean shape_set; PangoRectangle *shape_ink_rect; @@ -3621,6 +3620,8 @@ struct _ParaBreakState int remaining_width; /* Amount of space remaining on line; < 0 is infinite */ int hyphen_width; /* How much space a hyphen will take */ + + GList *baseline_shifts; }; static gboolean @@ -4320,10 +4321,12 @@ affects_itemization (PangoAttribute *attr, case PANGO_ATTR_ABSOLUTE_SIZE: case PANGO_ATTR_GRAVITY: case PANGO_ATTR_GRAVITY_HINT: + case PANGO_ATTR_FONT_SCALE: /* These need to be constant across runs */ case PANGO_ATTR_LETTER_SPACING: case PANGO_ATTR_SHAPE: case PANGO_ATTR_RISE: + case PANGO_ATTR_BASELINE_SHIFT: case PANGO_ATTR_LINE_HEIGHT: case PANGO_ATTR_ABSOLUTE_LINE_HEIGHT: case PANGO_ATTR_TEXT_TRANSFORM: @@ -4485,6 +4488,7 @@ pango_layout_check_lines (PangoLayout *layout) state.log_widths = NULL; state.num_log_widths = 0; + state.baseline_shifts = NULL; do { @@ -4593,6 +4597,7 @@ pango_layout_check_lines (PangoLayout *layout) while (!done); g_free (state.log_widths); + g_list_free_full (state.baseline_shifts, g_free); apply_attributes_to_runs (layout, attrs); layout->lines = g_slist_reverse (layout->lines); @@ -5220,6 +5225,7 @@ pango_layout_run_get_extents_and_height (PangoLayoutRun *run, PangoFontMetrics *metrics = NULL; gboolean has_underline; gboolean has_overline; + int y_offset; if (G_UNLIKELY (!run_ink && !run_logical && !line_logical && !height)) return; @@ -5313,6 +5319,8 @@ pango_layout_run_get_extents_and_height (PangoLayoutRun *run, *height = pango_font_metrics_get_height (metrics); } + y_offset = run->y_offset; + if (run->item->analysis.flags & PANGO_ANALYSIS_FLAG_CENTERED_BASELINE) { gboolean is_hinted = (run_logical->y & run_logical->height & (PANGO_SCALE - 1)) == 0; @@ -5321,17 +5329,14 @@ pango_layout_run_get_extents_and_height (PangoLayoutRun *run, if (is_hinted) adjustment = PANGO_UNITS_ROUND (adjustment); - properties.rise += adjustment; + y_offset += adjustment; } - if (properties.rise != 0) - { - if (run_ink) - run_ink->y -= properties.rise; + if (run_ink) + run_ink->y -= y_offset; - if (run_logical) - run_logical->y -= properties.rise; - } + if (run_logical) + run_logical->y -= y_offset; if (line_logical) { @@ -6147,6 +6152,149 @@ justify_words (PangoLayoutLine *line, state->remaining_width -= added_so_far; } +typedef struct { + PangoAttribute *attr; + int x_offset; + int y_offset; +} BaselineItem; + +static void +collect_baseline_shift (ParaBreakState *state, + PangoItem *item, + PangoItem *prev, + int *start_x_offset, + int *start_y_offset, + int *end_x_offset, + int *end_y_offset) +{ + *start_x_offset = 0; + *start_y_offset = 0; + *end_x_offset = 0; + *end_y_offset = 0; + + for (GSList *l = item->analysis.extra_attrs; l; l = l->next) + { + PangoAttribute *attr = l->data; + + if (attr->klass->type == PANGO_ATTR_RISE) + { + int value = ((PangoAttrInt *)attr)->value; + + *start_y_offset += value; + *end_y_offset -= value; + } + else if (attr->klass->type == PANGO_ATTR_BASELINE_SHIFT) + { + if (attr->start_index == item->offset) + { + BaselineItem *entry; + int value; + + entry = g_new0 (BaselineItem, 1); + entry->attr = attr; + state->baseline_shifts = g_list_prepend (state->baseline_shifts, entry); + + value = ((PangoAttrInt *)attr)->value; + + if (value > 1024 || value < -1024) + { + entry->y_offset = value; + /* FIXME: compute an x_offset from value to italic angle */ + } + else + { + int superscript_x_offset = 0; + int superscript_y_offset = 0; + int subscript_x_offset = 0; + int subscript_y_offset = 0; + + + if (prev) + { + hb_font_t *hb_font = pango_font_get_hb_font (prev->analysis.font); + hb_ot_metrics_get_position (hb_font, HB_OT_METRICS_TAG_SUPERSCRIPT_EM_Y_OFFSET, &superscript_y_offset); + hb_ot_metrics_get_position (hb_font, HB_OT_METRICS_TAG_SUPERSCRIPT_EM_X_OFFSET, &superscript_x_offset); + hb_ot_metrics_get_position (hb_font, HB_OT_METRICS_TAG_SUBSCRIPT_EM_Y_OFFSET, &subscript_y_offset); + hb_ot_metrics_get_position (hb_font, HB_OT_METRICS_TAG_SUBSCRIPT_EM_X_OFFSET, &subscript_x_offset); + } + + if (superscript_y_offset == 0) + superscript_y_offset = 5000; + if (subscript_y_offset == 0) + subscript_y_offset = 5000; + + switch (value) + { + case PANGO_BASELINE_SHIFT_NONE: + entry->x_offset = 0; + entry->y_offset = 0; + break; + case PANGO_BASELINE_SHIFT_SUPERSCRIPT: + entry->x_offset = superscript_x_offset; + entry->y_offset = superscript_y_offset; + break; + case PANGO_BASELINE_SHIFT_SUBSCRIPT: + entry->x_offset = subscript_x_offset; + entry->y_offset = -subscript_y_offset; + break; + default: + g_assert_not_reached (); + } + } + + *start_x_offset += entry->x_offset; + *start_y_offset += entry->y_offset; + } + + if (attr->end_index == item->offset + item->length) + { + BaselineItem *entry = state->baseline_shifts->data; + + if (attr->start_index == entry->attr->start_index && + attr->end_index == entry->attr->end_index && + ((PangoAttrInt *)attr)->value == ((PangoAttrInt *)entry->attr)->value) + { + *end_x_offset -= entry->x_offset; + *end_y_offset -= entry->y_offset; + } + else + g_warning ("Baseline attributes mismatch\n"); + + state->baseline_shifts = g_list_remove (state->baseline_shifts, entry); + g_free (entry); + } + } + } +} + +static void +apply_baseline_shift (PangoLayoutLine *line, + ParaBreakState *state) +{ + int y_offset = 0; + PangoItem *prev = NULL; + + for (GSList *l = line->runs; l; l = l->next) + { + PangoLayoutRun *run = l->data; + PangoItem *item = run->item; + int start_x_offset, end_x_offset; + int start_y_offset, end_y_offset; + + collect_baseline_shift (state, item, prev, &start_x_offset, &start_y_offset, &end_x_offset, &end_y_offset); + + y_offset += start_y_offset; + + run->y_offset = y_offset; + run->start_x_offset = start_x_offset; + run->end_x_offset = end_x_offset; + + y_offset += end_y_offset; + + prev = item; + } +} + static void pango_layout_line_postprocess (PangoLayoutLine *line, ParaBreakState *state, @@ -6167,6 +6315,8 @@ pango_layout_line_postprocess (PangoLayoutLine *line, */ line->runs = g_slist_reverse (line->runs); + apply_baseline_shift (line, state); + /* Ellipsize the line if necessary */ if (G_UNLIKELY (state->line_width >= 0 && @@ -6224,7 +6374,6 @@ pango_layout_get_item_properties (PangoItem *item, properties->oline_single = FALSE; properties->strikethrough = FALSE; properties->letter_spacing = 0; - properties->rise = 0; properties->shape_set = FALSE; properties->shape_ink_rect = NULL; properties->shape_logical_rect = NULL; @@ -6279,10 +6428,6 @@ pango_layout_get_item_properties (PangoItem *item, properties->strikethrough = ((PangoAttrInt *)attr)->value; break; - case PANGO_ATTR_RISE: - properties->rise = ((PangoAttrInt *)attr)->value; - break; - case PANGO_ATTR_LETTER_SPACING: properties->letter_spacing = ((PangoAttrInt *)attr)->value; break; @@ -6418,16 +6563,22 @@ update_run (PangoLayoutIter *iter, if (iter->run_list_link == iter->line->runs) iter->run_x = line_ext->logical_rect.x; else - iter->run_x += iter->run_width; + { + iter->run_x += iter->end_x_offset + iter->run_width; + if (iter->run) + iter->run_x += iter->run->start_x_offset; + } if (iter->run) { iter->run_width = pango_glyph_string_get_width (iter->run->glyphs); + iter->end_x_offset = iter->run->end_x_offset; } else { /* The empty run at the end of a line */ iter->run_width = 0; + iter->end_x_offset = 0; } if (iter->run) @@ -7110,8 +7261,6 @@ pango_layout_iter_get_cluster_extents (PangoLayoutIter *iter, PangoRectangle *ink_rect, PangoRectangle *logical_rect) { - ItemProperties properties; - if (ITER_IS_INVALID (iter)) return; @@ -7124,8 +7273,6 @@ pango_layout_iter_get_cluster_extents (PangoLayoutIter *iter, return; } - pango_layout_get_item_properties (iter->run->item, &properties); - pango_glyph_string_extents_range (iter->run->glyphs, iter->cluster_start, iter->next_cluster_glyph, @@ -7135,16 +7282,16 @@ pango_layout_iter_get_cluster_extents (PangoLayoutIter *iter, if (ink_rect) { - ink_rect->x += iter->cluster_x; - ink_rect->y -= properties.rise; + ink_rect->x += iter->cluster_x + iter->run->start_x_offset; + ink_rect->y -= iter->run->y_offset; offset_y (iter, &ink_rect->y); } if (logical_rect) { g_assert (logical_rect->width == iter->cluster_width); - logical_rect->x += iter->cluster_x; - logical_rect->y -= properties.rise; + logical_rect->x += iter->cluster_x + iter->run->start_x_offset; + logical_rect->y -= iter->run->y_offset; offset_y (iter, &logical_rect->y); } } @@ -7325,17 +7472,13 @@ pango_layout_iter_get_baseline (PangoLayoutIter *iter) int pango_layout_iter_get_run_baseline (PangoLayoutIter *iter) { - ItemProperties properties; - if (ITER_IS_INVALID (iter)) return 0; if (!iter->run) return iter->line_extents[iter->line_index].baseline; - pango_layout_get_item_properties (iter->run->item, &properties); - - return iter->line_extents[iter->line_index].baseline - properties.rise; + return iter->line_extents[iter->line_index].baseline - iter->run->y_offset; } /** |