summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBehdad Esfahbod <behdad@behdad.org>2017-07-31 23:03:30 +0100
committerBehdad Esfahbod <behdad@behdad.org>2017-07-31 23:04:36 +0100
commitfe0669798d617406b52a638fb2525b1f7527a2d6 (patch)
treefb07b695692ba66b11c8e79864f4ce5c97f386b0
parentf39ad9bab1f327062958b2750bf1f5609a9ee991 (diff)
downloadpango-fe0669798d617406b52a638fb2525b1f7527a2d6.tar.gz
Choose emoji font for color emoji
Fixes https://bugzilla.gnome.org/show_bug.cgi?id=785566
-rw-r--r--pango/pango-context.c45
-rw-r--r--pango/pango-emoji.c16
2 files changed, 50 insertions, 11 deletions
diff --git a/pango/pango-context.c b/pango/pango-context.c
index 0ba2a0cd..df011f6f 100644
--- a/pango/pango-context.c
+++ b/pango/pango-context.c
@@ -38,6 +38,7 @@
#include "pango-engine-private.h"
#include "pango-script-private.h"
+#include "pango-emoji-private.h"
/**
* PangoContext:
@@ -691,7 +692,8 @@ typedef enum {
LANG_CHANGED = 1 << 2,
FONT_CHANGED = 1 << 3,
DERIVED_LANG_CHANGED = 1 << 4,
- WIDTH_CHANGED = 1 << 5
+ WIDTH_CHANGED = 1 << 5,
+ EMOJI_CHANGED = 1 << 6,
} ChangedFlags;
@@ -738,6 +740,7 @@ struct _ItemizeState
gboolean free_attr_iter;
const char *attr_end;
PangoFontDescription *font_desc;
+ PangoFontDescription *emoji_font_desc;
PangoLanguage *lang;
GSList *extra_attrs;
gboolean copy_extra_attrs;
@@ -749,6 +752,7 @@ struct _ItemizeState
PangoScript script;
PangoWidthIter width_iter;
+ PangoEmojiIter emoji_iter;
PangoLanguage *derived_lang;
PangoEngineLang *lang_engine;
@@ -799,6 +803,12 @@ update_attr_iterator (ItemizeState *state)
else
state->attr_end = state->end;
+ if (state->emoji_font_desc)
+ {
+ pango_font_description_free (state->emoji_font_desc);
+ state->emoji_font_desc = NULL;
+ }
+
old_lang = state->lang;
if (state->font_desc)
pango_font_description_free (state->font_desc);
@@ -839,6 +849,8 @@ update_end (ItemizeState *state)
state->run_end = state->script_end;
if (state->width_iter.end < state->run_end)
state->run_end = state->width_iter.end;
+ if (state->emoji_iter.end < state->run_end)
+ state->run_end = state->emoji_iter.end;
}
/* g_unichar_iswide() uses EastAsianWidth, which is broken.
@@ -920,6 +932,11 @@ width_iter_init (PangoWidthIter* iter, const char* text, int length)
}
static void
+width_iter_fini (PangoWidthIter* iter)
+{
+}
+
+static void
itemize_state_init (ItemizeState *state,
PangoContext *context,
const char *text,
@@ -967,6 +984,7 @@ itemize_state_init (ItemizeState *state,
state->free_attr_iter = FALSE;
}
+ state->emoji_font_desc = NULL;
if (state->attr_iter)
{
state->font_desc = NULL;
@@ -992,8 +1010,8 @@ itemize_state_init (ItemizeState *state,
pango_script_iter_get_range (&state->script_iter, NULL,
&state->script_end, &state->script);
- /* Initialize the width iterator */
width_iter_init (&state->width_iter, text + start_index, length);
+ _pango_emoji_iter_init (&state->emoji_iter, text + start_index, length);
update_end (state);
@@ -1012,7 +1030,7 @@ itemize_state_init (ItemizeState *state,
state->cache = NULL;
state->base_font = NULL;
- state->changed = EMBEDDING_CHANGED | SCRIPT_CHANGED | LANG_CHANGED | FONT_CHANGED | WIDTH_CHANGED;
+ state->changed = EMBEDDING_CHANGED | SCRIPT_CHANGED | LANG_CHANGED | FONT_CHANGED | WIDTH_CHANGED | EMOJI_CHANGED;
}
static gboolean
@@ -1048,6 +1066,11 @@ itemize_state_next (ItemizeState *state)
width_iter_next (&state->width_iter);
state->changed |= WIDTH_CHANGED;
}
+ if (state->run_end == state->emoji_iter.end)
+ {
+ _pango_emoji_iter_next (&state->emoji_iter);
+ state->changed |= EMOJI_CHANGED;
+ }
update_end (state);
@@ -1352,6 +1375,11 @@ itemize_state_update_for_new_run (ItemizeState *state)
state->lang_engine = _pango_get_language_engine ();
}
+ if (state->changed & (EMOJI_CHANGED))
+ {
+ state->changed |= FONT_CHANGED;
+ }
+
if (state->changed & (FONT_CHANGED | DERIVED_LANG_CHANGED) &&
state->current_fonts)
{
@@ -1362,9 +1390,15 @@ itemize_state_update_for_new_run (ItemizeState *state)
if (!state->current_fonts)
{
+ gboolean is_emoji = state->emoji_iter.is_emoji;
+ if (is_emoji && !state->emoji_font_desc)
+ {
+ state->emoji_font_desc = pango_font_description_copy_static (state->font_desc);
+ pango_font_description_set_family_static (state->emoji_font_desc, "emoji");
+ }
state->current_fonts = pango_font_map_load_fontset (state->context->font_map,
state->context,
- state->font_desc,
+ is_emoji ? state->emoji_font_desc : state->font_desc,
state->derived_lang);
state->cache = get_font_cache (state->current_fonts);
}
@@ -1492,6 +1526,9 @@ itemize_state_finish (ItemizeState *state)
pango_attr_iterator_destroy (state->attr_iter);
_pango_script_iter_fini (&state->script_iter);
pango_font_description_free (state->font_desc);
+ pango_font_description_free (state->emoji_font_desc);
+ width_iter_fini (&state->width_iter);
+ _pango_emoji_iter_fini (&state->emoji_iter);
if (state->current_fonts)
g_object_unref (state->current_fonts);
diff --git a/pango/pango-emoji.c b/pango/pango-emoji.c
index 630a0e7f..0e332dff 100644
--- a/pango/pango-emoji.c
+++ b/pango/pango-emoji.c
@@ -160,7 +160,7 @@ _pango_emoji_iter_init (PangoEmojiIter *iter,
iter->start = text;
iter->end = text;
- iter->is_emoji = FALSE;
+ iter->is_emoji = (gboolean) 2; /* HACK */
_pango_emoji_iter_next (iter);
@@ -194,7 +194,7 @@ _pango_emoji_iter_next (PangoEmojiIter *iter)
* presentation for emoji that are part of a ZWJ sequence, example
* U+1F441 U+200D U+1F5E8, eye (text presentation) + ZWJ + left speech
* bubble, see below. */
- if ((!(ch == kZeroWidthJoinerCharacter && iter->is_emoji) &&
+ if ((!(ch == kZeroWidthJoinerCharacter && !iter->is_emoji) &&
ch != kVariationSelector15Character &&
ch != kVariationSelector16Character &&
ch != kCombiningEnclosingCircleBackslashCharacter &&
@@ -204,14 +204,14 @@ _pango_emoji_iter_next (PangoEmojiIter *iter)
ch == kMaleSignCharacter ||
ch == kFemaleSignCharacter ||
ch == kStaffOfAesculapiusCharacter) &&
- iter->is_emoji)) ||
+ !iter->is_emoji)) ||
current_emoji_type == PANGO_EMOJI_TYPE_INVALID) {
current_emoji_type = _pango_get_emoji_type (ch);
}
- if (iter->end < iter->text_end)
+ if (g_utf8_next_char (iter->end) < iter->text_end) /* Optimize. */
{
- gunichar peek_char = g_utf8_get_char (iter->end);
+ gunichar peek_char = g_utf8_get_char (g_utf8_next_char (iter->end));
/* Variation Selectors */
if (current_emoji_type ==
@@ -248,9 +248,11 @@ _pango_emoji_iter_next (PangoEmojiIter *iter)
}
}
- if (iter->is_emoji != PANGO_EMOJI_TYPE_IS_EMOJI (current_emoji_type) && iter->start != iter->text_start)
+ if (iter->is_emoji == (gboolean) 2)
+ iter->is_emoji = !PANGO_EMOJI_TYPE_IS_EMOJI (current_emoji_type);
+ if (iter->is_emoji == PANGO_EMOJI_TYPE_IS_EMOJI (current_emoji_type))
{
- iter->is_emoji = PANGO_EMOJI_TYPE_IS_EMOJI (current_emoji_type);
+ iter->is_emoji = !PANGO_EMOJI_TYPE_IS_EMOJI (current_emoji_type);
return TRUE;
}
}