Typeface.cpp revision ae1aa85d0c7305bb621f1f8003bd674285aa3b63
1/*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/**
18 * This is the implementation of the Typeface object. Historically, it has
19 * just been SkTypeface, but we are migrating to Minikin. For the time
20 * being, that choice is hidden under the USE_MINIKIN compile-time flag.
21 */
22
23#include "Typeface.h"
24
25#include "MinikinSkia.h"
26#include "SkTypeface.h"
27#include "SkPaint.h"
28
29#include <minikin/FontCollection.h>
30#include <minikin/FontFamily.h>
31#include <minikin/Layout.h>
32#include <utils/Log.h>
33
34namespace android {
35
36// Resolve the 1..9 weight based on base weight and bold flag
37static void resolveStyle(Typeface* typeface) {
38    int weight = typeface->fBaseWeight / 100;
39    if (typeface->fSkiaStyle & SkTypeface::kBold) {
40        weight += 3;
41    }
42    if (weight > 9) {
43        weight = 9;
44    }
45    bool italic = (typeface->fSkiaStyle & SkTypeface::kItalic) != 0;
46    typeface->fStyle = minikin::FontStyle(weight, italic);
47}
48
49Typeface* gDefaultTypeface = NULL;
50pthread_once_t gDefaultTypefaceOnce = PTHREAD_ONCE_INIT;
51
52// This installs a default typeface (from a hardcoded path) that allows
53// layouts to work (not crash on null pointer) before the default
54// typeface is set.
55// TODO: investigate why layouts are being created before Typeface.java
56// class initialization.
57static minikin::FontCollection *makeFontCollection() {
58    std::vector<minikin::FontFamily *>typefaces;
59    const char *fns[] = {
60        "/system/fonts/Roboto-Regular.ttf",
61    };
62
63    minikin::FontFamily *family = new minikin::FontFamily();
64    for (size_t i = 0; i < sizeof(fns)/sizeof(fns[0]); i++) {
65        const char *fn = fns[i];
66        ALOGD("makeFontCollection adding %s", fn);
67        SkTypeface *skFace = SkTypeface::CreateFromFile(fn);
68        if (skFace != NULL) {
69            // TODO: might be a nice optimization to get access to the underlying font
70            // data, but would require us opening the file ourselves and passing that
71            // to the appropriate Create method of SkTypeface.
72            minikin::MinikinFont *font = new MinikinFontSkia(skFace, NULL, 0, 0);
73            family->addFont(font);
74            font->Unref();
75        } else {
76            ALOGE("failed to create font %s", fn);
77        }
78    }
79    typefaces.push_back(family);
80
81    minikin::FontCollection *result = new minikin::FontCollection(typefaces);
82    family->Unref();
83    return result;
84}
85
86static void getDefaultTypefaceOnce() {
87  minikin::Layout::init();
88    if (gDefaultTypeface == NULL) {
89        // We expect the client to set a default typeface, but provide a
90        // default so we can make progress before that happens.
91        gDefaultTypeface = new Typeface;
92        gDefaultTypeface->fFontCollection = makeFontCollection();
93        gDefaultTypeface->fSkiaStyle = SkTypeface::kNormal;
94        gDefaultTypeface->fBaseWeight = 400;
95        resolveStyle(gDefaultTypeface);
96    }
97}
98
99Typeface* Typeface::resolveDefault(Typeface* src) {
100    if (src == NULL) {
101        pthread_once(&gDefaultTypefaceOnce, getDefaultTypefaceOnce);
102        return gDefaultTypeface;
103    } else {
104        return src;
105    }
106}
107
108Typeface* Typeface::createFromTypeface(Typeface* src, SkTypeface::Style style) {
109    Typeface* resolvedFace = Typeface::resolveDefault(src);
110    Typeface* result = new Typeface;
111    if (result != 0) {
112        result->fFontCollection = resolvedFace->fFontCollection;
113        result->fFontCollection->Ref();
114        result->fSkiaStyle = style;
115        result->fBaseWeight = resolvedFace->fBaseWeight;
116        resolveStyle(result);
117    }
118    return result;
119}
120
121Typeface* Typeface::createWeightAlias(Typeface* src, int weight) {
122    Typeface* resolvedFace = Typeface::resolveDefault(src);
123    Typeface* result = new Typeface;
124    if (result != 0) {
125        result->fFontCollection = resolvedFace->fFontCollection;
126        result->fFontCollection->Ref();
127        result->fSkiaStyle = resolvedFace->fSkiaStyle;
128        result->fBaseWeight = weight;
129        resolveStyle(result);
130    }
131    return result;
132}
133
134Typeface* Typeface::createFromFamilies(const std::vector<minikin::FontFamily*>& families) {
135    Typeface* result = new Typeface;
136    result->fFontCollection = new minikin::FontCollection(families);
137    if (families.empty()) {
138        ALOGW("createFromFamilies creating empty collection");
139        result->fSkiaStyle = SkTypeface::kNormal;
140    } else {
141        const minikin::FontStyle defaultStyle;
142        minikin::FontFamily* firstFamily = reinterpret_cast<minikin::FontFamily*>(families[0]);
143        minikin::MinikinFont* mf = firstFamily->getClosestMatch(defaultStyle).font;
144        if (mf != NULL) {
145            SkTypeface* skTypeface = reinterpret_cast<MinikinFontSkia*>(mf)->GetSkTypeface();
146            // TODO: probably better to query more precise style from family, will be important
147            // when we open up API to access 100..900 weights
148            result->fSkiaStyle = skTypeface->style();
149        } else {
150            result->fSkiaStyle = SkTypeface::kNormal;
151        }
152    }
153    result->fBaseWeight = 400;
154    resolveStyle(result);
155    return result;
156}
157
158void Typeface::unref() {
159    fFontCollection->Unref();
160    delete this;
161}
162
163void Typeface::setDefault(Typeface* face) {
164    gDefaultTypeface = face;
165}
166
167}
168