Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright 2011 Google Inc. | 2 * Copyright 2011 Google Inc. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
| 6 */ | 6 */ |
| 7 | 7 |
| 8 #include "SkEndian.h" | 8 #include "SkEndian.h" |
| 9 #include "SkFontStream.h" | 9 #include "SkFontStream.h" |
| 10 #include "SkStream.h" | 10 #include "SkStream.h" |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 36 uint32_t fLength; | 36 uint32_t fLength; |
| 37 }; | 37 }; |
| 38 | 38 |
| 39 /** Return the number of tables, or if this is a TTC (collection), return the | 39 /** Return the number of tables, or if this is a TTC (collection), return the |
| 40 number of tables in the first element of the collection. In either case, | 40 number of tables in the first element of the collection. In either case, |
| 41 if offsetToDir is not-null, set it to the offset to the beginning of the | 41 if offsetToDir is not-null, set it to the offset to the beginning of the |
| 42 table headers (SkSFNTDirEntry), relative to the start of the stream. | 42 table headers (SkSFNTDirEntry), relative to the start of the stream. |
| 43 | 43 |
| 44 On an error, return 0 for number of tables, and ignore offsetToDir | 44 On an error, return 0 for number of tables, and ignore offsetToDir |
| 45 */ | 45 */ |
| 46 static int count_tables(SkStream* stream, size_t* offsetToDir = NULL) { | 46 static int count_tables(SkStream* stream, int ttcIndex, size_t* offsetToDir) { |
|
bungeman-skia
2013/03/05 22:07:33
ttcIndex may well be perfectly well served by an i
| |
| 47 SkASSERT(ttcIndex >= 0); | |
| 48 | |
| 47 SkSharedTTHeader shared; | 49 SkSharedTTHeader shared; |
| 48 if (stream->read(&shared, sizeof(shared)) != sizeof(shared)) { | 50 if (stream->read(&shared, sizeof(shared)) != sizeof(shared)) { |
| 49 return 0; | 51 return 0; |
| 50 } | 52 } |
| 51 | 53 |
| 52 // by default, SkSFNTHeader is at the start of the stream | 54 // by default, SkSFNTHeader is at the start of the stream |
| 53 size_t offset = 0; | 55 size_t offset = 0; |
| 54 | 56 |
| 55 // if we're really a collection, the first 4-bytes will be 'ttcf' | 57 // if we're really a collection, the first 4-bytes will be 'ttcf' |
| 56 uint32_t tag = SkEndian_SwapBE32(shared.fCollection.fTag); | 58 uint32_t tag = SkEndian_SwapBE32(shared.fCollection.fTag); |
| 57 if (SkSetFourByteTag('t', 't', 'c', 'f') == tag) { | 59 if (SkSetFourByteTag('t', 't', 'c', 'f') == tag) { |
| 58 if (shared.fCollection.fNumOffsets == 0) { | 60 unsigned count = SkEndian_SwapBE32(shared.fCollection.fNumOffsets); |
| 61 if ((unsigned)ttcIndex >= count) { | |
| 59 return 0; | 62 return 0; |
| 60 } | 63 } |
| 61 // this is the offset to the first local SkSFNTHeader | 64 |
| 62 offset = SkEndian_SwapBE32(shared.fCollection.fOffset0); | 65 if (ttcIndex > 0) { // need to read more of the shared header |
| 66 stream->rewind(); | |
| 67 size_t amount = sizeof(shared) + ttcIndex * sizeof(uint32_t); | |
| 68 if (stream->read(&shared, amount) != amount) { | |
| 69 return 0; | |
| 70 } | |
| 71 } | |
| 72 // this is the offset to the local SkSFNTHeader | |
| 73 offset = SkEndian_SwapBE32((&shared.fCollection.fOffset0)[ttcIndex]); | |
| 63 stream->rewind(); | 74 stream->rewind(); |
| 64 if (stream->skip(offset) != offset) { | 75 if (stream->skip(offset) != offset) { |
| 65 return 0; | 76 return 0; |
| 66 } | 77 } |
| 67 if (stream->read(&shared, sizeof(shared)) != sizeof(shared)) { | 78 if (stream->read(&shared, sizeof(shared)) != sizeof(shared)) { |
| 68 return 0; | 79 return 0; |
| 69 } | 80 } |
| 70 } | 81 } |
| 71 | 82 |
| 72 if (offsetToDir) { | 83 if (offsetToDir) { |
| 73 // add the size of the header, so we will point to the DirEntries | 84 // add the size of the header, so we will point to the DirEntries |
| 74 *offsetToDir = offset + sizeof(SkSFNTHeader); | 85 *offsetToDir = offset + sizeof(SkSFNTHeader); |
| 75 } | 86 } |
| 76 return SkEndian_SwapBE16(shared.fSingle.fNumTables); | 87 return SkEndian_SwapBE16(shared.fSingle.fNumTables); |
| 77 } | 88 } |
| 78 | 89 |
| 79 /////////////////////////////////////////////////////////////////////////////// | 90 /////////////////////////////////////////////////////////////////////////////// |
| 80 | 91 |
| 81 struct SfntHeader { | 92 struct SfntHeader { |
| 82 SfntHeader() : fCount(0), fDir(NULL) {} | 93 SfntHeader() : fCount(0), fDir(NULL) {} |
| 83 ~SfntHeader() { sk_free(fDir); } | 94 ~SfntHeader() { sk_free(fDir); } |
| 84 | 95 |
| 85 /** If it returns true, then fCount and fDir are properly initialized. | 96 /** If it returns true, then fCount and fDir are properly initialized. |
| 86 Note: fDir will point to the raw array of SkSFNTDirEntry values, | 97 Note: fDir will point to the raw array of SkSFNTDirEntry values, |
| 87 meaning they will still be in the file's native endianness (BE). | 98 meaning they will still be in the file's native endianness (BE). |
| 88 | 99 |
| 89 fDir will be automatically freed when this object is destroyed | 100 fDir will be automatically freed when this object is destroyed |
| 90 */ | 101 */ |
| 91 bool init(SkStream* stream) { | 102 bool init(SkStream* stream, int ttcIndex) { |
| 92 stream->rewind(); | 103 stream->rewind(); |
| 93 | 104 |
| 94 size_t offsetToDir; | 105 size_t offsetToDir; |
| 95 fCount = count_tables(stream, &offsetToDir); | 106 fCount = count_tables(stream, ttcIndex, &offsetToDir); |
| 96 if (0 == fCount) { | 107 if (0 == fCount) { |
| 97 return false; | 108 return false; |
| 98 } | 109 } |
| 99 | 110 |
| 100 stream->rewind(); | 111 stream->rewind(); |
| 101 if (stream->skip(offsetToDir) != offsetToDir) { | 112 if (stream->skip(offsetToDir) != offsetToDir) { |
| 102 return false; | 113 return false; |
| 103 } | 114 } |
| 104 | 115 |
| 105 size_t size = fCount * sizeof(SkSFNTDirEntry); | 116 size_t size = fCount * sizeof(SkSFNTDirEntry); |
| 106 fDir = reinterpret_cast<SkSFNTDirEntry*>(sk_malloc_throw(size)); | 117 fDir = reinterpret_cast<SkSFNTDirEntry*>(sk_malloc_throw(size)); |
| 107 return stream->read(fDir, size) == size; | 118 return stream->read(fDir, size) == size; |
| 108 } | 119 } |
| 109 | 120 |
| 110 int fCount; | 121 int fCount; |
| 111 SkSFNTDirEntry* fDir; | 122 SkSFNTDirEntry* fDir; |
| 112 }; | 123 }; |
| 113 | 124 |
| 114 /////////////////////////////////////////////////////////////////////////////// | 125 /////////////////////////////////////////////////////////////////////////////// |
| 115 | 126 |
| 116 int SkFontStream::GetTableTags(SkStream* stream, SkFontTableTag tags[]) { | 127 int SkFontStream::CountTTCEntries(SkStream* stream) { |
| 128 stream->rewind(); | |
| 129 | |
| 130 SkSharedTTHeader shared; | |
| 131 if (stream->read(&shared, sizeof(shared)) != sizeof(shared)) { | |
| 132 return -1; | |
| 133 } | |
| 134 | |
| 135 // if we're really a collection, the first 4-bytes will be 'ttcf' | |
| 136 uint32_t tag = SkEndian_SwapBE32(shared.fCollection.fTag); | |
| 137 if (SkSetFourByteTag('t', 't', 'c', 'f') == tag) { | |
| 138 return SkEndian_SwapBE32(shared.fCollection.fNumOffsets); | |
| 139 } else { | |
| 140 return 0; | |
|
bungeman-skia
2013/03/05 22:07:33
The doc says return 0 for sfnt, but this returns 0
| |
| 141 } | |
| 142 } | |
| 143 | |
| 144 int SkFontStream::GetTableTags(SkStream* stream, int ttcIndex, | |
| 145 SkFontTableTag tags[]) { | |
| 117 SfntHeader header; | 146 SfntHeader header; |
| 118 if (!header.init(stream)) { | 147 if (!header.init(stream, ttcIndex)) { |
| 119 return 0; | 148 return 0; |
| 120 } | 149 } |
| 121 | 150 |
| 122 if (tags) { | 151 if (tags) { |
| 123 for (int i = 0; i < header.fCount; i++) { | 152 for (int i = 0; i < header.fCount; i++) { |
| 124 tags[i] = SkEndian_SwapBE32(header.fDir[i].fTag); | 153 tags[i] = SkEndian_SwapBE32(header.fDir[i].fTag); |
| 125 } | 154 } |
| 126 } | 155 } |
| 127 return header.fCount; | 156 return header.fCount; |
| 128 } | 157 } |
| 129 | 158 |
| 130 size_t SkFontStream::GetTableData(SkStream* stream, SkFontTableTag tag, | 159 size_t SkFontStream::GetTableData(SkStream* stream, int ttcIndex, |
| 160 SkFontTableTag tag, | |
| 131 size_t offset, size_t length, void* data) { | 161 size_t offset, size_t length, void* data) { |
| 132 SfntHeader header; | 162 SfntHeader header; |
| 133 if (!header.init(stream)) { | 163 if (!header.init(stream, ttcIndex)) { |
| 134 return 0; | 164 return 0; |
| 135 } | 165 } |
| 136 | 166 |
| 137 for (int i = 0; i < header.fCount; i++) { | 167 for (int i = 0; i < header.fCount; i++) { |
| 138 if (SkEndian_SwapBE32(header.fDir[i].fTag) == tag) { | 168 if (SkEndian_SwapBE32(header.fDir[i].fTag) == tag) { |
| 139 size_t realOffset = SkEndian_SwapBE32(header.fDir[i].fOffset); | 169 size_t realOffset = SkEndian_SwapBE32(header.fDir[i].fOffset); |
| 140 size_t realLength = SkEndian_SwapBE32(header.fDir[i].fLength); | 170 size_t realLength = SkEndian_SwapBE32(header.fDir[i].fLength); |
| 141 // now sanity check the caller's offset/length | 171 // now sanity check the caller's offset/length |
| 142 if (offset >= realLength) { | 172 if (offset >= realLength) { |
| 143 return 0; | 173 return 0; |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 160 } | 190 } |
| 161 if (stream->read(data, length) != length) { | 191 if (stream->read(data, length) != length) { |
| 162 return 0; | 192 return 0; |
| 163 } | 193 } |
| 164 } | 194 } |
| 165 return length; | 195 return length; |
| 166 } | 196 } |
| 167 } | 197 } |
| 168 return 0; | 198 return 0; |
| 169 } | 199 } |
| OLD | NEW |