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