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 |