mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
To optimize the font family search, mRanges is used for narrowing down the search range. However, mRanges is constructed from format 4 or format 12 entries. So, if the font supports a variation sequence but doesn't support the base character of the sequence, the font may not be listed in mRanges. The proper way to fix this issue is using format 14 subtable information for mRanges construction. However, this is not a trivial work since currently we rely on HarfBuzz for variation sequence lookup and it doesn't provide any API for retrieving coverage information. Thus, as the quick fix, iterate all font families in font fallback chain if the variation sequence is specified. Change-Id: I278da84be8fb8f553590e2e42ed450b7e4a34eca
646 lines
26 KiB
C++
646 lines
26 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.
|
|
*/
|
|
|
|
#include <gtest/gtest.h>
|
|
|
|
#include "FontTestUtils.h"
|
|
#include "MinikinFontForTest.h"
|
|
#include "UnicodeUtils.h"
|
|
|
|
using android::FontCollection;
|
|
using android::FontFamily;
|
|
using android::FontLanguage;
|
|
using android::FontStyle;
|
|
|
|
const char kItemizeFontXml[] = "/data/minikin/test/data/itemize.xml";
|
|
#define kTestFontDir "/data/minikin/test/data/"
|
|
|
|
const char kEmojiFont[] = kTestFontDir "Emoji.ttf";
|
|
const char kJAFont[] = kTestFontDir "Ja.ttf";
|
|
const char kKOFont[] = kTestFontDir "Ko.ttf";
|
|
const char kLatinBoldFont[] = kTestFontDir "Bold.ttf";
|
|
const char kLatinBoldItalicFont[] = kTestFontDir "BoldItalic.ttf";
|
|
const char kLatinFont[] = kTestFontDir "Regular.ttf";
|
|
const char kLatinItalicFont[] = kTestFontDir "Italic.ttf";
|
|
const char kZH_HansFont[] = kTestFontDir "ZhHans.ttf";
|
|
const char kZH_HantFont[] = kTestFontDir "ZhHant.ttf";
|
|
|
|
// Utility function for calling itemize function.
|
|
void itemize(FontCollection* collection, const char* str, FontStyle style,
|
|
std::vector<FontCollection::Run>* result) {
|
|
const size_t BUF_SIZE = 256;
|
|
uint16_t buf[BUF_SIZE];
|
|
size_t len;
|
|
|
|
result->clear();
|
|
ParseUnicode(buf, BUF_SIZE, str, &len, NULL);
|
|
collection->itemize(buf, len, style, result);
|
|
}
|
|
|
|
// Utility function to obtain font path associated with run.
|
|
const std::string& getFontPath(const FontCollection::Run& run) {
|
|
return ((MinikinFontForTest*)run.fakedFont.font)->fontPath();
|
|
}
|
|
|
|
TEST(FontCollectionItemizeTest, itemize_latin) {
|
|
std::unique_ptr<FontCollection> collection = getFontCollection(kTestFontDir, kItemizeFontXml);
|
|
std::vector<FontCollection::Run> runs;
|
|
|
|
const FontStyle kRegularStyle = FontStyle();
|
|
const FontStyle kItalicStyle = FontStyle(4, true);
|
|
const FontStyle kBoldStyle = FontStyle(7, false);
|
|
const FontStyle kBoldItalicStyle = FontStyle(7, true);
|
|
|
|
itemize(collection.get(), "'a' 'b' 'c' 'd' 'e'", kRegularStyle, &runs);
|
|
ASSERT_EQ(1U, runs.size());
|
|
EXPECT_EQ(0, runs[0].start);
|
|
EXPECT_EQ(5, runs[0].end);
|
|
EXPECT_EQ(kLatinFont, getFontPath(runs[0]));
|
|
EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeBold());
|
|
EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeItalic());
|
|
|
|
itemize(collection.get(), "'a' 'b' 'c' 'd' 'e'", kItalicStyle, &runs);
|
|
ASSERT_EQ(1U, runs.size());
|
|
EXPECT_EQ(0, runs[0].start);
|
|
EXPECT_EQ(5, runs[0].end);
|
|
EXPECT_EQ(kLatinItalicFont, getFontPath(runs[0]));
|
|
EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeBold());
|
|
EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeItalic());
|
|
|
|
itemize(collection.get(), "'a' 'b' 'c' 'd' 'e'", kBoldStyle, &runs);
|
|
ASSERT_EQ(1U, runs.size());
|
|
EXPECT_EQ(0, runs[0].start);
|
|
EXPECT_EQ(5, runs[0].end);
|
|
EXPECT_EQ(kLatinBoldFont, getFontPath(runs[0]));
|
|
EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeBold());
|
|
EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeItalic());
|
|
|
|
itemize(collection.get(), "'a' 'b' 'c' 'd' 'e'", kBoldItalicStyle, &runs);
|
|
ASSERT_EQ(1U, runs.size());
|
|
EXPECT_EQ(0, runs[0].start);
|
|
EXPECT_EQ(5, runs[0].end);
|
|
EXPECT_EQ(kLatinBoldItalicFont, getFontPath(runs[0]));
|
|
EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeBold());
|
|
EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeItalic());
|
|
|
|
// Continue if the specific characters (e.g. hyphen, comma, etc.) is
|
|
// followed.
|
|
itemize(collection.get(), "'a' ',' '-' 'd' '!'", kRegularStyle, &runs);
|
|
ASSERT_EQ(1U, runs.size());
|
|
EXPECT_EQ(0, runs[0].start);
|
|
EXPECT_EQ(5, runs[0].end);
|
|
EXPECT_EQ(kLatinFont, getFontPath(runs[0]));
|
|
EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeBold());
|
|
EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeItalic());
|
|
|
|
itemize(collection.get(), "'a' ',' '-' 'd' '!'", kRegularStyle, &runs);
|
|
ASSERT_EQ(1U, runs.size());
|
|
EXPECT_EQ(0, runs[0].start);
|
|
EXPECT_EQ(5, runs[0].end);
|
|
EXPECT_EQ(kLatinFont, getFontPath(runs[0]));
|
|
EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeBold());
|
|
EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeItalic());
|
|
|
|
// U+0301(COMBINING ACUTE ACCENT) must be in the same run with preceding
|
|
// chars if the font supports it.
|
|
itemize(collection.get(), "'a' U+0301", kRegularStyle, &runs);
|
|
ASSERT_EQ(1U, runs.size());
|
|
EXPECT_EQ(0, runs[0].start);
|
|
EXPECT_EQ(2, runs[0].end);
|
|
EXPECT_EQ(kLatinFont, getFontPath(runs[0]));
|
|
EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeBold());
|
|
EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeItalic());
|
|
}
|
|
|
|
TEST(FontCollectionItemizeTest, itemize_emoji) {
|
|
std::unique_ptr<FontCollection> collection = getFontCollection(kTestFontDir, kItemizeFontXml);
|
|
std::vector<FontCollection::Run> runs;
|
|
|
|
itemize(collection.get(), "U+1F469 U+1F467", FontStyle(), &runs);
|
|
ASSERT_EQ(1U, runs.size());
|
|
EXPECT_EQ(0, runs[0].start);
|
|
EXPECT_EQ(4, runs[0].end);
|
|
EXPECT_EQ(kEmojiFont, getFontPath(runs[0]));
|
|
EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeBold());
|
|
EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeItalic());
|
|
|
|
// U+20E3(COMBINING ENCLOSING KEYCAP) must be in the same run with preceding
|
|
// character if the font supports.
|
|
itemize(collection.get(), "'0' U+20E3", FontStyle(), &runs);
|
|
ASSERT_EQ(1U, runs.size());
|
|
EXPECT_EQ(0, runs[0].start);
|
|
EXPECT_EQ(2, runs[0].end);
|
|
EXPECT_EQ(kEmojiFont, getFontPath(runs[0]));
|
|
EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeBold());
|
|
EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeItalic());
|
|
|
|
itemize(collection.get(), "U+1F470 U+20E3", FontStyle(), &runs);
|
|
ASSERT_EQ(1U, runs.size());
|
|
EXPECT_EQ(0, runs[0].start);
|
|
EXPECT_EQ(3, runs[0].end);
|
|
EXPECT_EQ(kEmojiFont, getFontPath(runs[0]));
|
|
EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeBold());
|
|
EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeItalic());
|
|
|
|
itemize(collection.get(), "U+242EE U+1F470 U+20E3", FontStyle(), &runs);
|
|
ASSERT_EQ(2U, runs.size());
|
|
EXPECT_EQ(0, runs[0].start);
|
|
EXPECT_EQ(2, runs[0].end);
|
|
EXPECT_EQ(kZH_HantFont, getFontPath(runs[0]));
|
|
EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeBold());
|
|
EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeItalic());
|
|
|
|
EXPECT_EQ(2, runs[1].start);
|
|
EXPECT_EQ(5, runs[1].end);
|
|
EXPECT_EQ(kEmojiFont, getFontPath(runs[1]));
|
|
EXPECT_FALSE(runs[1].fakedFont.fakery.isFakeBold());
|
|
EXPECT_FALSE(runs[1].fakedFont.fakery.isFakeItalic());
|
|
|
|
// Currently there is no fonts which has a glyph for 'a' + U+20E3, so they
|
|
// are splitted into two.
|
|
itemize(collection.get(), "'a' U+20E3", FontStyle(), &runs);
|
|
ASSERT_EQ(2U, runs.size());
|
|
EXPECT_EQ(0, runs[0].start);
|
|
EXPECT_EQ(1, runs[0].end);
|
|
EXPECT_EQ(kLatinFont, getFontPath(runs[0]));
|
|
EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeBold());
|
|
EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeItalic());
|
|
|
|
EXPECT_EQ(1, runs[1].start);
|
|
EXPECT_EQ(2, runs[1].end);
|
|
EXPECT_EQ(kEmojiFont, getFontPath(runs[1]));
|
|
EXPECT_FALSE(runs[1].fakedFont.fakery.isFakeBold());
|
|
EXPECT_FALSE(runs[1].fakedFont.fakery.isFakeItalic());
|
|
}
|
|
|
|
TEST(FontCollectionItemizeTest, itemize_non_latin) {
|
|
std::unique_ptr<FontCollection> collection = getFontCollection(kTestFontDir, kItemizeFontXml);
|
|
std::vector<FontCollection::Run> runs;
|
|
|
|
FontStyle kJAStyle = FontStyle(FontLanguage("ja_JP", 5));
|
|
FontStyle kUSStyle = FontStyle(FontLanguage("en_US", 5));
|
|
FontStyle kZH_HansStyle = FontStyle(FontLanguage("zh_Hans", 7));
|
|
|
|
// All Japanese Hiragana characters.
|
|
itemize(collection.get(), "U+3042 U+3044 U+3046 U+3048 U+304A", kUSStyle, &runs);
|
|
ASSERT_EQ(1U, runs.size());
|
|
EXPECT_EQ(0, runs[0].start);
|
|
EXPECT_EQ(5, runs[0].end);
|
|
EXPECT_EQ(kJAFont, getFontPath(runs[0]));
|
|
EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeBold());
|
|
EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeItalic());
|
|
|
|
// All Korean Hangul characters.
|
|
itemize(collection.get(), "U+B300 U+D55C U+BBFC U+AD6D", kUSStyle, &runs);
|
|
ASSERT_EQ(1U, runs.size());
|
|
EXPECT_EQ(0, runs[0].start);
|
|
EXPECT_EQ(4, runs[0].end);
|
|
EXPECT_EQ(kKOFont, getFontPath(runs[0]));
|
|
EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeBold());
|
|
EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeItalic());
|
|
|
|
// All Han characters ja, zh-Hans font having.
|
|
// Japanese font should be selected if the specified language is Japanese.
|
|
itemize(collection.get(), "U+81ED U+82B1 U+5FCD", kJAStyle, &runs);
|
|
ASSERT_EQ(1U, runs.size());
|
|
EXPECT_EQ(0, runs[0].start);
|
|
EXPECT_EQ(3, runs[0].end);
|
|
EXPECT_EQ(kJAFont, getFontPath(runs[0]));
|
|
EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeBold());
|
|
EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeItalic());
|
|
|
|
// Simplified Chinese font should be selected if the specified language is Simplified
|
|
// Chinese.
|
|
itemize(collection.get(), "U+81ED U+82B1 U+5FCD", kZH_HansStyle, &runs);
|
|
ASSERT_EQ(1U, runs.size());
|
|
EXPECT_EQ(0, runs[0].start);
|
|
EXPECT_EQ(3, runs[0].end);
|
|
EXPECT_EQ(kZH_HansFont, getFontPath(runs[0]));
|
|
EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeBold());
|
|
EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeItalic());
|
|
|
|
// Fallbacks to other fonts if there is no glyph in the specified language's
|
|
// font. There is no character U+4F60 in Japanese.
|
|
itemize(collection.get(), "U+81ED U+4F60 U+5FCD", kJAStyle, &runs);
|
|
ASSERT_EQ(3U, runs.size());
|
|
EXPECT_EQ(0, runs[0].start);
|
|
EXPECT_EQ(1, runs[0].end);
|
|
EXPECT_EQ(kJAFont, getFontPath(runs[0]));
|
|
EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeBold());
|
|
EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeItalic());
|
|
|
|
EXPECT_EQ(1, runs[1].start);
|
|
EXPECT_EQ(2, runs[1].end);
|
|
EXPECT_EQ(kZH_HansFont, getFontPath(runs[1]));
|
|
EXPECT_FALSE(runs[1].fakedFont.fakery.isFakeBold());
|
|
EXPECT_FALSE(runs[1].fakedFont.fakery.isFakeItalic());
|
|
|
|
EXPECT_EQ(2, runs[2].start);
|
|
EXPECT_EQ(3, runs[2].end);
|
|
EXPECT_EQ(kJAFont, getFontPath(runs[2]));
|
|
EXPECT_FALSE(runs[2].fakedFont.fakery.isFakeBold());
|
|
EXPECT_FALSE(runs[2].fakedFont.fakery.isFakeItalic());
|
|
|
|
// Tone mark.
|
|
itemize(collection.get(), "U+4444 U+302D", FontStyle(), &runs);
|
|
ASSERT_EQ(1U, runs.size());
|
|
EXPECT_EQ(0, runs[0].start);
|
|
EXPECT_EQ(2, runs[0].end);
|
|
EXPECT_EQ(kZH_HansFont, getFontPath(runs[0]));
|
|
EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeBold());
|
|
EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeItalic());
|
|
}
|
|
|
|
TEST(FontCollectionItemizeTest, itemize_mixed) {
|
|
std::unique_ptr<FontCollection> collection = getFontCollection(kTestFontDir, kItemizeFontXml);
|
|
std::vector<FontCollection::Run> runs;
|
|
|
|
FontStyle kUSStyle = FontStyle(FontLanguage("en_US", 5));
|
|
|
|
itemize(collection.get(), "'a' U+4F60 'b' U+4F60 'c'", kUSStyle, &runs);
|
|
ASSERT_EQ(5U, runs.size());
|
|
EXPECT_EQ(0, runs[0].start);
|
|
EXPECT_EQ(1, runs[0].end);
|
|
EXPECT_EQ(kLatinFont, getFontPath(runs[0]));
|
|
EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeBold());
|
|
EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeItalic());
|
|
|
|
EXPECT_EQ(1, runs[1].start);
|
|
EXPECT_EQ(2, runs[1].end);
|
|
EXPECT_EQ(kZH_HansFont, getFontPath(runs[1]));
|
|
EXPECT_FALSE(runs[1].fakedFont.fakery.isFakeBold());
|
|
EXPECT_FALSE(runs[1].fakedFont.fakery.isFakeItalic());
|
|
|
|
EXPECT_EQ(2, runs[2].start);
|
|
EXPECT_EQ(3, runs[2].end);
|
|
EXPECT_EQ(kLatinFont, getFontPath(runs[2]));
|
|
EXPECT_FALSE(runs[2].fakedFont.fakery.isFakeBold());
|
|
EXPECT_FALSE(runs[2].fakedFont.fakery.isFakeItalic());
|
|
|
|
EXPECT_EQ(3, runs[3].start);
|
|
EXPECT_EQ(4, runs[3].end);
|
|
EXPECT_EQ(kZH_HansFont, getFontPath(runs[3]));
|
|
EXPECT_FALSE(runs[3].fakedFont.fakery.isFakeBold());
|
|
EXPECT_FALSE(runs[3].fakedFont.fakery.isFakeItalic());
|
|
|
|
EXPECT_EQ(4, runs[4].start);
|
|
EXPECT_EQ(5, runs[4].end);
|
|
EXPECT_EQ(kLatinFont, getFontPath(runs[4]));
|
|
EXPECT_FALSE(runs[4].fakedFont.fakery.isFakeBold());
|
|
EXPECT_FALSE(runs[4].fakedFont.fakery.isFakeItalic());
|
|
}
|
|
|
|
TEST(FontCollectionItemizeTest, itemize_variationSelector) {
|
|
std::unique_ptr<FontCollection> collection = getFontCollection(kTestFontDir, kItemizeFontXml);
|
|
std::vector<FontCollection::Run> runs;
|
|
|
|
// A glyph for U+4FAE is provided by both Japanese font and Simplified
|
|
// Chinese font. Also a glyph for U+242EE is provided by both Japanese and
|
|
// Traditional Chinese font. To avoid effects of device default locale,
|
|
// explicitly specify the locale.
|
|
FontStyle kZH_HansStyle = FontStyle(FontLanguage("zh_Hans", 7));
|
|
FontStyle kZH_HantStyle = FontStyle(FontLanguage("zh_Hant", 7));
|
|
|
|
// U+4FAE is available in both zh_Hans and ja font, but U+4FAE,U+FE00 is
|
|
// only available in ja font.
|
|
itemize(collection.get(), "U+4FAE", kZH_HansStyle, &runs);
|
|
ASSERT_EQ(1U, runs.size());
|
|
EXPECT_EQ(0, runs[0].start);
|
|
EXPECT_EQ(1, runs[0].end);
|
|
EXPECT_EQ(kZH_HansFont, getFontPath(runs[0]));
|
|
|
|
itemize(collection.get(), "U+4FAE U+FE00", kZH_HansStyle, &runs);
|
|
ASSERT_EQ(1U, runs.size());
|
|
EXPECT_EQ(0, runs[0].start);
|
|
EXPECT_EQ(2, runs[0].end);
|
|
EXPECT_EQ(kJAFont, getFontPath(runs[0]));
|
|
|
|
itemize(collection.get(), "U+4FAE U+4FAE U+FE00", kZH_HansStyle, &runs);
|
|
ASSERT_EQ(2U, runs.size());
|
|
EXPECT_EQ(0, runs[0].start);
|
|
EXPECT_EQ(1, runs[0].end);
|
|
EXPECT_EQ(kZH_HansFont, getFontPath(runs[0]));
|
|
EXPECT_EQ(1, runs[1].start);
|
|
EXPECT_EQ(3, runs[1].end);
|
|
EXPECT_EQ(kJAFont, getFontPath(runs[1]));
|
|
|
|
itemize(collection.get(), "U+4FAE U+4FAE U+FE00 U+4FAE", kZH_HansStyle, &runs);
|
|
ASSERT_EQ(3U, runs.size());
|
|
EXPECT_EQ(0, runs[0].start);
|
|
EXPECT_EQ(1, runs[0].end);
|
|
EXPECT_EQ(kZH_HansFont, getFontPath(runs[0]));
|
|
EXPECT_EQ(1, runs[1].start);
|
|
EXPECT_EQ(3, runs[1].end);
|
|
EXPECT_EQ(kJAFont, getFontPath(runs[1]));
|
|
EXPECT_EQ(3, runs[2].start);
|
|
EXPECT_EQ(4, runs[2].end);
|
|
EXPECT_EQ(kZH_HansFont, getFontPath(runs[2]));
|
|
|
|
// Validation selector after validation selector.
|
|
itemize(collection.get(), "U+4FAE U+FE00 U+FE00", kZH_HansStyle, &runs);
|
|
ASSERT_EQ(1U, runs.size());
|
|
EXPECT_EQ(0, runs[0].start);
|
|
EXPECT_EQ(3, runs[0].end);
|
|
EXPECT_EQ(kJAFont, getFontPath(runs[1]));
|
|
|
|
// No font supports U+242EE U+FE0E.
|
|
itemize(collection.get(), "U+4FAE U+FE0E", kZH_HansStyle, &runs);
|
|
ASSERT_EQ(1U, runs.size());
|
|
EXPECT_EQ(0, runs[0].start);
|
|
EXPECT_EQ(2, runs[0].end);
|
|
EXPECT_EQ(kZH_HansFont, getFontPath(runs[0]));
|
|
|
|
// Surrogate pairs handling.
|
|
// U+242EE is available in ja font and zh_Hant font.
|
|
// U+242EE U+FE00 is available only in ja font.
|
|
itemize(collection.get(), "U+242EE", kZH_HantStyle, &runs);
|
|
ASSERT_EQ(1U, runs.size());
|
|
EXPECT_EQ(0, runs[0].start);
|
|
EXPECT_EQ(2, runs[0].end);
|
|
EXPECT_EQ(kZH_HantFont, getFontPath(runs[0]));
|
|
|
|
itemize(collection.get(), "U+242EE U+FE00", kZH_HantStyle, &runs);
|
|
ASSERT_EQ(1U, runs.size());
|
|
EXPECT_EQ(0, runs[0].start);
|
|
EXPECT_EQ(3, runs[0].end);
|
|
EXPECT_EQ(kJAFont, getFontPath(runs[0]));
|
|
|
|
itemize(collection.get(), "U+242EE U+242EE U+FE00", kZH_HantStyle, &runs);
|
|
ASSERT_EQ(2U, runs.size());
|
|
EXPECT_EQ(0, runs[0].start);
|
|
EXPECT_EQ(2, runs[0].end);
|
|
EXPECT_EQ(kZH_HantFont, getFontPath(runs[0]));
|
|
EXPECT_EQ(2, runs[1].start);
|
|
EXPECT_EQ(5, runs[1].end);
|
|
EXPECT_EQ(kJAFont, getFontPath(runs[1]));
|
|
|
|
itemize(collection.get(), "U+242EE U+242EE U+FE00 U+242EE", kZH_HantStyle, &runs);
|
|
ASSERT_EQ(3U, runs.size());
|
|
EXPECT_EQ(0, runs[0].start);
|
|
EXPECT_EQ(2, runs[0].end);
|
|
EXPECT_EQ(kZH_HantFont, getFontPath(runs[0]));
|
|
EXPECT_EQ(2, runs[1].start);
|
|
EXPECT_EQ(5, runs[1].end);
|
|
EXPECT_EQ(kJAFont, getFontPath(runs[1]));
|
|
EXPECT_EQ(5, runs[2].start);
|
|
EXPECT_EQ(7, runs[2].end);
|
|
EXPECT_EQ(kZH_HantFont, getFontPath(runs[2]));
|
|
|
|
// Validation selector after validation selector.
|
|
itemize(collection.get(), "U+242EE U+FE00 U+FE00", kZH_HansStyle, &runs);
|
|
ASSERT_EQ(1U, runs.size());
|
|
EXPECT_EQ(0, runs[0].start);
|
|
EXPECT_EQ(4, runs[0].end);
|
|
EXPECT_EQ(kJAFont, getFontPath(runs[0]));
|
|
|
|
// No font supports U+242EE U+FE0E
|
|
itemize(collection.get(), "U+242EE U+FE0E", kZH_HantStyle, &runs);
|
|
ASSERT_EQ(1U, runs.size());
|
|
EXPECT_EQ(0, runs[0].start);
|
|
EXPECT_EQ(3, runs[0].end);
|
|
EXPECT_EQ(kZH_HantFont, getFontPath(runs[0]));
|
|
|
|
// Isolated variation selector supplement.
|
|
itemize(collection.get(), "U+FE00", FontStyle(), &runs);
|
|
ASSERT_EQ(1U, runs.size());
|
|
EXPECT_EQ(0, runs[0].start);
|
|
EXPECT_EQ(1, runs[0].end);
|
|
EXPECT_TRUE(runs[0].fakedFont.font == nullptr || kLatinFont == getFontPath(runs[0]));
|
|
|
|
itemize(collection.get(), "U+FE00", kZH_HantStyle, &runs);
|
|
ASSERT_EQ(1U, runs.size());
|
|
EXPECT_EQ(0, runs[0].start);
|
|
EXPECT_EQ(1, runs[0].end);
|
|
EXPECT_TRUE(runs[0].fakedFont.font == nullptr || kLatinFont == getFontPath(runs[0]));
|
|
}
|
|
|
|
TEST(FontCollectionItemizeTest, itemize_variationSelectorSupplement) {
|
|
std::unique_ptr<FontCollection> collection = getFontCollection(kTestFontDir, kItemizeFontXml);
|
|
std::vector<FontCollection::Run> runs;
|
|
|
|
// A glyph for U+845B is provided by both Japanese font and Simplified
|
|
// Chinese font. Also a glyph for U+242EE is provided by both Japanese and
|
|
// Traditional Chinese font. To avoid effects of device default locale,
|
|
// explicitly specify the locale.
|
|
FontStyle kZH_HansStyle = FontStyle(FontLanguage("zh_Hans", 7));
|
|
FontStyle kZH_HantStyle = FontStyle(FontLanguage("zh_Hant", 7));
|
|
|
|
// U+845B is available in both zh_Hans and ja font, but U+845B,U+E0100 is
|
|
// only available in ja font.
|
|
itemize(collection.get(), "U+845B", kZH_HansStyle, &runs);
|
|
ASSERT_EQ(1U, runs.size());
|
|
EXPECT_EQ(0, runs[0].start);
|
|
EXPECT_EQ(1, runs[0].end);
|
|
EXPECT_EQ(kZH_HansFont, getFontPath(runs[0]));
|
|
|
|
itemize(collection.get(), "U+845B U+E0100", kZH_HansStyle, &runs);
|
|
ASSERT_EQ(1U, runs.size());
|
|
EXPECT_EQ(0, runs[0].start);
|
|
EXPECT_EQ(3, runs[0].end);
|
|
EXPECT_EQ(kJAFont, getFontPath(runs[0]));
|
|
|
|
itemize(collection.get(), "U+845B U+845B U+E0100", kZH_HansStyle, &runs);
|
|
ASSERT_EQ(2U, runs.size());
|
|
EXPECT_EQ(0, runs[0].start);
|
|
EXPECT_EQ(1, runs[0].end);
|
|
EXPECT_EQ(kZH_HansFont, getFontPath(runs[0]));
|
|
EXPECT_EQ(1, runs[1].start);
|
|
EXPECT_EQ(4, runs[1].end);
|
|
EXPECT_EQ(kJAFont, getFontPath(runs[1]));
|
|
|
|
itemize(collection.get(), "U+845B U+845B U+E0100 U+845B", kZH_HansStyle, &runs);
|
|
ASSERT_EQ(3U, runs.size());
|
|
EXPECT_EQ(0, runs[0].start);
|
|
EXPECT_EQ(1, runs[0].end);
|
|
EXPECT_EQ(kZH_HansFont, getFontPath(runs[0]));
|
|
EXPECT_EQ(1, runs[1].start);
|
|
EXPECT_EQ(4, runs[1].end);
|
|
EXPECT_EQ(kJAFont, getFontPath(runs[1]));
|
|
EXPECT_EQ(4, runs[2].start);
|
|
EXPECT_EQ(5, runs[2].end);
|
|
EXPECT_EQ(kZH_HansFont, getFontPath(runs[2]));
|
|
|
|
// Validation selector after validation selector.
|
|
itemize(collection.get(), "U+845B U+E0100 U+E0100", kZH_HansStyle, &runs);
|
|
ASSERT_EQ(1U, runs.size());
|
|
EXPECT_EQ(0, runs[0].start);
|
|
EXPECT_EQ(5, runs[0].end);
|
|
EXPECT_EQ(kJAFont, getFontPath(runs[0]));
|
|
|
|
// No font supports U+845B U+E01E0.
|
|
itemize(collection.get(), "U+845B U+E01E0", kZH_HansStyle, &runs);
|
|
ASSERT_EQ(1U, runs.size());
|
|
EXPECT_EQ(0, runs[0].start);
|
|
EXPECT_EQ(3, runs[0].end);
|
|
EXPECT_EQ(kZH_HansFont, getFontPath(runs[0]));
|
|
|
|
// Isolated variation selector supplement
|
|
// Surrogate pairs handling.
|
|
// U+242EE is available in ja font and zh_Hant font.
|
|
// U+242EE U+E0100 is available only in ja font.
|
|
itemize(collection.get(), "U+242EE", kZH_HantStyle, &runs);
|
|
ASSERT_EQ(1U, runs.size());
|
|
EXPECT_EQ(0, runs[0].start);
|
|
EXPECT_EQ(2, runs[0].end);
|
|
EXPECT_EQ(kZH_HantFont, getFontPath(runs[0]));
|
|
|
|
itemize(collection.get(), "U+242EE U+E0101", kZH_HantStyle, &runs);
|
|
ASSERT_EQ(1U, runs.size());
|
|
EXPECT_EQ(0, runs[0].start);
|
|
EXPECT_EQ(4, runs[0].end);
|
|
EXPECT_EQ(kJAFont, getFontPath(runs[0]));
|
|
|
|
itemize(collection.get(), "U+242EE U+242EE U+E0101", kZH_HantStyle, &runs);
|
|
ASSERT_EQ(2U, runs.size());
|
|
EXPECT_EQ(0, runs[0].start);
|
|
EXPECT_EQ(2, runs[0].end);
|
|
EXPECT_EQ(kZH_HantFont, getFontPath(runs[0]));
|
|
EXPECT_EQ(2, runs[1].start);
|
|
EXPECT_EQ(6, runs[1].end);
|
|
EXPECT_EQ(kJAFont, getFontPath(runs[1]));
|
|
|
|
itemize(collection.get(), "U+242EE U+242EE U+E0101 U+242EE", kZH_HantStyle, &runs);
|
|
ASSERT_EQ(3U, runs.size());
|
|
EXPECT_EQ(0, runs[0].start);
|
|
EXPECT_EQ(2, runs[0].end);
|
|
EXPECT_EQ(kZH_HantFont, getFontPath(runs[0]));
|
|
EXPECT_EQ(2, runs[1].start);
|
|
EXPECT_EQ(6, runs[1].end);
|
|
EXPECT_EQ(kJAFont, getFontPath(runs[1]));
|
|
EXPECT_EQ(6, runs[2].start);
|
|
EXPECT_EQ(8, runs[2].end);
|
|
EXPECT_EQ(kZH_HantFont, getFontPath(runs[2]));
|
|
|
|
// Validation selector after validation selector.
|
|
itemize(collection.get(), "U+242EE U+E0100 U+E0100", kZH_HantStyle, &runs);
|
|
ASSERT_EQ(1U, runs.size());
|
|
EXPECT_EQ(0, runs[0].start);
|
|
EXPECT_EQ(6, runs[0].end);
|
|
EXPECT_EQ(kJAFont, getFontPath(runs[0]));
|
|
|
|
// No font supports U+242EE U+E01E0.
|
|
itemize(collection.get(), "U+242EE U+E01E0", kZH_HantStyle, &runs);
|
|
ASSERT_EQ(1U, runs.size());
|
|
EXPECT_EQ(0, runs[0].start);
|
|
EXPECT_EQ(4, runs[0].end);
|
|
EXPECT_EQ(kZH_HantFont, getFontPath(runs[0]));
|
|
|
|
// Isolated variation selector supplement.
|
|
itemize(collection.get(), "U+E0100", FontStyle(), &runs);
|
|
ASSERT_EQ(1U, runs.size());
|
|
EXPECT_EQ(0, runs[0].start);
|
|
EXPECT_EQ(2, runs[0].end);
|
|
EXPECT_TRUE(runs[0].fakedFont.font == nullptr || kLatinFont == getFontPath(runs[0]));
|
|
|
|
itemize(collection.get(), "U+E0100", kZH_HantStyle, &runs);
|
|
ASSERT_EQ(1U, runs.size());
|
|
EXPECT_EQ(0, runs[0].start);
|
|
EXPECT_EQ(2, runs[0].end);
|
|
EXPECT_TRUE(runs[0].fakedFont.font == nullptr || kLatinFont == getFontPath(runs[0]));
|
|
}
|
|
|
|
TEST(FontCollectionItemizeTest, itemize_no_crash) {
|
|
std::unique_ptr<FontCollection> collection = getFontCollection(kTestFontDir, kItemizeFontXml);
|
|
std::vector<FontCollection::Run> runs;
|
|
|
|
// Broken Surrogate pairs. Check only not crashing.
|
|
itemize(collection.get(), "'a' U+D83D 'a'", FontStyle(), &runs);
|
|
itemize(collection.get(), "'a' U+DC69 'a'", FontStyle(), &runs);
|
|
itemize(collection.get(), "'a' U+D83D U+D83D 'a'", FontStyle(), &runs);
|
|
itemize(collection.get(), "'a' U+DC69 U+DC69 'a'", FontStyle(), &runs);
|
|
|
|
// Isolated variation selector. Check only not crashing.
|
|
itemize(collection.get(), "U+FE00 U+FE00", FontStyle(), &runs);
|
|
itemize(collection.get(), "U+E0100 U+E0100", FontStyle(), &runs);
|
|
itemize(collection.get(), "U+FE00 U+E0100", FontStyle(), &runs);
|
|
itemize(collection.get(), "U+E0100 U+FE00", FontStyle(), &runs);
|
|
|
|
// Tone mark only. Check only not crashing.
|
|
itemize(collection.get(), "U+302D", FontStyle(), &runs);
|
|
itemize(collection.get(), "U+302D U+302D", FontStyle(), &runs);
|
|
|
|
// Tone mark and variation selector mixed. Check only not crashing.
|
|
itemize(collection.get(), "U+FE00 U+302D U+E0100", FontStyle(), &runs);
|
|
}
|
|
|
|
TEST(FontCollectionItemizeTest, itemize_fakery) {
|
|
std::unique_ptr<FontCollection> collection = getFontCollection(kTestFontDir, kItemizeFontXml);
|
|
std::vector<FontCollection::Run> runs;
|
|
|
|
FontStyle kJABoldStyle = FontStyle(FontLanguage("ja_JP", 5), 0, 7, false);
|
|
FontStyle kJAItalicStyle = FontStyle(FontLanguage("ja_JP", 5), 0, 5, true);
|
|
FontStyle kJABoldItalicStyle = FontStyle(FontLanguage("ja_JP", 5), 0, 7, true);
|
|
|
|
// Currently there is no italic or bold font for Japanese. FontFakery has
|
|
// the differences between desired and actual font style.
|
|
|
|
// All Japanese Hiragana characters.
|
|
itemize(collection.get(), "U+3042 U+3044 U+3046 U+3048 U+304A", kJABoldStyle, &runs);
|
|
ASSERT_EQ(1U, runs.size());
|
|
EXPECT_EQ(0, runs[0].start);
|
|
EXPECT_EQ(5, runs[0].end);
|
|
EXPECT_EQ(kJAFont, getFontPath(runs[0]));
|
|
EXPECT_TRUE(runs[0].fakedFont.fakery.isFakeBold());
|
|
EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeItalic());
|
|
|
|
// All Japanese Hiragana characters.
|
|
itemize(collection.get(), "U+3042 U+3044 U+3046 U+3048 U+304A", kJAItalicStyle, &runs);
|
|
ASSERT_EQ(1U, runs.size());
|
|
EXPECT_EQ(0, runs[0].start);
|
|
EXPECT_EQ(5, runs[0].end);
|
|
EXPECT_EQ(kJAFont, getFontPath(runs[0]));
|
|
EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeBold());
|
|
EXPECT_TRUE(runs[0].fakedFont.fakery.isFakeItalic());
|
|
|
|
// All Japanese Hiragana characters.
|
|
itemize(collection.get(), "U+3042 U+3044 U+3046 U+3048 U+304A", kJABoldItalicStyle, &runs);
|
|
ASSERT_EQ(1U, runs.size());
|
|
EXPECT_EQ(0, runs[0].start);
|
|
EXPECT_EQ(5, runs[0].end);
|
|
EXPECT_EQ(kJAFont, getFontPath(runs[0]));
|
|
EXPECT_TRUE(runs[0].fakedFont.fakery.isFakeBold());
|
|
EXPECT_TRUE(runs[0].fakedFont.fakery.isFakeItalic());
|
|
}
|
|
|
|
TEST(FontCollectionItemizeTest, itemize_vs_sequence_but_no_base_char) {
|
|
// kVSTestFont supports U+717D U+FE02 but doesn't support U+717D.
|
|
// kVSTestFont should be selected for U+717D U+FE02 even if it does not support the base code
|
|
// point.
|
|
const std::string kVSTestFont = kTestFontDir "VarioationSelectorTest-Regular.ttf";
|
|
|
|
std::vector<android::FontFamily*> families;
|
|
FontFamily* family1 = new FontFamily(FontLanguage(), android::VARIANT_DEFAULT);
|
|
family1->addFont(new MinikinFontForTest(kLatinFont));
|
|
families.push_back(family1);
|
|
|
|
FontFamily* family2 = new FontFamily(FontLanguage(), android::VARIANT_DEFAULT);
|
|
family2->addFont(new MinikinFontForTest(kVSTestFont));
|
|
families.push_back(family2);
|
|
|
|
FontCollection collection(families);
|
|
|
|
std::vector<FontCollection::Run> runs;
|
|
|
|
itemize(&collection, "U+717D U+FE02", FontStyle(), &runs);
|
|
ASSERT_EQ(1U, runs.size());
|
|
EXPECT_EQ(0, runs[0].start);
|
|
EXPECT_EQ(2, runs[0].end);
|
|
EXPECT_EQ(kVSTestFont, getFontPath(runs[0]));
|
|
|
|
family1->Unref();
|
|
family2->Unref();
|
|
}
|