blob: 5aef2a3acf2bf215e6234598916fa5d41feecd92 [file] [log] [blame]
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "third_party/blink/renderer/platform/text/character_property_data.h"
#include <stdio.h>
#include <cassert>
#include <cstring>
#include <memory>
#include <unicode/ucptrie.h>
#include <unicode/umutablecptrie.h>
#include "base/check.h"
#include "third_party/blink/renderer/platform/text/character_property.h"
namespace blink {
namespace {
const UChar32 kMaxCodepoint = 0x10FFFF;
#define ARRAY_LENGTH(a) (sizeof(a) / sizeof((a)[0]))
static void SetRanges(CharacterProperty* values,
const UChar32* ranges,
size_t length,
CharacterProperty value) {
assert(length % 2 == 0);
const UChar32* end = ranges + length;
for (; ranges != end; ranges += 2) {
assert(ranges[0] <= ranges[1] && ranges[1] <= kMaxCodepoint);
for (UChar32 c = ranges[0]; c <= ranges[1]; c++)
values[c] |= value;
}
}
static void SetValues(CharacterProperty* values,
const UChar32* begin,
size_t length,
CharacterProperty value) {
const UChar32* end = begin + length;
for (; begin != end; begin++) {
assert(*begin <= kMaxCodepoint);
values[*begin] |= value;
}
}
static void GenerateUTrieSerialized(FILE* fp, int32_t size, uint8_t* array) {
fprintf(fp,
"#include <cstdint>\n\n"
"namespace blink {\n\n"
"extern const int32_t kSerializedCharacterDataSize = %d;\n"
// The utrie2_openFromSerialized function requires character data to
// be aligned to 4 bytes.
"alignas(4) extern const uint8_t kSerializedCharacterData[] = {",
size);
for (int32_t i = 0; i < size;) {
fprintf(fp, "\n ");
for (int col = 0; col < 16 && i < size; col++, i++)
fprintf(fp, " 0x%02X,", array[i]);
}
fprintf(fp,
"\n};\n\n"
"} // namespace blink\n");
}
static void GenerateCharacterPropertyData(FILE* fp) {
// Create a value array of all possible code points.
const UChar32 kSize = kMaxCodepoint + 1;
std::unique_ptr<CharacterProperty[]> values(new CharacterProperty[kSize]);
memset(values.get(), 0, sizeof(CharacterProperty) * kSize);
#define SET(name) \
SetRanges(values.get(), name##Ranges, ARRAY_LENGTH(name##Ranges), \
CharacterProperty::name); \
SetValues(values.get(), name##Array, ARRAY_LENGTH(name##Array), \
CharacterProperty::name);
SET(kIsCJKIdeographOrSymbol);
SET(kIsPotentialCustomElementNameChar);
SET(kIsBidiControl);
SET(kIsHangul);
// Create a trie from the value array.
UErrorCode error = U_ZERO_ERROR;
std::unique_ptr<UMutableCPTrie, decltype(&umutablecptrie_close)> trie(
umutablecptrie_open(0, 0, &error), umutablecptrie_close);
assert(error == U_ZERO_ERROR);
UChar32 start = 0;
CharacterProperty value = values[0];
for (UChar32 c = 1;; c++) {
if (c < kSize && values[c] == value)
continue;
if (static_cast<uint32_t>(value)) {
umutablecptrie_setRange(trie.get(), start, c - 1,
static_cast<uint32_t>(value), &error);
assert(error == U_ZERO_ERROR);
}
if (c >= kSize)
break;
start = c;
value = values[start];
}
// Convert to immutable UCPTrie in order to be able to serialize.
std::unique_ptr<UCPTrie, decltype(&ucptrie_close)> immutable_trie(
umutablecptrie_buildImmutable(trie.get(), UCPTrieType::UCPTRIE_TYPE_FAST,
UCPTrieValueWidth::UCPTRIE_VALUE_BITS_16,
&error),
ucptrie_close);
assert(error == U_ZERO_ERROR);
int32_t serialized_size =
ucptrie_toBinary(immutable_trie.get(), nullptr, 0, &error);
error = U_ZERO_ERROR;
std::unique_ptr<uint8_t[]> serialized(new uint8_t[serialized_size]);
// Ensure 32-bit alignment, as ICU requires that to the ucptrie_toBinary call.
CHECK(!(reinterpret_cast<intptr_t>(serialized.get()) % 4));
serialized_size = ucptrie_toBinary(immutable_trie.get(), serialized.get(),
serialized_size, &error);
assert(error == U_ZERO_ERROR);
GenerateUTrieSerialized(fp, serialized_size, serialized.get());
}
} // namespace
} // namespace blink
int main(int argc, char** argv) {
// Write the serialized array to the source file.
if (argc <= 1) {
blink::GenerateCharacterPropertyData(stdout);
} else {
FILE* fp = fopen(argv[1], "wb");
blink::GenerateCharacterPropertyData(fp);
fclose(fp);
}
return 0;
}