This source file includes following definitions.
- valueInIntervalList
- characterRangeCodePath
- isCJKIdeograph
- isCJKIdeographOrSymbol
- expansionOpportunityCount
- expansionOpportunityCount
- canReceiveTextEmphasis
- normalizeSpacesInternal
- normalizeSpaces
- normalizeSpaces
#include "config.h"
#include "platform/fonts/Character.h"
#include "platform/fonts/FontPlatformFeatures.h"
#include "wtf/StdLibExtras.h"
#include "wtf/text/StringBuilder.h"
using namespace WTF;
using namespace Unicode;
namespace WebCore {
const uint8_t Character::s_roundingHackCharacterTable[256] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 1 , 1 , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1 , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 ,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1 , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
static const UChar32 cjkIsolatedSymbolsArray[] = {
0x2C7,
0x2CA,
0x2CB,
0x2D9,
0x2020, 0x2021, 0x2030, 0x203B, 0x203C, 0x2042, 0x2047, 0x2048, 0x2049, 0x2051,
0x20DD, 0x20DE, 0x2100, 0x2103, 0x2105, 0x2109, 0x210A, 0x2113, 0x2116, 0x2121,
0x212B, 0x213B, 0x2150, 0x2151, 0x2152, 0x217F, 0x2189, 0x2307, 0x2312, 0x23CE,
0x2423, 0x25A0, 0x25A1, 0x25A2, 0x25AA, 0x25AB, 0x25B1, 0x25B2, 0x25B3, 0x25B6,
0x25B7, 0x25BC, 0x25BD, 0x25C0, 0x25C1, 0x25C6, 0x25C7, 0x25C9, 0x25CB, 0x25CC,
0x25EF, 0x2605, 0x2606, 0x260E, 0x2616, 0x2617, 0x2640, 0x2642, 0x26A0, 0x26BD,
0x26BE, 0x2713, 0x271A, 0x273F, 0x2740, 0x2756, 0x2B1A, 0xFE10, 0xFE11, 0xFE12,
0xFE19, 0xFF1D,
0x1F100
};
template <class T, size_t size>
bool valueInIntervalList(const T (&intervalList)[size], const T& value)
{
const T* bound = std::upper_bound(&intervalList[0], &intervalList[size], value);
if ((bound - intervalList) % 2 == 1)
return true;
return bound > intervalList && *(bound - 1) == value;
}
CodePath Character::characterRangeCodePath(const UChar* characters, unsigned len)
{
static const UChar complexCodePathRanges[] = {
0x2E5, 0x2E9,
0x300, 0x36F,
0x0591, 0x05BD,
0x05BF, 0x05CF,
0x0600, 0x109F,
0x1100, 0x11FF,
0x135D, 0x135F,
0x1700, 0x18AF,
0x1900, 0x194F,
0x1980, 0x19DF,
0x1A00, 0x1CFF,
0x1DC0, 0x1DFF,
0x20D0, 0x20FF,
0x2CEF, 0x2CF1,
0x302A, 0x302F,
0xA67C, 0xA67D,
0xA6F0, 0xA6F1,
0xA800, 0xABFF,
0xD7B0, 0xD7FF,
0xFE00, 0xFE0F,
0xFE20, 0xFE2F
};
CodePath result = SimplePath;
for (unsigned i = 0; i < len; i++) {
const UChar c = characters[i];
if (c < 0x2E5)
continue;
if (c >= 0x1E00 && c <= 0x2000) {
result = SimpleWithGlyphOverflowPath;
continue;
}
if (c > 0xD7FF && c <= 0xDBFF) {
if (i == len - 1)
continue;
UChar next = characters[++i];
if (!U16_IS_TRAIL(next))
continue;
UChar32 supplementaryCharacter = U16_GET_SUPPLEMENTARY(c, next);
if (supplementaryCharacter < 0x1F1E6)
continue;
if (supplementaryCharacter <= 0x1F1FF)
return ComplexPath;
if (supplementaryCharacter < 0xE0100)
continue;
if (supplementaryCharacter <= 0xE01EF)
return ComplexPath;
continue;
}
if (valueInIntervalList(complexCodePathRanges, c))
return ComplexPath;
}
return result;
}
bool Character::isCJKIdeograph(UChar32 c)
{
static const UChar32 cjkIdeographRanges[] = {
0x2E80, 0x2FDF,
0x31C0, 0x31EF,
0x3400, 0x4DBF,
0x4E00, 0x9FFF,
0xF900, 0xFAFF,
0x20000, 0x2A6DF,
0x2A700, 0x2B81F,
0x2F800, 0x2FA1F
};
static size_t cjkIdeographRangesCount = WTF_ARRAY_LENGTH(cjkIdeographRanges);
if (c < cjkIdeographRanges[0] || c > cjkIdeographRanges[cjkIdeographRangesCount - 1])
return false;
return valueInIntervalList(cjkIdeographRanges, c);
}
bool Character::isCJKIdeographOrSymbol(UChar32 c)
{
if (c < 0x2C7)
return false;
static HashSet<UChar32>* cjkIsolatedSymbols = 0;
if (!cjkIsolatedSymbols) {
cjkIsolatedSymbols = new HashSet<UChar32>();
for (size_t i = 0; i < WTF_ARRAY_LENGTH(cjkIsolatedSymbolsArray); ++i)
cjkIsolatedSymbols->add(cjkIsolatedSymbolsArray[i]);
}
if (cjkIsolatedSymbols->contains(c))
return true;
if (isCJKIdeograph(c))
return true;
static const UChar32 cjkSymbolRanges[] = {
0x2156, 0x215A,
0x2160, 0x216B,
0x2170, 0x217B,
0x23BE, 0x23CC,
0x2460, 0x2492,
0x249C, 0x24FF,
0x25CE, 0x25D3,
0x25E2, 0x25E6,
0x2600, 0x2603,
0x2660, 0x266F,
0x2672, 0x267D,
0x2776, 0x277F,
0x2FF0, 0x302F,
0x3031, 0x312F,
0x3190, 0x31BF,
0x3200, 0x33FF,
0xF860, 0xF862,
0xFE30, 0xFE4F,
0xFF00, 0xFF0C,
0xFF0E, 0xFF1A,
0xFF1F, 0xFFEF,
0x1F110, 0x1F129,
0x1F130, 0x1F149,
0x1F150, 0x1F169,
0x1F170, 0x1F189,
0x1F200, 0x1F6FF
};
return valueInIntervalList(cjkSymbolRanges, c);
}
unsigned Character::expansionOpportunityCount(const LChar* characters, size_t length, TextDirection direction, bool& isAfterExpansion)
{
unsigned count = 0;
if (direction == LTR) {
for (size_t i = 0; i < length; ++i) {
if (treatAsSpace(characters[i])) {
count++;
isAfterExpansion = true;
} else {
isAfterExpansion = false;
}
}
} else {
for (size_t i = length; i > 0; --i) {
if (treatAsSpace(characters[i - 1])) {
count++;
isAfterExpansion = true;
} else {
isAfterExpansion = false;
}
}
}
return count;
}
unsigned Character::expansionOpportunityCount(const UChar* characters, size_t length, TextDirection direction, bool& isAfterExpansion)
{
static bool expandAroundIdeographs = FontPlatformFeatures::canExpandAroundIdeographsInComplexText();
unsigned count = 0;
if (direction == LTR) {
for (size_t i = 0; i < length; ++i) {
UChar32 character = characters[i];
if (treatAsSpace(character)) {
count++;
isAfterExpansion = true;
continue;
}
if (U16_IS_LEAD(character) && i + 1 < length && U16_IS_TRAIL(characters[i + 1])) {
character = U16_GET_SUPPLEMENTARY(character, characters[i + 1]);
i++;
}
if (expandAroundIdeographs && isCJKIdeographOrSymbol(character)) {
if (!isAfterExpansion)
count++;
count++;
isAfterExpansion = true;
continue;
}
isAfterExpansion = false;
}
} else {
for (size_t i = length; i > 0; --i) {
UChar32 character = characters[i - 1];
if (treatAsSpace(character)) {
count++;
isAfterExpansion = true;
continue;
}
if (U16_IS_TRAIL(character) && i > 1 && U16_IS_LEAD(characters[i - 2])) {
character = U16_GET_SUPPLEMENTARY(characters[i - 2], character);
i--;
}
if (expandAroundIdeographs && isCJKIdeographOrSymbol(character)) {
if (!isAfterExpansion)
count++;
count++;
isAfterExpansion = true;
continue;
}
isAfterExpansion = false;
}
}
return count;
}
bool Character::canReceiveTextEmphasis(UChar32 c)
{
CharCategory category = Unicode::category(c);
if (category & (Separator_Space | Separator_Line | Separator_Paragraph | Other_NotAssigned | Other_Control | Other_Format))
return false;
if (c == ethiopicWordspace || c == aegeanWordSeparatorLine || c == aegeanWordSeparatorDot
|| c == ugariticWordDivider || c == tibetanMarkIntersyllabicTsheg || c == tibetanMarkDelimiterTshegBstar)
return false;
return true;
}
template <typename CharacterType>
static inline String normalizeSpacesInternal(const CharacterType* characters, unsigned length)
{
StringBuilder normalized;
normalized.reserveCapacity(length);
for (unsigned i = 0; i < length; ++i)
normalized.append(Character::normalizeSpaces(characters[i]));
return normalized.toString();
}
String Character::normalizeSpaces(const LChar* characters, unsigned length)
{
return normalizeSpacesInternal(characters, length);
}
String Character::normalizeSpaces(const UChar* characters, unsigned length)
{
return normalizeSpacesInternal(characters, length);
}
}