TypefaceImpl.cpp revision 27bb05f2dccf1ac2ca55515aa0f4a99cd9c548a7
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#define LOG_TAG "TypefaceImpl"
24
25#include "jni.h"  // for jlong, remove when being passed proper type
26
27#include "SkStream.h"
28#include "SkTypeface.h"
29
30#include <vector>
31#include <minikin/FontCollection.h>
32#include <minikin/FontFamily.h>
33#include <minikin/Layout.h>
34#include "SkPaint.h"
35#include "MinikinSkia.h"
36
37#include "TypefaceImpl.h"
38#include "Utils.h"
39
40namespace android {
41
42// Any weight greater than or equal to this is considered "bold" for
43// legacy API.
44static const int kBoldThreshold = 6;
45
46static FontStyle styleFromSkiaStyle(SkTypeface::Style skiaStyle) {
47    int weight = (skiaStyle & SkTypeface::kBold) != 0 ? 7 : 4;
48    bool italic = (skiaStyle & SkTypeface::kItalic) != 0;
49    return FontStyle(weight, italic);
50}
51
52TypefaceImpl* gDefaultTypeface = NULL;
53pthread_once_t gDefaultTypefaceOnce = PTHREAD_ONCE_INIT;
54
55// This installs a default typeface (from a hardcoded path) that allows
56// layouts to work (not crash on null pointer) before the default
57// typeface is set.
58// TODO: investigate why layouts are being created before Typeface.java
59// class initialization.
60static FontCollection *makeFontCollection() {
61    std::vector<FontFamily *>typefaces;
62    const char *fns[] = {
63        "/system/fonts/Roboto-Regular.ttf",
64    };
65
66    FontFamily *family = new FontFamily();
67    for (size_t i = 0; i < sizeof(fns)/sizeof(fns[0]); i++) {
68        const char *fn = fns[i];
69        ALOGD("makeFontCollection adding %s", fn);
70        SkTypeface *skFace = SkTypeface::CreateFromFile(fn);
71        if (skFace != NULL) {
72            MinikinFont *font = new MinikinFontSkia(skFace);
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    FontCollection *result = new FontCollection(typefaces);
82    family->Unref();
83    return result;
84}
85
86static void getDefaultTypefaceOnce() {
87    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 TypefaceImpl;
92        gDefaultTypeface->fFontCollection = makeFontCollection();
93        gDefaultTypeface->fStyle = FontStyle();
94    }
95}
96
97TypefaceImpl* TypefaceImpl_resolveDefault(TypefaceImpl* src) {
98    if (src == NULL) {
99        pthread_once(&gDefaultTypefaceOnce, getDefaultTypefaceOnce);
100        return gDefaultTypeface;
101    } else {
102        return src;
103    }
104}
105
106TypefaceImpl* TypefaceImpl_createFromTypeface(TypefaceImpl* src, SkTypeface::Style style) {
107    TypefaceImpl* resolvedFace = TypefaceImpl_resolveDefault(src);
108    TypefaceImpl* result = new TypefaceImpl;
109    if (result != 0) {
110        result->fFontCollection = resolvedFace->fFontCollection;
111        result->fFontCollection->Ref();
112        result->fStyle = styleFromSkiaStyle(style);
113    }
114    return result;
115}
116
117static TypefaceImpl* createFromSkTypeface(SkTypeface* typeface) {
118    if (typeface == NULL) {
119        return NULL;
120    }
121    MinikinFont* minikinFont = new MinikinFontSkia(typeface);
122    std::vector<FontFamily *> typefaces;
123    FontFamily* family = new FontFamily();
124    family->addFont(minikinFont);
125    minikinFont->Unref();
126    typefaces.push_back(family);
127    TypefaceImpl* result = new TypefaceImpl;
128    result->fFontCollection = new FontCollection(typefaces);
129    family->Unref();
130    result->fStyle = FontStyle();  // TODO: improve
131    return result;
132}
133
134TypefaceImpl* TypefaceImpl_createFromFamilies(const jlong* families, size_t size) {
135    std::vector<FontFamily *>familyVec;
136    for (size_t i = 0; i < size; i++) {
137        FontFamily* family = reinterpret_cast<FontFamily*>(families[i]);
138        familyVec.push_back(family);
139    }
140    TypefaceImpl* result = new TypefaceImpl;
141    result->fFontCollection = new FontCollection(familyVec);
142    if (size == 0) {
143        ALOGW("createFromFamilies creating empty collection");
144        result->fStyle = FontStyle();
145    } else {
146        const FontStyle defaultStyle;
147        FontFamily* firstFamily = reinterpret_cast<FontFamily*>(families[0]);
148        MinikinFont* mf = firstFamily->getClosestMatch(defaultStyle).font;
149        if (mf != NULL) {
150            SkTypeface* skTypeface = reinterpret_cast<MinikinFontSkia*>(mf)->GetSkTypeface();
151            // TODO: probably better to query more precise style from family, will be important
152            // when we open up API to access 100..900 weights
153            result->fStyle = styleFromSkiaStyle(skTypeface->style());
154        } else {
155            result->fStyle = defaultStyle;
156        }
157    }
158    return result;
159}
160
161void TypefaceImpl_unref(TypefaceImpl* face) {
162    if (face != NULL) {
163        face->fFontCollection->Unref();
164    }
165    delete face;
166}
167
168int TypefaceImpl_getStyle(TypefaceImpl* face) {
169    FontStyle style = face->fStyle;
170    int result = style.getItalic() ? SkTypeface::kItalic : 0;
171    if (style.getWeight() >= kBoldThreshold) {
172        result |= SkTypeface::kBold;
173    }
174    return result;
175}
176
177void TypefaceImpl_setDefault(TypefaceImpl* face) {
178    gDefaultTypeface = face;
179}
180
181}
182