/* * Copyright 2024 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "codepoint.h" #include "util/size.h" #include #define MAX_LATIN_CODEPOINT 0x02AF #define MIN_SOFTBANK_EMOJI_CODEPOINT 0xE000 #define MAX_SOFTBANK_EMOJI_CODEPOINT 0xE537 #define MIN_UNIFIED_EMOJI_CODEPOINT 0x1F300 #define MAX_UNIFIED_EMOJI_CODEPOINT 0x1F6FF #define MIN_SYMBOLS_CODEPOINT 0x2000 #define MAX_SYMBOLS_CODEPOINT 0x2BFF #define MIN_IDEOGRAPH_CODEPOINT 0x2e80 #define MIN_SPECIAL_CODEPOINT 0xE0A0 #define MAX_SPECIAL_CODEPOINT 0xE0A2 #define MIN_SKIN_TONE_CODEPOINT 0x1F3FB #define MAX_SKIN_TONE_CODEPOINT 0x1F3FF // Note: Please keep these sorted static const Codepoint NONSTANDARD_EMOJI_CODEPOINTS[] = { 0x2192, // rightwards_arrow 0x25BA, // black_right_pointing_pointer 0x2605, // black_star 0x260E, // black_telephone 0x261D, // white_up_pointing_index 0x263A, // white_smiling_face 0x270A, // raised_fist 0x270B, // raised_hand 0x270C, // victory_hand 0x2764, // heavy_black_heart }; // Note: Please keep these sorted static const Codepoint END_OF_WORD_CODEPOINTS[] = { NULL_CODEPOINT, // 0x0 NEWLINE_CODEPOINT, // 0xa SPACE_CODEPOINT, // 0x20 HYPHEN_CODEPOINT, // 0x2d ZERO_WIDTH_SPACE_CODEPOINT // 0x200b }; // Note: Please keep these sorted static const Codepoint FORMATTING_CODEPOINTS[] = { 0x7F, // delete 0x200C, // zero-width non-joiner 0x200D, // zero-width joiner 0x200E, // left to right 0x200F, // right to left 0x202A, // bidirectional - right to left 0x202C, // bidirectional - pop direction 0x202D, // left to right override 0xFE0E, // variation selector 1 0xFE0F, // variation selector 2 0xFEFF, // zero-width-no-break }; // Note: Please keep these sorted static const Codepoint ZERO_WIDTH_CODEPOINTS[] = { ZERO_WIDTH_SPACE_CODEPOINT, WORD_JOINER_CODEPOINT, }; static bool codepoint_in_list(const Codepoint codepoint, const Codepoint *codepoints, size_t size) { for (size_t i = 0; i < size; ++i) { if (codepoints[i] >= codepoint) { return (codepoints[i] == codepoint); } } return false; } bool codepoint_is_formatting_indicator(const Codepoint codepoint) { return codepoint_in_list(codepoint, FORMATTING_CODEPOINTS, ARRAY_LENGTH(FORMATTING_CODEPOINTS)); } bool codepoint_is_ideograph(const Codepoint codepoint) { if (codepoint > MIN_IDEOGRAPH_CODEPOINT) { // non ideographic characters. This is an approximation that is good enough until // we start supporting some exotic scripts (e.g. tibetan) return true; } else { return false; } } // see http://www.unicode.org/reports/tr14/ for the whole enchilada bool codepoint_is_end_of_word(const Codepoint codepoint) { return codepoint_in_list(codepoint, END_OF_WORD_CODEPOINTS, ARRAY_LENGTH(END_OF_WORD_CODEPOINTS)); } // see http://unicode.org/reports/tr51/ section 2.2 "Diversity" bool codepoint_is_skin_tone_modifier(const Codepoint codepoint) { return (codepoint >= MIN_SKIN_TONE_CODEPOINT && codepoint <= MAX_SKIN_TONE_CODEPOINT); } bool codepoint_should_skip(const Codepoint codepoint) { return ((codepoint < 0x20 && codepoint != NEWLINE_CODEPOINT) || (codepoint_is_skin_tone_modifier(codepoint))); } bool codepoint_is_zero_width(const Codepoint codepoint) { return codepoint_in_list(codepoint, ZERO_WIDTH_CODEPOINTS, ARRAY_LENGTH(ZERO_WIDTH_CODEPOINTS)); } bool codepoint_is_latin(const Codepoint codepoint) { return (codepoint <= MAX_LATIN_CODEPOINT || (codepoint >= MIN_SYMBOLS_CODEPOINT && codepoint <= MAX_SYMBOLS_CODEPOINT)); } bool codepoint_is_emoji(const Codepoint codepoint) { // search for the codepoint in the list of nonstandard emoji codepoints first. const bool found = codepoint_in_list(codepoint, NONSTANDARD_EMOJI_CODEPOINTS, ARRAY_LENGTH(NONSTANDARD_EMOJI_CODEPOINTS)); if (found) { return true; } else { return ((codepoint >= MIN_SOFTBANK_EMOJI_CODEPOINT && codepoint <= MAX_SOFTBANK_EMOJI_CODEPOINT) || (codepoint >= MIN_UNIFIED_EMOJI_CODEPOINT && codepoint <= MAX_UNIFIED_EMOJI_CODEPOINT)); } } bool codepoint_is_special(const Codepoint codepoint) { return (codepoint >= MIN_SPECIAL_CODEPOINT && codepoint <= MAX_SPECIAL_CODEPOINT); }