vandebo@chromium.org | 2a22e10 | 2011-01-25 21:01:34 +0000 | [diff] [blame] | 1 | /* |
epoger@google.com | ec3ed6a | 2011-07-28 14:26:00 +0000 | [diff] [blame] | 2 | * Copyright 2011 The Android Open Source Project |
vandebo@chromium.org | 2a22e10 | 2011-01-25 21:01:34 +0000 | [diff] [blame] | 3 | * |
epoger@google.com | ec3ed6a | 2011-07-28 14:26:00 +0000 | [diff] [blame] | 4 | * Use of this source code is governed by a BSD-style license that can be |
| 5 | * found in the LICENSE file. |
vandebo@chromium.org | 2a22e10 | 2011-01-25 21:01:34 +0000 | [diff] [blame] | 6 | */ |
| 7 | |
vandebo@chromium.org | 325cb9a | 2011-03-30 18:36:29 +0000 | [diff] [blame] | 8 | #include "SkAdvancedTypefaceMetrics.h" |
reed@google.com | 5526ede | 2013-03-25 13:03:37 +0000 | [diff] [blame] | 9 | #include "SkFontDescriptor.h" |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 10 | #include "SkFontHost.h" |
commit-bot@chromium.org | f6351a0 | 2014-05-30 21:00:52 +0000 | [diff] [blame^] | 11 | #include "SkOnce.h" |
reed@google.com | 5526ede | 2013-03-25 13:03:37 +0000 | [diff] [blame] | 12 | #include "SkStream.h" |
| 13 | #include "SkTypeface.h" |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 14 | |
reed@google.com | e495905 | 2011-05-02 17:35:04 +0000 | [diff] [blame] | 15 | //#define TRACE_LIFECYCLE |
reed@google.com | 2f3dc9d | 2011-05-02 17:33:45 +0000 | [diff] [blame] | 16 | |
| 17 | #ifdef TRACE_LIFECYCLE |
| 18 | static int32_t gTypefaceCounter; |
| 19 | #endif |
| 20 | |
bungeman@google.com | fe74765 | 2013-03-25 19:36:11 +0000 | [diff] [blame] | 21 | SkTypeface::SkTypeface(Style style, SkFontID fontID, bool isFixedPitch) |
| 22 | : fUniqueID(fontID), fStyle(style), fIsFixedPitch(isFixedPitch) { |
reed@google.com | 2f3dc9d | 2011-05-02 17:33:45 +0000 | [diff] [blame] | 23 | #ifdef TRACE_LIFECYCLE |
| 24 | SkDebugf("SkTypeface: create %p fontID %d total %d\n", |
| 25 | this, fontID, ++gTypefaceCounter); |
| 26 | #endif |
| 27 | } |
| 28 | |
| 29 | SkTypeface::~SkTypeface() { |
| 30 | #ifdef TRACE_LIFECYCLE |
| 31 | SkDebugf("SkTypeface: destroy %p fontID %d total %d\n", |
| 32 | this, fUniqueID, --gTypefaceCounter); |
| 33 | #endif |
| 34 | } |
| 35 | |
| 36 | /////////////////////////////////////////////////////////////////////////////// |
| 37 | |
bungeman@google.com | 5c1d88d | 2013-08-21 17:20:57 +0000 | [diff] [blame] | 38 | class SkEmptyTypeface : public SkTypeface { |
| 39 | public: |
commit-bot@chromium.org | c4df655 | 2014-04-07 19:34:16 +0000 | [diff] [blame] | 40 | static SkEmptyTypeface* Create() { |
| 41 | return SkNEW(SkEmptyTypeface); |
| 42 | } |
bungeman@google.com | 5c1d88d | 2013-08-21 17:20:57 +0000 | [diff] [blame] | 43 | protected: |
commit-bot@chromium.org | c4df655 | 2014-04-07 19:34:16 +0000 | [diff] [blame] | 44 | SkEmptyTypeface() : SkTypeface(SkTypeface::kNormal, 0, true) { } |
| 45 | |
bungeman@google.com | 5c1d88d | 2013-08-21 17:20:57 +0000 | [diff] [blame] | 46 | virtual SkStream* onOpenStream(int* ttcIndex) const SK_OVERRIDE { return NULL; } |
| 47 | virtual SkScalerContext* onCreateScalerContext(const SkDescriptor*) const SK_OVERRIDE { |
| 48 | return NULL; |
| 49 | } |
| 50 | virtual void onFilterRec(SkScalerContextRec*) const SK_OVERRIDE { } |
| 51 | virtual SkAdvancedTypefaceMetrics* onGetAdvancedTypefaceMetrics( |
| 52 | SkAdvancedTypefaceMetrics::PerGlyphInfo, |
| 53 | const uint32_t*, uint32_t) const SK_OVERRIDE { return NULL; } |
| 54 | virtual void onGetFontDescriptor(SkFontDescriptor*, bool*) const SK_OVERRIDE { } |
bungeman@google.com | 3c996f8 | 2013-10-24 21:39:35 +0000 | [diff] [blame] | 55 | virtual int onCharsToGlyphs(const void* chars, Encoding encoding, |
| 56 | uint16_t glyphs[], int glyphCount) const SK_OVERRIDE { |
| 57 | if (glyphs && glyphCount > 0) { |
| 58 | sk_bzero(glyphs, glyphCount * sizeof(glyphs[0])); |
| 59 | } |
| 60 | return 0; |
| 61 | } |
bungeman@google.com | 5c1d88d | 2013-08-21 17:20:57 +0000 | [diff] [blame] | 62 | virtual int onCountGlyphs() const SK_OVERRIDE { return 0; }; |
| 63 | virtual int onGetUPEM() const SK_OVERRIDE { return 0; }; |
| 64 | class EmptyLocalizedStrings : public SkTypeface::LocalizedStrings { |
| 65 | public: |
| 66 | virtual bool next(SkTypeface::LocalizedString*) SK_OVERRIDE { return false; } |
| 67 | }; |
| 68 | virtual SkTypeface::LocalizedStrings* onCreateFamilyNameIterator() const SK_OVERRIDE { |
| 69 | return SkNEW(EmptyLocalizedStrings); |
| 70 | }; |
| 71 | virtual int onGetTableTags(SkFontTableTag tags[]) const SK_OVERRIDE { return 0; } |
| 72 | virtual size_t onGetTableData(SkFontTableTag, size_t, size_t, void*) const SK_OVERRIDE { |
| 73 | return 0; |
| 74 | } |
bungeman@google.com | 5c1d88d | 2013-08-21 17:20:57 +0000 | [diff] [blame] | 75 | }; |
| 76 | |
commit-bot@chromium.org | f6351a0 | 2014-05-30 21:00:52 +0000 | [diff] [blame^] | 77 | static SkTypeface* gDefaultTypefaces[] = { NULL, NULL, NULL, NULL }; |
| 78 | static const size_t FONT_STYLE_COUNT = SK_ARRAY_COUNT(gDefaultTypefaces); |
| 79 | static SkOnceFlag gDefaultTypefaceOnce[FONT_STYLE_COUNT] = { |
| 80 | SK_ONCE_INIT, SK_ONCE_INIT, SK_ONCE_INIT, SK_ONCE_INIT |
| 81 | }; |
| 82 | template <uintmax_t N> struct SkTIsPow2 { |
| 83 | static const bool value = (N & (N - 1)) == 0; |
| 84 | }; |
| 85 | SK_COMPILE_ASSERT(SkTIsPow2<FONT_STYLE_COUNT>::value, FONT_STYLE_COUNT_not_power_of_2); |
| 86 | |
| 87 | void SkTypeface::create_default_typeface(Style style) { |
| 88 | if (NULL == gDefaultTypefaces[style]) { |
| 89 | gDefaultTypefaces[style] = SkFontHost::CreateTypeface(NULL, NULL, style); |
| 90 | } |
| 91 | if (NULL == gDefaultTypefaces[style]) { |
| 92 | // FIXME: Use a singleton for SkEmptyTypeface. |
| 93 | gDefaultTypefaces[style] = SkEmptyTypeface::Create(); |
| 94 | } |
bungeman@google.com | 18b75e5 | 2014-01-09 17:13:32 +0000 | [diff] [blame] | 95 | } |
bungeman@google.com | 5c1d88d | 2013-08-21 17:20:57 +0000 | [diff] [blame] | 96 | |
bungeman@google.com | 18b75e5 | 2014-01-09 17:13:32 +0000 | [diff] [blame] | 97 | SkTypeface* SkTypeface::GetDefaultTypeface(Style style) { |
commit-bot@chromium.org | f6351a0 | 2014-05-30 21:00:52 +0000 | [diff] [blame^] | 98 | SkASSERT((size_t)style < FONT_STYLE_COUNT); |
bungeman@google.com | 18b75e5 | 2014-01-09 17:13:32 +0000 | [diff] [blame] | 99 | |
commit-bot@chromium.org | f6351a0 | 2014-05-30 21:00:52 +0000 | [diff] [blame^] | 100 | // mask off any other bits to avoid a crash in SK_RELEASE |
| 101 | style = (Style)(style & (FONT_STYLE_COUNT - 1)); |
| 102 | |
| 103 | SkOnce(&gDefaultTypefaceOnce[style], SkTypeface::create_default_typeface, style); |
| 104 | return gDefaultTypefaces[style]; |
reed@google.com | 538f784 | 2011-12-16 17:56:23 +0000 | [diff] [blame] | 105 | } |
| 106 | |
djsollen@google.com | 4fa748d | 2013-06-05 14:20:25 +0000 | [diff] [blame] | 107 | SkTypeface* SkTypeface::RefDefault(Style style) { |
| 108 | return SkRef(GetDefaultTypeface(style)); |
reed@google.com | fed86bd | 2013-03-14 15:04:57 +0000 | [diff] [blame] | 109 | } |
| 110 | |
reed@android.com | ef772dd | 2009-03-03 21:20:49 +0000 | [diff] [blame] | 111 | uint32_t SkTypeface::UniqueID(const SkTypeface* face) { |
reed@google.com | 538f784 | 2011-12-16 17:56:23 +0000 | [diff] [blame] | 112 | if (NULL == face) { |
bungeman@google.com | cb1bbb3 | 2012-10-12 18:48:35 +0000 | [diff] [blame] | 113 | face = GetDefaultTypeface(); |
reed@android.com | b1d9d2e | 2009-03-04 17:37:51 +0000 | [diff] [blame] | 114 | } |
reed@google.com | 538f784 | 2011-12-16 17:56:23 +0000 | [diff] [blame] | 115 | return face->uniqueID(); |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 116 | } |
| 117 | |
reed@android.com | ef772dd | 2009-03-03 21:20:49 +0000 | [diff] [blame] | 118 | bool SkTypeface::Equal(const SkTypeface* facea, const SkTypeface* faceb) { |
reed@android.com | b1d9d2e | 2009-03-04 17:37:51 +0000 | [diff] [blame] | 119 | return SkTypeface::UniqueID(facea) == SkTypeface::UniqueID(faceb); |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 120 | } |
| 121 | |
| 122 | /////////////////////////////////////////////////////////////////////////////// |
| 123 | |
reed@android.com | 069b827 | 2009-03-04 15:31:48 +0000 | [diff] [blame] | 124 | SkTypeface* SkTypeface::CreateFromName(const char name[], Style style) { |
djsollen@google.com | 4fa748d | 2013-06-05 14:20:25 +0000 | [diff] [blame] | 125 | if (NULL == name) { |
| 126 | return RefDefault(style); |
| 127 | } |
reed@google.com | 0389d93 | 2012-05-07 21:06:55 +0000 | [diff] [blame] | 128 | return SkFontHost::CreateTypeface(NULL, name, style); |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 129 | } |
| 130 | |
reed@android.com | ef772dd | 2009-03-03 21:20:49 +0000 | [diff] [blame] | 131 | SkTypeface* SkTypeface::CreateFromTypeface(const SkTypeface* family, Style s) { |
reed@google.com | 4969044 | 2013-03-04 14:39:47 +0000 | [diff] [blame] | 132 | if (family && family->style() == s) { |
| 133 | family->ref(); |
| 134 | return const_cast<SkTypeface*>(family); |
| 135 | } |
reed@google.com | 0389d93 | 2012-05-07 21:06:55 +0000 | [diff] [blame] | 136 | return SkFontHost::CreateTypeface(family, NULL, s); |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 137 | } |
| 138 | |
reed@android.com | ef772dd | 2009-03-03 21:20:49 +0000 | [diff] [blame] | 139 | SkTypeface* SkTypeface::CreateFromStream(SkStream* stream) { |
reed@android.com | b1d9d2e | 2009-03-04 17:37:51 +0000 | [diff] [blame] | 140 | return SkFontHost::CreateTypefaceFromStream(stream); |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 141 | } |
| 142 | |
reed@android.com | ef772dd | 2009-03-03 21:20:49 +0000 | [diff] [blame] | 143 | SkTypeface* SkTypeface::CreateFromFile(const char path[]) { |
reed@android.com | 03ca3d1 | 2008-12-22 15:35:46 +0000 | [diff] [blame] | 144 | return SkFontHost::CreateTypefaceFromFile(path); |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 145 | } |
| 146 | |
| 147 | /////////////////////////////////////////////////////////////////////////////// |
| 148 | |
reed@google.com | 5526ede | 2013-03-25 13:03:37 +0000 | [diff] [blame] | 149 | void SkTypeface::serialize(SkWStream* wstream) const { |
| 150 | bool isLocal = false; |
| 151 | SkFontDescriptor desc(this->style()); |
| 152 | this->onGetFontDescriptor(&desc, &isLocal); |
| 153 | |
| 154 | desc.serialize(wstream); |
| 155 | if (isLocal) { |
| 156 | int ttcIndex; // TODO: write this to the stream? |
| 157 | SkAutoTUnref<SkStream> rstream(this->openStream(&ttcIndex)); |
| 158 | if (rstream.get()) { |
| 159 | size_t length = rstream->getLength(); |
| 160 | wstream->writePackedUInt(length); |
| 161 | wstream->writeStream(rstream, length); |
| 162 | } else { |
| 163 | wstream->writePackedUInt(0); |
| 164 | } |
| 165 | } else { |
| 166 | wstream->writePackedUInt(0); |
| 167 | } |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 168 | } |
| 169 | |
| 170 | SkTypeface* SkTypeface::Deserialize(SkStream* stream) { |
reed@google.com | 5526ede | 2013-03-25 13:03:37 +0000 | [diff] [blame] | 171 | SkFontDescriptor desc(stream); |
| 172 | size_t length = stream->readPackedUInt(); |
| 173 | if (length > 0) { |
| 174 | void* addr = sk_malloc_flags(length, 0); |
| 175 | if (addr) { |
robertphillips@google.com | 9e9dfa3 | 2013-05-10 17:22:48 +0000 | [diff] [blame] | 176 | SkAutoTUnref<SkMemoryStream> localStream(SkNEW(SkMemoryStream)); |
| 177 | localStream->setMemoryOwned(addr, length); |
| 178 | |
bungeman@google.com | 2786d15 | 2013-04-09 19:29:45 +0000 | [diff] [blame] | 179 | if (stream->read(addr, length) == length) { |
| 180 | return SkTypeface::CreateFromStream(localStream.get()); |
| 181 | } else { |
| 182 | // Failed to read the full font data, so fall through and try to create from name. |
| 183 | // If this is because of EOF, all subsequent reads from the stream will be EOF. |
| 184 | // If this is because of a stream error, the stream is in an error state, |
| 185 | // do not attempt to skip any remaining bytes. |
| 186 | } |
| 187 | } else { |
| 188 | // failed to allocate, so just skip and create-from-name |
robertphillips@google.com | 1eb16b9 | 2013-04-09 17:35:29 +0000 | [diff] [blame] | 189 | stream->skip(length); |
reed@google.com | 5526ede | 2013-03-25 13:03:37 +0000 | [diff] [blame] | 190 | } |
reed@google.com | 5526ede | 2013-03-25 13:03:37 +0000 | [diff] [blame] | 191 | } |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 192 | |
reed@google.com | 5526ede | 2013-03-25 13:03:37 +0000 | [diff] [blame] | 193 | return SkTypeface::CreateFromName(desc.getFamilyName(), desc.getStyle()); |
vandebo@chromium.org | 2a22e10 | 2011-01-25 21:01:34 +0000 | [diff] [blame] | 194 | } |
reed@google.com | f11508d | 2012-04-17 18:01:31 +0000 | [diff] [blame] | 195 | |
| 196 | /////////////////////////////////////////////////////////////////////////////// |
| 197 | |
| 198 | int SkTypeface::countTables() const { |
reed@google.com | 6c66d2f | 2013-03-21 20:34:27 +0000 | [diff] [blame] | 199 | return this->onGetTableTags(NULL); |
reed@google.com | f11508d | 2012-04-17 18:01:31 +0000 | [diff] [blame] | 200 | } |
| 201 | |
| 202 | int SkTypeface::getTableTags(SkFontTableTag tags[]) const { |
reed@google.com | 6c66d2f | 2013-03-21 20:34:27 +0000 | [diff] [blame] | 203 | return this->onGetTableTags(tags); |
reed@google.com | f11508d | 2012-04-17 18:01:31 +0000 | [diff] [blame] | 204 | } |
| 205 | |
| 206 | size_t SkTypeface::getTableSize(SkFontTableTag tag) const { |
reed@google.com | 6c66d2f | 2013-03-21 20:34:27 +0000 | [diff] [blame] | 207 | return this->onGetTableData(tag, 0, ~0U, NULL); |
reed@google.com | f11508d | 2012-04-17 18:01:31 +0000 | [diff] [blame] | 208 | } |
| 209 | |
| 210 | size_t SkTypeface::getTableData(SkFontTableTag tag, size_t offset, size_t length, |
| 211 | void* data) const { |
reed@google.com | 6c66d2f | 2013-03-21 20:34:27 +0000 | [diff] [blame] | 212 | return this->onGetTableData(tag, offset, length, data); |
reed@google.com | f11508d | 2012-04-17 18:01:31 +0000 | [diff] [blame] | 213 | } |
| 214 | |
reed@google.com | fed86bd | 2013-03-14 15:04:57 +0000 | [diff] [blame] | 215 | SkStream* SkTypeface::openStream(int* ttcIndex) const { |
reed@google.com | 2cdc671 | 2013-03-21 18:22:00 +0000 | [diff] [blame] | 216 | int ttcIndexStorage; |
| 217 | if (NULL == ttcIndex) { |
| 218 | // So our subclasses don't need to check for null param |
| 219 | ttcIndex = &ttcIndexStorage; |
reed@google.com | fed86bd | 2013-03-14 15:04:57 +0000 | [diff] [blame] | 220 | } |
reed@google.com | 2cdc671 | 2013-03-21 18:22:00 +0000 | [diff] [blame] | 221 | return this->onOpenStream(ttcIndex); |
reed@google.com | fed86bd | 2013-03-14 15:04:57 +0000 | [diff] [blame] | 222 | } |
| 223 | |
reed@google.com | bcb42ae | 2013-07-02 13:56:39 +0000 | [diff] [blame] | 224 | int SkTypeface::charsToGlyphs(const void* chars, Encoding encoding, |
| 225 | uint16_t glyphs[], int glyphCount) const { |
| 226 | if (glyphCount <= 0) { |
| 227 | return 0; |
| 228 | } |
| 229 | if (NULL == chars || (unsigned)encoding > kUTF32_Encoding) { |
| 230 | if (glyphs) { |
| 231 | sk_bzero(glyphs, glyphCount * sizeof(glyphs[0])); |
| 232 | } |
| 233 | return 0; |
| 234 | } |
| 235 | return this->onCharsToGlyphs(chars, encoding, glyphs, glyphCount); |
| 236 | } |
| 237 | |
| 238 | int SkTypeface::countGlyphs() const { |
| 239 | return this->onCountGlyphs(); |
| 240 | } |
| 241 | |
reed@google.com | 4b2af9c | 2012-07-31 17:24:44 +0000 | [diff] [blame] | 242 | int SkTypeface::getUnitsPerEm() const { |
reed@google.com | 38c37dd | 2013-03-21 15:36:26 +0000 | [diff] [blame] | 243 | // should we try to cache this in the base-class? |
| 244 | return this->onGetUPEM(); |
reed@google.com | 4b2af9c | 2012-07-31 17:24:44 +0000 | [diff] [blame] | 245 | } |
mike@reedtribe.org | dc09f07 | 2013-03-03 01:15:48 +0000 | [diff] [blame] | 246 | |
reed@google.com | 35fe737 | 2013-10-30 15:07:03 +0000 | [diff] [blame] | 247 | bool SkTypeface::getKerningPairAdjustments(const uint16_t glyphs[], int count, |
| 248 | int32_t adjustments[]) const { |
| 249 | SkASSERT(count >= 0); |
| 250 | // check for the only legal way to pass a NULL.. everything is 0 |
| 251 | // in which case they just want to know if this face can possibly support |
| 252 | // kerning (true) or never (false). |
| 253 | if (NULL == glyphs || NULL == adjustments) { |
| 254 | SkASSERT(NULL == glyphs); |
| 255 | SkASSERT(0 == count); |
| 256 | SkASSERT(NULL == adjustments); |
| 257 | } |
| 258 | return this->onGetKerningPairAdjustments(glyphs, count, adjustments); |
| 259 | } |
| 260 | |
bungeman@google.com | 839702b | 2013-08-07 17:09:22 +0000 | [diff] [blame] | 261 | SkTypeface::LocalizedStrings* SkTypeface::createFamilyNameIterator() const { |
| 262 | return this->onCreateFamilyNameIterator(); |
bungeman@google.com | a980269 | 2013-08-07 02:45:25 +0000 | [diff] [blame] | 263 | } |
| 264 | |
reed@google.com | 08df48d | 2013-07-29 18:54:08 +0000 | [diff] [blame] | 265 | void SkTypeface::getFamilyName(SkString* name) const { |
| 266 | bool isLocal = false; |
| 267 | SkFontDescriptor desc(this->style()); |
| 268 | this->onGetFontDescriptor(&desc, &isLocal); |
| 269 | name->set(desc.getFamilyName()); |
| 270 | } |
| 271 | |
reed@google.com | 5526ede | 2013-03-25 13:03:37 +0000 | [diff] [blame] | 272 | SkAdvancedTypefaceMetrics* SkTypeface::getAdvancedTypefaceMetrics( |
| 273 | SkAdvancedTypefaceMetrics::PerGlyphInfo info, |
| 274 | const uint32_t* glyphIDs, |
| 275 | uint32_t glyphIDsCount) const { |
vandebo@chromium.org | 5f209e6 | 2013-12-10 17:22:41 +0000 | [diff] [blame] | 276 | return this->onGetAdvancedTypefaceMetrics(info, glyphIDs, glyphIDsCount); |
reed@google.com | 5526ede | 2013-03-25 13:03:37 +0000 | [diff] [blame] | 277 | } |
mike@reedtribe.org | dc09f07 | 2013-03-03 01:15:48 +0000 | [diff] [blame] | 278 | |
reed@google.com | 35fe737 | 2013-10-30 15:07:03 +0000 | [diff] [blame] | 279 | /////////////////////////////////////////////////////////////////////////////// |
| 280 | |
| 281 | bool SkTypeface::onGetKerningPairAdjustments(const uint16_t glyphs[], int count, |
| 282 | int32_t adjustments[]) const { |
| 283 | return false; |
| 284 | } |