15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Copyright © 2009  Red Hat, Inc.
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Copyright © 2009  Keith Stribley
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Copyright © 2011  Google, Inc.
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *  This is part of HarfBuzz, a text shaping library.
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Permission is hereby granted, without written agreement and without
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * license or royalty fees, to use, copy, modify, and distribute this
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * software and its documentation for any purpose, provided that the
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * above copyright notice and the following two paragraphs appear in
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * all copies of this software.
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * DAMAGE.
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Red Hat Author(s): Behdad Esfahbod
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Google Author(s): Behdad Esfahbod
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "hb-private.hh"
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "hb-icu.h"
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "hb-unicode-private.hh"
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <unicode/uchar.h>
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <unicode/unorm.h>
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <unicode/ustring.h>
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <unicode/uversion.h>
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)hb_script_t
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)hb_icu_script_to_script (UScriptCode script)
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (unlikely (script == USCRIPT_INVALID_CODE))
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return HB_SCRIPT_INVALID;
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return hb_script_from_string (uscript_getShortName (script), -1);
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)UScriptCode
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)hb_icu_script_from_script (hb_script_t script)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (unlikely (script == HB_SCRIPT_INVALID))
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return USCRIPT_INVALID_CODE;
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (unsigned int i = 0; i < USCRIPT_CODE_LIMIT; i++)
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (unlikely (hb_icu_script_to_script ((UScriptCode) i) == script))
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return (UScriptCode) i;
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return USCRIPT_UNKNOWN;
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static hb_unicode_combining_class_t
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)hb_icu_unicode_combining_class (hb_unicode_funcs_t *ufuncs HB_UNUSED,
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				hb_codepoint_t      unicode,
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				void               *user_data HB_UNUSED)
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (hb_unicode_combining_class_t) u_getCombiningClass (unicode);
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static unsigned int
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)hb_icu_unicode_eastasian_width (hb_unicode_funcs_t *ufuncs HB_UNUSED,
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				hb_codepoint_t      unicode,
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				void               *user_data HB_UNUSED)
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (u_getIntPropertyValue(unicode, UCHAR_EAST_ASIAN_WIDTH))
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  case U_EA_WIDE:
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  case U_EA_FULLWIDTH:
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 2;
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  case U_EA_NEUTRAL:
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  case U_EA_AMBIGUOUS:
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  case U_EA_HALFWIDTH:
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  case U_EA_NARROW:
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 1;
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return 1;
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static hb_unicode_general_category_t
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)hb_icu_unicode_general_category (hb_unicode_funcs_t *ufuncs HB_UNUSED,
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				 hb_codepoint_t      unicode,
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				 void               *user_data HB_UNUSED)
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (u_getIntPropertyValue(unicode, UCHAR_GENERAL_CATEGORY))
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  case U_UNASSIGNED:			return HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED;
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  case U_UPPERCASE_LETTER:		return HB_UNICODE_GENERAL_CATEGORY_UPPERCASE_LETTER;
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  case U_LOWERCASE_LETTER:		return HB_UNICODE_GENERAL_CATEGORY_LOWERCASE_LETTER;
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  case U_TITLECASE_LETTER:		return HB_UNICODE_GENERAL_CATEGORY_TITLECASE_LETTER;
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  case U_MODIFIER_LETTER:		return HB_UNICODE_GENERAL_CATEGORY_MODIFIER_LETTER;
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  case U_OTHER_LETTER:			return HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER;
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  case U_NON_SPACING_MARK:		return HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK;
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  case U_ENCLOSING_MARK:		return HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK;
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  case U_COMBINING_SPACING_MARK:	return HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK;
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  case U_DECIMAL_DIGIT_NUMBER:		return HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER;
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  case U_LETTER_NUMBER:			return HB_UNICODE_GENERAL_CATEGORY_LETTER_NUMBER;
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  case U_OTHER_NUMBER:			return HB_UNICODE_GENERAL_CATEGORY_OTHER_NUMBER;
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  case U_SPACE_SEPARATOR:		return HB_UNICODE_GENERAL_CATEGORY_SPACE_SEPARATOR;
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  case U_LINE_SEPARATOR:		return HB_UNICODE_GENERAL_CATEGORY_LINE_SEPARATOR;
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  case U_PARAGRAPH_SEPARATOR:		return HB_UNICODE_GENERAL_CATEGORY_PARAGRAPH_SEPARATOR;
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  case U_CONTROL_CHAR:			return HB_UNICODE_GENERAL_CATEGORY_CONTROL;
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  case U_FORMAT_CHAR:			return HB_UNICODE_GENERAL_CATEGORY_FORMAT;
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  case U_PRIVATE_USE_CHAR:		return HB_UNICODE_GENERAL_CATEGORY_PRIVATE_USE;
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  case U_SURROGATE:			return HB_UNICODE_GENERAL_CATEGORY_SURROGATE;
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  case U_DASH_PUNCTUATION:		return HB_UNICODE_GENERAL_CATEGORY_DASH_PUNCTUATION;
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  case U_START_PUNCTUATION:		return HB_UNICODE_GENERAL_CATEGORY_OPEN_PUNCTUATION;
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  case U_END_PUNCTUATION:		return HB_UNICODE_GENERAL_CATEGORY_CLOSE_PUNCTUATION;
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  case U_CONNECTOR_PUNCTUATION:		return HB_UNICODE_GENERAL_CATEGORY_CONNECT_PUNCTUATION;
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  case U_OTHER_PUNCTUATION:		return HB_UNICODE_GENERAL_CATEGORY_OTHER_PUNCTUATION;
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  case U_MATH_SYMBOL:			return HB_UNICODE_GENERAL_CATEGORY_MATH_SYMBOL;
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  case U_CURRENCY_SYMBOL:		return HB_UNICODE_GENERAL_CATEGORY_CURRENCY_SYMBOL;
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  case U_MODIFIER_SYMBOL:		return HB_UNICODE_GENERAL_CATEGORY_MODIFIER_SYMBOL;
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  case U_OTHER_SYMBOL:			return HB_UNICODE_GENERAL_CATEGORY_OTHER_SYMBOL;
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  case U_INITIAL_PUNCTUATION:		return HB_UNICODE_GENERAL_CATEGORY_INITIAL_PUNCTUATION;
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  case U_FINAL_PUNCTUATION:		return HB_UNICODE_GENERAL_CATEGORY_FINAL_PUNCTUATION;
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED;
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static hb_codepoint_t
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)hb_icu_unicode_mirroring (hb_unicode_funcs_t *ufuncs HB_UNUSED,
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			  hb_codepoint_t      unicode,
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			  void               *user_data HB_UNUSED)
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return u_charMirror(unicode);
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static hb_script_t
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)hb_icu_unicode_script (hb_unicode_funcs_t *ufuncs HB_UNUSED,
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		       hb_codepoint_t      unicode,
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		       void               *user_data HB_UNUSED)
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UErrorCode status = U_ZERO_ERROR;
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UScriptCode scriptCode = uscript_getScript(unicode, &status);
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (unlikely (U_FAILURE (status)))
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return HB_SCRIPT_UNKNOWN;
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return hb_icu_script_to_script (scriptCode);
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if U_ICU_VERSION_MAJOR_NUM >= 49
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const UNormalizer2 *normalizer;
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static hb_bool_t
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)hb_icu_unicode_compose (hb_unicode_funcs_t *ufuncs HB_UNUSED,
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			hb_codepoint_t      a,
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			hb_codepoint_t      b,
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			hb_codepoint_t     *ab,
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			void               *user_data HB_UNUSED)
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if U_ICU_VERSION_MAJOR_NUM >= 49
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UChar32 ret = unorm2_composePair (normalizer, a, b);
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (ret < 0) return false;
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *ab = ret;
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* We don't ifdef-out the fallback code such that compiler always
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   * sees it and makes sure it's compilable. */
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UChar utf16[4], normalized[5];
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned int len;
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  hb_bool_t ret, err;
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UErrorCode icu_err;
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  len = 0;
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  err = false;
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  U16_APPEND (utf16, len, ARRAY_LENGTH (utf16), a, err);
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (err) return false;
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  U16_APPEND (utf16, len, ARRAY_LENGTH (utf16), b, err);
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (err) return false;
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  icu_err = U_ZERO_ERROR;
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  len = unorm_normalize (utf16, len, UNORM_NFC, 0, normalized, ARRAY_LENGTH (normalized), &icu_err);
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (U_FAILURE (icu_err))
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (u_countChar32 (normalized, len) == 1) {
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    U16_GET_UNSAFE (normalized, 0, *ab);
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ret = true;
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ret = false;
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ret;
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static hb_bool_t
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)hb_icu_unicode_decompose (hb_unicode_funcs_t *ufuncs HB_UNUSED,
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			  hb_codepoint_t      ab,
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			  hb_codepoint_t     *a,
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			  hb_codepoint_t     *b,
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			  void               *user_data HB_UNUSED)
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if U_ICU_VERSION_MAJOR_NUM >= 49
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UChar decomposed[4];
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int len;
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UErrorCode icu_err = U_ZERO_ERROR;
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    len = unorm2_getRawDecomposition (normalizer, ab, decomposed,
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				      ARRAY_LENGTH (decomposed), &icu_err);
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (U_FAILURE (icu_err) || len < 0) return false;
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    len = u_countChar32 (decomposed, len);
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (len == 1) {
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      U16_GET_UNSAFE (decomposed, 0, *a);
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      *b = 0;
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return *a != ab;
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else if (len == 2) {
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      len =0;
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      U16_NEXT_UNSAFE (decomposed, len, *a);
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      U16_NEXT_UNSAFE (decomposed, len, *b);
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* We don't ifdef-out the fallback code such that compiler always
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   * sees it and makes sure it's compilable. */
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UChar utf16[2], normalized[2 * HB_UNICODE_MAX_DECOMPOSITION_LEN + 1];
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned int len;
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  hb_bool_t ret, err;
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UErrorCode icu_err;
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* This function is a monster! Maybe it wasn't a good idea adding a
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   * pairwise decompose API... */
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* Watchout for the dragons.  Err, watchout for macros changing len. */
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  len = 0;
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  err = false;
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  U16_APPEND (utf16, len, ARRAY_LENGTH (utf16), ab, err);
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (err) return false;
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  icu_err = U_ZERO_ERROR;
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  len = unorm_normalize (utf16, len, UNORM_NFD, 0, normalized, ARRAY_LENGTH (normalized), &icu_err);
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (U_FAILURE (icu_err))
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  len = u_countChar32 (normalized, len);
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (len == 1) {
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    U16_GET_UNSAFE (normalized, 0, *a);
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *b = 0;
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ret = *a != ab;
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (len == 2) {
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    len =0;
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    U16_NEXT_UNSAFE (normalized, len, *a);
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    U16_NEXT_UNSAFE (normalized, len, *b);
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /* Here's the ugly part: if ab decomposes to a single character and
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * that character decomposes again, we have to detect that and undo
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * the second part :-(. */
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UChar recomposed[20];
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    icu_err = U_ZERO_ERROR;
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    unorm_normalize (normalized, len, UNORM_NFC, 0, recomposed, ARRAY_LENGTH (recomposed), &icu_err);
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (U_FAILURE (icu_err))
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    hb_codepoint_t c;
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    U16_GET_UNSAFE (recomposed, 0, c);
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (c != *a && c != ab) {
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      *a = c;
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      *b = 0;
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ret = true;
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /* If decomposed to more than two characters, take the last one,
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * and recompose the rest to get the first component. */
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    U16_PREV_UNSAFE (normalized, len, *b); /* Changes len in-place. */
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UChar recomposed[18 * 2];
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    icu_err = U_ZERO_ERROR;
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    len = unorm_normalize (normalized, len, UNORM_NFC, 0, recomposed, ARRAY_LENGTH (recomposed), &icu_err);
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (U_FAILURE (icu_err))
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /* We expect that recomposed has exactly one character now. */
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (unlikely (u_countChar32 (recomposed, len) != 1))
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    U16_GET_UNSAFE (recomposed, 0, *a);
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ret = true;
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ret;
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static unsigned int
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)hb_icu_unicode_decompose_compatibility (hb_unicode_funcs_t *ufuncs HB_UNUSED,
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)					hb_codepoint_t      u,
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)					hb_codepoint_t     *decomposed,
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)					void               *user_data HB_UNUSED)
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UChar utf16[2], normalized[2 * HB_UNICODE_MAX_DECOMPOSITION_LEN + 1];
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned int len;
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int32_t utf32_len;
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  hb_bool_t err;
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UErrorCode icu_err;
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* Copy @u into a UTF-16 array to be passed to ICU. */
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  len = 0;
3265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  err = false;
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  U16_APPEND (utf16, len, ARRAY_LENGTH (utf16), u, err);
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (err)
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* Normalise the codepoint using NFKD mode. */
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  icu_err = U_ZERO_ERROR;
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  len = unorm_normalize (utf16, len, UNORM_NFKD, 0, normalized, ARRAY_LENGTH (normalized), &icu_err);
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (icu_err)
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* Convert the decomposed form from UTF-16 to UTF-32. */
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  icu_err = U_ZERO_ERROR;
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  u_strToUTF32 ((UChar32*) decomposed, HB_UNICODE_MAX_DECOMPOSITION_LEN, &utf32_len, normalized, len, &icu_err);
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (icu_err)
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return utf32_len;
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)hb_unicode_funcs_t *
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)hb_icu_get_unicode_funcs (void)
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static const hb_unicode_funcs_t _hb_icu_unicode_funcs = {
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HB_OBJECT_HEADER_STATIC,
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NULL, /* parent */
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    true, /* immutable */
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    {
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define HB_UNICODE_FUNC_IMPLEMENT(name) hb_icu_unicode_##name,
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#undef HB_UNICODE_FUNC_IMPLEMENT
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if U_ICU_VERSION_MAJOR_NUM >= 49
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!hb_atomic_ptr_get (&normalizer)) {
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UErrorCode icu_err = U_ZERO_ERROR;
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /* We ignore failure in getNFCInstace(). */
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    hb_atomic_ptr_cmpexch (&normalizer, NULL, unorm2_getNFCInstance (&icu_err));
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return const_cast<hb_unicode_funcs_t *> (&_hb_icu_unicode_funcs);
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
373