Typeface.cpp revision ba3028c1fc9fca2d45acc841557da2c9a83923bf
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 <pthread.h> 26#include <fcntl.h> // For tests. 27#include <sys/stat.h> // For tests. 28#include <sys/mman.h> // For tests. 29 30#include "MinikinSkia.h" 31#include "SkTypeface.h" 32#include "SkPaint.h" 33#include "SkStream.h" // Fot tests. 34 35#include <minikin/FontCollection.h> 36#include <minikin/FontFamily.h> 37#include <minikin/Layout.h> 38#include <utils/Log.h> 39 40namespace android { 41 42// Resolve the 1..9 weight based on base weight and bold flag 43static void resolveStyle(Typeface* 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 = minikin::FontStyle(weight, italic); 53} 54 55Typeface* gDefaultTypeface = NULL; 56 57Typeface* Typeface::resolveDefault(Typeface* src) { 58 LOG_ALWAYS_FATAL_IF(gDefaultTypeface == nullptr); 59 return src == nullptr ? gDefaultTypeface : src; 60} 61 62Typeface* Typeface::createFromTypeface(Typeface* src, SkTypeface::Style style) { 63 Typeface* resolvedFace = Typeface::resolveDefault(src); 64 Typeface* result = new Typeface; 65 if (result != nullptr) { 66 result->fFontCollection = resolvedFace->fFontCollection; 67 result->fFontCollection->Ref(); 68 result->fSkiaStyle = style; 69 result->fBaseWeight = resolvedFace->fBaseWeight; 70 resolveStyle(result); 71 } 72 return result; 73} 74 75Typeface* Typeface::createFromTypefaceWithVariation(Typeface* src, 76 const std::vector<minikin::FontVariation>& variations) { 77 Typeface* resolvedFace = Typeface::resolveDefault(src); 78 Typeface* result = new Typeface(); 79 if (result != nullptr) { 80 result->fFontCollection = 81 resolvedFace->fFontCollection->createCollectionWithVariation(variations); 82 if (result->fFontCollection == nullptr) { 83 // None of passed axes are supported by this collection. 84 // So we will reuse the same collection with incrementing reference count. 85 result->fFontCollection = resolvedFace->fFontCollection; 86 result->fFontCollection->Ref(); 87 } 88 result->fSkiaStyle = resolvedFace->fSkiaStyle; 89 result->fBaseWeight = resolvedFace->fBaseWeight; 90 resolveStyle(result); 91 } 92 return result; 93} 94 95Typeface* Typeface::createWeightAlias(Typeface* src, int weight) { 96 Typeface* resolvedFace = Typeface::resolveDefault(src); 97 Typeface* result = new Typeface; 98 if (result != nullptr) { 99 result->fFontCollection = resolvedFace->fFontCollection; 100 result->fFontCollection->Ref(); 101 result->fSkiaStyle = resolvedFace->fSkiaStyle; 102 result->fBaseWeight = weight; 103 resolveStyle(result); 104 } 105 return result; 106} 107 108Typeface* Typeface::createFromFamilies(const std::vector<minikin::FontFamily*>& families) { 109 Typeface* result = new Typeface; 110 result->fFontCollection = new minikin::FontCollection(families); 111 if (families.empty()) { 112 ALOGW("createFromFamilies creating empty collection"); 113 result->fSkiaStyle = SkTypeface::kNormal; 114 } else { 115 const minikin::FontStyle defaultStyle; 116 minikin::FontFamily* firstFamily = reinterpret_cast<minikin::FontFamily*>(families[0]); 117 minikin::MinikinFont* mf = firstFamily->getClosestMatch(defaultStyle).font; 118 if (mf != NULL) { 119 SkTypeface* skTypeface = reinterpret_cast<MinikinFontSkia*>(mf)->GetSkTypeface(); 120 // TODO: probably better to query more precise style from family, will be important 121 // when we open up API to access 100..900 weights 122 result->fSkiaStyle = skTypeface->style(); 123 } else { 124 result->fSkiaStyle = SkTypeface::kNormal; 125 } 126 } 127 result->fBaseWeight = 400; 128 resolveStyle(result); 129 return result; 130} 131 132void Typeface::unref() { 133 fFontCollection->Unref(); 134 delete this; 135} 136 137void Typeface::setDefault(Typeface* face) { 138 gDefaultTypeface = face; 139} 140 141void Typeface::setRobotoTypefaceForTest() { 142 const char* kRobotoFont = "/system/fonts/Roboto-Regular.ttf"; 143 144 int fd = open(kRobotoFont, O_RDONLY); 145 LOG_ALWAYS_FATAL_IF(fd == -1, "Failed to open file %s", kRobotoFont); 146 struct stat st = {}; 147 LOG_ALWAYS_FATAL_IF(fstat(fd, &st) == -1, "Failed to stat file %s", kRobotoFont); 148 void* data = mmap(nullptr, st.st_size, PROT_READ, MAP_SHARED, fd, 0); 149 std::unique_ptr<SkMemoryStream> fontData(new SkMemoryStream(data, st.st_size)); 150 sk_sp<SkTypeface> typeface = SkTypeface::MakeFromStream(fontData.release()); 151 LOG_ALWAYS_FATAL_IF(typeface == nullptr, "Failed to make typeface from %s", kRobotoFont); 152 153 minikin::MinikinFont* font = new MinikinFontSkia(std::move(typeface), data, st.st_size, 0); 154 minikin::FontFamily* family = new minikin::FontFamily( 155 std::vector<minikin::Font>({ minikin::Font(font, minikin::FontStyle()) })); 156 font->Unref(); 157 158 std::vector<minikin::FontFamily*> typefaces = { family }; 159 minikin::FontCollection *collection = new minikin::FontCollection(typefaces); 160 family->Unref(); 161 162 Typeface* hwTypeface = new Typeface(); 163 hwTypeface->fFontCollection = collection; 164 hwTypeface->fSkiaStyle = SkTypeface::kNormal; 165 hwTypeface->fBaseWeight = 400; 166 hwTypeface->fStyle = minikin::FontStyle(4 /* weight */, false /* italic */); 167 168 Typeface::setDefault(hwTypeface); 169} 170 171} 172