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