mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Merge "Introduce unit tests for FontCollection::itemize."
This commit is contained in:
commit
2ea397d74c
@ -27,18 +27,28 @@ LOCAL_STATIC_LIBRARIES := libminikin
|
||||
# pulled in by the build system (and thus sadly must be repeated).
|
||||
|
||||
LOCAL_SHARED_LIBRARIES := \
|
||||
libharfbuzz_ng \
|
||||
libskia \
|
||||
libft2 \
|
||||
liblog \
|
||||
libz \
|
||||
libharfbuzz_ng \
|
||||
libicuuc \
|
||||
libutils
|
||||
liblog \
|
||||
libutils \
|
||||
libz
|
||||
|
||||
LOCAL_STATIC_LIBRARIES += \
|
||||
libxml2
|
||||
|
||||
LOCAL_SRC_FILES += \
|
||||
FontCollectionItemizeTest.cpp \
|
||||
FontTestUtils.cpp \
|
||||
MinikinFontForTest.cpp \
|
||||
GraphemeBreakTests.cpp \
|
||||
LayoutUtilsTest.cpp \
|
||||
UnicodeUtils.cpp
|
||||
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../libs/minikin/
|
||||
LOCAL_C_INCLUDES := \
|
||||
$(LOCAL_PATH)/../libs/minikin/ \
|
||||
external/libxml2/include \
|
||||
external/skia/src/core \
|
||||
|
||||
include $(BUILD_NATIVE_TEST)
|
||||
|
||||
343
tests/FontCollectionItemizeTest.cpp
Normal file
343
tests/FontCollectionItemizeTest.cpp
Normal file
@ -0,0 +1,343 @@
|
||||
/*
|
||||
* 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::FontLanguage;
|
||||
using android::FontStyle;
|
||||
|
||||
const char kEmojiFont[] = "/system/fonts/NotoColorEmoji.ttf";
|
||||
const char kJAFont[] = "/system/fonts/NotoSansJP-Regular.otf";
|
||||
const char kKOFont[] = "/system/fonts/NotoSansKR-Regular.otf";
|
||||
const char kLatinBoldFont[] = "/system/fonts/Roboto-Bold.ttf";
|
||||
const char kLatinBoldItalicFont[] = "/system/fonts/Roboto-BoldItalic.ttf";
|
||||
const char kLatinFont[] = "/system/fonts/Roboto-Regular.ttf";
|
||||
const char kLatinItalicFont[] = "/system/fonts/Roboto-Italic.ttf";
|
||||
const char kZH_HansFont[] = "/system/fonts/NotoSansSC-Regular.otf";
|
||||
const char kZH_HantFont[] = "/system/fonts/NotoSansTC-Regular.otf";
|
||||
|
||||
// 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();
|
||||
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();
|
||||
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());
|
||||
|
||||
// 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();
|
||||
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();
|
||||
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_no_crash) {
|
||||
std::unique_ptr<FontCollection> collection = getFontCollection();
|
||||
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();
|
||||
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());
|
||||
}
|
||||
|
||||
// TODO(11256006): Add Variation Selector test cases once it is supported.
|
||||
81
tests/FontTestUtils.cpp
Normal file
81
tests/FontTestUtils.cpp
Normal file
@ -0,0 +1,81 @@
|
||||
/*
|
||||
* 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 <libxml/tree.h>
|
||||
|
||||
#include <minikin/FontCollection.h>
|
||||
#include <minikin/FontFamily.h>
|
||||
|
||||
#include "MinikinFontForTest.h"
|
||||
|
||||
const char kFontDir[] = "/system/fonts/";
|
||||
const char kFontXml[] = "/system/etc/fonts.xml";
|
||||
|
||||
std::unique_ptr<android::FontCollection> getFontCollection() {
|
||||
xmlDoc* doc = xmlReadFile(kFontXml, NULL, 0);
|
||||
xmlNode* familySet = xmlDocGetRootElement(doc);
|
||||
|
||||
std::vector<android::FontFamily*> families;
|
||||
for (xmlNode* familyNode = familySet->children; familyNode; familyNode = familyNode->next) {
|
||||
if (xmlStrcmp(familyNode->name, (const xmlChar*)"family") != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
xmlChar* variantXmlch = xmlGetProp(familyNode, (const xmlChar*)"variant");
|
||||
int variant = android::VARIANT_DEFAULT;
|
||||
if (variantXmlch) {
|
||||
if (xmlStrcmp(variantXmlch, (const xmlChar*)"elegant") == 0) {
|
||||
variant = android::VARIANT_ELEGANT;
|
||||
} else if (xmlStrcmp(variantXmlch, (const xmlChar*)"compact") == 0) {
|
||||
variant = android::VARIANT_COMPACT;
|
||||
}
|
||||
}
|
||||
|
||||
xmlChar* lang = xmlGetProp(familyNode, (const xmlChar*)"lang");
|
||||
|
||||
android::FontFamily* family = new android::FontFamily(
|
||||
android::FontLanguage((const char*)lang, xmlStrlen(lang)), variant);
|
||||
|
||||
for (xmlNode* fontNode = familyNode->children; fontNode; fontNode = fontNode->next) {
|
||||
if (xmlStrcmp(fontNode->name, (const xmlChar*)"font") != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int weight = atoi((const char*)(xmlGetProp(fontNode, (const xmlChar*)"weight"))) / 100;
|
||||
bool italic = xmlStrcmp(
|
||||
xmlGetProp(fontNode, (const xmlChar*)"style"), (const xmlChar*)"italic") == 0;
|
||||
|
||||
xmlChar* fontFileName = xmlNodeListGetString(doc, fontNode->xmlChildrenNode, 1);
|
||||
std::string fontPath = kFontDir + std::string((const char*)fontFileName);
|
||||
xmlFree(fontFileName);
|
||||
|
||||
if (access(fontPath.c_str(), R_OK) != 0) {
|
||||
// Skip not accessible fonts.
|
||||
continue;
|
||||
}
|
||||
|
||||
family->addFont(new MinikinFontForTest(fontPath), android::FontStyle(weight, italic));
|
||||
}
|
||||
families.push_back(family);
|
||||
}
|
||||
xmlFreeDoc(doc);
|
||||
|
||||
std::unique_ptr<android::FontCollection> r(new android::FontCollection(families));
|
||||
for (size_t i = 0; i < families.size(); ++i) {
|
||||
families[i]->Unref();
|
||||
}
|
||||
return r;
|
||||
}
|
||||
30
tests/FontTestUtils.h
Normal file
30
tests/FontTestUtils.h
Normal file
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef MINIKIN_FONT_TEST_UTILS_H
|
||||
#define MINIKIN_FONT_TEST_UTILS_H
|
||||
|
||||
#include <minikin/FontCollection.h>
|
||||
|
||||
/**
|
||||
* Returns FontCollection from installed fonts.
|
||||
*
|
||||
* This function reads /system/etc/fonts.xml and make font families and
|
||||
* collections of them. MinikinFontForTest is used for FontFamily creation.
|
||||
*/
|
||||
std::unique_ptr<android::FontCollection> getFontCollection();
|
||||
|
||||
#endif // MINIKIN_FONT_TEST_UTILS_H
|
||||
62
tests/MinikinFontForTest.cpp
Normal file
62
tests/MinikinFontForTest.cpp
Normal file
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* 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 "MinikinFontForTest.h"
|
||||
|
||||
#include <minikin/MinikinFont.h>
|
||||
|
||||
#include <SkTypeface.h>
|
||||
|
||||
#include <cutils/log.h>
|
||||
|
||||
MinikinFontForTest::MinikinFontForTest(const std::string& font_path) : mFontPath(font_path) {
|
||||
mTypeface = SkTypeface::CreateFromFile(font_path.c_str());
|
||||
}
|
||||
|
||||
MinikinFontForTest::~MinikinFontForTest() {
|
||||
}
|
||||
|
||||
bool MinikinFontForTest::GetGlyph(uint32_t codepoint, uint32_t *glyph) const {
|
||||
LOG_ALWAYS_FATAL("MinikinFontForTest::GetGlyph is not yet implemented");
|
||||
return false;
|
||||
}
|
||||
|
||||
float MinikinFontForTest::GetHorizontalAdvance(
|
||||
uint32_t glyph_id, const android::MinikinPaint &paint) const {
|
||||
LOG_ALWAYS_FATAL("MinikinFontForTest::GetHorizontalAdvance is not yet implemented");
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
void MinikinFontForTest::GetBounds(android::MinikinRect* bounds, uint32_t glyph_id,
|
||||
const android::MinikinPaint& paint) const {
|
||||
LOG_ALWAYS_FATAL("MinikinFontForTest::GetBounds is not yet implemented");
|
||||
}
|
||||
|
||||
bool MinikinFontForTest::GetTable(uint32_t tag, uint8_t *buf, size_t *size) {
|
||||
if (buf == NULL) {
|
||||
const size_t tableSize = mTypeface->getTableSize(tag);
|
||||
*size = tableSize;
|
||||
return tableSize != 0;
|
||||
} else {
|
||||
const size_t actualSize = mTypeface->getTableData(tag, 0, *size, buf);
|
||||
*size = actualSize;
|
||||
return actualSize != 0;
|
||||
}
|
||||
}
|
||||
|
||||
int32_t MinikinFontForTest::GetUniqueId() const {
|
||||
return mTypeface->uniqueID();
|
||||
}
|
||||
38
tests/MinikinFontForTest.h
Normal file
38
tests/MinikinFontForTest.h
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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 <minikin/MinikinFont.h>
|
||||
|
||||
class SkTypeface;
|
||||
|
||||
class MinikinFontForTest : public android::MinikinFont {
|
||||
public:
|
||||
explicit MinikinFontForTest(const std::string& font_path);
|
||||
~MinikinFontForTest();
|
||||
|
||||
// MinikinFont overrides.
|
||||
bool GetGlyph(uint32_t codepoint, uint32_t *glyph) const;
|
||||
float GetHorizontalAdvance(uint32_t glyph_id, const android::MinikinPaint &paint) const;
|
||||
void GetBounds(android::MinikinRect* bounds, uint32_t glyph_id,
|
||||
const android::MinikinPaint& paint) const;
|
||||
bool GetTable(uint32_t tag, uint8_t *buf, size_t *size);
|
||||
int32_t GetUniqueId() const;
|
||||
|
||||
const std::string& fontPath() const { return mFontPath; }
|
||||
private:
|
||||
SkTypeface *mTypeface;
|
||||
const std::string mFontPath;
|
||||
};
|
||||
Loading…
x
Reference in New Issue
Block a user