[pango/pango2: 5/7] Support Emoji presentation




commit fe4fc164f9c2a7d6d5c95cd532025fc75a59fc93
Author: Matthias Clasen <mclasen redhat com>
Date:   Fri Jul 8 21:03:08 2022 -0400

    Support Emoji presentation
    
    Add a context property and attribute for influencing
    the presentation of Emoji. Emoji whose presentation is
    explicitly set in the text via variation selectors are
    not changed.
    
    Related: #298

 pango2/emoji_presentation_scanner.c  | 615 ++++++++++++++++++++++-------------
 pango2/emoji_presentation_scanner.rl |  17 +-
 pango2/itemize.c                     |  30 +-
 pango2/pango-attr-list.c             |   4 +
 pango2/pango-attributes.c            |  19 ++
 pango2/pango-attributes.h            |   5 +
 pango2/pango-context-private.h       |   2 +
 pango2/pango-context.c               |  42 +++
 pango2/pango-context.h               |   5 +
 pango2/pango-emoji-private.h         |  26 +-
 pango2/pango-emoji.c                 |  59 +++-
 pango2/pango-markup.c                |  14 +
 pango2/pango-types.h                 |  24 ++
 pango2/serializer.c                  |  11 +
 14 files changed, 603 insertions(+), 270 deletions(-)
---
diff --git a/pango2/emoji_presentation_scanner.c b/pango2/emoji_presentation_scanner.c
index e40b9d457..69c2ae9f5 100644
--- a/pango2/emoji_presentation_scanner.c
+++ b/pango2/emoji_presentation_scanner.c
@@ -1,82 +1,84 @@
-
-#line 1 "emoji_presentation_scanner.rl"
+#line 1 "pango2/emoji_presentation_scanner.rl"
 // Copyright 2018 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 
