1a033630e805c407080221e20b236b6054f324670Raph Levien/* 2a033630e805c407080221e20b236b6054f324670Raph Levien * Copyright (C) 2013 The Android Open Source Project 3a033630e805c407080221e20b236b6054f324670Raph Levien * 4a033630e805c407080221e20b236b6054f324670Raph Levien * Licensed under the Apache License, Version 2.0 (the "License"); 5a033630e805c407080221e20b236b6054f324670Raph Levien * you may not use this file except in compliance with the License. 6a033630e805c407080221e20b236b6054f324670Raph Levien * You may obtain a copy of the License at 7a033630e805c407080221e20b236b6054f324670Raph Levien * 8a033630e805c407080221e20b236b6054f324670Raph Levien * http://www.apache.org/licenses/LICENSE-2.0 9a033630e805c407080221e20b236b6054f324670Raph Levien * 10a033630e805c407080221e20b236b6054f324670Raph Levien * Unless required by applicable law or agreed to in writing, software 11a033630e805c407080221e20b236b6054f324670Raph Levien * distributed under the License is distributed on an "AS IS" BASIS, 12a033630e805c407080221e20b236b6054f324670Raph Levien * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13a033630e805c407080221e20b236b6054f324670Raph Levien * See the License for the specific language governing permissions and 14a033630e805c407080221e20b236b6054f324670Raph Levien * limitations under the License. 15a033630e805c407080221e20b236b6054f324670Raph Levien */ 16a033630e805c407080221e20b236b6054f324670Raph Levien 17a033630e805c407080221e20b236b6054f324670Raph Levien/** 18a033630e805c407080221e20b236b6054f324670Raph Levien * This is the implementation of the Typeface object. Historically, it has 19a033630e805c407080221e20b236b6054f324670Raph Levien * just been SkTypeface, but we are migrating to Minikin. For the time 20a033630e805c407080221e20b236b6054f324670Raph Levien * being, that choice is hidden under the USE_MINIKIN compile-time flag. 21a033630e805c407080221e20b236b6054f324670Raph Levien */ 22a033630e805c407080221e20b236b6054f324670Raph Levien 23bad99183916ba2bac6659efc8a28273e344ba511sergeyv#include "Typeface.h" 241a73f732f91e97c9c66b808c245ddda36a10e987Raph Levien 25dccca44ffda4836b56a21da95a046c9708ffd49csergeyv#include "MinikinSkia.h" 26a033630e805c407080221e20b236b6054f324670Raph Levien#include "SkTypeface.h" 27dccca44ffda4836b56a21da95a046c9708ffd49csergeyv#include "SkPaint.h" 28a033630e805c407080221e20b236b6054f324670Raph Levien 29a033630e805c407080221e20b236b6054f324670Raph Levien#include <minikin/FontCollection.h> 30a033630e805c407080221e20b236b6054f324670Raph Levien#include <minikin/FontFamily.h> 31a033630e805c407080221e20b236b6054f324670Raph Levien#include <minikin/Layout.h> 32dccca44ffda4836b56a21da95a046c9708ffd49csergeyv#include <utils/Log.h> 33a033630e805c407080221e20b236b6054f324670Raph Levien 34a033630e805c407080221e20b236b6054f324670Raph Leviennamespace android { 35a033630e805c407080221e20b236b6054f324670Raph Levien 36117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien// Resolve the 1..9 weight based on base weight and bold flag 37bad99183916ba2bac6659efc8a28273e344ba511sergeyvstatic void resolveStyle(Typeface* typeface) { 38117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien int weight = typeface->fBaseWeight / 100; 39117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien if (typeface->fSkiaStyle & SkTypeface::kBold) { 40117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien weight += 3; 41117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien } 42117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien if (weight > 9) { 43117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien weight = 9; 44117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien } 45117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien bool italic = (typeface->fSkiaStyle & SkTypeface::kItalic) != 0; 46117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien typeface->fStyle = FontStyle(weight, italic); 47a033630e805c407080221e20b236b6054f324670Raph Levien} 48a033630e805c407080221e20b236b6054f324670Raph Levien 49bad99183916ba2bac6659efc8a28273e344ba511sergeyvTypeface* gDefaultTypeface = NULL; 50a033630e805c407080221e20b236b6054f324670Raph Levienpthread_once_t gDefaultTypefaceOnce = PTHREAD_ONCE_INIT; 51a033630e805c407080221e20b236b6054f324670Raph Levien 529a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien// This installs a default typeface (from a hardcoded path) that allows 539a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien// layouts to work (not crash on null pointer) before the default 549a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien// typeface is set. 559a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien// TODO: investigate why layouts are being created before Typeface.java 569a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien// class initialization. 57a033630e805c407080221e20b236b6054f324670Raph Levienstatic FontCollection *makeFontCollection() { 58a033630e805c407080221e20b236b6054f324670Raph Levien std::vector<FontFamily *>typefaces; 59a033630e805c407080221e20b236b6054f324670Raph Levien const char *fns[] = { 60a033630e805c407080221e20b236b6054f324670Raph Levien "/system/fonts/Roboto-Regular.ttf", 61a033630e805c407080221e20b236b6054f324670Raph Levien }; 62a033630e805c407080221e20b236b6054f324670Raph Levien 63a033630e805c407080221e20b236b6054f324670Raph Levien FontFamily *family = new FontFamily(); 64a033630e805c407080221e20b236b6054f324670Raph Levien for (size_t i = 0; i < sizeof(fns)/sizeof(fns[0]); i++) { 65a033630e805c407080221e20b236b6054f324670Raph Levien const char *fn = fns[i]; 669a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien ALOGD("makeFontCollection adding %s", fn); 67a033630e805c407080221e20b236b6054f324670Raph Levien SkTypeface *skFace = SkTypeface::CreateFromFile(fn); 689a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien if (skFace != NULL) { 69296bf8c55aaba0025f3e5b904fda3b6e15686753Raph Levien // TODO: might be a nice optimization to get access to the underlying font 70296bf8c55aaba0025f3e5b904fda3b6e15686753Raph Levien // data, but would require us opening the file ourselves and passing that 71296bf8c55aaba0025f3e5b904fda3b6e15686753Raph Levien // to the appropriate Create method of SkTypeface. 72296bf8c55aaba0025f3e5b904fda3b6e15686753Raph Levien MinikinFont *font = new MinikinFontSkia(skFace, NULL, 0, 0); 739a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien family->addFont(font); 7415cf4757dc0099301662f8a26da561434cc07cfaRaph Levien font->Unref(); 759a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien } else { 769a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien ALOGE("failed to create font %s", fn); 779a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien } 78a033630e805c407080221e20b236b6054f324670Raph Levien } 79a033630e805c407080221e20b236b6054f324670Raph Levien typefaces.push_back(family); 80a033630e805c407080221e20b236b6054f324670Raph Levien 8115cf4757dc0099301662f8a26da561434cc07cfaRaph Levien FontCollection *result = new FontCollection(typefaces); 8215cf4757dc0099301662f8a26da561434cc07cfaRaph Levien family->Unref(); 8315cf4757dc0099301662f8a26da561434cc07cfaRaph Levien return result; 84a033630e805c407080221e20b236b6054f324670Raph Levien} 85a033630e805c407080221e20b236b6054f324670Raph Levien 86a033630e805c407080221e20b236b6054f324670Raph Levienstatic void getDefaultTypefaceOnce() { 87a033630e805c407080221e20b236b6054f324670Raph Levien Layout::init(); 889a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien if (gDefaultTypeface == NULL) { 899a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien // We expect the client to set a default typeface, but provide a 909a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien // default so we can make progress before that happens. 91bad99183916ba2bac6659efc8a28273e344ba511sergeyv gDefaultTypeface = new Typeface; 929a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien gDefaultTypeface->fFontCollection = makeFontCollection(); 93117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien gDefaultTypeface->fSkiaStyle = SkTypeface::kNormal; 94117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien gDefaultTypeface->fBaseWeight = 400; 95117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien resolveStyle(gDefaultTypeface); 969a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien } 97a033630e805c407080221e20b236b6054f324670Raph Levien} 98a033630e805c407080221e20b236b6054f324670Raph Levien 99bad99183916ba2bac6659efc8a28273e344ba511sergeyvTypeface* Typeface::resolveDefault(Typeface* src) { 100a033630e805c407080221e20b236b6054f324670Raph Levien if (src == NULL) { 101a033630e805c407080221e20b236b6054f324670Raph Levien pthread_once(&gDefaultTypefaceOnce, getDefaultTypefaceOnce); 102a033630e805c407080221e20b236b6054f324670Raph Levien return gDefaultTypeface; 103a033630e805c407080221e20b236b6054f324670Raph Levien } else { 104a033630e805c407080221e20b236b6054f324670Raph Levien return src; 105a033630e805c407080221e20b236b6054f324670Raph Levien } 106a033630e805c407080221e20b236b6054f324670Raph Levien} 107a033630e805c407080221e20b236b6054f324670Raph Levien 108bad99183916ba2bac6659efc8a28273e344ba511sergeyvTypeface* Typeface::createFromTypeface(Typeface* src, SkTypeface::Style style) { 109bad99183916ba2bac6659efc8a28273e344ba511sergeyv Typeface* resolvedFace = Typeface::resolveDefault(src); 110bad99183916ba2bac6659efc8a28273e344ba511sergeyv Typeface* result = new Typeface; 111a033630e805c407080221e20b236b6054f324670Raph Levien if (result != 0) { 112a033630e805c407080221e20b236b6054f324670Raph Levien result->fFontCollection = resolvedFace->fFontCollection; 11315cf4757dc0099301662f8a26da561434cc07cfaRaph Levien result->fFontCollection->Ref(); 114117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien result->fSkiaStyle = style; 115117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien result->fBaseWeight = resolvedFace->fBaseWeight; 116117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien resolveStyle(result); 117a033630e805c407080221e20b236b6054f324670Raph Levien } 118a033630e805c407080221e20b236b6054f324670Raph Levien return result; 119a033630e805c407080221e20b236b6054f324670Raph Levien} 120a033630e805c407080221e20b236b6054f324670Raph Levien 121bad99183916ba2bac6659efc8a28273e344ba511sergeyvTypeface* Typeface::createWeightAlias(Typeface* src, int weight) { 122bad99183916ba2bac6659efc8a28273e344ba511sergeyv Typeface* resolvedFace = Typeface::resolveDefault(src); 123bad99183916ba2bac6659efc8a28273e344ba511sergeyv Typeface* result = new Typeface; 124117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien if (result != 0) { 125117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien result->fFontCollection = resolvedFace->fFontCollection; 126117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien result->fFontCollection->Ref(); 127117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien result->fSkiaStyle = resolvedFace->fSkiaStyle; 128117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien result->fBaseWeight = weight; 129117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien resolveStyle(result); 130117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien } 131a033630e805c407080221e20b236b6054f324670Raph Levien return result; 132a033630e805c407080221e20b236b6054f324670Raph Levien} 133a033630e805c407080221e20b236b6054f324670Raph Levien 134bad99183916ba2bac6659efc8a28273e344ba511sergeyvTypeface* Typeface::createFromFamilies(const std::vector<FontFamily*>& families) { 135bad99183916ba2bac6659efc8a28273e344ba511sergeyv Typeface* result = new Typeface; 136dccca44ffda4836b56a21da95a046c9708ffd49csergeyv result->fFontCollection = new FontCollection(families); 137dccca44ffda4836b56a21da95a046c9708ffd49csergeyv if (families.empty()) { 1381633caef58ebd0bc3b0c5da15dde2fb425b77c43Raph Levien ALOGW("createFromFamilies creating empty collection"); 139117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien result->fSkiaStyle = SkTypeface::kNormal; 1401633caef58ebd0bc3b0c5da15dde2fb425b77c43Raph Levien } else { 1411633caef58ebd0bc3b0c5da15dde2fb425b77c43Raph Levien const FontStyle defaultStyle; 1421633caef58ebd0bc3b0c5da15dde2fb425b77c43Raph Levien FontFamily* firstFamily = reinterpret_cast<FontFamily*>(families[0]); 1431fc0fa87d42ce9268ece76b85b9edc834593e53aRaph Levien MinikinFont* mf = firstFamily->getClosestMatch(defaultStyle).font; 14427bb05f2dccf1ac2ca55515aa0f4a99cd9c548a7Raph Levien if (mf != NULL) { 14527bb05f2dccf1ac2ca55515aa0f4a99cd9c548a7Raph Levien SkTypeface* skTypeface = reinterpret_cast<MinikinFontSkia*>(mf)->GetSkTypeface(); 14627bb05f2dccf1ac2ca55515aa0f4a99cd9c548a7Raph Levien // TODO: probably better to query more precise style from family, will be important 14727bb05f2dccf1ac2ca55515aa0f4a99cd9c548a7Raph Levien // when we open up API to access 100..900 weights 148117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien result->fSkiaStyle = skTypeface->style(); 14927bb05f2dccf1ac2ca55515aa0f4a99cd9c548a7Raph Levien } else { 150117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien result->fSkiaStyle = SkTypeface::kNormal; 15127bb05f2dccf1ac2ca55515aa0f4a99cd9c548a7Raph Levien } 1521633caef58ebd0bc3b0c5da15dde2fb425b77c43Raph Levien } 153117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien result->fBaseWeight = 400; 154117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien resolveStyle(result); 1551a73f732f91e97c9c66b808c245ddda36a10e987Raph Levien return result; 1561a73f732f91e97c9c66b808c245ddda36a10e987Raph Levien} 1571a73f732f91e97c9c66b808c245ddda36a10e987Raph Levien 158bad99183916ba2bac6659efc8a28273e344ba511sergeyvvoid Typeface::unref() { 159bad99183916ba2bac6659efc8a28273e344ba511sergeyv fFontCollection->Unref(); 160bad99183916ba2bac6659efc8a28273e344ba511sergeyv delete this; 161a033630e805c407080221e20b236b6054f324670Raph Levien} 162a033630e805c407080221e20b236b6054f324670Raph Levien 163bad99183916ba2bac6659efc8a28273e344ba511sergeyvvoid Typeface::setDefault(Typeface* face) { 1649a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien gDefaultTypeface = face; 1659a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien} 1669a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien 167a033630e805c407080221e20b236b6054f324670Raph Levien} 168