1d94647e2cd187bf4a4c8fb1c0c15c3d23c1293acBehdad Esfahbod/* 22409d5f8d7dd8b535ce5ea29e933f7db27d33793Behdad Esfahbod * Copyright © 2009 Red Hat, Inc. 32409d5f8d7dd8b535ce5ea29e933f7db27d33793Behdad Esfahbod * Copyright © 2009 Keith Stribley 42409d5f8d7dd8b535ce5ea29e933f7db27d33793Behdad Esfahbod * Copyright © 2011 Google, Inc. 5d94647e2cd187bf4a4c8fb1c0c15c3d23c1293acBehdad Esfahbod * 6c755cb3e3ac55156d0d2ec05adea7a650b97cc41Behdad Esfahbod * This is part of HarfBuzz, a text shaping library. 7d94647e2cd187bf4a4c8fb1c0c15c3d23c1293acBehdad Esfahbod * 8d94647e2cd187bf4a4c8fb1c0c15c3d23c1293acBehdad Esfahbod * Permission is hereby granted, without written agreement and without 9d94647e2cd187bf4a4c8fb1c0c15c3d23c1293acBehdad Esfahbod * license or royalty fees, to use, copy, modify, and distribute this 10d94647e2cd187bf4a4c8fb1c0c15c3d23c1293acBehdad Esfahbod * software and its documentation for any purpose, provided that the 11d94647e2cd187bf4a4c8fb1c0c15c3d23c1293acBehdad Esfahbod * above copyright notice and the following two paragraphs appear in 12d94647e2cd187bf4a4c8fb1c0c15c3d23c1293acBehdad Esfahbod * all copies of this software. 13d94647e2cd187bf4a4c8fb1c0c15c3d23c1293acBehdad Esfahbod * 14d94647e2cd187bf4a4c8fb1c0c15c3d23c1293acBehdad Esfahbod * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR 15d94647e2cd187bf4a4c8fb1c0c15c3d23c1293acBehdad Esfahbod * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 16d94647e2cd187bf4a4c8fb1c0c15c3d23c1293acBehdad Esfahbod * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN 17d94647e2cd187bf4a4c8fb1c0c15c3d23c1293acBehdad Esfahbod * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 18d94647e2cd187bf4a4c8fb1c0c15c3d23c1293acBehdad Esfahbod * DAMAGE. 19d94647e2cd187bf4a4c8fb1c0c15c3d23c1293acBehdad Esfahbod * 20d94647e2cd187bf4a4c8fb1c0c15c3d23c1293acBehdad Esfahbod * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, 21d94647e2cd187bf4a4c8fb1c0c15c3d23c1293acBehdad Esfahbod * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 22d94647e2cd187bf4a4c8fb1c0c15c3d23c1293acBehdad Esfahbod * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 23d94647e2cd187bf4a4c8fb1c0c15c3d23c1293acBehdad Esfahbod * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO 24d94647e2cd187bf4a4c8fb1c0c15c3d23c1293acBehdad Esfahbod * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 25d94647e2cd187bf4a4c8fb1c0c15c3d23c1293acBehdad Esfahbod * 26d94647e2cd187bf4a4c8fb1c0c15c3d23c1293acBehdad Esfahbod * Red Hat Author(s): Behdad Esfahbod 272409d5f8d7dd8b535ce5ea29e933f7db27d33793Behdad Esfahbod * Google Author(s): Behdad Esfahbod 28d94647e2cd187bf4a4c8fb1c0c15c3d23c1293acBehdad Esfahbod */ 29d94647e2cd187bf4a4c8fb1c0c15c3d23c1293acBehdad Esfahbod 30c57d454accff66e5f2c58006e8fb40bc020b6182Behdad Esfahbod#include "hb-private.hh" 31d94647e2cd187bf4a4c8fb1c0c15c3d23c1293acBehdad Esfahbod 32d94647e2cd187bf4a4c8fb1c0c15c3d23c1293acBehdad Esfahbod#include "hb-icu.h" 33d94647e2cd187bf4a4c8fb1c0c15c3d23c1293acBehdad Esfahbod 34fb194b8794898f51eb596fa4092c26606889d376Behdad Esfahbod#include "hb-unicode-private.hh" 35d94647e2cd187bf4a4c8fb1c0c15c3d23c1293acBehdad Esfahbod 36d94647e2cd187bf4a4c8fb1c0c15c3d23c1293acBehdad Esfahbod#include <unicode/uchar.h> 37498e1a9be673bb02c00aac3f12bb4c6993a85910Behdad Esfahbod#include <unicode/unorm.h> 3836a4f4a482456ee816dcb59befa0b0538ba487dfBehdad Esfahbod#include <unicode/ustring.h> 394ac4c6f2e12ddc8bf5e750671321458218b6e0c8Behdad Esfahbod#include <unicode/uversion.h> 40acdba3f90b232fc12fcb200dca2584481b339118Behdad Esfahbod 41acdba3f90b232fc12fcb200dca2584481b339118Behdad Esfahbod 42f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbodhb_script_t 43f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbodhb_icu_script_to_script (UScriptCode script) 44d94647e2cd187bf4a4c8fb1c0c15c3d23c1293acBehdad Esfahbod{ 454d559cddbb3b3a5c12c5167eba69598618a9f283Behdad Esfahbod if (unlikely (script == USCRIPT_INVALID_CODE)) 464d559cddbb3b3a5c12c5167eba69598618a9f283Behdad Esfahbod return HB_SCRIPT_INVALID; 474d559cddbb3b3a5c12c5167eba69598618a9f283Behdad Esfahbod 484c9fe88d30036340fe592bcbc375049b84602b8bBehdad Esfahbod return hb_script_from_string (uscript_getShortName (script), -1); 49d94647e2cd187bf4a4c8fb1c0c15c3d23c1293acBehdad Esfahbod} 50d94647e2cd187bf4a4c8fb1c0c15c3d23c1293acBehdad Esfahbod 51f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad EsfahbodUScriptCode 52f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbodhb_icu_script_from_script (hb_script_t script) 53d94647e2cd187bf4a4c8fb1c0c15c3d23c1293acBehdad Esfahbod{ 544d559cddbb3b3a5c12c5167eba69598618a9f283Behdad Esfahbod if (unlikely (script == HB_SCRIPT_INVALID)) 554d559cddbb3b3a5c12c5167eba69598618a9f283Behdad Esfahbod return USCRIPT_INVALID_CODE; 56afab01cf7caca79cf6dfabe6827d1703be1a74f7Behdad Esfahbod 574d559cddbb3b3a5c12c5167eba69598618a9f283Behdad Esfahbod for (unsigned int i = 0; i < USCRIPT_CODE_LIMIT; i++) 584d559cddbb3b3a5c12c5167eba69598618a9f283Behdad Esfahbod if (unlikely (hb_icu_script_to_script ((UScriptCode) i) == script)) 594d559cddbb3b3a5c12c5167eba69598618a9f283Behdad Esfahbod return (UScriptCode) i; 602fd0c577e322ccbf762927bc4600b3ea31db4c80Ryan Lortie 61f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbod return USCRIPT_UNKNOWN; 62f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbod} 63f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbod 64f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbod 6521fdcee00125b6e1c09f0bed3064d16ccd3a7a5dBehdad Esfahbodstatic hb_unicode_combining_class_t 66fca0923b04aeff9369849da97d247a647611f346Behdad Esfahbodhb_icu_unicode_combining_class (hb_unicode_funcs_t *ufuncs HB_UNUSED, 67fca0923b04aeff9369849da97d247a647611f346Behdad Esfahbod hb_codepoint_t unicode, 68fca0923b04aeff9369849da97d247a647611f346Behdad Esfahbod void *user_data HB_UNUSED) 69f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbod 70f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbod{ 7121fdcee00125b6e1c09f0bed3064d16ccd3a7a5dBehdad Esfahbod return (hb_unicode_combining_class_t) u_getCombiningClass (unicode); 72f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbod} 73f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbod 74f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbodstatic unsigned int 75fca0923b04aeff9369849da97d247a647611f346Behdad Esfahbodhb_icu_unicode_eastasian_width (hb_unicode_funcs_t *ufuncs HB_UNUSED, 76fca0923b04aeff9369849da97d247a647611f346Behdad Esfahbod hb_codepoint_t unicode, 77fca0923b04aeff9369849da97d247a647611f346Behdad Esfahbod void *user_data HB_UNUSED) 78f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbod{ 79f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbod switch (u_getIntPropertyValue(unicode, UCHAR_EAST_ASIAN_WIDTH)) 80f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbod { 81f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbod case U_EA_WIDE: 82f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbod case U_EA_FULLWIDTH: 83f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbod return 2; 84f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbod case U_EA_NEUTRAL: 85f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbod case U_EA_AMBIGUOUS: 86f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbod case U_EA_HALFWIDTH: 87f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbod case U_EA_NARROW: 88f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbod return 1; 89f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbod } 90f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbod return 1; 91f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbod} 92f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbod 93f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbodstatic hb_unicode_general_category_t 94fca0923b04aeff9369849da97d247a647611f346Behdad Esfahbodhb_icu_unicode_general_category (hb_unicode_funcs_t *ufuncs HB_UNUSED, 95fca0923b04aeff9369849da97d247a647611f346Behdad Esfahbod hb_codepoint_t unicode, 96fca0923b04aeff9369849da97d247a647611f346Behdad Esfahbod void *user_data HB_UNUSED) 97f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbod{ 98f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbod switch (u_getIntPropertyValue(unicode, UCHAR_GENERAL_CATEGORY)) 99f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbod { 100f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbod case U_UNASSIGNED: return HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED; 101f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbod 102f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbod case U_UPPERCASE_LETTER: return HB_UNICODE_GENERAL_CATEGORY_UPPERCASE_LETTER; 103f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbod case U_LOWERCASE_LETTER: return HB_UNICODE_GENERAL_CATEGORY_LOWERCASE_LETTER; 104f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbod case U_TITLECASE_LETTER: return HB_UNICODE_GENERAL_CATEGORY_TITLECASE_LETTER; 105f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbod case U_MODIFIER_LETTER: return HB_UNICODE_GENERAL_CATEGORY_MODIFIER_LETTER; 106f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbod case U_OTHER_LETTER: return HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER; 107f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbod 108f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbod case U_NON_SPACING_MARK: return HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK; 109f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbod case U_ENCLOSING_MARK: return HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK; 1105157e12a55f943b7fc5be7dce0b2ee1bcacca6ecBehdad Esfahbod case U_COMBINING_SPACING_MARK: return HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK; 111f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbod 112f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbod case U_DECIMAL_DIGIT_NUMBER: return HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER; 113f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbod case U_LETTER_NUMBER: return HB_UNICODE_GENERAL_CATEGORY_LETTER_NUMBER; 114f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbod case U_OTHER_NUMBER: return HB_UNICODE_GENERAL_CATEGORY_OTHER_NUMBER; 115f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbod 116f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbod case U_SPACE_SEPARATOR: return HB_UNICODE_GENERAL_CATEGORY_SPACE_SEPARATOR; 117f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbod case U_LINE_SEPARATOR: return HB_UNICODE_GENERAL_CATEGORY_LINE_SEPARATOR; 118f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbod case U_PARAGRAPH_SEPARATOR: return HB_UNICODE_GENERAL_CATEGORY_PARAGRAPH_SEPARATOR; 119f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbod 120f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbod case U_CONTROL_CHAR: return HB_UNICODE_GENERAL_CATEGORY_CONTROL; 121f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbod case U_FORMAT_CHAR: return HB_UNICODE_GENERAL_CATEGORY_FORMAT; 122f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbod case U_PRIVATE_USE_CHAR: return HB_UNICODE_GENERAL_CATEGORY_PRIVATE_USE; 123f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbod case U_SURROGATE: return HB_UNICODE_GENERAL_CATEGORY_SURROGATE; 124f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbod 125f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbod 126f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbod case U_DASH_PUNCTUATION: return HB_UNICODE_GENERAL_CATEGORY_DASH_PUNCTUATION; 127f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbod case U_START_PUNCTUATION: return HB_UNICODE_GENERAL_CATEGORY_OPEN_PUNCTUATION; 128f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbod case U_END_PUNCTUATION: return HB_UNICODE_GENERAL_CATEGORY_CLOSE_PUNCTUATION; 129f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbod case U_CONNECTOR_PUNCTUATION: return HB_UNICODE_GENERAL_CATEGORY_CONNECT_PUNCTUATION; 130f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbod case U_OTHER_PUNCTUATION: return HB_UNICODE_GENERAL_CATEGORY_OTHER_PUNCTUATION; 131f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbod 132f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbod case U_MATH_SYMBOL: return HB_UNICODE_GENERAL_CATEGORY_MATH_SYMBOL; 133f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbod case U_CURRENCY_SYMBOL: return HB_UNICODE_GENERAL_CATEGORY_CURRENCY_SYMBOL; 134f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbod case U_MODIFIER_SYMBOL: return HB_UNICODE_GENERAL_CATEGORY_MODIFIER_SYMBOL; 135f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbod case U_OTHER_SYMBOL: return HB_UNICODE_GENERAL_CATEGORY_OTHER_SYMBOL; 136f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbod 137f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbod case U_INITIAL_PUNCTUATION: return HB_UNICODE_GENERAL_CATEGORY_INITIAL_PUNCTUATION; 138f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbod case U_FINAL_PUNCTUATION: return HB_UNICODE_GENERAL_CATEGORY_FINAL_PUNCTUATION; 139f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbod } 140f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbod 141f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbod return HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED; 142f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbod} 143f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbod 144f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbodstatic hb_codepoint_t 145fca0923b04aeff9369849da97d247a647611f346Behdad Esfahbodhb_icu_unicode_mirroring (hb_unicode_funcs_t *ufuncs HB_UNUSED, 146fca0923b04aeff9369849da97d247a647611f346Behdad Esfahbod hb_codepoint_t unicode, 147fca0923b04aeff9369849da97d247a647611f346Behdad Esfahbod void *user_data HB_UNUSED) 148f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbod{ 149f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbod return u_charMirror(unicode); 150f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbod} 151f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbod 152f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbodstatic hb_script_t 153fca0923b04aeff9369849da97d247a647611f346Behdad Esfahbodhb_icu_unicode_script (hb_unicode_funcs_t *ufuncs HB_UNUSED, 154fca0923b04aeff9369849da97d247a647611f346Behdad Esfahbod hb_codepoint_t unicode, 155fca0923b04aeff9369849da97d247a647611f346Behdad Esfahbod void *user_data HB_UNUSED) 156f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbod{ 157f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbod UErrorCode status = U_ZERO_ERROR; 158f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbod UScriptCode scriptCode = uscript_getScript(unicode, &status); 159f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbod 160889caa52fa1bef61013ec1d127f84d7d5907ef1eBehdad Esfahbod if (unlikely (U_FAILURE (status))) 16103034acb8a9fdd33135bc3775a1f932da9ebdd42Behdad Esfahbod return HB_SCRIPT_UNKNOWN; 16203034acb8a9fdd33135bc3775a1f932da9ebdd42Behdad Esfahbod 163f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbod return hb_icu_script_to_script (scriptCode); 164d94647e2cd187bf4a4c8fb1c0c15c3d23c1293acBehdad Esfahbod} 165d94647e2cd187bf4a4c8fb1c0c15c3d23c1293acBehdad Esfahbod 166d5045a5f4017631a4660f985fe451c5a64c42ca0Behdad Esfahbod#if U_ICU_VERSION_MAJOR_NUM >= 49 167d5045a5f4017631a4660f985fe451c5a64c42ca0Behdad Esfahbodstatic const UNormalizer2 *normalizer; 168d5045a5f4017631a4660f985fe451c5a64c42ca0Behdad Esfahbod#endif 169d5045a5f4017631a4660f985fe451c5a64c42ca0Behdad Esfahbod 170fca0923b04aeff9369849da97d247a647611f346Behdad Esfahbodstatic hb_bool_t 171fca0923b04aeff9369849da97d247a647611f346Behdad Esfahbodhb_icu_unicode_compose (hb_unicode_funcs_t *ufuncs HB_UNUSED, 172fca0923b04aeff9369849da97d247a647611f346Behdad Esfahbod hb_codepoint_t a, 173fca0923b04aeff9369849da97d247a647611f346Behdad Esfahbod hb_codepoint_t b, 174fca0923b04aeff9369849da97d247a647611f346Behdad Esfahbod hb_codepoint_t *ab, 175fca0923b04aeff9369849da97d247a647611f346Behdad Esfahbod void *user_data HB_UNUSED) 176fca0923b04aeff9369849da97d247a647611f346Behdad Esfahbod{ 177d5045a5f4017631a4660f985fe451c5a64c42ca0Behdad Esfahbod#if U_ICU_VERSION_MAJOR_NUM >= 49 178d5045a5f4017631a4660f985fe451c5a64c42ca0Behdad Esfahbod { 179d5045a5f4017631a4660f985fe451c5a64c42ca0Behdad Esfahbod UChar32 ret = unorm2_composePair (normalizer, a, b); 180d5045a5f4017631a4660f985fe451c5a64c42ca0Behdad Esfahbod if (ret < 0) return false; 181d5045a5f4017631a4660f985fe451c5a64c42ca0Behdad Esfahbod *ab = ret; 182d5045a5f4017631a4660f985fe451c5a64c42ca0Behdad Esfahbod return true; 183d5045a5f4017631a4660f985fe451c5a64c42ca0Behdad Esfahbod } 184d5045a5f4017631a4660f985fe451c5a64c42ca0Behdad Esfahbod#endif 185d5045a5f4017631a4660f985fe451c5a64c42ca0Behdad Esfahbod 186d5045a5f4017631a4660f985fe451c5a64c42ca0Behdad Esfahbod /* We don't ifdef-out the fallback code such that compiler always 187d5045a5f4017631a4660f985fe451c5a64c42ca0Behdad Esfahbod * sees it and makes sure it's compilable. */ 188498e1a9be673bb02c00aac3f12bb4c6993a85910Behdad Esfahbod 189498e1a9be673bb02c00aac3f12bb4c6993a85910Behdad Esfahbod UChar utf16[4], normalized[5]; 190b1914b8bd08ecdea79930dda7e3bb2ae9e6134a1Behdad Esfahbod unsigned int len; 191498e1a9be673bb02c00aac3f12bb4c6993a85910Behdad Esfahbod hb_bool_t ret, err; 192498e1a9be673bb02c00aac3f12bb4c6993a85910Behdad Esfahbod UErrorCode icu_err; 193498e1a9be673bb02c00aac3f12bb4c6993a85910Behdad Esfahbod 194498e1a9be673bb02c00aac3f12bb4c6993a85910Behdad Esfahbod len = 0; 1950594a2448440208efa0acac9a5d8d52d43108289Behdad Esfahbod err = false; 196498e1a9be673bb02c00aac3f12bb4c6993a85910Behdad Esfahbod U16_APPEND (utf16, len, ARRAY_LENGTH (utf16), a, err); 1970594a2448440208efa0acac9a5d8d52d43108289Behdad Esfahbod if (err) return false; 198498e1a9be673bb02c00aac3f12bb4c6993a85910Behdad Esfahbod U16_APPEND (utf16, len, ARRAY_LENGTH (utf16), b, err); 1990594a2448440208efa0acac9a5d8d52d43108289Behdad Esfahbod if (err) return false; 200498e1a9be673bb02c00aac3f12bb4c6993a85910Behdad Esfahbod 201498e1a9be673bb02c00aac3f12bb4c6993a85910Behdad Esfahbod icu_err = U_ZERO_ERROR; 202498e1a9be673bb02c00aac3f12bb4c6993a85910Behdad Esfahbod len = unorm_normalize (utf16, len, UNORM_NFC, 0, normalized, ARRAY_LENGTH (normalized), &icu_err); 203889caa52fa1bef61013ec1d127f84d7d5907ef1eBehdad Esfahbod if (U_FAILURE (icu_err)) 2040594a2448440208efa0acac9a5d8d52d43108289Behdad Esfahbod return false; 20536a4f4a482456ee816dcb59befa0b0538ba487dfBehdad Esfahbod if (u_countChar32 (normalized, len) == 1) { 206498e1a9be673bb02c00aac3f12bb4c6993a85910Behdad Esfahbod U16_GET_UNSAFE (normalized, 0, *ab); 2070594a2448440208efa0acac9a5d8d52d43108289Behdad Esfahbod ret = true; 208498e1a9be673bb02c00aac3f12bb4c6993a85910Behdad Esfahbod } else { 2090594a2448440208efa0acac9a5d8d52d43108289Behdad Esfahbod ret = false; 210498e1a9be673bb02c00aac3f12bb4c6993a85910Behdad Esfahbod } 211498e1a9be673bb02c00aac3f12bb4c6993a85910Behdad Esfahbod 212498e1a9be673bb02c00aac3f12bb4c6993a85910Behdad Esfahbod return ret; 213fca0923b04aeff9369849da97d247a647611f346Behdad Esfahbod} 214fca0923b04aeff9369849da97d247a647611f346Behdad Esfahbod 215fca0923b04aeff9369849da97d247a647611f346Behdad Esfahbodstatic hb_bool_t 216fca0923b04aeff9369849da97d247a647611f346Behdad Esfahbodhb_icu_unicode_decompose (hb_unicode_funcs_t *ufuncs HB_UNUSED, 217fca0923b04aeff9369849da97d247a647611f346Behdad Esfahbod hb_codepoint_t ab, 218fca0923b04aeff9369849da97d247a647611f346Behdad Esfahbod hb_codepoint_t *a, 219fca0923b04aeff9369849da97d247a647611f346Behdad Esfahbod hb_codepoint_t *b, 220fca0923b04aeff9369849da97d247a647611f346Behdad Esfahbod void *user_data HB_UNUSED) 221fca0923b04aeff9369849da97d247a647611f346Behdad Esfahbod{ 222d5045a5f4017631a4660f985fe451c5a64c42ca0Behdad Esfahbod#if U_ICU_VERSION_MAJOR_NUM >= 49 223d5045a5f4017631a4660f985fe451c5a64c42ca0Behdad Esfahbod { 224d5045a5f4017631a4660f985fe451c5a64c42ca0Behdad Esfahbod UChar decomposed[4]; 225d5045a5f4017631a4660f985fe451c5a64c42ca0Behdad Esfahbod int len; 226d5045a5f4017631a4660f985fe451c5a64c42ca0Behdad Esfahbod UErrorCode icu_err = U_ZERO_ERROR; 227d5045a5f4017631a4660f985fe451c5a64c42ca0Behdad Esfahbod len = unorm2_getRawDecomposition (normalizer, ab, decomposed, 228d5045a5f4017631a4660f985fe451c5a64c42ca0Behdad Esfahbod ARRAY_LENGTH (decomposed), &icu_err); 229d5045a5f4017631a4660f985fe451c5a64c42ca0Behdad Esfahbod if (U_FAILURE (icu_err) || len < 0) return false; 230d5045a5f4017631a4660f985fe451c5a64c42ca0Behdad Esfahbod 231d5045a5f4017631a4660f985fe451c5a64c42ca0Behdad Esfahbod len = u_countChar32 (decomposed, len); 232d5045a5f4017631a4660f985fe451c5a64c42ca0Behdad Esfahbod if (len == 1) { 233d5045a5f4017631a4660f985fe451c5a64c42ca0Behdad Esfahbod U16_GET_UNSAFE (decomposed, 0, *a); 234d5045a5f4017631a4660f985fe451c5a64c42ca0Behdad Esfahbod *b = 0; 235d5045a5f4017631a4660f985fe451c5a64c42ca0Behdad Esfahbod return *a != ab; 236d5045a5f4017631a4660f985fe451c5a64c42ca0Behdad Esfahbod } else if (len == 2) { 237d5045a5f4017631a4660f985fe451c5a64c42ca0Behdad Esfahbod len =0; 238d5045a5f4017631a4660f985fe451c5a64c42ca0Behdad Esfahbod U16_NEXT_UNSAFE (decomposed, len, *a); 239d5045a5f4017631a4660f985fe451c5a64c42ca0Behdad Esfahbod U16_NEXT_UNSAFE (decomposed, len, *b); 240d5045a5f4017631a4660f985fe451c5a64c42ca0Behdad Esfahbod } 241d5045a5f4017631a4660f985fe451c5a64c42ca0Behdad Esfahbod return true; 242d5045a5f4017631a4660f985fe451c5a64c42ca0Behdad Esfahbod } 243d5045a5f4017631a4660f985fe451c5a64c42ca0Behdad Esfahbod#endif 244d5045a5f4017631a4660f985fe451c5a64c42ca0Behdad Esfahbod 245d5045a5f4017631a4660f985fe451c5a64c42ca0Behdad Esfahbod /* We don't ifdef-out the fallback code such that compiler always 246d5045a5f4017631a4660f985fe451c5a64c42ca0Behdad Esfahbod * sees it and makes sure it's compilable. */ 247d5045a5f4017631a4660f985fe451c5a64c42ca0Behdad Esfahbod 248378d279bbf692195c4654e312dae854ab3be04cfBehdad Esfahbod UChar utf16[2], normalized[2 * HB_UNICODE_MAX_DECOMPOSITION_LEN + 1]; 249b1914b8bd08ecdea79930dda7e3bb2ae9e6134a1Behdad Esfahbod unsigned int len; 250498e1a9be673bb02c00aac3f12bb4c6993a85910Behdad Esfahbod hb_bool_t ret, err; 251498e1a9be673bb02c00aac3f12bb4c6993a85910Behdad Esfahbod UErrorCode icu_err; 252498e1a9be673bb02c00aac3f12bb4c6993a85910Behdad Esfahbod 25363c0ef4a0763e579c9c80887bbfbd2651de05067Behdad Esfahbod /* This function is a monster! Maybe it wasn't a good idea adding a 25463c0ef4a0763e579c9c80887bbfbd2651de05067Behdad Esfahbod * pairwise decompose API... */ 25563c0ef4a0763e579c9c80887bbfbd2651de05067Behdad Esfahbod /* Watchout for the dragons. Err, watchout for macros changing len. */ 25663c0ef4a0763e579c9c80887bbfbd2651de05067Behdad Esfahbod 257498e1a9be673bb02c00aac3f12bb4c6993a85910Behdad Esfahbod len = 0; 2580594a2448440208efa0acac9a5d8d52d43108289Behdad Esfahbod err = false; 259498e1a9be673bb02c00aac3f12bb4c6993a85910Behdad Esfahbod U16_APPEND (utf16, len, ARRAY_LENGTH (utf16), ab, err); 2600594a2448440208efa0acac9a5d8d52d43108289Behdad Esfahbod if (err) return false; 261498e1a9be673bb02c00aac3f12bb4c6993a85910Behdad Esfahbod 262498e1a9be673bb02c00aac3f12bb4c6993a85910Behdad Esfahbod icu_err = U_ZERO_ERROR; 263498e1a9be673bb02c00aac3f12bb4c6993a85910Behdad Esfahbod len = unorm_normalize (utf16, len, UNORM_NFD, 0, normalized, ARRAY_LENGTH (normalized), &icu_err); 264889caa52fa1bef61013ec1d127f84d7d5907ef1eBehdad Esfahbod if (U_FAILURE (icu_err)) 2650594a2448440208efa0acac9a5d8d52d43108289Behdad Esfahbod return false; 266498e1a9be673bb02c00aac3f12bb4c6993a85910Behdad Esfahbod 26736a4f4a482456ee816dcb59befa0b0538ba487dfBehdad Esfahbod len = u_countChar32 (normalized, len); 268498e1a9be673bb02c00aac3f12bb4c6993a85910Behdad Esfahbod 269498e1a9be673bb02c00aac3f12bb4c6993a85910Behdad Esfahbod if (len == 1) { 270498e1a9be673bb02c00aac3f12bb4c6993a85910Behdad Esfahbod U16_GET_UNSAFE (normalized, 0, *a); 271498e1a9be673bb02c00aac3f12bb4c6993a85910Behdad Esfahbod *b = 0; 272498e1a9be673bb02c00aac3f12bb4c6993a85910Behdad Esfahbod ret = *a != ab; 273498e1a9be673bb02c00aac3f12bb4c6993a85910Behdad Esfahbod } else if (len == 2) { 27463c0ef4a0763e579c9c80887bbfbd2651de05067Behdad Esfahbod len =0; 27563c0ef4a0763e579c9c80887bbfbd2651de05067Behdad Esfahbod U16_NEXT_UNSAFE (normalized, len, *a); 27663c0ef4a0763e579c9c80887bbfbd2651de05067Behdad Esfahbod U16_NEXT_UNSAFE (normalized, len, *b); 27763c0ef4a0763e579c9c80887bbfbd2651de05067Behdad Esfahbod 278498e1a9be673bb02c00aac3f12bb4c6993a85910Behdad Esfahbod /* Here's the ugly part: if ab decomposes to a single character and 279498e1a9be673bb02c00aac3f12bb4c6993a85910Behdad Esfahbod * that character decomposes again, we have to detect that and undo 280498e1a9be673bb02c00aac3f12bb4c6993a85910Behdad Esfahbod * the second part :-(. */ 281498e1a9be673bb02c00aac3f12bb4c6993a85910Behdad Esfahbod UChar recomposed[20]; 282498e1a9be673bb02c00aac3f12bb4c6993a85910Behdad Esfahbod icu_err = U_ZERO_ERROR; 28363c0ef4a0763e579c9c80887bbfbd2651de05067Behdad Esfahbod unorm_normalize (normalized, len, UNORM_NFC, 0, recomposed, ARRAY_LENGTH (recomposed), &icu_err); 284889caa52fa1bef61013ec1d127f84d7d5907ef1eBehdad Esfahbod if (U_FAILURE (icu_err)) 2850594a2448440208efa0acac9a5d8d52d43108289Behdad Esfahbod return false; 28663c0ef4a0763e579c9c80887bbfbd2651de05067Behdad Esfahbod hb_codepoint_t c; 28763c0ef4a0763e579c9c80887bbfbd2651de05067Behdad Esfahbod U16_GET_UNSAFE (recomposed, 0, c); 28863c0ef4a0763e579c9c80887bbfbd2651de05067Behdad Esfahbod if (c != *a && c != ab) { 28963c0ef4a0763e579c9c80887bbfbd2651de05067Behdad Esfahbod *a = c; 290498e1a9be673bb02c00aac3f12bb4c6993a85910Behdad Esfahbod *b = 0; 291498e1a9be673bb02c00aac3f12bb4c6993a85910Behdad Esfahbod } 2920594a2448440208efa0acac9a5d8d52d43108289Behdad Esfahbod ret = true; 293498e1a9be673bb02c00aac3f12bb4c6993a85910Behdad Esfahbod } else { 294498e1a9be673bb02c00aac3f12bb4c6993a85910Behdad Esfahbod /* If decomposed to more than two characters, take the last one, 295498e1a9be673bb02c00aac3f12bb4c6993a85910Behdad Esfahbod * and recompose the rest to get the first component. */ 296a18280a8ce9128fc9d75f8a367ae8ce0886a9599Behdad Esfahbod U16_PREV_UNSAFE (normalized, len, *b); /* Changes len in-place. */ 297a18280a8ce9128fc9d75f8a367ae8ce0886a9599Behdad Esfahbod UChar recomposed[18 * 2]; 298498e1a9be673bb02c00aac3f12bb4c6993a85910Behdad Esfahbod icu_err = U_ZERO_ERROR; 299498e1a9be673bb02c00aac3f12bb4c6993a85910Behdad Esfahbod len = unorm_normalize (normalized, len, UNORM_NFC, 0, recomposed, ARRAY_LENGTH (recomposed), &icu_err); 300889caa52fa1bef61013ec1d127f84d7d5907ef1eBehdad Esfahbod if (U_FAILURE (icu_err)) 3010594a2448440208efa0acac9a5d8d52d43108289Behdad Esfahbod return false; 302498e1a9be673bb02c00aac3f12bb4c6993a85910Behdad Esfahbod /* We expect that recomposed has exactly one character now. */ 303a18280a8ce9128fc9d75f8a367ae8ce0886a9599Behdad Esfahbod if (unlikely (u_countChar32 (recomposed, len) != 1)) 304a18280a8ce9128fc9d75f8a367ae8ce0886a9599Behdad Esfahbod return false; 305498e1a9be673bb02c00aac3f12bb4c6993a85910Behdad Esfahbod U16_GET_UNSAFE (recomposed, 0, *a); 3060594a2448440208efa0acac9a5d8d52d43108289Behdad Esfahbod ret = true; 307498e1a9be673bb02c00aac3f12bb4c6993a85910Behdad Esfahbod } 308498e1a9be673bb02c00aac3f12bb4c6993a85910Behdad Esfahbod 309498e1a9be673bb02c00aac3f12bb4c6993a85910Behdad Esfahbod return ret; 310fca0923b04aeff9369849da97d247a647611f346Behdad Esfahbod} 311fca0923b04aeff9369849da97d247a647611f346Behdad Esfahbod 312378d279bbf692195c4654e312dae854ab3be04cfBehdad Esfahbodstatic unsigned int 313378d279bbf692195c4654e312dae854ab3be04cfBehdad Esfahbodhb_icu_unicode_decompose_compatibility (hb_unicode_funcs_t *ufuncs HB_UNUSED, 314378d279bbf692195c4654e312dae854ab3be04cfBehdad Esfahbod hb_codepoint_t u, 315378d279bbf692195c4654e312dae854ab3be04cfBehdad Esfahbod hb_codepoint_t *decomposed, 316378d279bbf692195c4654e312dae854ab3be04cfBehdad Esfahbod void *user_data HB_UNUSED) 317378d279bbf692195c4654e312dae854ab3be04cfBehdad Esfahbod{ 318378d279bbf692195c4654e312dae854ab3be04cfBehdad Esfahbod UChar utf16[2], normalized[2 * HB_UNICODE_MAX_DECOMPOSITION_LEN + 1]; 319b1914b8bd08ecdea79930dda7e3bb2ae9e6134a1Behdad Esfahbod unsigned int len; 320378d279bbf692195c4654e312dae854ab3be04cfBehdad Esfahbod int32_t utf32_len; 321378d279bbf692195c4654e312dae854ab3be04cfBehdad Esfahbod hb_bool_t err; 322378d279bbf692195c4654e312dae854ab3be04cfBehdad Esfahbod UErrorCode icu_err; 323378d279bbf692195c4654e312dae854ab3be04cfBehdad Esfahbod 324378d279bbf692195c4654e312dae854ab3be04cfBehdad Esfahbod /* Copy @u into a UTF-16 array to be passed to ICU. */ 325378d279bbf692195c4654e312dae854ab3be04cfBehdad Esfahbod len = 0; 326378d279bbf692195c4654e312dae854ab3be04cfBehdad Esfahbod err = FALSE; 327378d279bbf692195c4654e312dae854ab3be04cfBehdad Esfahbod U16_APPEND (utf16, len, ARRAY_LENGTH (utf16), u, err); 328378d279bbf692195c4654e312dae854ab3be04cfBehdad Esfahbod if (err) 329378d279bbf692195c4654e312dae854ab3be04cfBehdad Esfahbod return 0; 330378d279bbf692195c4654e312dae854ab3be04cfBehdad Esfahbod 331378d279bbf692195c4654e312dae854ab3be04cfBehdad Esfahbod /* Normalise the codepoint using NFKD mode. */ 332378d279bbf692195c4654e312dae854ab3be04cfBehdad Esfahbod icu_err = U_ZERO_ERROR; 333378d279bbf692195c4654e312dae854ab3be04cfBehdad Esfahbod len = unorm_normalize (utf16, len, UNORM_NFKD, 0, normalized, ARRAY_LENGTH (normalized), &icu_err); 334378d279bbf692195c4654e312dae854ab3be04cfBehdad Esfahbod if (icu_err) 335378d279bbf692195c4654e312dae854ab3be04cfBehdad Esfahbod return 0; 336378d279bbf692195c4654e312dae854ab3be04cfBehdad Esfahbod 337378d279bbf692195c4654e312dae854ab3be04cfBehdad Esfahbod /* Convert the decomposed form from UTF-16 to UTF-32. */ 338378d279bbf692195c4654e312dae854ab3be04cfBehdad Esfahbod icu_err = U_ZERO_ERROR; 339378d279bbf692195c4654e312dae854ab3be04cfBehdad Esfahbod u_strToUTF32 ((UChar32*) decomposed, HB_UNICODE_MAX_DECOMPOSITION_LEN, &utf32_len, normalized, len, &icu_err); 340378d279bbf692195c4654e312dae854ab3be04cfBehdad Esfahbod if (icu_err) 341378d279bbf692195c4654e312dae854ab3be04cfBehdad Esfahbod return 0; 342378d279bbf692195c4654e312dae854ab3be04cfBehdad Esfahbod 343378d279bbf692195c4654e312dae854ab3be04cfBehdad Esfahbod return utf32_len; 344378d279bbf692195c4654e312dae854ab3be04cfBehdad Esfahbod} 345378d279bbf692195c4654e312dae854ab3be04cfBehdad Esfahbod 346fca368c4682624346a0aaee690e1ad6ed4c0b337Behdad Esfahbod 347d5045a5f4017631a4660f985fe451c5a64c42ca0Behdad Esfahbodhb_unicode_funcs_t * 348d5045a5f4017631a4660f985fe451c5a64c42ca0Behdad Esfahbodhb_icu_get_unicode_funcs (void) 349d5045a5f4017631a4660f985fe451c5a64c42ca0Behdad Esfahbod{ 350d5045a5f4017631a4660f985fe451c5a64c42ca0Behdad Esfahbod static const hb_unicode_funcs_t _hb_icu_unicode_funcs = { 351d5045a5f4017631a4660f985fe451c5a64c42ca0Behdad Esfahbod HB_OBJECT_HEADER_STATIC, 352be4560a3b5e8599cbe2b29a01a60c21c9e2b194fBehdad Esfahbod 353d5045a5f4017631a4660f985fe451c5a64c42ca0Behdad Esfahbod NULL, /* parent */ 354d5045a5f4017631a4660f985fe451c5a64c42ca0Behdad Esfahbod true, /* immutable */ 355d5045a5f4017631a4660f985fe451c5a64c42ca0Behdad Esfahbod { 356fca0923b04aeff9369849da97d247a647611f346Behdad Esfahbod#define HB_UNICODE_FUNC_IMPLEMENT(name) hb_icu_unicode_##name, 357d5045a5f4017631a4660f985fe451c5a64c42ca0Behdad Esfahbod HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS 358fca0923b04aeff9369849da97d247a647611f346Behdad Esfahbod#undef HB_UNICODE_FUNC_IMPLEMENT 359d5045a5f4017631a4660f985fe451c5a64c42ca0Behdad Esfahbod } 360d5045a5f4017631a4660f985fe451c5a64c42ca0Behdad Esfahbod }; 361d94647e2cd187bf4a4c8fb1c0c15c3d23c1293acBehdad Esfahbod 362d5045a5f4017631a4660f985fe451c5a64c42ca0Behdad Esfahbod#if U_ICU_VERSION_MAJOR_NUM >= 49 363d5045a5f4017631a4660f985fe451c5a64c42ca0Behdad Esfahbod if (!hb_atomic_ptr_get (&normalizer)) { 364d5045a5f4017631a4660f985fe451c5a64c42ca0Behdad Esfahbod UErrorCode icu_err = U_ZERO_ERROR; 365d5045a5f4017631a4660f985fe451c5a64c42ca0Behdad Esfahbod /* We ignore failure in getNFCInstace(). */ 366d5045a5f4017631a4660f985fe451c5a64c42ca0Behdad Esfahbod hb_atomic_ptr_cmpexch (&normalizer, NULL, unorm2_getNFCInstance (&icu_err)); 367d5045a5f4017631a4660f985fe451c5a64c42ca0Behdad Esfahbod } 368d5045a5f4017631a4660f985fe451c5a64c42ca0Behdad Esfahbod#endif 369f06ab8a4262c759b4723614fd28f55ee77aa8466Behdad Esfahbod return const_cast<hb_unicode_funcs_t *> (&_hb_icu_unicode_funcs); 370d94647e2cd187bf4a4c8fb1c0c15c3d23c1293acBehdad Esfahbod} 371acdba3f90b232fc12fcb200dca2584481b339118Behdad Esfahbod 372acdba3f90b232fc12fcb200dca2584481b339118Behdad Esfahbod 373