summaryrefslogtreecommitdiff
path: root/pango/pango-layout.c
diff options
context:
space:
mode:
Diffstat (limited to 'pango/pango-layout.c')
-rw-r--r--pango/pango-layout.c201
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;
}
/**