TypefaceImpl.cpp revision 1633caef58ebd0bc3b0c5da15dde2fb425b77c43
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#ifdef USE_MINIKIN
31#include <vector>
32#include <minikin/FontCollection.h>
33#include <minikin/FontFamily.h>
34#include <minikin/Layout.h>
35#include "MinikinSkia.h"
36#endif
37
38#include "TypefaceImpl.h"
39#include "Utils.h"
40
41namespace android {
42
43#ifdef USE_MINIKIN
44
45// Any weight greater than or equal to this is considered "bold" for
46// legacy API.
47static const int kBoldThreshold = 6;
48
49static FontStyle styleFromSkiaStyle(SkTypeface::Style skiaStyle) {
50    int weight = (skiaStyle & SkTypeface::kBold) != 0 ? 7 : 4;
51    bool italic = (skiaStyle & SkTypeface::kItalic) != 0;
52    return FontStyle(weight, italic);
53}
54
55TypefaceImpl* gDefaultTypeface = NULL;
56pthread_once_t gDefaultTypefaceOnce = PTHREAD_ONCE_INIT;
57
58// This installs a default typeface (from a hardcoded path) that allows
59// layouts to work (not crash on null pointer) before the default
60// typeface is set.
61// TODO: investigate why layouts are being created before Typeface.java
62// class initialization.
63static FontCollection *makeFontCollection() {
64    std::vector<FontFamily *>typefaces;
65    const char *fns[] = {
66        "/system/fonts/Roboto-Regular.ttf",
67    };
68
69    FontFamily *family = new FontFamily();
70    for (size_t i = 0; i < sizeof(fns)/sizeof(fns[0]); i++) {
71        const char *fn = fns[i];
72        ALOGD("makeFontCollection adding %s", fn);
73        SkTypeface *skFace = SkTypeface::CreateFromFile(fn);
74        if (skFace != NULL) {
75            MinikinFont *font = new MinikinFontSkia(skFace);
76            family->addFont(font);
77            font->Unref();
78        } else {
79            ALOGE("failed to create font %s", fn);
80        }
81    }
82    typefaces.push_back(family);
83
84    FontCollection *result = new FontCollection(typefaces);
85    family->Unref();
86    return result;
87}
88
89static void getDefaultTypefaceOnce() {
90    Layout::init();
91    if (gDefaultTypeface == NULL) {
92        // We expect the client to set a default typeface, but provide a
93        // default so we can make progress before that happens.
94        gDefaultTypeface = new TypefaceImpl;
95        gDefaultTypeface->fFontCollection = makeFontCollection();
96        gDefaultTypeface->fStyle = FontStyle();
97    }
98}
99
100TypefaceImpl* TypefaceImpl_resolveDefault(TypefaceImpl* src) {
101    if (src == NULL) {
102        pthread_once(&gDefaultTypefaceOnce, getDefaultTypefaceOnce);
103        return gDefaultTypeface;
104    } else {
105        return src;
106    }
107}
108
109TypefaceImpl* TypefaceImpl_createFromTypeface(TypefaceImpl* src, SkTypeface::Style style) {
110    TypefaceImpl* resolvedFace = TypefaceImpl_resolveDefault(src);
111    TypefaceImpl* result = new TypefaceImpl;
112    if (result != 0) {
113        result->fFontCollection = resolvedFace->fFontCollection;
114        result->fFontCollection->Ref();
115        result->fStyle = styleFromSkiaStyle(style);
116    }
117    return result;
118}
119
120static TypefaceImpl* createFromSkTypeface(SkTypeface* typeface) {
121    if (typeface == NULL) {
122        return NULL;
123    }
124    MinikinFont* minikinFont = new MinikinFontSkia(typeface);
125    std::vector<FontFamily *> typefaces;
126    FontFamily* family = new FontFamily();
127    family->addFont(minikinFont);
128    minikinFont->Unref();
129    typefaces.push_back(family);
130    TypefaceImpl* result = new TypefaceImpl;
131    result->fFontCollection = new FontCollection(typefaces);
132    family->Unref();
133    result->fStyle = FontStyle();  // TODO: improve
134    return result;
135}
136
137// Delete when removing USE_MINIKIN ifdef
138TypefaceImpl* TypefaceImpl_createFromName(const char* name, SkTypeface::Style style) {
139    SkTypeface* face = SkTypeface::CreateFromName(name, style);
140    return createFromSkTypeface(face);
141}
142
143// Delete when removing USE_MINIKIN ifdef
144TypefaceImpl* TypefaceImpl_createFromFile(const char* filename) {
145    SkTypeface* face = SkTypeface::CreateFromFile(filename);
146    return createFromSkTypeface(face);
147}
148
149// Delete when removing USE_MINIKIN ifdef
150TypefaceImpl* TypefaceImpl_createFromAsset(Asset* asset) {
151    SkStream* stream = new AssetStreamAdaptor(asset,
152                                              AssetStreamAdaptor::kYes_OwnAsset,
153                                              AssetStreamAdaptor::kYes_HasMemoryBase);
154    SkTypeface* face = SkTypeface::CreateFromStream(stream);
155    // SkTypeFace::CreateFromStream calls ref() on the stream, so we
156    // need to unref it here or it won't be freed later on
157    stream->unref();
158    return createFromSkTypeface(face);
159}
160
161TypefaceImpl* TypefaceImpl_createFromFamilies(const jlong* families, size_t size) {
162    std::vector<FontFamily *>familyVec;
163    for (size_t i = 0; i < size; i++) {
164        FontFamily* family = reinterpret_cast<FontFamily*>(families[i]);
165        familyVec.push_back(family);
166    }
167    TypefaceImpl* result = new TypefaceImpl;
168    result->fFontCollection = new FontCollection(familyVec);
169    if (size == 0) {
170        ALOGW("createFromFamilies creating empty collection");
171        result->fStyle = FontStyle();
172    } else {
173        const FontStyle defaultStyle;
174        FontFamily* firstFamily = reinterpret_cast<FontFamily*>(families[0]);
175        MinikinFont* mf = firstFamily->getClosestMatch(defaultStyle);
176        SkTypeface* skTypeface = reinterpret_cast<MinikinFontSkia*>(mf)->GetSkTypeface();
177        // TODO: probably better to query more precise style from family, will be important
178        // when we open up API to access 100..900 weights
179        result->fStyle = styleFromSkiaStyle(skTypeface->style());
180    }
181    return result;
182}
183
184void TypefaceImpl_unref(TypefaceImpl* face) {
185    if (face != NULL) {
186        face->fFontCollection->Unref();
187    }
188    delete face;
189}
190
191int TypefaceImpl_getStyle(TypefaceImpl* face) {
192    FontStyle style = face->fStyle;
193    int result = style.getItalic() ? SkTypeface::kItalic : 0;
194    if (style.getWeight() >= kBoldThreshold) {
195        result |= SkTypeface::kBold;
196    }
197    return result;
198}
199
200void TypefaceImpl_setDefault(TypefaceImpl* face) {
201    gDefaultTypeface = face;
202}
203
204#else  // USE_MINIKIN
205
206/* Just use SkTypeface instead. */
207
208typedef SkTypeface TypefaceImpl;
209
210TypefaceImpl* TypefaceImpl_createFromTypeface(TypefaceImpl* src, SkTypeface::Style style) {
211    return SkTypeface::CreateFromTypeface(src, style);
212}
213
214TypefaceImpl* TypefaceImpl_createFromName(const char* name, SkTypeface::Style style) {
215    return SkTypeface::CreateFromName(name, style);
216}
217
218TypefaceImpl* TypefaceImpl_createFromFile(const char* filename) {
219    return SkTypeface::CreateFromFile(filename);
220}
221
222TypefaceImpl* TypefaceImpl_createFromAsset(Asset* asset) {
223    SkStream* stream = new AssetStreamAdaptor(asset,
224                                              AssetStreamAdaptor::kYes_OwnAsset,
225                                              AssetStreamAdaptor::kYes_HasMemoryBase);
226    SkTypeface* face = SkTypeface::CreateFromStream(stream);
227    // SkTypeFace::CreateFromStream calls ref() on the stream, so we
228    // need to unref it here or it won't be freed later on
229    stream->unref();
230
231    return face;
232}
233
234TypefaceImpl* TypefaceImpl_createFromFamilies(const jlong* families, size_t size) {
235    // Should never be called in non-Minikin builds
236    return 0;
237}
238
239void TypefaceImpl_unref(TypefaceImpl* face) {
240    SkSafeUnref(face);
241}
242
243int TypefaceImpl_getStyle(TypefaceImpl* face) {
244    return face->style();
245}
246
247void TypefaceImpl_setDefault(TypefaceImpl* face) {
248}
249
250#endif  // USE_MINIKIN
251
252}
253