blob: 31a483a4284c859a1598036be187ef49f2e7cff5 [file]
/*
* Copyright 2023 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "include/private/SkDebug.h"
#include "modules/skunicode/src/SkUnicode_hardcoded.h"
#include <algorithm>
#include <array>
#include <utility>
bool SkUnicodeHardCodedCharProperties::isControl(SkUnichar utf8) {
// Match u_iscntrl across Cc (Control), Cf (Format), Zl (Line Separator),
// and Zp (Paragraph Separator) categories
static constexpr std::array<std::pair<SkUnichar, SkUnichar>, 23> ranges {{
{0x0000, 0x001F},
{0x007F, 0x009F},
{0x00AD, 0x00AD},
{0x0600, 0x0605},
{0x061C, 0x061C},
{0x06DD, 0x06DD},
{0x070F, 0x070F},
{0x0890, 0x0891},
{0x08E2, 0x08E2},
{0x180E, 0x180E},
{0x200B, 0x200F},
{0x2028, 0x202E},
{0x2060, 0x2064},
{0x2066, 0x206F},
{0xFEFF, 0xFEFF},
{0xFFF9, 0xFFFB},
{0x110BD, 0x110BD},
{0x110CD, 0x110CD},
{0x13430, 0x1343F},
{0x1BCA0, 0x1BCA3},
{0x1D173, 0x1D17A},
{0xE0001, 0xE0001},
{0xE0020, 0xE007F},
}};
// Ranges are sorted in ascending order, allowing early exit once utf8 precedes r.first
for (const auto& r : ranges) {
if (utf8 < r.first) {
return false;
}
if (utf8 <= r.second) {
return true;
}
}
return false;
}
bool SkUnicodeHardCodedCharProperties::isWhitespace(SkUnichar unichar) {
// Include ASCII information separators U+001C..U+001F (FS..US) to match u_isWhitespace
static constexpr std::array<SkUnichar, 25> whitespaces {
0x0009, // character tabulation
0x000A, // line feed
0x000B, // line tabulation
0x000C, // form feed
0x000D, // carriage return
0x001C, // file separator
0x001D, // group separator
0x001E, // record separator
0x001F, // unit separator
0x0020, // space
//0x0085, // next line
//0x00A0, // no-break space
0x1680, // ogham space mark
0x2000, // en quad
0x2001, // em quad
0x2002, // en space
0x2003, // em space
0x2004, // three-per-em space
0x2005, // four-per-em space
0x2006, // six-per-em space
//0x2007, // figure space
0x2008, // punctuation space
0x2009, // thin space
0x200A, // hair space
0x2028, // line separator
0x2029, // paragraph separator
//0x202F, // narrow no-break space
0x205F, // medium mathematical space
0x3000};// ideographic space
return std::find(whitespaces.begin(), whitespaces.end(), unichar) != whitespaces.end();
}
bool SkUnicodeHardCodedCharProperties::isSpace(SkUnichar unichar) {
// Include ASCII information separators U+001C..U+001F (FS..US) to match u_isspace
static constexpr std::array<SkUnichar, 29> spaces {
0x0009, // character tabulation
0x000A, // line feed
0x000B, // line tabulation
0x000C, // form feed
0x000D, // carriage return
0x001C, // file separator
0x001D, // group separator
0x001E, // record separator
0x001F, // unit separator
0x0020, // space
0x0085, // next line
0x00A0, // no-break space
0x1680, // ogham space mark
0x2000, // en quad
0x2001, // em quad
0x2002, // en space
0x2003, // em space
0x2004, // three-per-em space
0x2005, // four-per-em space
0x2006, // six-per-em space
0x2007, // figure space
0x2008, // punctuation space
0x2009, // thin space
0x200A, // hair space
0x2028, // line separator
0x2029, // paragraph separator
0x202F, // narrow no-break space
0x205F, // medium mathematical space
0x3000}; // ideographic space
return std::find(spaces.begin(), spaces.end(), unichar) != spaces.end();
}
bool SkUnicodeHardCodedCharProperties::isTabulation(SkUnichar utf8) {
return utf8 == '\t';
}
bool SkUnicodeHardCodedCharProperties::isHardBreak(SkUnichar utf8) {
// Match UAX #14 LF (U+000A) and BK (U+000B, U+000C, U+2028, U+2029) mandatory line breaks
return utf8 == '\n' || utf8 == '\v' || utf8 == '\f' ||
utf8 == u'\u2028' || utf8 == u'\u2029';
}
bool SkUnicodeHardCodedCharProperties::IsDefaultIgnorable(SkUnichar utf8) {
// Match UCHAR_DEFAULT_IGNORABLE_CODE_POINT across all Unicode code points
static constexpr std::array<std::pair<SkUnichar, SkUnichar>, 17> ranges {{
{0x00AD, 0x00AD},
{0x034F, 0x034F},
{0x061C, 0x061C},
{0x115F, 0x1160},
{0x17B4, 0x17B5},
{0x180B, 0x180F},
{0x200B, 0x200F},
{0x202A, 0x202E},
{0x2060, 0x206F},
{0x3164, 0x3164},
{0xFE00, 0xFE0F},
{0xFEFF, 0xFEFF},
{0xFFA0, 0xFFA0},
{0xFFF0, 0xFFF8},
{0x1BCA0, 0x1BCA3},
{0x1D173, 0x1D17A},
{0xE0000, 0xE0FFF},
}};
auto it = std::ranges::lower_bound(
ranges, utf8, {}, &std::pair<SkUnichar, SkUnichar>::second);
return it != ranges.end() && utf8 >= it->first;
}
bool SkUnicodeHardCodedCharProperties::isDefaultIgnorable(SkUnichar utf8) {
return IsDefaultIgnorable(utf8);
}
bool SkUnicodeHardCodedCharProperties::isEmoji(SkUnichar unichar) {
if (unichar == '#' || unichar == '*' || (unichar >= '0' && unichar <= '9')) {
return true;
}
static constexpr std::pair<SkUnichar, SkUnichar> emojiRanges[] = {
{0x203C, 0x203C}, {0x2049, 0x2049}, {0x2122, 0x2122}, {0x2139, 0x2139},
{0x2194, 0x2199}, {0x21A9, 0x21AA}, {0x2300, 0x23FF}, {0x25AA, 0x25AB},
{0x25B6, 0x25B6}, {0x25C0, 0x25C0}, {0x25FB, 0x25FE}, {0x2600, 0x27BF},
{0x2934, 0x2935}, {0x2B05, 0x2B07}, {0x2B1B, 0x2B1C}, {0x2B50, 0x2B50},
{0x2B55, 0x2B55}, {0x3030, 0x3030}, {0x303D, 0x303D}, {0x3297, 0x3297},
{0x3299, 0x3299}, {0x1F000, 0x1F02F}, {0x1F0A0, 0x1F0FF}, {0x1F100, 0x1F64F},
{0x1F680, 0x1F6FF}, {0x1F700, 0x1F77F}, {0x1F780, 0x1F7FF}, {0x1F800, 0x1F8FF},
{0x1F900, 0x1FAFF}
};
for (const auto& r : emojiRanges) {
if (unichar >= r.first && unichar <= r.second) {
return true;
}
}
return false;
}
bool SkUnicodeHardCodedCharProperties::isEmojiComponent(SkUnichar unichar) {
return (unichar >= 0x1F3FB && unichar <= 0x1F3FF) ||
(unichar >= 0x1F1E6 && unichar <= 0x1F1FF) ||
unichar == 0x200D || unichar == 0xFE0F;
}
bool SkUnicodeHardCodedCharProperties::isEmojiModifier(SkUnichar unichar) {
return unichar >= 0x1F3FB && unichar <= 0x1F3FF;
}
bool SkUnicodeHardCodedCharProperties::isEmojiModifierBase(SkUnichar unichar) {
return this->isEmoji(unichar) && !this->isEmojiModifier(unichar);
}
bool SkUnicodeHardCodedCharProperties::isRegionalIndicator(SkUnichar unichar) {
return unichar >= 0x1F1E6 && unichar <= 0x1F1FF;
}
bool SkUnicodeHardCodedCharProperties::isIdeographic(SkUnichar unichar) {
static constexpr std::array<std::pair<SkUnichar, SkUnichar>, 8> ranges {{
{4352, 4607}, // Hangul Jamo
{11904, 42191}, // CJK_Radicals
{43072, 43135}, // Phags_Pa
{44032, 55215}, // Hangul_Syllables
{63744, 64255}, // CJK_Compatibility_Ideographs
{65072, 65103}, // CJK_Compatibility_Forms
{65381, 65500}, // Katakana_Hangul_Halfwidth
{131072, 196607}// Supplementary_Ideographic_Plane
}};
for (auto range : ranges) {
// Block upper bounds in ranges are inclusive codepoints (e.g. U+11FF, U+D7AF)
if (range.first <= unichar && range.second >= unichar) {
return true;
}
}
return false;
}