1a033630e805c407080221e20b236b6054f324670Raph Levien/*
2a033630e805c407080221e20b236b6054f324670Raph Levien * Copyright (C) 2013 The Android Open Source Project
3a033630e805c407080221e20b236b6054f324670Raph Levien *
4a033630e805c407080221e20b236b6054f324670Raph Levien * Licensed under the Apache License, Version 2.0 (the "License");
5a033630e805c407080221e20b236b6054f324670Raph Levien * you may not use this file except in compliance with the License.
6a033630e805c407080221e20b236b6054f324670Raph Levien * You may obtain a copy of the License at
7a033630e805c407080221e20b236b6054f324670Raph Levien *
8a033630e805c407080221e20b236b6054f324670Raph Levien *      http://www.apache.org/licenses/LICENSE-2.0
9a033630e805c407080221e20b236b6054f324670Raph Levien *
10a033630e805c407080221e20b236b6054f324670Raph Levien * Unless required by applicable law or agreed to in writing, software
11a033630e805c407080221e20b236b6054f324670Raph Levien * distributed under the License is distributed on an "AS IS" BASIS,
12a033630e805c407080221e20b236b6054f324670Raph Levien * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13a033630e805c407080221e20b236b6054f324670Raph Levien * See the License for the specific language governing permissions and
14a033630e805c407080221e20b236b6054f324670Raph Levien * limitations under the License.
15a033630e805c407080221e20b236b6054f324670Raph Levien */
16a033630e805c407080221e20b236b6054f324670Raph Levien
17a033630e805c407080221e20b236b6054f324670Raph Levien/**
18a033630e805c407080221e20b236b6054f324670Raph Levien * This is the implementation of the Typeface object. Historically, it has
19a033630e805c407080221e20b236b6054f324670Raph Levien * just been SkTypeface, but we are migrating to Minikin. For the time
20a033630e805c407080221e20b236b6054f324670Raph Levien * being, that choice is hidden under the USE_MINIKIN compile-time flag.
21a033630e805c407080221e20b236b6054f324670Raph Levien */
22a033630e805c407080221e20b236b6054f324670Raph Levien
23bad99183916ba2bac6659efc8a28273e344ba511sergeyv#include "Typeface.h"
241a73f732f91e97c9c66b808c245ddda36a10e987Raph Levien
25dccca44ffda4836b56a21da95a046c9708ffd49csergeyv#include "MinikinSkia.h"
26a033630e805c407080221e20b236b6054f324670Raph Levien#include "SkTypeface.h"
27dccca44ffda4836b56a21da95a046c9708ffd49csergeyv#include "SkPaint.h"
28a033630e805c407080221e20b236b6054f324670Raph Levien
29a033630e805c407080221e20b236b6054f324670Raph Levien#include <minikin/FontCollection.h>
30a033630e805c407080221e20b236b6054f324670Raph Levien#include <minikin/FontFamily.h>
31a033630e805c407080221e20b236b6054f324670Raph Levien#include <minikin/Layout.h>
32dccca44ffda4836b56a21da95a046c9708ffd49csergeyv#include <utils/Log.h>
33a033630e805c407080221e20b236b6054f324670Raph Levien
34a033630e805c407080221e20b236b6054f324670Raph Leviennamespace android {
35a033630e805c407080221e20b236b6054f324670Raph Levien
36117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien// Resolve the 1..9 weight based on base weight and bold flag
37bad99183916ba2bac6659efc8a28273e344ba511sergeyvstatic void resolveStyle(Typeface* typeface) {
38117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien    int weight = typeface->fBaseWeight / 100;
39117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien    if (typeface->fSkiaStyle & SkTypeface::kBold) {
40117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien        weight += 3;
41117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien    }
42117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien    if (weight > 9) {
43117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien        weight = 9;
44117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien    }
45117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien    bool italic = (typeface->fSkiaStyle & SkTypeface::kItalic) != 0;
46117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien    typeface->fStyle = FontStyle(weight, italic);
47a033630e805c407080221e20b236b6054f324670Raph Levien}
48a033630e805c407080221e20b236b6054f324670Raph Levien
49bad99183916ba2bac6659efc8a28273e344ba511sergeyvTypeface* gDefaultTypeface = NULL;
50a033630e805c407080221e20b236b6054f324670Raph Levienpthread_once_t gDefaultTypefaceOnce = PTHREAD_ONCE_INIT;
51a033630e805c407080221e20b236b6054f324670Raph Levien
529a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien// This installs a default typeface (from a hardcoded path) that allows
539a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien// layouts to work (not crash on null pointer) before the default
549a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien// typeface is set.
559a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien// TODO: investigate why layouts are being created before Typeface.java
569a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien// class initialization.
57a033630e805c407080221e20b236b6054f324670Raph Levienstatic FontCollection *makeFontCollection() {
58a033630e805c407080221e20b236b6054f324670Raph Levien    std::vector<FontFamily *>typefaces;
59a033630e805c407080221e20b236b6054f324670Raph Levien    const char *fns[] = {
60a033630e805c407080221e20b236b6054f324670Raph Levien        "/system/fonts/Roboto-Regular.ttf",
61a033630e805c407080221e20b236b6054f324670Raph Levien    };
62a033630e805c407080221e20b236b6054f324670Raph Levien
63a033630e805c407080221e20b236b6054f324670Raph Levien    FontFamily *family = new FontFamily();
64a033630e805c407080221e20b236b6054f324670Raph Levien    for (size_t i = 0; i < sizeof(fns)/sizeof(fns[0]); i++) {
65a033630e805c407080221e20b236b6054f324670Raph Levien        const char *fn = fns[i];
669a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien        ALOGD("makeFontCollection adding %s", fn);
67a033630e805c407080221e20b236b6054f324670Raph Levien        SkTypeface *skFace = SkTypeface::CreateFromFile(fn);
689a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien        if (skFace != NULL) {
69296bf8c55aaba0025f3e5b904fda3b6e15686753Raph Levien            // TODO: might be a nice optimization to get access to the underlying font
70296bf8c55aaba0025f3e5b904fda3b6e15686753Raph Levien            // data, but would require us opening the file ourselves and passing that
71296bf8c55aaba0025f3e5b904fda3b6e15686753Raph Levien            // to the appropriate Create method of SkTypeface.
72296bf8c55aaba0025f3e5b904fda3b6e15686753Raph Levien            MinikinFont *font = new MinikinFontSkia(skFace, NULL, 0, 0);
739a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien            family->addFont(font);
7415cf4757dc0099301662f8a26da561434cc07cfaRaph Levien            font->Unref();
759a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien        } else {
769a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien            ALOGE("failed to create font %s", fn);
779a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien        }
78a033630e805c407080221e20b236b6054f324670Raph Levien    }
79a033630e805c407080221e20b236b6054f324670Raph Levien    typefaces.push_back(family);
80a033630e805c407080221e20b236b6054f324670Raph Levien
8115cf4757dc0099301662f8a26da561434cc07cfaRaph Levien    FontCollection *result = new FontCollection(typefaces);
8215cf4757dc0099301662f8a26da561434cc07cfaRaph Levien    family->Unref();
8315cf4757dc0099301662f8a26da561434cc07cfaRaph Levien    return result;
84a033630e805c407080221e20b236b6054f324670Raph Levien}
85a033630e805c407080221e20b236b6054f324670Raph Levien
86a033630e805c407080221e20b236b6054f324670Raph Levienstatic void getDefaultTypefaceOnce() {
87a033630e805c407080221e20b236b6054f324670Raph Levien    Layout::init();
889a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien    if (gDefaultTypeface == NULL) {
899a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien        // We expect the client to set a default typeface, but provide a
909a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien        // default so we can make progress before that happens.
91bad99183916ba2bac6659efc8a28273e344ba511sergeyv        gDefaultTypeface = new Typeface;
929a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien        gDefaultTypeface->fFontCollection = makeFontCollection();
93117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien        gDefaultTypeface->fSkiaStyle = SkTypeface::kNormal;
94117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien        gDefaultTypeface->fBaseWeight = 400;
95117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien        resolveStyle(gDefaultTypeface);
969a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien    }
97a033630e805c407080221e20b236b6054f324670Raph Levien}
98a033630e805c407080221e20b236b6054f324670Raph Levien
99bad99183916ba2bac6659efc8a28273e344ba511sergeyvTypeface* Typeface::resolveDefault(Typeface* src) {
100a033630e805c407080221e20b236b6054f324670Raph Levien    if (src == NULL) {
101a033630e805c407080221e20b236b6054f324670Raph Levien        pthread_once(&gDefaultTypefaceOnce, getDefaultTypefaceOnce);
102a033630e805c407080221e20b236b6054f324670Raph Levien        return gDefaultTypeface;
103a033630e805c407080221e20b236b6054f324670Raph Levien    } else {
104a033630e805c407080221e20b236b6054f324670Raph Levien        return src;
105a033630e805c407080221e20b236b6054f324670Raph Levien    }
106a033630e805c407080221e20b236b6054f324670Raph Levien}
107a033630e805c407080221e20b236b6054f324670Raph Levien
108bad99183916ba2bac6659efc8a28273e344ba511sergeyvTypeface* Typeface::createFromTypeface(Typeface* src, SkTypeface::Style style) {
109bad99183916ba2bac6659efc8a28273e344ba511sergeyv    Typeface* resolvedFace = Typeface::resolveDefault(src);
110bad99183916ba2bac6659efc8a28273e344ba511sergeyv    Typeface* result = new Typeface;
111a033630e805c407080221e20b236b6054f324670Raph Levien    if (result != 0) {
112a033630e805c407080221e20b236b6054f324670Raph Levien        result->fFontCollection = resolvedFace->fFontCollection;
11315cf4757dc0099301662f8a26da561434cc07cfaRaph Levien        result->fFontCollection->Ref();
114117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien        result->fSkiaStyle = style;
115117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien        result->fBaseWeight = resolvedFace->fBaseWeight;
116117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien        resolveStyle(result);
117a033630e805c407080221e20b236b6054f324670Raph Levien    }
118a033630e805c407080221e20b236b6054f324670Raph Levien    return result;
119a033630e805c407080221e20b236b6054f324670Raph Levien}
120a033630e805c407080221e20b236b6054f324670Raph Levien
121bad99183916ba2bac6659efc8a28273e344ba511sergeyvTypeface* Typeface::createWeightAlias(Typeface* src, int weight) {
122bad99183916ba2bac6659efc8a28273e344ba511sergeyv    Typeface* resolvedFace = Typeface::resolveDefault(src);
123bad99183916ba2bac6659efc8a28273e344ba511sergeyv    Typeface* result = new Typeface;
124117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien    if (result != 0) {
125117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien        result->fFontCollection = resolvedFace->fFontCollection;
126117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien        result->fFontCollection->Ref();
127117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien        result->fSkiaStyle = resolvedFace->fSkiaStyle;
128117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien        result->fBaseWeight = weight;
129117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien        resolveStyle(result);
130117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien    }
131a033630e805c407080221e20b236b6054f324670Raph Levien    return result;
132a033630e805c407080221e20b236b6054f324670Raph Levien}
133a033630e805c407080221e20b236b6054f324670Raph Levien
134bad99183916ba2bac6659efc8a28273e344ba511sergeyvTypeface* Typeface::createFromFamilies(const std::vector<FontFamily*>& families) {
135bad99183916ba2bac6659efc8a28273e344ba511sergeyv    Typeface* result = new Typeface;
136dccca44ffda4836b56a21da95a046c9708ffd49csergeyv    result->fFontCollection = new FontCollection(families);
137dccca44ffda4836b56a21da95a046c9708ffd49csergeyv    if (families.empty()) {
1381633caef58ebd0bc3b0c5da15dde2fb425b77c43Raph Levien        ALOGW("createFromFamilies creating empty collection");
139117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien        result->fSkiaStyle = SkTypeface::kNormal;
1401633caef58ebd0bc3b0c5da15dde2fb425b77c43Raph Levien    } else {
1411633caef58ebd0bc3b0c5da15dde2fb425b77c43Raph Levien        const FontStyle defaultStyle;
1421633caef58ebd0bc3b0c5da15dde2fb425b77c43Raph Levien        FontFamily* firstFamily = reinterpret_cast<FontFamily*>(families[0]);
1431fc0fa87d42ce9268ece76b85b9edc834593e53aRaph Levien        MinikinFont* mf = firstFamily->getClosestMatch(defaultStyle).font;
14427bb05f2dccf1ac2ca55515aa0f4a99cd9c548a7Raph Levien        if (mf != NULL) {
14527bb05f2dccf1ac2ca55515aa0f4a99cd9c548a7Raph Levien            SkTypeface* skTypeface = reinterpret_cast<MinikinFontSkia*>(mf)->GetSkTypeface();
14627bb05f2dccf1ac2ca55515aa0f4a99cd9c548a7Raph Levien            // TODO: probably better to query more precise style from family, will be important
14727bb05f2dccf1ac2ca55515aa0f4a99cd9c548a7Raph Levien            // when we open up API to access 100..900 weights
148117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien            result->fSkiaStyle = skTypeface->style();
14927bb05f2dccf1ac2ca55515aa0f4a99cd9c548a7Raph Levien        } else {
150117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien            result->fSkiaStyle = SkTypeface::kNormal;
15127bb05f2dccf1ac2ca55515aa0f4a99cd9c548a7Raph Levien        }
1521633caef58ebd0bc3b0c5da15dde2fb425b77c43Raph Levien    }
153117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien    result->fBaseWeight = 400;
154117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien    resolveStyle(result);
1551a73f732f91e97c9c66b808c245ddda36a10e987Raph Levien    return result;
1561a73f732f91e97c9c66b808c245ddda36a10e987Raph Levien}
1571a73f732f91e97c9c66b808c245ddda36a10e987Raph Levien
158bad99183916ba2bac6659efc8a28273e344ba511sergeyvvoid Typeface::unref() {
159bad99183916ba2bac6659efc8a28273e344ba511sergeyv    fFontCollection->Unref();
160bad99183916ba2bac6659efc8a28273e344ba511sergeyv    delete this;
161a033630e805c407080221e20b236b6054f324670Raph Levien}
162a033630e805c407080221e20b236b6054f324670Raph Levien
163bad99183916ba2bac6659efc8a28273e344ba511sergeyvvoid Typeface::setDefault(Typeface* face) {
1649a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien    gDefaultTypeface = face;
1659a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien}
1669a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien
167a033630e805c407080221e20b236b6054f324670Raph Levien}
168