Commit fd51b468 authored by Matthias Clasen's avatar Matthias Clasen
Browse files

Implement font-dependent scaling

Add a new font-scale attribute to indicate font size
changes due to super- and subscript shifts, and handle
it during item post-processing to find the right font
sizes.
parent 303b4fb7
......@@ -34,6 +34,7 @@
#include "pango-attributes-private.h"
#include "pango-item-private.h"
#include <hb-ot.h>
/* {{{ Font cache */
......@@ -1019,6 +1020,169 @@ itemize_state_finish (ItemizeState *state)
if (state->base_font)
g_object_unref (state->base_font);
}
/* }}} */
/* {{{ Post-processing */
typedef struct {
PangoAttribute *attr;
double scale;
} ScaleItem;
static gboolean
collect_font_scale (PangoContext *context,
GList **stack,
PangoItem *item,
PangoItem *prev,
double *scale)
{
gboolean retval = FALSE;
GList *l;
for (GSList *l = item->analysis.extra_attrs; l; l = l->next)
{
PangoAttribute *attr = l->data;
if (attr->klass->type == PANGO_ATTR_FONT_SCALE)
{
if (attr->start_index == item->offset)
{
ScaleItem *entry;
hb_font_t *hb_font;
int y_scale;
hb_position_t y_size;
entry = g_new (ScaleItem, 1);
entry->attr = attr;
*stack = g_list_prepend (*stack, entry);
hb_font = pango_font_get_hb_font (prev->analysis.font);
hb_font_get_scale (hb_font, NULL, &y_scale);
switch (((PangoAttrInt *)attr)->value)
{
case PANGO_FONT_SCALE_NONE:
break;
case PANGO_FONT_SCALE_SUPERSCRIPT:
if (hb_ot_metrics_get_position (hb_font,
HB_OT_METRICS_TAG_SUPERSCRIPT_EM_Y_SIZE,
&y_size))
entry->scale = y_size / (double) y_scale;
else
entry->scale = 1 / 1.2;
break;
case PANGO_FONT_SCALE_SUBSCRIPT:
if (hb_ot_metrics_get_position (hb_font,
HB_OT_METRICS_TAG_SUBSCRIPT_EM_Y_SIZE,
&y_size))
entry->scale = y_size / (double) y_scale;
else
entry->scale = 1 / 1.2;
break;
default:
g_assert_not_reached ();
}
}
}
}
*scale = 1.0;
for (l = *stack; l; l = l->next)
{
ScaleItem *entry = l->data;
*scale *= entry->scale;
retval = TRUE;
}
l = *stack;
while (l)
{
ScaleItem *entry = l->data;
GList *next = l->next;
if (entry->attr->end_index == item->offset + item->length)
{
*stack = g_list_delete_link (*stack, l);
g_free (entry);
}
l = next;
}
return retval;
}
static void
apply_scale_to_item (PangoContext *context,
PangoItem *item,
double scale)
{
PangoFontDescription *desc;
double size;
desc = pango_font_describe (item->analysis.font);
size = scale * pango_font_description_get_size (desc);
if (pango_font_description_get_size_is_absolute (desc))
pango_font_description_set_absolute_size (desc, size);
else
pango_font_description_set_size (desc, size);
g_object_unref (item->analysis.font);
item->analysis.font = pango_font_map_load_font (context->font_map, context, desc);
pango_font_description_free (desc);
}
static void
apply_font_scale (PangoContext *context,
GList *items)
{
PangoItem *prev;
GList *stack = NULL;
for (GList *l = items; l; l = l->next)
{
PangoItem *item = l->data;
double scale;
if (collect_font_scale (context, &stack, item, prev, &scale))
apply_scale_to_item (context, item, scale);
prev = item;
}
if (stack != NULL)
{
g_warning ("Leftover font scales");
g_list_free_full (stack, g_free);
}
}
static GList *
post_process_items (PangoContext *context,
GList *items)
{
items = g_list_reverse (items);
/* Compute the char offset for each item */
{
int char_offset = 0;
for (GList *l = items; l; l = l->next)
{
PangoItemPrivate *item = l->data;
item->char_offset = char_offset;
char_offset += item->num_chars;
}
}
/* apply font-scale */
apply_font_scale (context, items);
return items;
}
/* }}} */
/* {{{ Public API */
......@@ -1034,8 +1198,6 @@ pango_itemize_with_font (PangoContext *context,
const PangoFontDescription *desc)
{
ItemizeState state;
GList *items;
int char_offset;
if (length == 0 || g_utf8_get_char (text + start_index) == '\0')
return NULL;
......@@ -1049,18 +1211,7 @@ pango_itemize_with_font (PangoContext *context,
itemize_state_finish (&state);
items = g_list_reverse (state.result);
/* Compute the char offset for each item */
char_offset = 0;
for (GList *l = items; l; l = l->next)
{
PangoItemPrivate *item = l->data;
item->char_offset = char_offset;
char_offset += item->num_chars;
}
return items;
return post_process_items (context, state.result);
}
/**
......@@ -1154,6 +1305,6 @@ pango_itemize (PangoContext *context,
NULL);
}
/* }}} */
/* }}} */
/* vim:set foldmethod=marker expandtab: */
......@@ -947,6 +947,20 @@ pango_attr_baseline_shift_new (int rise)
return pango_attr_int_new (&klass, (int)rise);
}
PangoAttribute *
pango_attr_font_scale_new (PangoFontScale scale)
{
static const PangoAttrClass klass = {
PANGO_ATTR_FONT_SCALE,
pango_attr_int_copy,
pango_attr_int_destroy,
pango_attr_int_equal
};
return pango_attr_int_new (&klass, (int)scale);
}
/**
* pango_attr_scale_new:
* @scale_factor: factor to scale the font
......@@ -1558,6 +1572,7 @@ pango_attribute_as_int (PangoAttribute *attr)
case PANGO_ATTR_WORD:
case PANGO_ATTR_SENTENCE:
case PANGO_ATTR_BASELINE_SHIFT:
case PANGO_ATTR_FONT_SCALE:
return (PangoAttrInt *)attr;
default:
......@@ -2847,10 +2862,14 @@ pango_attr_iterator_get_font (PangoAttrIterator *iterator,
{
gboolean found = FALSE;
/* Hack: special-case FONT_FEATURES. We don't want them to
* override each other, so we never merge them. This should
* be fixed when we implement attr-merging. */
if (attr->klass->type != PANGO_ATTR_FONT_FEATURES)
/* Hack: special-case FONT_FEATURES, BASELINE_SHIFT and FONT_SCALE.
* We don't want these to accumulate, not override each other,
* so we never merge them.
* This needs to be handled more systematically.
*/
if (attr->klass->type != PANGO_ATTR_FONT_FEATURES &&
attr->klass->type != PANGO_ATTR_BASELINE_SHIFT &&
attr->klass->type != PANGO_ATTR_FONT_SCALE)
{
GSList *tmp_list = *extra_attrs;
while (tmp_list)
......@@ -2917,7 +2936,9 @@ pango_attr_iterator_get_attrs (PangoAttrIterator *iterator)
GSList *tmp_list2;
gboolean found = FALSE;
if (attr->klass->type != PANGO_ATTR_FONT_DESC)
if (attr->klass->type != PANGO_ATTR_FONT_DESC &&
attr->klass->type != PANGO_ATTR_BASELINE_SHIFT &&
attr->klass->type != PANGO_ATTR_FONT_SCALE)
for (tmp_list2 = attrs; tmp_list2; tmp_list2 = tmp_list2->next)
{
PangoAttribute *old_attr = tmp_list2->data;
......
......@@ -79,7 +79,8 @@ typedef struct _PangoAttrFontFeatures PangoAttrFontFeatures;
* @PANGO_ATTR_ABSOLUTE_LINE_HEIGHT: line height ([struct@Pango.AttrInt]). Since: 1.50
* @PANGO_ATTR_WORD: override segmentation to classify the range of the attribute as a single word ([struct@Pango.AttrInt]). Since 1.50
* @PANGO_ATTR_SENTENCE: override segmentation to classify the range of the attribute as a single sentence ([struct@Pango.AttrInt]). Since 1.50
* @PANGO_ATTR_BASELINE_SHIFT: baseline displacement ([struct@Pango.AttrSize]). Since 1.50
* @PANGO_ATTR_BASELINE_SHIFT: baseline displacement ([struct@Pango.AttrInt]). Since 1.50
* @PANGO_ATTR_FONT_SCALE: font-relative size change ([struct@Pango.AttrInt]). Since 1.50
*
* The `PangoAttrType` distinguishes between different types of attributes.
*
......@@ -127,6 +128,7 @@ typedef enum
PANGO_ATTR_WORD, /* PangoAttrInt */
PANGO_ATTR_SENTENCE, /* PangoAttrInt */
PANGO_ATTR_BASELINE_SHIFT, /* PangoAttrSize */
PANGO_ATTR_FONT_SCALE, /* PangoAttrInt */
} PangoAttrType;
/**
......@@ -245,6 +247,12 @@ typedef enum {
PANGO_BASELINE_SHIFT_SUBSCRIPT,
} PangoBaselineShift;
typedef enum {
PANGO_FONT_SCALE_NONE,
PANGO_FONT_SCALE_SUPERSCRIPT,
PANGO_FONT_SCALE_SUBSCRIPT,
} PangoFontScale;
/**
* PANGO_ATTR_INDEX_FROM_TEXT_BEGINNING:
*
......@@ -536,6 +544,8 @@ PANGO_AVAILABLE_IN_ALL
PangoAttribute * pango_attr_rise_new (int rise);
PANGO_AVAILABLE_IN_1_50
PangoAttribute * pango_attr_baseline_shift_new (int shift);
PANGO_AVAILABLE_IN_1_50
PangoAttribute * pango_attr_font_scale_new (PangoFontScale scale);
PANGO_AVAILABLE_IN_ALL
PangoAttribute * pango_attr_scale_new (double scale_factor);
PANGO_AVAILABLE_IN_1_4
......
......@@ -4321,6 +4321,7 @@ 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:
......
......@@ -1232,6 +1232,7 @@ span_parse_func (MarkupData *md G_GNUC_UNUSED,
const char *line_height = NULL;
const char *text_transform = NULL;
const char *segment = NULL;
const char *font_scale = NULL;
g_markup_parse_context_get_position (context,
&line_number, &char_number);
......@@ -1286,6 +1287,7 @@ span_parse_func (MarkupData *md G_GNUC_UNUSED,
CHECK_ATTRIBUTE2(style, "font_style");
CHECK_ATTRIBUTE2(variant, "font_variant");
CHECK_ATTRIBUTE2(weight, "font_weight");
CHECK_ATTRIBUTE(font_scale);
CHECK_ATTRIBUTE (foreground);
CHECK_ATTRIBUTE2(foreground, "fgcolor");
......@@ -1699,6 +1701,16 @@ span_parse_func (MarkupData *md G_GNUC_UNUSED,
}
if (G_UNLIKELY (font_scale))
{
PangoFontScale scale;
if (!span_parse_enum ("font_scale", font_scale, PANGO_TYPE_FONT_SCALE, (int*)(void*)&scale, line_number, error))
goto error;
add_attribute (tag, pango_attr_font_scale_new (scale));
}
if (G_UNLIKELY (letter_spacing))
{
gint n = 0;
......
......@@ -73,6 +73,7 @@ affects_itemization (PangoAttribute *attr,
case PANGO_ATTR_ABSOLUTE_SIZE:
case PANGO_ATTR_GRAVITY:
case PANGO_ATTR_GRAVITY_HINT:
case PANGO_ATTR_FONT_SCALE:
/* These are part of ItemProperties, so need to break runs */
case PANGO_ATTR_LETTER_SPACING:
case PANGO_ATTR_SHAPE:
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment