[pango] Choose emoji font for color emoji



commit fe0669798d617406b52a638fb2525b1f7527a2d6
Author: Behdad Esfahbod <behdad behdad org>
Date:   Mon Jul 31 23:03:30 2017 +0100

    Choose emoji font for color emoji
    
    Fixes https://bugzilla.gnome.org/show_bug.cgi?id=785566

 pango/pango-context.c |   45 +++++++++++++++++++++++++++++++++++++++++----
 pango/pango-emoji.c   |   16 +++++++++-------
 2 files changed, 50 insertions(+), 11 deletions(-)
---
diff --git a/pango/pango-context.c b/pango/pango-context.c
index 0ba2a0c..df011f6 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 630a0e7..0e332df 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;
     }
   }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]