11c2bd209d11e59ea3a31d49ec4e97725fd711beaSeigo Nonaka/*
21c2bd209d11e59ea3a31d49ec4e97725fd711beaSeigo Nonaka * Copyright (C) 2015 The Android Open Source Project
31c2bd209d11e59ea3a31d49ec4e97725fd711beaSeigo Nonaka *
41c2bd209d11e59ea3a31d49ec4e97725fd711beaSeigo Nonaka * Licensed under the Apache License, Version 2.0 (the "License");
51c2bd209d11e59ea3a31d49ec4e97725fd711beaSeigo Nonaka * you may not use this file except in compliance with the License.
61c2bd209d11e59ea3a31d49ec4e97725fd711beaSeigo Nonaka * You may obtain a copy of the License at
71c2bd209d11e59ea3a31d49ec4e97725fd711beaSeigo Nonaka *
81c2bd209d11e59ea3a31d49ec4e97725fd711beaSeigo Nonaka *      http://www.apache.org/licenses/LICENSE-2.0
91c2bd209d11e59ea3a31d49ec4e97725fd711beaSeigo Nonaka *
101c2bd209d11e59ea3a31d49ec4e97725fd711beaSeigo Nonaka * Unless required by applicable law or agreed to in writing, software
111c2bd209d11e59ea3a31d49ec4e97725fd711beaSeigo Nonaka * distributed under the License is distributed on an "AS IS" BASIS,
121c2bd209d11e59ea3a31d49ec4e97725fd711beaSeigo Nonaka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
131c2bd209d11e59ea3a31d49ec4e97725fd711beaSeigo Nonaka * See the License for the specific language governing permissions and
141c2bd209d11e59ea3a31d49ec4e97725fd711beaSeigo Nonaka * limitations under the License.
151c2bd209d11e59ea3a31d49ec4e97725fd711beaSeigo Nonaka */
161c2bd209d11e59ea3a31d49ec4e97725fd711beaSeigo Nonaka
17555d84c6f98eafcbe677cdcb8e9605760acd8ce5Mark Salyzyn#define LOG_TAG "Minikin"
181c2bd209d11e59ea3a31d49ec4e97725fd711beaSeigo Nonaka
19555d84c6f98eafcbe677cdcb8e9605760acd8ce5Mark Salyzyn#include <libxml/tree.h>
2039ab40115fae6d0c948e435233b3dd997ee7d8e5Mark Salyzyn#include <log/log.h>
211d461589869ee5b7102f96271b0ef0a776ab513cSeigo Nonaka#include <unistd.h>
22198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka
231d461589869ee5b7102f96271b0ef0a776ab513cSeigo Nonaka#include "minikin/FontCollection.h"
241d461589869ee5b7102f96271b0ef0a776ab513cSeigo Nonaka#include "minikin/FontFamily.h"
25b47e9b21077d2a0847a64fa713aa9892196b5d2aSeigo Nonaka#include "minikin/LocaleList.h"
266c8722e217ff5238f0b849152d7936959a728103Seigo Nonaka
27e1cfa7d7a17f9e24a27132032ec2f77a63e99913Seigo Nonaka#include "FontTestUtils.h"
289dffc23bd79a82e75181e33974af05da62dc6306Seigo Nonaka#include "FreeTypeMinikinFontForTest.h"
297fbdd83e92a76c955c67a1c761088b36daf7158cSeigo Nonaka#include "LocaleListCache.h"
30b02135558f85d94772183b08e6e0c454bca00d22Seigo Nonaka#include "MinikinInternal.h"
311c2bd209d11e59ea3a31d49ec4e97725fd711beaSeigo Nonaka
3214e2d136aaef271ba131f917cf5f27baa31ae5adSeigo Nonakanamespace minikin {
3314e2d136aaef271ba131f917cf5f27baa31ae5adSeigo Nonaka
34b02135558f85d94772183b08e6e0c454bca00d22Seigo Nonakanamespace {
35b02135558f85d94772183b08e6e0c454bca00d22Seigo Nonakastd::string xmlTrim(const std::string& in) {
36b02135558f85d94772183b08e6e0c454bca00d22Seigo Nonaka    if (in.empty()) {
37b02135558f85d94772183b08e6e0c454bca00d22Seigo Nonaka        return in;
38b02135558f85d94772183b08e6e0c454bca00d22Seigo Nonaka    }
39b02135558f85d94772183b08e6e0c454bca00d22Seigo Nonaka    const char XML_SPACES[] = "\u0020\u000D\u000A\u0009";
40b02135558f85d94772183b08e6e0c454bca00d22Seigo Nonaka    const size_t start = in.find_first_not_of(XML_SPACES);  // inclusive
41b02135558f85d94772183b08e6e0c454bca00d22Seigo Nonaka    const size_t end = in.find_last_not_of(XML_SPACES);     // inclusive
42b02135558f85d94772183b08e6e0c454bca00d22Seigo Nonaka    MINIKIN_ASSERT(start != std::string::npos, "Not a valid file name \"%s\"", in.c_str());
43b02135558f85d94772183b08e6e0c454bca00d22Seigo Nonaka    MINIKIN_ASSERT(end != std::string::npos, "Not a valid file name \"%s\"", in.c_str());
44b02135558f85d94772183b08e6e0c454bca00d22Seigo Nonaka    return in.substr(start, end - start + 1 /* +1 since end is inclusive */);
45b02135558f85d94772183b08e6e0c454bca00d22Seigo Nonaka}
46b02135558f85d94772183b08e6e0c454bca00d22Seigo Nonaka
47b02135558f85d94772183b08e6e0c454bca00d22Seigo Nonaka}  // namespace
48b02135558f85d94772183b08e6e0c454bca00d22Seigo Nonaka
4954e248ac7fa00d430092a8e993c83fccd4f72df5Seigo Nonakastd::vector<std::shared_ptr<FontFamily>> getFontFamilies(const std::string& fontDir,
5054e248ac7fa00d430092a8e993c83fccd4f72df5Seigo Nonaka                                                         const std::string& xmlPath) {
5154e248ac7fa00d430092a8e993c83fccd4f72df5Seigo Nonaka    xmlDoc* doc = xmlReadFile(xmlPath.c_str(), NULL, 0);
521c2bd209d11e59ea3a31d49ec4e97725fd711beaSeigo Nonaka    xmlNode* familySet = xmlDocGetRootElement(doc);
531c2bd209d11e59ea3a31d49ec4e97725fd711beaSeigo Nonaka
54dfbc6e374259f9d81940b5195ac013b02429af27Seigo Nonaka    std::vector<std::shared_ptr<FontFamily>> families;
551c2bd209d11e59ea3a31d49ec4e97725fd711beaSeigo Nonaka    for (xmlNode* familyNode = familySet->children; familyNode; familyNode = familyNode->next) {
561c2bd209d11e59ea3a31d49ec4e97725fd711beaSeigo Nonaka        if (xmlStrcmp(familyNode->name, (const xmlChar*)"family") != 0) {
571c2bd209d11e59ea3a31d49ec4e97725fd711beaSeigo Nonaka            continue;
581c2bd209d11e59ea3a31d49ec4e97725fd711beaSeigo Nonaka        }
591c2bd209d11e59ea3a31d49ec4e97725fd711beaSeigo Nonaka
601c2bd209d11e59ea3a31d49ec4e97725fd711beaSeigo Nonaka        xmlChar* variantXmlch = xmlGetProp(familyNode, (const xmlChar*)"variant");
61538122d159ef845767ea430a5541248e85e43717Seigo Nonaka        FontFamily::Variant variant = FontFamily::Variant::DEFAULT;
621c2bd209d11e59ea3a31d49ec4e97725fd711beaSeigo Nonaka        if (variantXmlch) {
631c2bd209d11e59ea3a31d49ec4e97725fd711beaSeigo Nonaka            if (xmlStrcmp(variantXmlch, (const xmlChar*)"elegant") == 0) {
64538122d159ef845767ea430a5541248e85e43717Seigo Nonaka                variant = FontFamily::Variant::ELEGANT;
651c2bd209d11e59ea3a31d49ec4e97725fd711beaSeigo Nonaka            } else if (xmlStrcmp(variantXmlch, (const xmlChar*)"compact") == 0) {
66538122d159ef845767ea430a5541248e85e43717Seigo Nonaka                variant = FontFamily::Variant::COMPACT;
671c2bd209d11e59ea3a31d49ec4e97725fd711beaSeigo Nonaka            }
681c2bd209d11e59ea3a31d49ec4e97725fd711beaSeigo Nonaka        }
691c2bd209d11e59ea3a31d49ec4e97725fd711beaSeigo Nonaka
7041718c770d0ae12133270a4ee4a8dbd27851480dSeigo Nonaka        std::vector<Font> fonts;
711c2bd209d11e59ea3a31d49ec4e97725fd711beaSeigo Nonaka        for (xmlNode* fontNode = familyNode->children; fontNode; fontNode = fontNode->next) {
721c2bd209d11e59ea3a31d49ec4e97725fd711beaSeigo Nonaka            if (xmlStrcmp(fontNode->name, (const xmlChar*)"font") != 0) {
731c2bd209d11e59ea3a31d49ec4e97725fd711beaSeigo Nonaka                continue;
741c2bd209d11e59ea3a31d49ec4e97725fd711beaSeigo Nonaka            }
751c2bd209d11e59ea3a31d49ec4e97725fd711beaSeigo Nonaka
76538122d159ef845767ea430a5541248e85e43717Seigo Nonaka            uint16_t weight = atoi((const char*)(xmlGetProp(fontNode, (const xmlChar*)"weight")));
776c8722e217ff5238f0b849152d7936959a728103Seigo Nonaka            FontStyle::Slant italic = static_cast<FontStyle::Slant>(
786c8722e217ff5238f0b849152d7936959a728103Seigo Nonaka                    xmlStrcmp(xmlGetProp(fontNode, (const xmlChar*)"style"),
796c8722e217ff5238f0b849152d7936959a728103Seigo Nonaka                              (const xmlChar*)"italic") == 0);
805e6bc85d69a97d8db6c068e56614aaac02da347aSeigo Nonaka            xmlChar* index = xmlGetProp(familyNode, (const xmlChar*)"index");
811c2bd209d11e59ea3a31d49ec4e97725fd711beaSeigo Nonaka
821c2bd209d11e59ea3a31d49ec4e97725fd711beaSeigo Nonaka            xmlChar* fontFileName = xmlNodeListGetString(doc, fontNode->xmlChildrenNode, 1);
83b02135558f85d94772183b08e6e0c454bca00d22Seigo Nonaka            const std::string fontPath = xmlTrim(fontDir + std::string((const char*)fontFileName));
841c2bd209d11e59ea3a31d49ec4e97725fd711beaSeigo Nonaka            xmlFree(fontFileName);
851c2bd209d11e59ea3a31d49ec4e97725fd711beaSeigo Nonaka
86b02135558f85d94772183b08e6e0c454bca00d22Seigo Nonaka            // TODO: Support font variation axis.
87b02135558f85d94772183b08e6e0c454bca00d22Seigo Nonaka
885e6bc85d69a97d8db6c068e56614aaac02da347aSeigo Nonaka            if (access(fontPath.c_str(), R_OK) != 0) {
895e6bc85d69a97d8db6c068e56614aaac02da347aSeigo Nonaka                ALOGW("%s is not found.", fontPath.c_str());
905e6bc85d69a97d8db6c068e56614aaac02da347aSeigo Nonaka                continue;
915e6bc85d69a97d8db6c068e56614aaac02da347aSeigo Nonaka            }
9281c79d6e1e49562c9bc33c14826017dd5e33ebecSeigo Nonaka
93a22996e31226e3dcbfb0c57d03ca9ac54028fc28Seigo Nonaka            FontStyle style(weight, italic);
945e6bc85d69a97d8db6c068e56614aaac02da347aSeigo Nonaka            if (index == nullptr) {
9580a9239d6943878f28a898537e060f821b9aa603Seigo Nonaka                std::shared_ptr<MinikinFont> minikinFont =
96e1cfa7d7a17f9e24a27132032ec2f77a63e99913Seigo Nonaka                        std::make_shared<FreeTypeMinikinFontForTest>(fontPath);
97a22996e31226e3dcbfb0c57d03ca9ac54028fc28Seigo Nonaka                fonts.push_back(Font::Builder(minikinFont).setStyle(style).build());
985e6bc85d69a97d8db6c068e56614aaac02da347aSeigo Nonaka            } else {
9980a9239d6943878f28a898537e060f821b9aa603Seigo Nonaka                std::shared_ptr<MinikinFont> minikinFont =
100e1cfa7d7a17f9e24a27132032ec2f77a63e99913Seigo Nonaka                        std::make_shared<FreeTypeMinikinFontForTest>(fontPath,
101e1cfa7d7a17f9e24a27132032ec2f77a63e99913Seigo Nonaka                                                                     atoi((const char*)index));
102a22996e31226e3dcbfb0c57d03ca9ac54028fc28Seigo Nonaka                fonts.push_back(Font::Builder(minikinFont).setStyle(style).build());
1035e6bc85d69a97d8db6c068e56614aaac02da347aSeigo Nonaka            }
1041c2bd209d11e59ea3a31d49ec4e97725fd711beaSeigo Nonaka        }
10541718c770d0ae12133270a4ee4a8dbd27851480dSeigo Nonaka
10641718c770d0ae12133270a4ee4a8dbd27851480dSeigo Nonaka        xmlChar* lang = xmlGetProp(familyNode, (const xmlChar*)"lang");
107dfbc6e374259f9d81940b5195ac013b02429af27Seigo Nonaka        std::shared_ptr<FontFamily> family;
10841718c770d0ae12133270a4ee4a8dbd27851480dSeigo Nonaka        if (lang == nullptr) {
10980a9239d6943878f28a898537e060f821b9aa603Seigo Nonaka            family = std::make_shared<FontFamily>(variant, std::move(fonts));
11041718c770d0ae12133270a4ee4a8dbd27851480dSeigo Nonaka        } else {
111b47e9b21077d2a0847a64fa713aa9892196b5d2aSeigo Nonaka            uint32_t langId = registerLocaleList(std::string((const char*)lang, xmlStrlen(lang)));
11280a9239d6943878f28a898537e060f821b9aa603Seigo Nonaka            family = std::make_shared<FontFamily>(langId, variant, std::move(fonts));
11341718c770d0ae12133270a4ee4a8dbd27851480dSeigo Nonaka        }
1141c2bd209d11e59ea3a31d49ec4e97725fd711beaSeigo Nonaka        families.push_back(family);
1151c2bd209d11e59ea3a31d49ec4e97725fd711beaSeigo Nonaka    }
1161c2bd209d11e59ea3a31d49ec4e97725fd711beaSeigo Nonaka    xmlFreeDoc(doc);
11780a9239d6943878f28a898537e060f821b9aa603Seigo Nonaka    return families;
11880a9239d6943878f28a898537e060f821b9aa603Seigo Nonaka}
1199dffc23bd79a82e75181e33974af05da62dc6306Seigo Nonaka
1209dffc23bd79a82e75181e33974af05da62dc6306Seigo Nonakastd::shared_ptr<FontCollection> buildFontCollection(const std::string& filePath) {
121e1cfa7d7a17f9e24a27132032ec2f77a63e99913Seigo Nonaka    return std::make_shared<FontCollection>(buildFontFamily(filePath));
122e1cfa7d7a17f9e24a27132032ec2f77a63e99913Seigo Nonaka}
123e1cfa7d7a17f9e24a27132032ec2f77a63e99913Seigo Nonaka
124e1cfa7d7a17f9e24a27132032ec2f77a63e99913Seigo Nonakastd::shared_ptr<FontFamily> buildFontFamily(const std::string& filePath) {
12554e248ac7fa00d430092a8e993c83fccd4f72df5Seigo Nonaka    auto font = std::make_shared<FreeTypeMinikinFontForTest>(getTestFontPath(filePath));
126e1cfa7d7a17f9e24a27132032ec2f77a63e99913Seigo Nonaka    std::vector<Font> fonts;
127a22996e31226e3dcbfb0c57d03ca9ac54028fc28Seigo Nonaka    fonts.push_back(Font::Builder(font).build());
128e1cfa7d7a17f9e24a27132032ec2f77a63e99913Seigo Nonaka    return std::make_shared<FontFamily>(std::move(fonts));
1299dffc23bd79a82e75181e33974af05da62dc6306Seigo Nonaka}
1309dffc23bd79a82e75181e33974af05da62dc6306Seigo Nonaka
1317fbdd83e92a76c955c67a1c761088b36daf7158cSeigo Nonakastd::shared_ptr<FontFamily> buildFontFamily(const std::string& filePath, const std::string& lang) {
1323998e6fc7fb9cdd27e056253fa2af6de221da926Seigo Nonaka    auto font = std::make_shared<FreeTypeMinikinFontForTest>(getTestFontPath(filePath));
1337fbdd83e92a76c955c67a1c761088b36daf7158cSeigo Nonaka    std::vector<Font> fonts;
1347fbdd83e92a76c955c67a1c761088b36daf7158cSeigo Nonaka    fonts.push_back(Font::Builder(font).build());
1357fbdd83e92a76c955c67a1c761088b36daf7158cSeigo Nonaka    return std::make_shared<FontFamily>(LocaleListCache::getId(lang), FontFamily::Variant::DEFAULT,
1367fbdd83e92a76c955c67a1c761088b36daf7158cSeigo Nonaka                                        std::move(fonts));
1377fbdd83e92a76c955c67a1c761088b36daf7158cSeigo Nonaka}
1387fbdd83e92a76c955c67a1c761088b36daf7158cSeigo Nonaka
13914e2d136aaef271ba131f917cf5f27baa31ae5adSeigo Nonaka}  // namespace minikin
140