From f39ad9bab1f327062958b2750bf1f5609a9ee991 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Mon, 31 Jul 2017 21:45:16 +0100 Subject: Add data files and routines for emoji itemization Ported from Chromium. Not hooked yet. --- pango/Makefile.am | 3 + pango/pango-emoji-private.h | 49 ++++++ pango/pango-emoji-table.h | 403 ++++++++++++++++++++++++++++++++++++++++++++ pango/pango-emoji.c | 266 +++++++++++++++++++++++++++++ tools/Makefile.am | 1 + tools/gen-emoji-table.py | 64 +++++++ 6 files changed, 786 insertions(+) create mode 100644 pango/pango-emoji-private.h create mode 100644 pango/pango-emoji-table.h create mode 100644 pango/pango-emoji.c create mode 100755 tools/gen-emoji-table.py diff --git a/pango/Makefile.am b/pango/Makefile.am index 95b4dd2a..ac889151 100644 --- a/pango/Makefile.am +++ b/pango/Makefile.am @@ -75,6 +75,9 @@ libpango_1_0_la_SOURCES = \ pango-color-table.h \ pango-context.c \ pango-coverage.c \ + pango-emoji.c \ + pango-emoji-private.h \ + pango-emoji-table.h \ pango-engine.c \ pango-engine-private.h \ pango-fontmap.c \ diff --git a/pango/pango-emoji-private.h b/pango/pango-emoji-private.h new file mode 100644 index 00000000..eb8a52a7 --- /dev/null +++ b/pango/pango-emoji-private.h @@ -0,0 +1,49 @@ +/* Pango + * pango-emoji-private.h: Emoji handling, private definitions + * + * Copyright (C) 2017 Google, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __PANGO_EMOJI_PRIVATE_H__ +#define __PANGO_EMOJI_PRIVATE_H__ + +#include + +typedef struct _PangoEmojiIter PangoEmojiIter; + +struct _PangoEmojiIter +{ + const gchar *text_start; + const gchar *text_end; + const gchar *start; + const gchar *end; + gboolean is_emoji; +}; + +PangoEmojiIter * +_pango_emoji_iter_init (PangoEmojiIter *iter, + const char *text, + int length); + +gboolean +_pango_emoji_iter_next (PangoEmojiIter *iter); + +void +_pango_emoji_iter_fini (PangoEmojiIter *iter); + +#endif /* __PANGO_EMOJI_PRIVATE_H__ */ diff --git a/pango/pango-emoji-table.h b/pango/pango-emoji-table.h new file mode 100644 index 00000000..7688b578 --- /dev/null +++ b/pango/pango-emoji-table.h @@ -0,0 +1,403 @@ +/* == Start of generated table == */ +/* + * The following tables are generated by running: + * + * ./gen-emoji-table.py emoji-data.txt + * + * on file with this header: + * + * # emoji-data.txt + * # Date: 2016-06-02, 09:26:10 GMT + * # © 2016 Unicode®, Inc. + * # Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. + * # For terms of use, see http://www.unicode.org/terms_of_use.html + * # + * # Emoji Data for UTR #51 + * # Version: 3.0 + * # + * # For documentation and usage, see http://www.unicode.org/reports/tr51 + */ + +#ifndef PANGO_EMOJI_TABLE_H +#define PANGO_EMOJI_TABLE_H + +#include + +struct Interval { + gunichar start, end; +}; + +static const struct Interval _pango_Emoji_table[] = +{ + {0x0023, 0x0023}, + {0x002A, 0x002A}, + {0x0030, 0x0039}, + {0x00A9, 0x00A9}, + {0x00AE, 0x00AE}, + {0x203C, 0x203C}, + {0x2049, 0x2049}, + {0x2122, 0x2122}, + {0x2139, 0x2139}, + {0x2194, 0x2199}, + {0x21A9, 0x21AA}, + {0x231A, 0x231B}, + {0x2328, 0x2328}, + {0x23CF, 0x23CF}, + {0x23E9, 0x23F3}, + {0x23F8, 0x23FA}, + {0x24C2, 0x24C2}, + {0x25AA, 0x25AB}, + {0x25B6, 0x25B6}, + {0x25C0, 0x25C0}, + {0x25FB, 0x25FE}, + {0x2600, 0x2604}, + {0x260E, 0x260E}, + {0x2611, 0x2611}, + {0x2614, 0x2615}, + {0x2618, 0x2618}, + {0x261D, 0x261D}, + {0x2620, 0x2620}, + {0x2622, 0x2623}, + {0x2626, 0x2626}, + {0x262A, 0x262A}, + {0x262E, 0x262F}, + {0x2638, 0x263A}, + {0x2648, 0x2653}, + {0x2660, 0x2660}, + {0x2663, 0x2663}, + {0x2665, 0x2666}, + {0x2668, 0x2668}, + {0x267B, 0x267B}, + {0x267F, 0x267F}, + {0x2692, 0x2694}, + {0x2696, 0x2697}, + {0x2699, 0x2699}, + {0x269B, 0x269C}, + {0x26A0, 0x26A1}, + {0x26AA, 0x26AB}, + {0x26B0, 0x26B1}, + {0x26BD, 0x26BE}, + {0x26C4, 0x26C5}, + {0x26C8, 0x26C8}, + {0x26CE, 0x26CE}, + {0x26CF, 0x26CF}, + {0x26D1, 0x26D1}, + {0x26D3, 0x26D4}, + {0x26E9, 0x26EA}, + {0x26F0, 0x26F5}, + {0x26F7, 0x26FA}, + {0x26FD, 0x26FD}, + {0x2702, 0x2702}, + {0x2705, 0x2705}, + {0x2708, 0x2709}, + {0x270A, 0x270B}, + {0x270C, 0x270D}, + {0x270F, 0x270F}, + {0x2712, 0x2712}, + {0x2714, 0x2714}, + {0x2716, 0x2716}, + {0x271D, 0x271D}, + {0x2721, 0x2721}, + {0x2728, 0x2728}, + {0x2733, 0x2734}, + {0x2744, 0x2744}, + {0x2747, 0x2747}, + {0x274C, 0x274C}, + {0x274E, 0x274E}, + {0x2753, 0x2755}, + {0x2757, 0x2757}, + {0x2763, 0x2764}, + {0x2795, 0x2797}, + {0x27A1, 0x27A1}, + {0x27B0, 0x27B0}, + {0x27BF, 0x27BF}, + {0x2934, 0x2935}, + {0x2B05, 0x2B07}, + {0x2B1B, 0x2B1C}, + {0x2B50, 0x2B50}, + {0x2B55, 0x2B55}, + {0x3030, 0x3030}, + {0x303D, 0x303D}, + {0x3297, 0x3297}, + {0x3299, 0x3299}, + {0x1F004, 0x1F004}, + {0x1F0CF, 0x1F0CF}, + {0x1F170, 0x1F171}, + {0x1F17E, 0x1F17E}, + {0x1F17F, 0x1F17F}, + {0x1F18E, 0x1F18E}, + {0x1F191, 0x1F19A}, + {0x1F1E6, 0x1F1FF}, + {0x1F201, 0x1F202}, + {0x1F21A, 0x1F21A}, + {0x1F22F, 0x1F22F}, + {0x1F232, 0x1F23A}, + {0x1F250, 0x1F251}, + {0x1F300, 0x1F320}, + {0x1F321, 0x1F321}, + {0x1F324, 0x1F32C}, + {0x1F32D, 0x1F32F}, + {0x1F330, 0x1F335}, + {0x1F336, 0x1F336}, + {0x1F337, 0x1F37C}, + {0x1F37D, 0x1F37D}, + {0x1F37E, 0x1F37F}, + {0x1F380, 0x1F393}, + {0x1F396, 0x1F397}, + {0x1F399, 0x1F39B}, + {0x1F39E, 0x1F39F}, + {0x1F3A0, 0x1F3C4}, + {0x1F3C5, 0x1F3C5}, + {0x1F3C6, 0x1F3CA}, + {0x1F3CB, 0x1F3CE}, + {0x1F3CF, 0x1F3D3}, + {0x1F3D4, 0x1F3DF}, + {0x1F3E0, 0x1F3F0}, + {0x1F3F3, 0x1F3F5}, + {0x1F3F7, 0x1F3F7}, + {0x1F3F8, 0x1F3FF}, + {0x1F400, 0x1F43E}, + {0x1F43F, 0x1F43F}, + {0x1F440, 0x1F440}, + {0x1F441, 0x1F441}, + {0x1F442, 0x1F4F7}, + {0x1F4F8, 0x1F4F8}, + {0x1F4F9, 0x1F4FC}, + {0x1F4FD, 0x1F4FD}, + {0x1F4FF, 0x1F4FF}, + {0x1F500, 0x1F53D}, + {0x1F549, 0x1F54A}, + {0x1F54B, 0x1F54E}, + {0x1F550, 0x1F567}, + {0x1F56F, 0x1F570}, + {0x1F573, 0x1F579}, + {0x1F57A, 0x1F57A}, + {0x1F587, 0x1F587}, + {0x1F58A, 0x1F58D}, + {0x1F590, 0x1F590}, + {0x1F595, 0x1F596}, + {0x1F5A4, 0x1F5A4}, + {0x1F5A5, 0x1F5A5}, + {0x1F5A8, 0x1F5A8}, + {0x1F5B1, 0x1F5B2}, + {0x1F5BC, 0x1F5BC}, + {0x1F5C2, 0x1F5C4}, + {0x1F5D1, 0x1F5D3}, + {0x1F5DC, 0x1F5DE}, + {0x1F5E1, 0x1F5E1}, + {0x1F5E3, 0x1F5E3}, + {0x1F5E8, 0x1F5E8}, + {0x1F5EF, 0x1F5EF}, + {0x1F5F3, 0x1F5F3}, + {0x1F5FA, 0x1F5FA}, + {0x1F5FB, 0x1F5FF}, + {0x1F600, 0x1F600}, + {0x1F601, 0x1F610}, + {0x1F611, 0x1F611}, + {0x1F612, 0x1F614}, + {0x1F615, 0x1F615}, + {0x1F616, 0x1F616}, + {0x1F617, 0x1F617}, + {0x1F618, 0x1F618}, + {0x1F619, 0x1F619}, + {0x1F61A, 0x1F61A}, + {0x1F61B, 0x1F61B}, + {0x1F61C, 0x1F61E}, + {0x1F61F, 0x1F61F}, + {0x1F620, 0x1F625}, + {0x1F626, 0x1F627}, + {0x1F628, 0x1F62B}, + {0x1F62C, 0x1F62C}, + {0x1F62D, 0x1F62D}, + {0x1F62E, 0x1F62F}, + {0x1F630, 0x1F633}, + {0x1F634, 0x1F634}, + {0x1F635, 0x1F640}, + {0x1F641, 0x1F642}, + {0x1F643, 0x1F644}, + {0x1F645, 0x1F64F}, + {0x1F680, 0x1F6C5}, + {0x1F6CB, 0x1F6CF}, + {0x1F6D0, 0x1F6D0}, + {0x1F6D1, 0x1F6D2}, + {0x1F6E0, 0x1F6E5}, + {0x1F6E9, 0x1F6E9}, + {0x1F6EB, 0x1F6EC}, + {0x1F6F0, 0x1F6F0}, + {0x1F6F3, 0x1F6F3}, + {0x1F6F4, 0x1F6F6}, + {0x1F910, 0x1F918}, + {0x1F919, 0x1F91E}, + {0x1F920, 0x1F927}, + {0x1F930, 0x1F930}, + {0x1F933, 0x1F93A}, + {0x1F93C, 0x1F93E}, + {0x1F940, 0x1F945}, + {0x1F947, 0x1F94B}, + {0x1F950, 0x1F95E}, + {0x1F980, 0x1F984}, + {0x1F985, 0x1F991}, + {0x1F9C0, 0x1F9C0}, +}; + +static const struct Interval _pango_Emoji_Presentation_table[] = +{ + {0x231A, 0x231B}, + {0x23E9, 0x23EC}, + {0x23F0, 0x23F0}, + {0x23F3, 0x23F3}, + {0x25FD, 0x25FE}, + {0x2614, 0x2615}, + {0x2648, 0x2653}, + {0x267F, 0x267F}, + {0x2693, 0x2693}, + {0x26A1, 0x26A1}, + {0x26AA, 0x26AB}, + {0x26BD, 0x26BE}, + {0x26C4, 0x26C5}, + {0x26CE, 0x26CE}, + {0x26D4, 0x26D4}, + {0x26EA, 0x26EA}, + {0x26F2, 0x26F3}, + {0x26F5, 0x26F5}, + {0x26FA, 0x26FA}, + {0x26FD, 0x26FD}, + {0x2705, 0x2705}, + {0x270A, 0x270B}, + {0x2728, 0x2728}, + {0x274C, 0x274C}, + {0x274E, 0x274E}, + {0x2753, 0x2755}, + {0x2757, 0x2757}, + {0x2795, 0x2797}, + {0x27B0, 0x27B0}, + {0x27BF, 0x27BF}, + {0x2B1B, 0x2B1C}, + {0x2B50, 0x2B50}, + {0x2B55, 0x2B55}, + {0x1F004, 0x1F004}, + {0x1F0CF, 0x1F0CF}, + {0x1F18E, 0x1F18E}, + {0x1F191, 0x1F19A}, + {0x1F1E6, 0x1F1FF}, + {0x1F201, 0x1F201}, + {0x1F21A, 0x1F21A}, + {0x1F22F, 0x1F22F}, + {0x1F232, 0x1F236}, + {0x1F238, 0x1F23A}, + {0x1F250, 0x1F251}, + {0x1F300, 0x1F320}, + {0x1F32D, 0x1F32F}, + {0x1F330, 0x1F335}, + {0x1F337, 0x1F37C}, + {0x1F37E, 0x1F37F}, + {0x1F380, 0x1F393}, + {0x1F3A0, 0x1F3C4}, + {0x1F3C5, 0x1F3C5}, + {0x1F3C6, 0x1F3CA}, + {0x1F3CF, 0x1F3D3}, + {0x1F3E0, 0x1F3F0}, + {0x1F3F4, 0x1F3F4}, + {0x1F3F8, 0x1F3FF}, + {0x1F400, 0x1F43E}, + {0x1F440, 0x1F440}, + {0x1F442, 0x1F4F7}, + {0x1F4F8, 0x1F4F8}, + {0x1F4F9, 0x1F4FC}, + {0x1F4FF, 0x1F4FF}, + {0x1F500, 0x1F53D}, + {0x1F54B, 0x1F54E}, + {0x1F550, 0x1F567}, + {0x1F57A, 0x1F57A}, + {0x1F595, 0x1F596}, + {0x1F5A4, 0x1F5A4}, + {0x1F5FB, 0x1F5FF}, + {0x1F600, 0x1F600}, + {0x1F601, 0x1F610}, + {0x1F611, 0x1F611}, + {0x1F612, 0x1F614}, + {0x1F615, 0x1F615}, + {0x1F616, 0x1F616}, + {0x1F617, 0x1F617}, + {0x1F618, 0x1F618}, + {0x1F619, 0x1F619}, + {0x1F61A, 0x1F61A}, + {0x1F61B, 0x1F61B}, + {0x1F61C, 0x1F61E}, + {0x1F61F, 0x1F61F}, + {0x1F620, 0x1F625}, + {0x1F626, 0x1F627}, + {0x1F628, 0x1F62B}, + {0x1F62C, 0x1F62C}, + {0x1F62D, 0x1F62D}, + {0x1F62E, 0x1F62F}, + {0x1F630, 0x1F633}, + {0x1F634, 0x1F634}, + {0x1F635, 0x1F640}, + {0x1F641, 0x1F642}, + {0x1F643, 0x1F644}, + {0x1F645, 0x1F64F}, + {0x1F680, 0x1F6C5}, + {0x1F6CC, 0x1F6CC}, + {0x1F6D0, 0x1F6D0}, + {0x1F6D1, 0x1F6D2}, + {0x1F6EB, 0x1F6EC}, + {0x1F6F4, 0x1F6F6}, + {0x1F910, 0x1F918}, + {0x1F919, 0x1F91E}, + {0x1F920, 0x1F927}, + {0x1F930, 0x1F930}, + {0x1F933, 0x1F93A}, + {0x1F93C, 0x1F93E}, + {0x1F940, 0x1F945}, + {0x1F947, 0x1F94B}, + {0x1F950, 0x1F95E}, + {0x1F980, 0x1F984}, + {0x1F985, 0x1F991}, + {0x1F9C0, 0x1F9C0}, +}; + +static const struct Interval _pango_Emoji_Modifier_table[] = +{ + {0x1F3FB, 0x1F3FF}, +}; + +static const struct Interval _pango_Emoji_Modifier_Base_table[] = +{ + {0x261D, 0x261D}, + {0x26F9, 0x26F9}, + {0x270A, 0x270B}, + {0x270C, 0x270D}, + {0x1F385, 0x1F385}, + {0x1F3C3, 0x1F3C4}, + {0x1F3CA, 0x1F3CA}, + {0x1F3CB, 0x1F3CB}, + {0x1F442, 0x1F443}, + {0x1F446, 0x1F450}, + {0x1F466, 0x1F469}, + {0x1F46E, 0x1F46E}, + {0x1F470, 0x1F478}, + {0x1F47C, 0x1F47C}, + {0x1F481, 0x1F483}, + {0x1F485, 0x1F487}, + {0x1F4AA, 0x1F4AA}, + {0x1F575, 0x1F575}, + {0x1F57A, 0x1F57A}, + {0x1F590, 0x1F590}, + {0x1F595, 0x1F596}, + {0x1F645, 0x1F647}, + {0x1F64B, 0x1F64F}, + {0x1F6A3, 0x1F6A3}, + {0x1F6B4, 0x1F6B6}, + {0x1F6C0, 0x1F6C0}, + {0x1F918, 0x1F918}, + {0x1F919, 0x1F91E}, + {0x1F926, 0x1F926}, + {0x1F930, 0x1F930}, + {0x1F933, 0x1F939}, + {0x1F93C, 0x1F93E}, +}; + +#endif /* PANGO_EMOJI_TABLE_H */ + +/* == End of generated table == */ diff --git a/pango/pango-emoji.c b/pango/pango-emoji.c new file mode 100644 index 00000000..630a0e7f --- /dev/null +++ b/pango/pango-emoji.c @@ -0,0 +1,266 @@ +/* Pango + * pango-emoji.c: Emoji handling + * + * Copyright (C) 2017 Google, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Implementation of pango_emoji_iter is derived from Chromium: + * + * https://cs.chromium.org/chromium/src/third_party/WebKit/Source/platform/fonts/FontFallbackPriority.h + * https://cs.chromium.org/chromium/src/third_party/WebKit/Source/platform/text/CharacterEmoji.cpp + * https://cs.chromium.org/chromium/src/third_party/WebKit/Source/platform/fonts/SymbolsIterator.cpp + * + * // Copyright 2015 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. + */ + +#include "config.h" +#include +#include + +#include "pango-emoji-private.h" +#include "pango-emoji-table.h" + + +static int +interval_compare (const void *key, const void *elt) +{ + gunichar c = GPOINTER_TO_UINT (key); + struct Interval *interval = (struct Interval *)elt; + + if (c < interval->start) + return -1; + if (c > interval->end) + return +1; + + return 0; +} + +#define DEFINE_pango_Is_(name) \ +static gboolean \ +_pango_Is_##name (gunichar ch) \ +{ \ + /* bsearch() is declared attribute(nonnull(1)) so we can't validly search \ + * for a NULL key */ \ + /* \ + if (G_UNLIKELY (ch == 0)) \ + return FALSE; \ + */ \ + \ + if (bsearch (GUINT_TO_POINTER (ch), \ + _pango_##name##_table, \ + G_N_ELEMENTS (_pango_##name##_table), \ + sizeof _pango_##name##_table[0], \ + interval_compare)) \ + return TRUE; \ + \ + return FALSE; \ +} + +DEFINE_pango_Is_(Emoji) +DEFINE_pango_Is_(Emoji_Presentation) +DEFINE_pango_Is_(Emoji_Modifier) +DEFINE_pango_Is_(Emoji_Modifier_Base) + + +static gboolean +_pango_Is_Emoji_Text_Default (gunichar ch) +{ + return _pango_Is_Emoji (ch) && !_pango_Is_Emoji_Presentation (ch); +} + +static gboolean +_pango_Is_Emoji_Emoji_Default (gunichar ch) +{ + return _pango_Is_Emoji_Presentation (ch); +} + +static gboolean +_pango_Is_Emoji_Keycap_Base (gunichar ch) +{ + return (ch >= '0' && ch <= '9') || ch == '#' || ch == '*'; +} + +static gboolean +_pango_Is_Regional_Indicator (gunichar ch) +{ + return (ch >= 0x1F1E6 && ch <= 0x1F1FF); +} + + +const gunichar kCombiningEnclosingCircleBackslashCharacter = 0x20E0; +const gunichar kCombiningEnclosingKeycapCharacter = 0x20E3; +const gunichar kEyeCharacter = 0x1F441; +const gunichar kFemaleSignCharacter = 0x2640; +const gunichar kLeftSpeechBubbleCharacter = 0x1F5E8; +const gunichar kMaleSignCharacter = 0x2642; +const gunichar kRainbowCharacter = 0x1F308; +const gunichar kStaffOfAesculapiusCharacter = 0x2695; +const gunichar kVariationSelector15Character = 0xFE0E; +const gunichar kVariationSelector16Character = 0xFE0F; +const gunichar kWavingWhiteFlagCharacter = 0x1F3F3; +const gunichar kZeroWidthJoinerCharacter = 0x200D; + + +typedef enum { + PANGO_EMOJI_TYPE_INVALID, + PANGO_EMOJI_TYPE_TEXT, /* For regular non-symbols text */ + PANGO_EMOJI_TYPE_EMOJI_TEXT, /* For emoji in text presentaiton */ + PANGO_EMOJI_TYPE_EMOJI_EMOJI /* For emoji in emoji presentation */ +} PangoEmojiType; + +static PangoEmojiType +_pango_get_emoji_type (gunichar codepoint) +{ + /* Those should only be Emoji presentation as combinations of two. */ + if (_pango_Is_Emoji_Keycap_Base (codepoint) || + _pango_Is_Regional_Indicator (codepoint)) + return PANGO_EMOJI_TYPE_TEXT; + + if (codepoint == kCombiningEnclosingKeycapCharacter) + return PANGO_EMOJI_TYPE_EMOJI_EMOJI; + + if (_pango_Is_Emoji_Emoji_Default (codepoint) || + _pango_Is_Emoji_Modifier_Base (codepoint) || + _pango_Is_Emoji_Modifier (codepoint)) + return PANGO_EMOJI_TYPE_EMOJI_EMOJI; + + if (_pango_Is_Emoji_Text_Default (codepoint)) + return PANGO_EMOJI_TYPE_EMOJI_TEXT; + + return PANGO_EMOJI_TYPE_TEXT; +} + + +PangoEmojiIter * +_pango_emoji_iter_init (PangoEmojiIter *iter, + const char *text, + int length) +{ + iter->text_start = text; + if (length >= 0) + iter->text_end = text + length; + else + iter->text_end = text + strlen (text); + + iter->start = text; + iter->end = text; + iter->is_emoji = FALSE; + + _pango_emoji_iter_next (iter); + + return iter; +} + +void +_pango_emoji_iter_fini (PangoEmojiIter *iter) +{ +} + +#define PANGO_EMOJI_TYPE_IS_EMOJI(typ) ((typ) == PANGO_EMOJI_TYPE_EMOJI_EMOJI) + +gboolean +_pango_emoji_iter_next (PangoEmojiIter *iter) +{ + PangoEmojiType current_emoji_type = PANGO_EMOJI_TYPE_INVALID; + + if (iter->end == iter->text_end) + return FALSE; + + iter->start = iter->end; + + for (; iter->end < iter->text_end; iter->end = g_utf8_next_char (iter->end)) + { + gunichar ch = g_utf8_get_char (iter->end); + + /* Except at the beginning, ZWJ just carries over the emoji or neutral + * text type, VS15 & VS16 we just carry over as well, since we already + * resolved those through lookahead. Also, don't downgrade to text + * 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) && + ch != kVariationSelector15Character && + ch != kVariationSelector16Character && + ch != kCombiningEnclosingCircleBackslashCharacter && + !_pango_Is_Regional_Indicator(ch) && + !((ch == kLeftSpeechBubbleCharacter || + ch == kRainbowCharacter || + ch == kMaleSignCharacter || + ch == kFemaleSignCharacter || + ch == kStaffOfAesculapiusCharacter) && + iter->is_emoji)) || + current_emoji_type == PANGO_EMOJI_TYPE_INVALID) { + current_emoji_type = _pango_get_emoji_type (ch); + } + + if (iter->end < iter->text_end) + { + gunichar peek_char = g_utf8_get_char (iter->end); + + /* Variation Selectors */ + if (current_emoji_type == + PANGO_EMOJI_TYPE_EMOJI_EMOJI && + peek_char == kVariationSelector15Character) { + current_emoji_type = PANGO_EMOJI_TYPE_EMOJI_TEXT; + } + + if ((current_emoji_type == + PANGO_EMOJI_TYPE_EMOJI_TEXT || + _pango_Is_Emoji_Keycap_Base(ch)) && + peek_char == kVariationSelector16Character) { + current_emoji_type = PANGO_EMOJI_TYPE_EMOJI_EMOJI; + } + + /* Combining characters Keycap... */ + if (_pango_Is_Emoji_Keycap_Base(ch) && + peek_char == kCombiningEnclosingKeycapCharacter) { + current_emoji_type = PANGO_EMOJI_TYPE_EMOJI_EMOJI; + }; + + /* Regional indicators */ + if (_pango_Is_Regional_Indicator(ch) && + _pango_Is_Regional_Indicator(peek_char)) { + current_emoji_type = PANGO_EMOJI_TYPE_EMOJI_EMOJI; + } + + /* Upgrade text presentation emoji to emoji presentation when followed by + * ZWJ, Example U+1F441 U+200D U+1F5E8, eye + ZWJ + left speech bubble. */ + if ((ch == kEyeCharacter || + ch == kWavingWhiteFlagCharacter) && + peek_char == kZeroWidthJoinerCharacter) { + current_emoji_type = PANGO_EMOJI_TYPE_EMOJI_EMOJI; + } + } + + if (iter->is_emoji != PANGO_EMOJI_TYPE_IS_EMOJI (current_emoji_type) && iter->start != iter->text_start) + { + iter->is_emoji = PANGO_EMOJI_TYPE_IS_EMOJI (current_emoji_type); + return TRUE; + } + } + + iter->is_emoji = PANGO_EMOJI_TYPE_IS_EMOJI (current_emoji_type); + + return TRUE; +} + + +/********************************************************** + * End of code from Chromium + **********************************************************/ diff --git a/tools/Makefile.am b/tools/Makefile.am index eb34f31f..83d243f2 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -12,6 +12,7 @@ EXTRA_PROGRAMS = \ EXTRA_DIST= \ gen-color-table.pl \ + gen-emoji-table.py \ rgb.txt gen_script_for_lang_SOURCES = gen-script-for-lang.c diff --git a/tools/gen-emoji-table.py b/tools/gen-emoji-table.py new file mode 100755 index 00000000..600fe80f --- /dev/null +++ b/tools/gen-emoji-table.py @@ -0,0 +1,64 @@ +#!/usr/bin/python + +from __future__ import print_function, division, absolute_import +import sys +import os.path +from collections import OrderedDict + +if len (sys.argv) != 2: + print("usage: ./gen-emoji-table.py emoji-data.txt", file=sys.stderr) + sys.exit (1) + +f = open(sys.argv[1]) +header = [f.readline () for _ in range(10)] + +sets = OrderedDict() +for line in f.readlines(): + line = line.strip() + if not line or line[0] == '#': + continue + rang, typ = [s.strip() for s in line.split('#')[0].split(';')[:2]] + + rang = [int(s, 16) for s in rang.split('..')] + if len(rang) > 1: + start, end = rang + else: + start = end = rang[0] + + if typ not in sets: + sets[typ] = set() + sets[typ].add((start, end)) + + + +print("/* == Start of generated table == */") +print("/*") +print(" * The following tables are generated by running:") +print(" *") +print(" * ./gen-emoji-table.py emoji-data.txt") +print(" *") +print(" * on file with this header:") +print(" *") +for l in header: + print(" * %s" % (l.strip())) +print(" */") +print() +print("#ifndef PANGO_EMOJI_TABLE_H") +print("#define PANGO_EMOJI_TABLE_H") +print() +print("#include ") +print() +print("struct Interval {\n gunichar start, end;\n};") + +for typ,s in sets.items(): + print() + print("static const struct Interval _pango_%s_table[] =" % typ) + print("{") + for pair in sorted(s): + print(" {0x%04X, 0x%04X}," % pair) + print("};") + +print() +print("#endif /* PANGO_EMOJI_TABLE_H */") +print() +print("/* == End of generated table == */") -- cgit v1.2.1