-#line 9 "emoji_presentation_scanner.c"
-static const char _emoji_presentation_actions[] = {
-        0, 1, 0, 1, 1, 1, 5, 1, 
-        6, 1, 7, 1, 8, 1, 9, 1, 
-        10, 1, 11, 2, 2, 3, 2, 2, 
-        4
+#line 6 "pango2/emoji_presentation_scanner.c"
+static const signed char _emoji_presentation_actions[] = {
+       0, 1, 0, 1, 1, 1, 7, 1,
+       8, 1, 9, 1, 10, 1, 11, 1,
+       12, 1, 13, 1, 14, 2, 2, 3,
+       2, 2, 4, 2, 2, 5, 2, 2,
+       6, 0
 };
 
-static const char _emoji_presentation_key_offsets[] = {
-        0, 5, 7, 14, 18, 20, 21, 24, 
-        29, 30, 34, 36
+static const signed char _emoji_presentation_key_offsets[] = {
+       0, 5, 7, 14, 18, 20, 21, 24,
+       29, 30, 34, 36, 0
 };
 
 static const unsigned char _emoji_presentation_trans_keys[] = {
-        3u, 7u, 13u, 0u, 2u, 14u, 15u, 2u, 
-        3u, 6u, 7u, 13u, 0u, 1u, 9u, 10u, 
-        11u, 12u, 10u, 12u, 10u, 4u, 10u, 12u, 
-        4u, 9u, 10u, 11u, 12u, 6u, 9u, 10u, 
-        11u, 12u, 8u, 10u, 9u, 10u, 11u, 12u, 
-        14u, 0
-};
-
-static const char _emoji_presentation_single_lengths[] = {
-        3, 2, 5, 4, 2, 1, 3, 5, 
-        1, 4, 2, 5
+       3u, 7u, 13u, 0u, 2u, 14u, 15u, 0u,
+       1u, 2u, 3u, 6u, 7u, 13u, 9u, 10u,
+       11u, 12u, 10u, 12u, 10u, 4u, 10u, 12u,
+       4u, 9u, 10u, 11u, 12u, 6u, 9u, 10u,
+       11u, 12u, 8u, 10u, 9u, 10u, 11u, 12u,
+       14u, 0u
 };
 
-static const char _emoji_presentation_range_lengths[] = {
-        1, 0, 1, 0, 0, 0, 0, 0, 
-        0, 0, 0, 0
+static const signed char _emoji_presentation_single_lengths[] = {
+       3, 2, 7, 4, 2, 1, 3, 5,
+       1, 4, 2, 5, 0
 };
 
-static const char _emoji_presentation_index_offsets[] = {
-        0, 5, 8, 15, 20, 23, 25, 29, 
-        35, 37, 42, 45
+static const signed char _emoji_presentation_range_lengths[] = {
+       1, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0
 };
 
-static const char _emoji_presentation_indicies[] = {
-        2, 1, 1, 1, 0, 4, 5, 3, 
-        7, 8, 10, 11, 12, 6, 9, 5, 
-        13, 14, 15, 0, 13, 15, 16, 13, 
-        16, 15, 13, 15, 16, 15, 5, 13, 
-        14, 15, 16, 5, 17, 5, 13, 14, 
-        18, 17, 5, 13, 16, 5, 13, 14, 
-        15, 4, 16, 0
+static const signed char _emoji_presentation_index_offsets[] = {
+       0, 5, 8, 16, 21, 24, 26, 30,
+       36, 38, 43, 46, 0
 };
 
-static const char _emoji_presentation_trans_targs[] = {
-        2, 4, 6, 2, 1, 2, 3, 3, 
-        7, 2, 8, 9, 11, 0, 2, 5, 
-        2, 2, 10
+static const signed char _emoji_presentation_cond_targs[] = {
+       6, 4, 4, 4, 2, 1, 2, 2,
+       3, 3, 3, 7, 8, 9, 11, 2,
+       2, 0, 2, 5, 2, 0, 5, 2,
+       0, 2, 5, 0, 5, 2, 5, 2,
+       0, 2, 5, 2, 2, 2, 2, 0,
+       2, 10, 2, 2, 0, 2, 2, 0,
+       2, 5, 1, 2, 2, 2, 2, 2,
+       2, 2, 2, 2, 2, 2, 2, 2,
+       0
 };
 
-static const char _emoji_presentation_trans_actions[] = {
-        17, 19, 19, 15, 0, 7, 22, 19, 
-        19, 9, 0, 22, 19, 0, 5, 19, 
-        11, 13, 19
+static const signed char _emoji_presentation_cond_actions[] = {
+       27, 27, 27, 27, 19, 0, 7, 17,
+       30, 21, 27, 27, 0, 30, 27, 9,
+       7, 0, 5, 24, 19, 0, 27, 13,
+       0, 19, 27, 0, 27, 13, 27, 7,
+       0, 5, 24, 13, 7, 15, 7, 0,
+       5, 24, 15, 7, 0, 11, 7, 0,
+       5, 24, 0, 13, 19, 17, 0, 19,
+       13, 19, 13, 13, 15, 15, 11, 13,
+       0
 };
 
-static const char _emoji_presentation_to_state_actions[] = {
-        0, 0, 1, 0, 0, 0, 0, 0, 
-        0, 0, 0, 0
+static const signed char _emoji_presentation_to_state_actions[] = {
+       0, 0, 1, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0
 };
 
-static const char _emoji_presentation_from_state_actions[] = {
-        0, 0, 3, 0, 0, 0, 0, 0, 
-        0, 0, 0, 0
+static const signed char _emoji_presentation_from_state_actions[] = {
+       0, 0, 3, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0
 };
 
-static const char _emoji_presentation_eof_trans[] = {
-        1, 4, 0, 1, 17, 17, 17, 17, 
-        18, 18, 17, 17
+static const signed char _emoji_presentation_eof_trans[] = {
+       53, 54, 55, 56, 57, 58, 59, 60,
+       61, 62, 63, 64, 0
 };
 
 static const int emoji_presentation_start = 2;
@@ -84,197 +86,342 @@ static const int emoji_presentation_start = 2;
 static const int emoji_presentation_en_text_and_emoji_run = 2;
 
 
-#line 9 "emoji_presentation_scanner.rl"
+#line 9 "pango2/emoji_presentation_scanner.rl"
 
 
 
-#line 78 "emoji_presentation_scanner.rl"
+#line 81 "pango2/emoji_presentation_scanner.rl"
 
 
 static emoji_text_iter_t
 scan_emoji_presentation (emoji_text_iter_t p,
-    const emoji_text_iter_t pe,
-    bool* is_emoji)
+const emoji_text_iter_t pe,
+EmojiPresentation *state,
+gboolean *explicit)
 {
-  emoji_text_iter_t te;
-  const emoji_text_iter_t eof = pe;
-
-  unsigned act;
-  int cs;
-
-  
-#line 107 "emoji_presentation_scanner.c"
-        {
-        cs = emoji_presentation_start;
-        te = 0;
-        act = 0;
-        }
-
-#line 115 "emoji_presentation_scanner.c"
-        {
-        int _klen;
-        unsigned int _trans;
-        const char *_acts;
-        unsigned int _nacts;
-        const unsigned char *_keys;
-
-        if ( p == pe )
-                goto _test_eof;
-_resume:
-        _acts = _emoji_presentation_actions + _emoji_presentation_from_state_actions[cs];
-        _nacts = (unsigned int) *_acts++;
-        while ( _nacts-- > 0 ) {
-                switch ( *_acts++ ) {
-        case 1:
+       emoji_text_iter_t ts, te;
+       const emoji_text_iter_t eof = pe;
+       
+       unsigned act;
+       int cs;
+       
+
+#line 104 "pango2/emoji_presentation_scanner.c"
+       {
+               cs = (int)emoji_presentation_start;
+               ts = 0;
+               te = 0;
+               act = 0;
+       }
+
+#line 110 "pango2/emoji_presentation_scanner.c"
+       {
+               int _klen;
+               unsigned int _trans = 0;
+               const unsigned char * _keys;
+               const signed char * _acts;
+               unsigned int _nacts;
+               _resume: {}
+               if ( p == pe && p != eof )
+                       goto _out;
+               _acts = ( _emoji_presentation_actions + (_emoji_presentation_from_state_actions[cs]));
+               _nacts = (unsigned int)(*( _acts));
+               _acts += 1;
+               while ( _nacts > 0 ) {
+                       switch ( (*( _acts)) ) {
+                               case 1:  {
+                                               {
 #line 1 "NONE"
-        break;
-#line 134 "emoji_presentation_scanner.c"
-                }
-        }
-
-        _keys = _emoji_presentation_trans_keys + _emoji_presentation_key_offsets[cs];
-        _trans = _emoji_presentation_index_offsets[cs];
-
-        _klen = _emoji_presentation_single_lengths[cs];
-        if ( _klen > 0 ) {
-                const unsigned char *_lower = _keys;
-                const unsigned char *_mid;
-                const unsigned char *_upper = _keys + _klen - 1;
-                while (1) {
-                        if ( _upper < _lower )
-                                break;
-
-                        _mid = _lower + ((_upper-_lower) >> 1);
-                        if ( (*p) < *_mid )
-                                _upper = _mid - 1;
-                        else if ( (*p) > *_mid )
-                                _lower = _mid + 1;
-                        else {
-                                _trans += (unsigned int)(_mid - _keys);
-                                goto _match;
-                        }
-                }
-                _keys += _klen;
-                _trans += _klen;
-        }
-
-        _klen = _emoji_presentation_range_lengths[cs];
-        if ( _klen > 0 ) {
-                const unsigned char *_lower = _keys;
-                const unsigned char *_mid;
-                const unsigned char *_upper = _keys + (_klen<<1) - 2;
-                while (1) {
-                        if ( _upper < _lower )
-                                break;
-
-                        _mid = _lower + (((_upper-_lower) >> 1) & ~1);
-                        if ( (*p) < _mid[0] )
-                                _upper = _mid - 2;
-                        else if ( (*p) > _mid[1] )
-                                _lower = _mid + 2;
-                        else {
-                                _trans += (unsigned int)((_mid - _keys)>>1);
-                                goto _match;
-                        }
-                }
-                _trans += _klen;
-        }
-
-_match:
-        _trans = _emoji_presentation_indicies[_trans];
-_eof_trans:
-        cs = _emoji_presentation_trans_targs[_trans];
-
-        if ( _emoji_presentation_trans_actions[_trans] == 0 )
-                goto _again;
-
-        _acts = _emoji_presentation_actions + _emoji_presentation_trans_actions[_trans];
-        _nacts = (unsigned int) *_acts++;
-        while ( _nacts-- > 0 )
-        {
-                switch ( *_acts++ )
-                {
-        case 2:
+                                               {ts = p;}}
+                                       
+#line 129 "pango2/emoji_presentation_scanner.c"
+
+                                       break; 
+                               }
+                       }
+                       _nacts -= 1;
+                       _acts += 1;
+               }
+               
+               if ( p == eof ) {
+                       if ( _emoji_presentation_eof_trans[cs] > 0 ) {
+                               _trans = (unsigned int)_emoji_presentation_eof_trans[cs] - 1;
+                       }
+               }
+               else {
+                       _keys = ( _emoji_presentation_trans_keys + (_emoji_presentation_key_offsets[cs]));
+                       _trans = (unsigned int)_emoji_presentation_index_offsets[cs];
+                       
+                       _klen = (int)_emoji_presentation_single_lengths[cs];
+                       if ( _klen > 0 ) {
+                               const unsigned char *_lower = _keys;
+                               const unsigned char *_upper = _keys + _klen - 1;
+                               const unsigned char *_mid;
+                               while ( 1 ) {
+                                       if ( _upper < _lower ) {
+                                               _keys += _klen;
+                                               _trans += (unsigned int)_klen;
+                                               break;
+                                       }
+                                       
+                                       _mid = _lower + ((_upper-_lower) >> 1);
+                                       if ( ( (*( p))) < (*( _mid)) )
+                                               _upper = _mid - 1;
+                                       else if ( ( (*( p))) > (*( _mid)) )
+                                               _lower = _mid + 1;
+                                       else {
+                                               _trans += (unsigned int)(_mid - _keys);
+                                               goto _match;
+                                       }
+                               }
+                       }
+                       
+                       _klen = (int)_emoji_presentation_range_lengths[cs];
+                       if ( _klen > 0 ) {
+                               const unsigned char *_lower = _keys;
+                               const unsigned char *_upper = _keys + (_klen<<1) - 2;
+                               const unsigned char *_mid;
+                               while ( 1 ) {
+                                       if ( _upper < _lower ) {
+                                               _trans += (unsigned int)_klen;
+                                               break;
+                                       }
+                                       
+                                       _mid = _lower + (((_upper-_lower) >> 1) & ~1);
+                                       if ( ( (*( p))) < (*( _mid)) )
+                                               _upper = _mid - 2;
+                                       else if ( ( (*( p))) > (*( _mid + 1)) )
+                                               _lower = _mid + 2;
+                                       else {
+                                               _trans += (unsigned int)((_mid - _keys)>>1);
+                                               break;
+                                       }
+                               }
+                       }
+                       
+                       _match: {}
+               }
+               cs = (int)_emoji_presentation_cond_targs[_trans];
+               
+               if ( _emoji_presentation_cond_actions[_trans] != 0 ) {
+                       
+                       _acts = ( _emoji_presentation_actions + (_emoji_presentation_cond_actions[_trans]));
+                       _nacts = (unsigned int)(*( _acts));
+                       _acts += 1;
+                       while ( _nacts > 0 ) {
+                               switch ( (*( _acts)) )
+                               {
+                                       case 2:  {
+                                                       {
 #line 1 "NONE"
-        {te = p+1;}
-        break;
-        case 3:
-#line 74 "emoji_presentation_scanner.rl"
-        {act = 2;}
-        break;
-        case 4:
-#line 75 "emoji_presentation_scanner.rl"
-        {act = 3;}
-        break;
-        case 5:
-#line 73 "emoji_presentation_scanner.rl"
-        {te = p+1;{ *is_emoji = false; return te; }}
-        break;
-        case 6:
-#line 74 "emoji_presentation_scanner.rl"
-        {te = p+1;{ *is_emoji = true; return te; }}
-        break;
-        case 7:
-#line 75 "emoji_presentation_scanner.rl"
-        {te = p+1;{ *is_emoji = false; return te; }}
-        break;
-        case 8:
-#line 74 "emoji_presentation_scanner.rl"
-        {te = p;p--;{ *is_emoji = true; return te; }}
-        break;
-        case 9:
-#line 75 "emoji_presentation_scanner.rl"
-        {te = p;p--;{ *is_emoji = false; return te; }}
-        break;
-        case 10:
-#line 74 "emoji_presentation_scanner.rl"
-        {{p = ((te))-1;}{ *is_emoji = true; return te; }}
-        break;
-        case 11:
+                                                       {te = p+1;}}
+                                               
+#line 210 "pango2/emoji_presentation_scanner.c"
+
+                                               break; 
+                                       }
+                                       case 3:  {
+                                                       {
+#line 75 "pango2/emoji_presentation_scanner.rl"
+                                                       {act = 2;}}
+                                               
+#line 218 "pango2/emoji_presentation_scanner.c"
+
+                                               break; 
+                                       }
+                                       case 4:  {
+                                                       {
+#line 76 "pango2/emoji_presentation_scanner.rl"
+                                                       {act = 3;}}
+                                               
+#line 226 "pango2/emoji_presentation_scanner.c"
+
+                                               break; 
+                                       }
+                                       case 5:  {
+                                                       {
+#line 77 "pango2/emoji_presentation_scanner.rl"
+                                                       {act = 4;}}
+                                               
+#line 234 "pango2/emoji_presentation_scanner.c"
+
+                                               break; 
+                                       }
+                                       case 6:  {
+                                                       {
+#line 78 "pango2/emoji_presentation_scanner.rl"
+                                                       {act = 5;}}
+                                               
+#line 242 "pango2/emoji_presentation_scanner.c"
+
+                                               break; 
+                                       }
+                                       case 7:  {
+                                                       {
+#line 74 "pango2/emoji_presentation_scanner.rl"
+                                                       {te = p+1;{
+#line 74 "pango2/emoji_presentation_scanner.rl"
+                                                                       *state = EMOJI_PRESENTATION_TEXT; 
*explicit = TRUE; return te; }
+                                                       }}
+                                               
+#line 253 "pango2/emoji_presentation_scanner.c"
+
+                                               break; 
+                                       }
+                                       case 8:  {
+                                                       {
+#line 77 "pango2/emoji_presentation_scanner.rl"
+                                                       {te = p+1;{
+#line 77 "pango2/emoji_presentation_scanner.rl"
+                                                                       *state = EMOJI_PRESENTATION_EMOJI; 
*explicit = FALSE; return te; }
+                                                       }}
+                                               
+#line 264 "pango2/emoji_presentation_scanner.c"
+
+                                               break; 
+                                       }
+                                       case 9:  {
+                                                       {
+#line 78 "pango2/emoji_presentation_scanner.rl"
+                                                       {te = p+1;{
+#line 78 "pango2/emoji_presentation_scanner.rl"
+                                                                       *state = EMOJI_PRESENTATION_NONE; 
*explicit = TRUE; return te; }
+                                                       }}
+                                               
+#line 275 "pango2/emoji_presentation_scanner.c"
+
+                                               break; 
+                                       }
+                                       case 10:  {
+                                                       {
+#line 76 "pango2/emoji_presentation_scanner.rl"
+                                                       {te = p;p = p - 1;{
+#line 76 "pango2/emoji_presentation_scanner.rl"
+                                                                       *state = EMOJI_PRESENTATION_EMOJI; 
*explicit = TRUE; return te; }
+                                                       }}
+                                               
+#line 286 "pango2/emoji_presentation_scanner.c"
+
+                                               break; 
+                                       }
+                                       case 11:  {
+                                                       {
+#line 77 "pango2/emoji_presentation_scanner.rl"
+                                                       {te = p;p = p - 1;{
+#line 77 "pango2/emoji_presentation_scanner.rl"
+                                                                       *state = EMOJI_PRESENTATION_EMOJI; 
*explicit = FALSE; return te; }
+                                                       }}
+                                               
+#line 297 "pango2/emoji_presentation_scanner.c"
+
+                                               break; 
+                                       }
+                                       case 12:  {
+                                                       {
+#line 78 "pango2/emoji_presentation_scanner.rl"
+                                                       {te = p;p = p - 1;{
+#line 78 "pango2/emoji_presentation_scanner.rl"
+                                                                       *state = EMOJI_PRESENTATION_NONE; 
*explicit = TRUE; return te; }
+                                                       }}
+                                               
+#line 308 "pango2/emoji_presentation_scanner.c"
+
+                                               break; 
+                                       }
+                                       case 13:  {
+                                                       {
+#line 77 "pango2/emoji_presentation_scanner.rl"
+                                                       {p = ((te))-1;
+                                                               {
+#line 77 "pango2/emoji_presentation_scanner.rl"
+                                                                       *state = EMOJI_PRESENTATION_EMOJI; 
*explicit = FALSE; return te; }
+                                                       }}
+                                               
+#line 320 "pango2/emoji_presentation_scanner.c"
+
+                                               break; 
+                                       }
+                                       case 14:  {
+                                                       {
 #line 1 "NONE"
-        {       switch( act ) {
-        case 2:
-        {{p = ((te))-1;} *is_emoji = true; return te; }
-        break;
-        case 3:
-        {{p = ((te))-1;} *is_emoji = false; return te; }
-        break;
-        }
-        }
-        break;
-#line 248 "emoji_presentation_scanner.c"
-                }
-        }
-
-_again:
-        _acts = _emoji_presentation_actions + _emoji_presentation_to_state_actions[cs];
-        _nacts = (unsigned int) *_acts++;
-        while ( _nacts-- > 0 ) {
-                switch ( *_acts++ ) {
-        case 0:
+                                                       {switch( act ) {
+                                                                       case 2:  {
+                                                                               p = ((te))-1;
+                                                                               {
+#line 75 "pango2/emoji_presentation_scanner.rl"
+                                                                                       *state = 
EMOJI_PRESENTATION_TEXT; *explicit = FALSE; return te; }
+                                                                               break; 
+                                                                       }
+                                                                       case 3:  {
+                                                                               p = ((te))-1;
+                                                                               {
+#line 76 "pango2/emoji_presentation_scanner.rl"
+                                                                                       *state = 
EMOJI_PRESENTATION_EMOJI; *explicit = TRUE; return te; }
+                                                                               break; 
+                                                                       }
+                                                                       case 4:  {
+                                                                               p = ((te))-1;
+                                                                               {
+#line 77 "pango2/emoji_presentation_scanner.rl"
+                                                                                       *state = 
EMOJI_PRESENTATION_EMOJI; *explicit = FALSE; return te; }
+                                                                               break; 
+                                                                       }
+                                                                       case 5:  {
+                                                                               p = ((te))-1;
+                                                                               {
+#line 78 "pango2/emoji_presentation_scanner.rl"
+                                                                                       *state = 
EMOJI_PRESENTATION_NONE; *explicit = TRUE; return te; }
+                                                                               break; 
+                                                                       }
+                                                               }}
+                                               }
+                                               
+#line 358 "pango2/emoji_presentation_scanner.c"
+
+                                               break; 
+                                       }
+                               }
+                               _nacts -= 1;
+                               _acts += 1;
+                       }
+                       
+               }
+               
+               if ( p == eof ) {
+                       if ( cs >= 2 )
+                               goto _out;
+               }
+               else {
+                       _acts = ( _emoji_presentation_actions + (_emoji_presentation_to_state_actions[cs]));
+                       _nacts = (unsigned int)(*( _acts));
+                       _acts += 1;
+                       while ( _nacts > 0 ) {
+                               switch ( (*( _acts)) ) {
+                                       case 0:  {
+                                                       {
 #line 1 "NONE"
-        break;
-#line 261 "emoji_presentation_scanner.c"
-                }
-        }
-
-        if ( ++p != pe )
-                goto _resume;
-        _test_eof: {}
-        if ( p == eof )
-        {
-        if ( _emoji_presentation_eof_trans[cs] > 0 ) {
-                _trans = _emoji_presentation_eof_trans[cs] - 1;
-                goto _eof_trans;
-        }
-        }
-
-        }
-
-#line 94 "emoji_presentation_scanner.rl"
-
-
-  /* Should not be reached. */
-  *is_emoji = false;
-  return pe;
+                                                       {ts = 0;}}
+                                               
+#line 383 "pango2/emoji_presentation_scanner.c"
+
+                                               break; 
+                                       }
+                               }
+                               _nacts -= 1;
+                               _acts += 1;
+                       }
+                       
+                       p += 1;
+                       goto _resume;
+               }
+               _out: {}
+       }
+       
+#line 98 "pango2/emoji_presentation_scanner.rl"
+
+       
+       /* Should not be reached. */
+       *state = EMOJI_PRESENTATION_NONE;
+       *explicit = FALSE;
+       return pe;
 }
diff --git a/pango2/emoji_presentation_scanner.rl b/pango2/emoji_presentation_scanner.rl
index d9c269195..85892bf5a 100644
--- a/pango2/emoji_presentation_scanner.rl
+++ b/pango2/emoji_presentation_scanner.rl
@@ -5,7 +5,7 @@
 %%{
   machine emoji_presentation;
   alphtype unsigned char;
-  write data noerror nofinal noentry;
+  write data noerror nofinal;
 }%%
 
 %%{
@@ -64,15 +64,18 @@ emoji_presentation = EMOJI_EMOJI_PRESENTATION | TAG_BASE | EMOJI_MODIFIER_BASE |
 
 emoji_run = emoji_presentation;
 
+text_emoji = EMOJI_TEXT_PRESENTATION;
 text_presentation_emoji = any_emoji VS15;
 text_run = any;
 
 text_and_emoji_run := |*
 # In order to give the the VS15 sequences higher priority than detecting
 # emoji sequences they are listed first as scanner token here.
-text_presentation_emoji => { *is_emoji = false; return te; };
-emoji_run => { *is_emoji = true; return te; };
-text_run => { *is_emoji = false; return te; };
+text_presentation_emoji => { *state = EMOJI_PRESENTATION_TEXT; *explicit = TRUE; return te; };
+text_emoji => { *state = EMOJI_PRESENTATION_TEXT; *explicit = FALSE; return te; };
+emoji_presentation_sequence => { *state = EMOJI_PRESENTATION_EMOJI; *explicit = TRUE; return te; };
+emoji_run => { *state = EMOJI_PRESENTATION_EMOJI; *explicit = FALSE; return te; };
+text_run => { *state = EMOJI_PRESENTATION_NONE; *explicit = TRUE; return te; };
 *|;
 
 }%%
@@ -80,7 +83,8 @@ text_run => { *is_emoji = false; return te; };
 static emoji_text_iter_t
 scan_emoji_presentation (emoji_text_iter_t p,
     const emoji_text_iter_t pe,
-    bool* is_emoji)
+    EmojiPresentation *state,
+    gboolean *explicit)
 {
   emoji_text_iter_t ts, te;
   const emoji_text_iter_t eof = pe;
@@ -94,6 +98,7 @@ scan_emoji_presentation (emoji_text_iter_t p,
   }%%
 
   /* Should not be reached. */
-  *is_emoji = false;
+  *state = EMOJI_PRESENTATION_NONE;
+  *explicit = FALSE;
   return pe;
 }
diff --git a/pango2/itemize.c b/pango2/itemize.c
index 1cf4e6eaf..537600d3c 100644
--- a/pango2/itemize.c
+++ b/pango2/itemize.c
@@ -321,6 +321,7 @@ struct _ItemizeState
 
   Pango2WidthIter width_iter;
   Pango2EmojiIter emoji_iter;
+  Pango2EmojiPresentation preferred;
 
   Pango2Language *derived_lang;
 
@@ -366,6 +367,7 @@ update_attr_iterator (ItemizeState *state)
   Pango2Language *old_lang;
   Pango2Attribute *attr;
   int end_index;
+  Pango2EmojiPresentation old_preferred;
 
   pango2_attr_iterator_range (state->attr_iter, NULL, &end_index);
   if (end_index < state->end - state->text)
@@ -404,9 +406,15 @@ update_attr_iterator (ItemizeState *state)
   attr = find_attribute (state->extra_attrs, PANGO2_ATTR_GRAVITY_HINT);
   state->gravity_hint = attr == NULL ? state->context->gravity_hint : (Pango2GravityHint)attr->int_value;
 
+  old_preferred = state->preferred;
+  attr = find_attribute (state->extra_attrs, PANGO2_ATTR_EMOJI_PRESENTATION);
+  state->preferred = attr ? attr->int_value : state->context->presentation;
+
   state->changed |= FONT_CHANGED;
   if (state->lang != old_lang)
     state->changed |= LANG_CHANGED;
+  if (state->preferred != old_preferred)
+    state->changed |= EMOJI_CHANGED;
 }
 
 static void
@@ -460,6 +468,8 @@ itemize_state_init (ItemizeState                *state,
   state->gravity_hint = state->context->gravity_hint;
   state->resolved_gravity = PANGO2_GRAVITY_AUTO;
 
+  state->preferred = context->presentation;
+
   /* Initialize the attribute iterator
    */
   if (cached_iter)
@@ -505,11 +515,11 @@ itemize_state_init (ItemizeState                *state,
                                &state->script_end, &state->script);
 
   width_iter_init (&state->width_iter, text + start_index, length);
-  _pango2_emoji_iter_init (&state->emoji_iter, text + start_index, length);
+  pango2_emoji_iter_init (&state->emoji_iter, text + start_index, length);
 
   if (!PANGO2_GRAVITY_IS_VERTICAL (state->context->resolved_gravity))
     state->width_iter.end = state->end;
-  else if (state->emoji_iter.is_emoji)
+  else if (pango2_emoji_iter_get (&state->emoji_iter, state->preferred) == EMOJI_PRESENTATION_EMOJI)
     state->width_iter.end = MAX (state->width_iter.end, state->emoji_iter.end);
 
   update_end (state);
@@ -557,10 +567,10 @@ itemize_state_next (ItemizeState *state)
     }
   if (state->run_end == state->emoji_iter.end)
     {
-      _pango2_emoji_iter_next (&state->emoji_iter);
+      pango2_emoji_iter_next (&state->emoji_iter);
       state->changed |= EMOJI_CHANGED;
 
-      if (state->emoji_iter.is_emoji)
+      if (pango2_emoji_iter_get (&state->emoji_iter, state->preferred) == EMOJI_PRESENTATION_EMOJI)
         state->width_iter.end = MAX (state->width_iter.end, state->emoji_iter.end);
     }
   if (state->run_end == state->width_iter.end)
@@ -874,16 +884,18 @@ itemize_state_update_for_new_run (ItemizeState *state)
 
   if (!state->current_fonts)
     {
-      gboolean is_emoji = state->emoji_iter.is_emoji;
+      gboolean is_emoji = pango2_emoji_iter_get (&state->emoji_iter, state->preferred) == 
EMOJI_PRESENTATION_EMOJI;
+
       if (is_emoji && !state->emoji_font_desc)
         {
           state->emoji_font_desc = pango2_font_description_copy_static (state->font_desc);
           pango2_font_description_set_family_static (state->emoji_font_desc, "emoji");
         }
+
       state->current_fonts = pango2_font_map_load_fontset (state->context->font_map,
-                                                          state->context,
-                                                          is_emoji ? state->emoji_font_desc : 
state->font_desc,
-                                                          state->derived_lang);
+                                                           state->context,
+                                                           is_emoji ? state->emoji_font_desc : 
state->font_desc,
+                                                           state->derived_lang);
       state->cache = get_font_cache (state->current_fonts);
     }
 
@@ -1022,7 +1034,7 @@ itemize_state_finish (ItemizeState *state)
   pango2_font_description_free (state->font_desc);
   pango2_font_description_free (state->emoji_font_desc);
   width_iter_fini (&state->width_iter);
-  _pango2_emoji_iter_fini (&state->emoji_iter);
+  pango2_emoji_iter_fini (&state->emoji_iter);
 
   if (state->current_fonts)
     g_object_unref (state->current_fonts);
diff --git a/pango2/pango-attr-list.c b/pango2/pango-attr-list.c
index eae66d87f..a47b68146 100644
--- a/pango2/pango-attr-list.c
+++ b/pango2/pango-attr-list.c
@@ -1264,6 +1264,10 @@ pango2_attr_list_from_string (const char *text)
           if (!is_valid_end_char (*endp)) goto fail;
           break;
 
+        case PANGO2_ATTR_EMOJI_PRESENTATION:
+          ENUM_ATTR(emoji_presentation, Pango2EmojiPresentation, PANGO2_EMOJI_PRESENTATION_AUTO, 
PANGO2_EMOJI_PRESENTATION_EMOJI);
+          break;
+
         case PANGO2_ATTR_SHAPE:
         default:
           g_assert_not_reached ();
diff --git a/pango2/pango-attributes.c b/pango2/pango-attributes.c
index 2c72c9c04..749af63fa 100644
--- a/pango2/pango-attributes.c
+++ b/pango2/pango-attributes.c
@@ -864,6 +864,25 @@ pango2_attr_shape_new (Pango2Rectangle        *ink_rect,
   return attr;
 }
 
+/**
+ * pango2_attr_emoji_presentation_new:
+ * @presentation: a `Pango2EmojiPresentation` value
+ *
+ * Creates a new Emoji presentation attribute.
+ *
+ * Emoji presentation attributes override the preference for
+ * whether Emoji should be presented a text or as color Emoji.
+ *
+ * Return value: (transfer full): the newly allocated
+ *   `Pango2Attribute`, which should be freed with
+ *   [method@Pango2.Attribute.destroy]
+ */
+Pango2Attribute *
+pango2_attr_emoji_presentation_new (Pango2EmojiPresentation presentation)
+{
+  return pango2_attr_int_new (PANGO2_ATTR_EMOJI_PRESENTATION, presentation);
+}
+
 /* }}} */
 /* {{{ Private API */
 
diff --git a/pango2/pango-attributes.h b/pango2/pango-attributes.h
index 990d90e15..6a960d73a 100644
--- a/pango2/pango-attributes.h
+++ b/pango2/pango-attributes.h
@@ -73,6 +73,7 @@ G_BEGIN_DECLS
  * @PANGO2_ATTR_LINE_SPACING: space to add to the leading from the
  *   font metrics (if not overridden by a line height attribute)
  * @PANGO2_ATTR_SHAPE: override glyph shapes (requires renderer support)
+ * @PANGO2_ATTR_EMOJI_PRESENTATION: override Emoji presentation
  *
  * `Pango2AttrType` contains predefined attribute types.
  *
@@ -122,6 +123,7 @@ typedef enum
   PANGO2_ATTR_FONT_SCALE           = PANGO2_ATTR_TYPE (INT, ITEMIZATION, ACCUMULATES),
   PANGO2_ATTR_LINE_SPACING         = PANGO2_ATTR_TYPE (INT, ITEMIZATION, OVERRIDES),
   PANGO2_ATTR_SHAPE                = PANGO2_ATTR_TYPE (POINTER, ITEMIZATION, OVERRIDES),
+  PANGO2_ATTR_EMOJI_PRESENTATION   = PANGO2_ATTR_TYPE (INT, ITEMIZATION, OVERRIDES),
 } Pango2AttrType;
 
 #undef PANGO2_ATTR_TYPE
@@ -319,4 +321,7 @@ Pango2Attribute *        pango2_attr_shape_new                    (Pango2Rectang
                                                                    Pango2AttrDataCopyFunc  copy,
                                                                    GDestroyNotify          destroy);
 
+PANGO2_AVAILABLE_IN_ALL
+Pango2Attribute *        pango2_attr_emoji_presentation_new       (Pango2EmojiPresentation presentation);
+
 G_END_DECLS
diff --git a/pango2/pango-context-private.h b/pango2/pango-context-private.h
index 4ec65da6e..31c19d672 100644
--- a/pango2/pango-context-private.h
+++ b/pango2/pango-context-private.h
@@ -50,6 +50,8 @@ struct _Pango2Context
 
   GQuark palette;
 
+  Pango2EmojiPresentation presentation;
+
 #ifdef HAVE_CAIRO
   gboolean set_options_explicit;
 
diff --git a/pango2/pango-context.c b/pango2/pango-context.c
index a6b6ee243..f6d28e11c 100644
--- a/pango2/pango-context.c
+++ b/pango2/pango-context.c
@@ -70,6 +70,7 @@ enum {
   PROP_MATRIX,
   PROP_ROUND_GLYPH_POSITIONS,
   PROP_PALETTE,
+  PROP_EMOJI_PRESENTATION,
   N_PROPERTIES
 };
 
@@ -90,6 +91,7 @@ pango2_context_init (Pango2Context *context)
   context->font_map = NULL;
   context->round_glyph_positions = TRUE;
   context->palette = g_quark_from_static_string (PANGO2_COLOR_PALETTE_DEFAULT);
+  context->presentation = PANGO2_EMOJI_PRESENTATION_AUTO;
 
   context->font_desc = pango2_font_description_new ();
   pango2_font_description_set_family_static (context->font_desc, "serif");
@@ -146,6 +148,10 @@ pango2_context_set_property (GObject      *object,
       pango2_context_set_palette (context, g_value_get_string (value));
       break;
 
+    case PROP_EMOJI_PRESENTATION:
+      pango2_context_set_emoji_presentation (context, g_value_get_enum (value));
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
     }
@@ -197,6 +203,10 @@ pango2_context_get_property (GObject    *object,
       g_value_set_string (value, pango2_context_get_palette (context));
       break;
 
+    case PROP_EMOJI_PRESENTATION:
+      g_value_set_enum (value, pango2_context_get_emoji_presentation (context));
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
     }
@@ -326,6 +336,17 @@ pango2_context_class_init (Pango2ContextClass *klass)
     g_param_spec_string ("palette", NULL, NULL, "default",
                           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
 
+  /**
+   * Pango2Context:emoji-presentation: (attributes 
org.gtk.Property.get=pango2_context_get_emoji_presentation 
org.gtk.Property.set=pango2_context_set_emoji_presentation)
+   *
+   * The preferred Emoji presentation style.
+   */
+  properties[PROP_EMOJI_PRESENTATION] =
+    g_param_spec_enum ("emoji-presentation", NULL, NULL,
+                       PANGO2_TYPE_EMOJI_PRESENTATION,
+                       PANGO2_EMOJI_PRESENTATION_AUTO,
+                       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
   g_object_class_install_properties (object_class, N_PROPERTIES, properties);
 }
 
@@ -1119,3 +1140,24 @@ pango2_context_get_palette (Pango2Context *context)
 
   return g_quark_to_string (context->palette);
 }
+
+void
+pango2_context_set_emoji_presentation (Pango2Context           *context,
+                                       Pango2EmojiPresentation  presentation)
+{
+  g_return_if_fail (PANGO2_IS_CONTEXT (context));
+
+  if (context->presentation == presentation)
+    return;
+
+  context->presentation = presentation;
+  g_object_notify_by_pspec (G_OBJECT (context), properties[PROP_EMOJI_PRESENTATION]);
+}
+
+Pango2EmojiPresentation
+pango2_context_get_emoji_presentation (Pango2Context *context)
+{
+  g_return_val_if_fail (PANGO2_IS_CONTEXT (context), PANGO2_EMOJI_PRESENTATION_AUTO);
+
+  return context->presentation;
+}
diff --git a/pango2/pango-context.h b/pango2/pango-context.h
index 219014982..6a2df34e8 100644
--- a/pango2/pango-context.h
+++ b/pango2/pango-context.h
@@ -105,6 +105,11 @@ void                     pango2_context_set_palette               (Pango2Context
 PANGO2_AVAILABLE_IN_ALL
 const char *             pango2_context_get_palette               (Pango2Context                 *context);
 
+PANGO2_AVAILABLE_IN_ALL
+void                     pango2_context_set_emoji_presentation    (Pango2Context                 *context,
+                                                                   Pango2EmojiPresentation        
presentation);
+PANGO2_AVAILABLE_IN_ALL
+Pango2EmojiPresentation  pango2_context_get_emoji_presentation    (Pango2Context                 *context);
 
 
 G_END_DECLS
diff --git a/pango2/pango-emoji-private.h b/pango2/pango-emoji-private.h
index f7578bf4b..30a2fa62b 100644
--- a/pango2/pango-emoji-private.h
+++ b/pango2/pango-emoji-private.h
@@ -20,6 +20,7 @@
 #pragma once
 
 #include <glib.h>
+#include "pango-types.h"
 
 gboolean
 _pango2_Is_Emoji_Base_Character (gunichar ch);
@@ -29,13 +30,21 @@ _pango2_Is_Emoji_Extended_Pictographic (gunichar ch);
 
 typedef struct _Pango2EmojiIter Pango2EmojiIter;
 
+typedef enum {
+  EMOJI_PRESENTATION_NONE,
+  EMOJI_PRESENTATION_TEXT,
+  EMOJI_PRESENTATION_EMOJI,
+} EmojiPresentation;
+
 struct _Pango2EmojiIter
 {
   const char *text_start;
   const char *text_end;
   const char *start;
   const char *end;
-  gboolean is_emoji;
+
+  gboolean explicit;
+  EmojiPresentation state;
 
   unsigned char *types;
   unsigned int n_chars;
@@ -43,12 +52,17 @@ struct _Pango2EmojiIter
 };
 
 Pango2EmojiIter *
-_pango2_emoji_iter_init (Pango2EmojiIter *iter,
-                         const char      *text,
-                         int              length);
+pango2_emoji_iter_init (Pango2EmojiIter *iter,
+                        const char      *text,
+                        int              length);
 
 gboolean
-_pango2_emoji_iter_next (Pango2EmojiIter *iter);
+pango2_emoji_iter_next (Pango2EmojiIter *iter);
+
 
 void
-_pango2_emoji_iter_fini (Pango2EmojiIter *iter);
+pango2_emoji_iter_fini (Pango2EmojiIter *iter);
+
+EmojiPresentation
+pango2_emoji_iter_get (Pango2EmojiIter         *iter,
+                       Pango2EmojiPresentation  preferred);
diff --git a/pango2/pango-emoji.c b/pango2/pango-emoji.c
index aa82e9ece..15a7129e8 100644
--- a/pango2/pango-emoji.c
+++ b/pango2/pango-emoji.c
@@ -49,6 +49,7 @@
 #include <stdlib.h>
 #include <string.h>
 
+#include "pango-types.h"
 #include "pango-emoji-private.h"
 #include "pango-emoji-table.h"
 
@@ -200,21 +201,21 @@ _pango2_EmojiSegmentationCategory (gunichar codepoint)
   return kMaxEmojiScannerCategory;
 }
 
-
 typedef gboolean bool;
 enum { false = FALSE, true = TRUE };
 typedef unsigned char *emoji_text_iter_t;
 
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wswitch-default"
+#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
 #include "emoji_presentation_scanner.c"
 #pragma GCC diagnostic pop
 
 
 Pango2EmojiIter *
-_pango2_emoji_iter_init (Pango2EmojiIter *iter,
-                       const char     *text,
-                       int             length)
+pango2_emoji_iter_init (Pango2EmojiIter *iter,
+                        const char      *text,
+                        int              length)
 {
   unsigned int n_chars = g_utf8_strlen (text, length);
   unsigned char *types = g_malloc (n_chars);
@@ -233,28 +234,29 @@ _pango2_emoji_iter_init (Pango2EmojiIter *iter,
     iter->text_end = text + length;
   else
     iter->text_end = text + strlen (text);
-  iter->is_emoji = FALSE;
+  iter->state = EMOJI_PRESENTATION_NONE;
 
   iter->types = types;
   iter->n_chars = n_chars;
   iter->cursor = 0;
 
-  _pango2_emoji_iter_next (iter);
+  pango2_emoji_iter_next (iter);
 
   return iter;
 }
 
 void
-_pango2_emoji_iter_fini (Pango2EmojiIter *iter)
+pango2_emoji_iter_fini (Pango2EmojiIter *iter)
 {
   g_free (iter->types);
 }
 
 gboolean
-_pango2_emoji_iter_next (Pango2EmojiIter *iter)
+pango2_emoji_iter_next (Pango2EmojiIter *iter)
 {
   unsigned int old_cursor, cursor;
-  gboolean is_emoji;
+  EmojiPresentation state;
+  gboolean explicit;
 
   if (iter->end >= iter->text_end)
     return FALSE;
@@ -263,27 +265,54 @@ _pango2_emoji_iter_next (Pango2EmojiIter *iter)
 
   old_cursor = cursor = iter->cursor;
   cursor = scan_emoji_presentation (iter->types + cursor,
-                                   iter->types + iter->n_chars,
-                                   &is_emoji) - iter->types;
+                                    iter->types + iter->n_chars,
+                                    &state, &explicit) - iter->types;
   do
   {
     iter->cursor = cursor;
-    iter->is_emoji = is_emoji;
+    iter->state = state;
+    iter->explicit = explicit;
 
     if (cursor == iter->n_chars)
       break;
 
     cursor = scan_emoji_presentation (iter->types + cursor,
-                                     iter->types + iter->n_chars,
-                                     &is_emoji) - iter->types;
+                                      iter->types + iter->n_chars,
+                                      &state, &explicit) - iter->types;
   }
-  while (iter->is_emoji == is_emoji);
+  while (iter->state == state && iter->explicit == explicit);
 
   iter->end = g_utf8_offset_to_pointer (iter->start, iter->cursor - old_cursor);
 
   return TRUE;
 }
 
+EmojiPresentation
+pango2_emoji_iter_get (Pango2EmojiIter         *iter,
+                       Pango2EmojiPresentation  preferred)
+{
+  gboolean explicit;
+
+  if (preferred == PANGO2_EMOJI_PRESENTATION_AUTO)
+    explicit = TRUE;
+  else
+    explicit = iter->explicit;
+
+  switch (iter->state)
+    {
+    case EMOJI_PRESENTATION_NONE:
+      return EMOJI_PRESENTATION_NONE;
+      break;
+    case EMOJI_PRESENTATION_TEXT:
+      return explicit ? EMOJI_PRESENTATION_TEXT : (EmojiPresentation)preferred;
+      break;
+    case EMOJI_PRESENTATION_EMOJI:
+      return explicit ? EMOJI_PRESENTATION_EMOJI : (EmojiPresentation)preferred;
+      break;
+    default:
+      g_assert_not_reached ();
+    }
+}
 
 /**********************************************************
  * End of code from Chromium
diff --git a/pango2/pango-markup.c b/pango2/pango-markup.c
index 91c9aded0..6b1d10754 100644
--- a/pango2/pango-markup.c
+++ b/pango2/pango-markup.c
@@ -1349,6 +1349,7 @@ span_parse_func (MarkupData            *md G_GNUC_UNUSED,
   const char *text_transform = NULL;
   const char *segment = NULL;
   const char *font_scale = NULL;
+  const char *emoji_presentation = NULL;
 
   g_markup_parse_context_get_position (context,
                                        &line_number, &char_number);
@@ -1388,6 +1389,9 @@ span_parse_func (MarkupData            *md G_GNUC_UNUSED,
       case 'c':
         CHECK_ATTRIBUTE2 (foreground, "color");
         break;
+      case 'e':
+        CHECK_ATTRIBUTE (emoji_presentation);
+        break;
       case 'f':
         CHECK_ATTRIBUTE (fallback);
         CHECK_ATTRIBUTE2 (desc, "font");
@@ -1892,6 +1896,16 @@ span_parse_func (MarkupData            *md G_GNUC_UNUSED,
         }
     }
 
+  if (G_UNLIKELY (emoji_presentation))
+    {
+      Pango2EmojiPresentation ep;
+
+      if (!span_parse_enum ("emoji_presentation", emoji_presentation, PANGO2_TYPE_EMOJI_PRESENTATION, 
(int*)(void*)&ep, line_number, error))
+        goto error;
+
+      add_attribute (tag, pango2_attr_emoji_presentation_new (ep));
+    }
+
   return TRUE;
 
  error:
diff --git a/pango2/pango-types.h b/pango2/pango-types.h
index fb045f144..7dfb9a993 100644
--- a/pango2/pango-types.h
+++ b/pango2/pango-types.h
@@ -342,6 +342,30 @@ typedef enum
  */
 #define PANGO2_COLOR_PALETTE_DARK   "dark"
 
+/**
+ * Pango2EmojiPresentation:
+ * @PANGO2_EMOJI_PRESENTATION_AUTO: Present Emoji with to their
+ *   default presentation according to Unicode
+ * @PANGO2_EMOJI_PRESENTATION_TEXT: Prefer text presentation
+ * @PANGO2_EMOJI_PRESENTATION_EMOJI: Prefer Emoji presentation
+ *
+ * `Pango2EmojiPresentation` describes a preference for Emoji
+ * presentation style.
+ *
+ * See [method@Pango2.Context.set_emoji_presentation] or
+ * [func@Pango2.attr_emoji_presentation_new] for ways to communicate
+ * Emoji presentation style preferences to Pango.
+ *
+ * Note that even with such a preference, Pango will respect
+ * Emoji presentation style if it has been explicitly selected
+ * with a Unicode [variation selector](https://unicode.org/reports/tr51/#Emoji_Variation_Sequences).
+ */
+typedef enum {
+  PANGO2_EMOJI_PRESENTATION_AUTO,
+  PANGO2_EMOJI_PRESENTATION_TEXT,
+  PANGO2_EMOJI_PRESENTATION_EMOJI
+} Pango2EmojiPresentation;
+
 /*
  * PANGO2_DECLARE_INTERNAL_TYPE:
  * @ModuleObjName: The name of the new type, in camel case (like GtkWidget)
diff --git a/pango2/serializer.c b/pango2/serializer.c
index 8f18f11bd..cf0f57da1 100644
--- a/pango2/serializer.c
+++ b/pango2/serializer.c
@@ -267,6 +267,13 @@ static const char *tab_unit_names[] = {
   NULL
 };
 
+static const char *emoji_presentation_names[] = {
+  "auto",
+  "text",
+  "emoji",
+  NULL
+};
+
 /* }}} */
 /* {{{ Serialization */
 
@@ -1124,6 +1131,10 @@ attr_for_type (GtkJsonParser *parser,
       attr = pango2_attr_paragraph_new ();
       break;
 
+    case PANGO2_ATTR_EMOJI_PRESENTATION:
+      attr = pango2_attr_emoji_presentation_new ((Pango2EmojiPresentation) parser_select_string (parser, 
emoji_presentation_names));
+      break;
+
     }
 
   attr->start_index = start;


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