mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
The motivation of this CL is enhance the font fallback score design to support multiple language font fallback. This CL contains following changes: - Break language based font score into two: script-based score and primary-language-based score. - The primary-language-based score is 0 if the script-based score is 0. If the script-based score is not 0 and the primary language is the as same as the requested one, the font gets an extra score of 1. - The language score gets a higher multiplier for languages higher in the locale list. Bug: 25122318 Bug: 26168983 Change-Id: Ib999997a88e6977e341f4c325e2a1b41a59db2d5
145 lines
4.6 KiB
C++
145 lines
4.6 KiB
C++
/*
|
|
* Copyright (C) 2015 The Android Open Source Project
|
|
*
|
|
* 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.
|
|
*/
|
|
|
|
#define LOG_TAG "Minikin"
|
|
|
|
#include "FontLanguage.h"
|
|
|
|
#include <hb.h>
|
|
#include <unicode/uloc.h>
|
|
|
|
namespace android {
|
|
|
|
#define SCRIPT_TAG(c1, c2, c3, c4) \
|
|
(((uint32_t)(c1)) << 24 | ((uint32_t)(c2)) << 16 | ((uint32_t)(c3)) << 8 | \
|
|
((uint32_t)(c4)))
|
|
|
|
// Parse BCP 47 language identifier into internal structure
|
|
FontLanguage::FontLanguage(const char* buf, size_t length) : FontLanguage() {
|
|
size_t i;
|
|
for (i = 0; i < length; i++) {
|
|
char c = buf[i];
|
|
if (c == '-' || c == '_') break;
|
|
}
|
|
if (i == 2 || i == 3) { // only accept two or three letter language code.
|
|
mLanguage = buf[0] | (buf[1] << 8) | ((i == 3) ? (buf[2] << 16) : 0);
|
|
} else {
|
|
// We don't understand anything other than two-letter or three-letter
|
|
// language codes, so we skip parsing the rest of the string.
|
|
mLanguage = 0ul;
|
|
return;
|
|
}
|
|
|
|
size_t next;
|
|
for (i++; i < length; i = next + 1) {
|
|
for (next = i; next < length; next++) {
|
|
char c = buf[next];
|
|
if (c == '-' || c == '_') break;
|
|
}
|
|
if (next - i == 4 && 'A' <= buf[i] && buf[i] <= 'Z') {
|
|
mScript = SCRIPT_TAG(buf[i], buf[i + 1], buf[i + 2], buf[i + 3]);
|
|
}
|
|
}
|
|
|
|
mSubScriptBits = scriptToSubScriptBits(mScript);
|
|
}
|
|
|
|
//static
|
|
uint8_t FontLanguage::scriptToSubScriptBits(uint32_t script) {
|
|
uint8_t subScriptBits = 0u;
|
|
switch (script) {
|
|
case SCRIPT_TAG('H', 'a', 'n', 'g'):
|
|
subScriptBits = kHangulFlag;
|
|
break;
|
|
case SCRIPT_TAG('H', 'a', 'n', 'i'):
|
|
subScriptBits = kHanFlag;
|
|
break;
|
|
case SCRIPT_TAG('H', 'a', 'n', 's'):
|
|
subScriptBits = kHanFlag | kSimplifiedChineseFlag;
|
|
break;
|
|
case SCRIPT_TAG('H', 'a', 'n', 't'):
|
|
subScriptBits = kHanFlag | kTraditionalChineseFlag;
|
|
break;
|
|
case SCRIPT_TAG('H', 'i', 'r', 'a'):
|
|
subScriptBits = kHiraganaFlag;
|
|
break;
|
|
case SCRIPT_TAG('H', 'r', 'k', 't'):
|
|
subScriptBits = kKatakanaFlag | kHiraganaFlag;
|
|
break;
|
|
case SCRIPT_TAG('J', 'p', 'a', 'n'):
|
|
subScriptBits = kHanFlag | kKatakanaFlag | kHiraganaFlag;
|
|
break;
|
|
case SCRIPT_TAG('K', 'a', 'n', 'a'):
|
|
subScriptBits = kKatakanaFlag;
|
|
break;
|
|
case SCRIPT_TAG('K', 'o', 'r', 'e'):
|
|
subScriptBits = kHanFlag | kHangulFlag;
|
|
break;
|
|
case SCRIPT_TAG('Z', 's', 'y', 'e'):
|
|
subScriptBits = kEmojiFlag;
|
|
break;
|
|
}
|
|
return subScriptBits;
|
|
}
|
|
|
|
std::string FontLanguage::getString() const {
|
|
if (mLanguage == 0ul) {
|
|
return "und";
|
|
}
|
|
char buf[16];
|
|
size_t i = 0;
|
|
buf[i++] = mLanguage & 0xFF ;
|
|
buf[i++] = (mLanguage >> 8) & 0xFF;
|
|
char third_letter = (mLanguage >> 16) & 0xFF;
|
|
if (third_letter != 0) buf[i++] = third_letter;
|
|
if (mScript != 0) {
|
|
buf[i++] = '-';
|
|
buf[i++] = (mScript >> 24) & 0xFFu;
|
|
buf[i++] = (mScript >> 16) & 0xFFu;
|
|
buf[i++] = (mScript >> 8) & 0xFFu;
|
|
buf[i++] = mScript & 0xFFu;
|
|
}
|
|
return std::string(buf, i);
|
|
}
|
|
|
|
bool FontLanguage::isEqualScript(const FontLanguage& other) const {
|
|
return other.mScript == mScript;
|
|
}
|
|
|
|
bool FontLanguage::supportsScript(uint8_t requestedBits) const {
|
|
return requestedBits != 0 && (mSubScriptBits & requestedBits) == requestedBits;
|
|
}
|
|
|
|
bool FontLanguage::supportsHbScript(hb_script_t script) const {
|
|
static_assert(SCRIPT_TAG('J', 'p', 'a', 'n') == HB_TAG('J', 'p', 'a', 'n'),
|
|
"The Minikin script and HarfBuzz hb_script_t have different encodings.");
|
|
if (script == mScript) return true;
|
|
return supportsScript(scriptToSubScriptBits(script));
|
|
}
|
|
|
|
int FontLanguage::getScoreFor(const FontLanguage other) const {
|
|
if (isUnsupported() || other.isUnsupported()) {
|
|
return 0;
|
|
} else if (isEqualScript(other) || supportsScript(other.mSubScriptBits)) {
|
|
return mLanguage == other.mLanguage ? 2 : 1;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
#undef SCRIPT_TAG
|
|
} // namespace android
|