summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSeigo Nonaka <nona@google.com>2015-09-16 20:31:35 +0900
committerSeigo Nonaka <nona@google.com>2015-09-18 15:40:51 +0900
commit1c2bd209d11e59ea3a31d49ec4e97725fd711bea (patch)
tree290928ff0b27b50803932f0e2549691bde976fd7
parent4e3adc6fb2073d5b466b88b8f5329d281038aba1 (diff)
downloadandroid_frameworks_minikin-1c2bd209d11e59ea3a31d49ec4e97725fd711bea.tar.gz
android_frameworks_minikin-1c2bd209d11e59ea3a31d49ec4e97725fd711bea.tar.bz2
android_frameworks_minikin-1c2bd209d11e59ea3a31d49ec4e97725fd711bea.zip
Introduce unit tests for FontCollection::itemize.
Introduced tests depend on installed font list in running device. I verified these test passed on Nexus 5(hammerhead), Nexus 6(shamu) and Nexus 9(volantis). Bug: 11256006 Bug: 17759267 Change-Id: I6f806370e17f6c6d3dad8df0cb70bb475a827873
-rw-r--r--tests/Android.mk20
-rw-r--r--tests/FontCollectionItemizeTest.cpp343
-rw-r--r--tests/FontTestUtils.cpp81
-rw-r--r--tests/FontTestUtils.h30
-rw-r--r--tests/MinikinFontForTest.cpp62
-rw-r--r--tests/MinikinFontForTest.h38
6 files changed, 569 insertions, 5 deletions
diff --git a/tests/Android.mk b/tests/Android.mk
index 00847e3..680cbe9 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -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)
diff --git a/tests/FontCollectionItemizeTest.cpp b/tests/FontCollectionItemizeTest.cpp
new file mode 100644
index 0000000..cabc967
--- /dev/null
+++ b/tests/FontCollectionItemizeTest.cpp
@@ -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.
diff --git a/tests/FontTestUtils.cpp b/tests/FontTestUtils.cpp
new file mode 100644
index 0000000..e5d6c2a
--- /dev/null
+++ b/tests/FontTestUtils.cpp
@@ -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;
+}
diff --git a/tests/FontTestUtils.h b/tests/FontTestUtils.h
new file mode 100644
index 0000000..d53956f
--- /dev/null
+++ b/tests/FontTestUtils.h
@@ -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
diff --git a/tests/MinikinFontForTest.cpp b/tests/MinikinFontForTest.cpp
new file mode 100644
index 0000000..2d29e80
--- /dev/null
+++ b/tests/MinikinFontForTest.cpp
@@ -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();
+}
diff --git a/tests/MinikinFontForTest.h b/tests/MinikinFontForTest.h
new file mode 100644
index 0000000..ecebb7e
--- /dev/null
+++ b/tests/MinikinFontForTest.h
@@ -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;
+};