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// Resolve the 1..9 weight based on base weight and bold flag
43static void resolveStyle(TypefaceImpl* typeface) {
44    int weight = typeface->fBaseWeight / 100;
45    if (typeface->fSkiaStyle & SkTypeface::kBold) {
46        weight += 3;
47    }
48    if (weight > 9) {
49        weight = 9;
50    }
51    bool italic = (typeface->fSkiaStyle & SkTypeface::kItalic) != 0;
52    typeface->fStyle = 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->fSkiaStyle = SkTypeface::kNormal;
97        gDefaultTypeface->fBaseWeight = 400;
98        resolveStyle(gDefaultTypeface);
99    }
100}
101
102TypefaceImpl* TypefaceImpl_resolveDefault(TypefaceImpl* src) {
103    if (src == NULL) {
104        pthread_once(&gDefaultTypefaceOnce, getDefaultTypefaceOnce);
105        return gDefaultTypeface;
106    } else {
107        return src;
108    }
109}
110
111TypefaceImpl* TypefaceImpl_createFromTypeface(TypefaceImpl* src, SkTypeface::Style style) {
112    TypefaceImpl* resolvedFace = TypefaceImpl_resolveDefault(src);
113    TypefaceImpl* result = new TypefaceImpl;
114    if (result != 0) {
115        result->fFontCollection = resolvedFace->fFontCollection;
116        result->fFontCollection->Ref();
117        result->fSkiaStyle = style;
118        result->fBaseWeight = resolvedFace->fBaseWeight;
119        resolveStyle(result);
120    }
121    return result;
122}
123
124TypefaceImpl* TypefaceImpl_createWeightAlias(TypefaceImpl* src, int weight) {
125    TypefaceImpl* resolvedFace = TypefaceImpl_resolveDefault(src);
126    TypefaceImpl* result = new TypefaceImpl;
127    if (result != 0) {
128        result->fFontCollection = resolvedFace->fFontCollection;
129        result->fFontCollection->Ref();
130        result->fSkiaStyle = resolvedFace->fSkiaStyle;
131        result->fBaseWeight = weight;
132        resolveStyle(result);
133    }
134    return result;
135}
136
137TypefaceImpl* TypefaceImpl_createFromFamilies(const jlong* families, size_t size) {
138    std::vector<FontFamily *>familyVec;
139    for (size_t i = 0; i < size; i++) {
140        FontFamily* family = reinterpret_cast<FontFamily*>(families[i]);
141        familyVec.push_back(family);
142    }
143    TypefaceImpl* result = new TypefaceImpl;
144    result->fFontCollection = new FontCollection(familyVec);
145    if (size == 0) {
146        ALOGW("createFromFamilies creating empty collection");
147        result->fSkiaStyle = SkTypeface::kNormal;
148    } else {
149        const FontStyle defaultStyle;
150        FontFamily* firstFamily = reinterpret_cast<FontFamily*>(families[0]);
151        MinikinFont* mf = firstFamily->getClosestMatch(defaultStyle).font;
152        if (mf != NULL) {
153            SkTypeface* skTypeface = reinterpret_cast<MinikinFontSkia*>(mf)->GetSkTypeface();
154            // TODO: probably better to query more precise style from family, will be important
155            // when we open up API to access 100..900 weights
156            result->fSkiaStyle = skTypeface->style();
157        } else {
158            result->fSkiaStyle = SkTypeface::kNormal;
159        }
160    }
161    result->fBaseWeight = 400;
162    resolveStyle(result);
163    return result;
164}
165
166void TypefaceImpl_unref(TypefaceImpl* face) {
167    if (face != NULL) {
168        face->fFontCollection->Unref();
169    }
170    delete face;
171}
172
173int TypefaceImpl_getStyle(TypefaceImpl* face) {
174    return face->fSkiaStyle;
175}
176
177void TypefaceImpl_setDefault(TypefaceImpl* face) {
178    gDefaultTypeface = face;
179}
180
181}
182