From 5e6bc85d69a97d8db6c068e56614aaac02da347a Mon Sep 17 00:00:00 2001 From: Seigo Nonaka Date: Thu, 16 Jun 2016 16:58:14 +0900 Subject: [PATCH] Introduce FontCollection perftest This CL introduces performance tests for FontCollection. To support TTC file in /system/fonts, this CL also extends FontTestUtils Bug:29142734 Change-Id: I9d8ad24ca55f61031b85623ab7c26234239e4f41 --- tests/perftests/Android.mk | 17 +++++- tests/perftests/FontCollection.cpp | 90 ++++++++++++++++++++++++++++++ tests/util/FontTestUtils.cpp | 33 +++++++---- tests/util/MinikinFontForTest.cpp | 9 +++ tests/util/MinikinFontForTest.h | 1 + 5 files changed, 137 insertions(+), 13 deletions(-) create mode 100644 tests/perftests/FontCollection.cpp diff --git a/tests/perftests/Android.mk b/tests/perftests/Android.mk index d3ed600b6ee..de5769c7436 100644 --- a/tests/perftests/Android.mk +++ b/tests/perftests/Android.mk @@ -18,7 +18,10 @@ LOCAL_PATH := $(call my-dir) perftest_src_files := \ ../util/FileUtils.cpp \ + ../util/FontTestUtils.cpp \ + ../util/MinikinFontForTest.cpp \ ../util/UnicodeUtils.cpp \ + FontCollection.cpp \ FontLanguage.cpp \ GraphemeBreak.cpp \ Hyphenator.cpp \ @@ -29,12 +32,20 @@ include $(CLEAR_VARS) LOCAL_MODULE := minikin_perftests LOCAL_CPPFLAGS := -Werror -Wall -Wextra LOCAL_SRC_FILES := $(perftest_src_files) -LOCAL_STATIC_LIBRARIES := libminikin +LOCAL_STATIC_LIBRARIES := \ + libminikin \ + libxml2 + LOCAL_SHARED_LIBRARIES := \ + libharfbuzz_ng \ libicuuc \ - liblog + liblog \ + libskia + LOCAL_C_INCLUDES := \ $(LOCAL_PATH)/../ \ $(LOCAL_PATH)/../../libs/minikin \ - external/harfbuzz_ng/src + external/harfbuzz_ng/src \ + external/libxml2/include + include $(BUILD_NATIVE_BENCHMARK) diff --git a/tests/perftests/FontCollection.cpp b/tests/perftests/FontCollection.cpp new file mode 100644 index 00000000000..490f5d85fea --- /dev/null +++ b/tests/perftests/FontCollection.cpp @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2016 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 + +#include +#include +#include +#include +#include + +namespace minikin { + +const char* SYSTEM_FONT_PATH = "/system/fonts/"; +const char* SYSTEM_FONT_XML = "/system/etc/fonts.xml"; + +static void BM_FontCollection_hasVariationSelector(benchmark::State& state) { + MinikinAutoUnref collection( + getFontCollection(SYSTEM_FONT_PATH, SYSTEM_FONT_XML)); + + uint32_t baseCp = state.range_x(); + uint32_t vsCp = state.range_y(); + + char titleBuffer[64]; + snprintf(titleBuffer, 64, "hasVariationSelector U+%04X,U+%04X", baseCp, vsCp); + state.SetLabel(titleBuffer); + + while (state.KeepRunning()) { + collection->hasVariationSelector(baseCp, vsCp); + } +} + +// TODO: Rewrite with BENCHMARK_CAPTURE for better test name. +BENCHMARK(BM_FontCollection_hasVariationSelector) + ->ArgPair(0x2708, 0xFE0F) + ->ArgPair(0x2708, 0xFE0E) + ->ArgPair(0x3402, 0xE0100); + +struct ItemizeTestCases { + std::string itemizeText; + std::string languageTag; + std::string labelText; +} ITEMIZE_TEST_CASES[] = { + { "'A' 'n' 'd' 'r' 'o' 'i' 'd'", "en", "English" }, + { "U+4E16", "zh-Hans", "CJK Ideograph" }, + { "U+4E16", "zh-Hans,zh-Hant,ja,en,es,pt,fr,de", "CJK Ideograph with many language fallback" }, + { "U+3402 U+E0100", "ja", "CJK Ideograph with variation selector" }, + { "'A' 'n' U+0E1A U+0E31 U+0645 U+062D U+0648", "en", "Mixture of English, Thai and Arabic" }, + { "U+2708 U+FE0E", "en", "Emoji with variation selector" }, + { "U+0031 U+FE0F U+20E3", "en", "KEYCAP" }, +}; + +static void BM_FontCollection_itemize(benchmark::State& state) { + MinikinAutoUnref collection( + getFontCollection(SYSTEM_FONT_PATH, SYSTEM_FONT_XML)); + + size_t testIndex = state.range_x(); + state.SetLabel("Itemize: " + ITEMIZE_TEST_CASES[testIndex].labelText); + + uint16_t buffer[64]; + size_t utf16_length = 0; + ParseUnicode( + buffer, 64, ITEMIZE_TEST_CASES[testIndex].itemizeText.c_str(), &utf16_length, nullptr); + std::vector result; + FontStyle style(FontStyle::registerLanguageList(ITEMIZE_TEST_CASES[testIndex].languageTag)); + + android::AutoMutex _l(gMinikinLock); + while (state.KeepRunning()) { + result.clear(); + collection->itemize(buffer, utf16_length, style, &result); + } +} + +// TODO: Rewrite with BENCHMARK_CAPTURE once it is available in Android. +BENCHMARK(BM_FontCollection_itemize) + ->Arg(0)->Arg(1)->Arg(2)->Arg(3)->Arg(4)->Arg(5)->Arg(6); + +} // namespace minikin diff --git a/tests/util/FontTestUtils.cpp b/tests/util/FontTestUtils.cpp index eaf3610df26..246c87231af 100644 --- a/tests/util/FontTestUtils.cpp +++ b/tests/util/FontTestUtils.cpp @@ -47,10 +47,14 @@ FontCollection* getFontCollection(const char* fontDir, const char* fontXml) { } xmlChar* lang = xmlGetProp(familyNode, (const xmlChar*)"lang"); - uint32_t langId = FontStyle::registerLanguageList( - std::string((const char*)lang, xmlStrlen(lang))); - - FontFamily* family = new FontFamily(langId, variant); + FontFamily* family; + if (lang == nullptr) { + family = new FontFamily(variant); + } else { + uint32_t langId = FontStyle::registerLanguageList( + std::string((const char*)lang, xmlStrlen(lang))); + family = new FontFamily(langId, variant); + } for (xmlNode* fontNode = familyNode->children; fontNode; fontNode = fontNode->next) { if (xmlStrcmp(fontNode->name, (const xmlChar*)"font") != 0) { @@ -60,18 +64,27 @@ FontCollection* getFontCollection(const char* fontDir, const char* fontXml) { int weight = atoi((const char*)(xmlGetProp(fontNode, (const xmlChar*)"weight"))) / 100; bool italic = xmlStrcmp( xmlGetProp(fontNode, (const xmlChar*)"style"), (const xmlChar*)"italic") == 0; + xmlChar* index = xmlGetProp(familyNode, (const xmlChar*)"index"); xmlChar* fontFileName = xmlNodeListGetString(doc, fontNode->xmlChildrenNode, 1); std::string fontPath = fontDir + std::string((const char*)fontFileName); xmlFree(fontFileName); - LOG_ALWAYS_FATAL_IF(access(fontPath.c_str(), R_OK) != 0, - "%s is not found", fontPath.c_str()); + if (access(fontPath.c_str(), R_OK) != 0) { + ALOGW("%s is not found.", fontPath.c_str()); + continue; + } - MinikinAutoUnref - minikinFont(MinikinFontForTest::createFromFile(fontPath)); - - family->addFont(minikinFont.get(), FontStyle(weight, italic)); + if (index == nullptr) { + MinikinAutoUnref + minikinFont(MinikinFontForTest::createFromFile(fontPath)); + family->addFont(minikinFont.get(), FontStyle(weight, italic)); + } else { + MinikinAutoUnref + minikinFont(MinikinFontForTest::createFromFileWithIndex(fontPath, + atoi((const char*)index))); + family->addFont(minikinFont.get(), FontStyle(weight, italic)); + } } families.push_back(family); } diff --git a/tests/util/MinikinFontForTest.cpp b/tests/util/MinikinFontForTest.cpp index 93e3e66d2df..392d5b2ea54 100644 --- a/tests/util/MinikinFontForTest.cpp +++ b/tests/util/MinikinFontForTest.cpp @@ -32,6 +32,15 @@ MinikinFontForTest* MinikinFontForTest::createFromFile(const std::string& font_p return font; } +// static +MinikinFontForTest* MinikinFontForTest::createFromFileWithIndex(const std::string& font_path, + int index) { + SkTypeface* typeface = SkTypeface::CreateFromFile(font_path.c_str(), index); + MinikinFontForTest* font = new MinikinFontForTest(font_path, typeface); + SkSafeUnref(typeface); + return font; +} + MinikinFontForTest::MinikinFontForTest(const std::string& font_path, SkTypeface* typeface) : MinikinFont(typeface->uniqueID()), mTypeface(typeface), diff --git a/tests/util/MinikinFontForTest.h b/tests/util/MinikinFontForTest.h index bfd8421525b..7b5322ca0b1 100644 --- a/tests/util/MinikinFontForTest.h +++ b/tests/util/MinikinFontForTest.h @@ -31,6 +31,7 @@ public: // Helper function for creating MinikinFontForTest instance from font file. // Calller need to unref returned object. static MinikinFontForTest* createFromFile(const std::string& font_path); + static MinikinFontForTest* createFromFileWithIndex(const std::string& font_path, int index); // MinikinFont overrides. float GetHorizontalAdvance(uint32_t glyph_id, const MinikinPaint &paint) const;