1 /*
2 * Copyright 2011 Google Inc. All Rights Reserved.
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 #include "sfntly/table/bitmap/index_sub_table_format4.h"
18
19 #include "sfntly/table/bitmap/eblc_table.h"
20
21 namespace sfntly {
22 /******************************************************************************
23 * IndexSubTableFormat4 class
24 ******************************************************************************/
~IndexSubTableFormat4()25 IndexSubTableFormat4::~IndexSubTableFormat4() {
26 }
27
NumGlyphs()28 int32_t IndexSubTableFormat4::NumGlyphs() {
29 return IndexSubTableFormat4::NumGlyphs(data_, 0);
30 }
31
GlyphStartOffset(int32_t glyph_id)32 int32_t IndexSubTableFormat4::GlyphStartOffset(int32_t glyph_id) {
33 int32_t loca = CheckGlyphRange(glyph_id);
34 if (loca == -1) {
35 return -1;
36 }
37 int32_t pair_index = FindCodeOffsetPair(glyph_id);
38 if (pair_index < 0) {
39 return -1;
40 }
41 return data_->ReadUShort(EblcTable::Offset::kIndexSubTable4_glyphArray +
42 pair_index *
43 EblcTable::Offset::kCodeOffsetPairLength +
44 EblcTable::Offset::kCodeOffsetPair_offset);
45 }
46
GlyphLength(int32_t glyph_id)47 int32_t IndexSubTableFormat4::GlyphLength(int32_t glyph_id) {
48 int32_t loca = CheckGlyphRange(glyph_id);
49 if (loca == -1) {
50 return -1;
51 }
52
53 int32_t pair_index = FindCodeOffsetPair(glyph_id);
54 if (pair_index < 0) {
55 return -1;
56 }
57 return data_->ReadUShort(
58 EblcTable::Offset::kIndexSubTable4_glyphArray +
59 (pair_index + 1) * EblcTable::Offset::kCodeOffsetPairLength +
60 EblcTable::Offset::kCodeOffsetPair_offset) -
61 data_->ReadUShort(
62 EblcTable::Offset::kIndexSubTable4_glyphArray +
63 (pair_index) * EblcTable::Offset::kCodeOffsetPairLength +
64 EblcTable::Offset::kCodeOffsetPair_offset);
65 }
66
IndexSubTableFormat4(ReadableFontData * data,int32_t first,int32_t last)67 IndexSubTableFormat4::IndexSubTableFormat4(ReadableFontData* data,
68 int32_t first,
69 int32_t last)
70 : IndexSubTable(data, first, last) {
71 }
72
FindCodeOffsetPair(int32_t glyph_id)73 int32_t IndexSubTableFormat4::FindCodeOffsetPair(int32_t glyph_id) {
74 return data_->SearchUShort(EblcTable::Offset::kIndexSubTable4_glyphArray,
75 EblcTable::Offset::kCodeOffsetPairLength,
76 NumGlyphs(),
77 glyph_id);
78 }
79
NumGlyphs(ReadableFontData * data,int32_t table_offset)80 int32_t IndexSubTableFormat4::NumGlyphs(ReadableFontData* data,
81 int32_t table_offset) {
82 int32_t num_glyphs = data->ReadULongAsInt(table_offset +
83 EblcTable::Offset::kIndexSubTable4_numGlyphs);
84 return num_glyphs;
85 }
86
87 /******************************************************************************
88 * IndexSubTableFormat4::CodeOffsetPair related class
89 ******************************************************************************/
CodeOffsetPair(int32_t glyph_code,int32_t offset)90 IndexSubTableFormat4::CodeOffsetPair::CodeOffsetPair(int32_t glyph_code,
91 int32_t offset)
92 : glyph_code_(glyph_code), offset_(offset) {
93 }
94
CodeOffsetPairBuilder()95 IndexSubTableFormat4::CodeOffsetPairBuilder::CodeOffsetPairBuilder()
96 : CodeOffsetPair(0, 0) {
97 }
98
CodeOffsetPairBuilder(int32_t glyph_code,int32_t offset)99 IndexSubTableFormat4::CodeOffsetPairBuilder::CodeOffsetPairBuilder(
100 int32_t glyph_code, int32_t offset)
101 : CodeOffsetPair(glyph_code, offset) {
102 }
103
operator ()(const CodeOffsetPair & lhs,const CodeOffsetPair & rhs)104 bool IndexSubTableFormat4::CodeOffsetPairGlyphCodeComparator::operator()(
105 const CodeOffsetPair& lhs, const CodeOffsetPair& rhs) {
106 return lhs.glyph_code() < rhs.glyph_code();
107 }
108
109 /******************************************************************************
110 * IndexSubTableFormat4::Builder class
111 ******************************************************************************/
~Builder()112 IndexSubTableFormat4::Builder::~Builder() {
113 }
114
NumGlyphs()115 int32_t IndexSubTableFormat4::Builder::NumGlyphs() {
116 return GetOffsetArray()->size() - 1;
117 }
118
GlyphLength(int32_t glyph_id)119 int32_t IndexSubTableFormat4::Builder::GlyphLength(int32_t glyph_id) {
120 int32_t loca = CheckGlyphRange(glyph_id);
121 if (loca == -1) {
122 return 0;
123 }
124 int32_t pair_index = FindCodeOffsetPair(glyph_id);
125 if (pair_index == -1) {
126 return 0;
127 }
128 return GetOffsetArray()->at(pair_index + 1).offset() -
129 GetOffsetArray()->at(pair_index).offset();
130 }
131
GlyphStartOffset(int32_t glyph_id)132 int32_t IndexSubTableFormat4::Builder::GlyphStartOffset(int32_t glyph_id) {
133 int32_t loca = CheckGlyphRange(glyph_id);
134 if (loca == -1) {
135 return -1;
136 }
137 int32_t pair_index = FindCodeOffsetPair(glyph_id);
138 if (pair_index == -1) {
139 return -1;
140 }
141 return GetOffsetArray()->at(pair_index).offset();
142 }
143
144 CALLER_ATTACH IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator*
GetIterator()145 IndexSubTableFormat4::Builder::GetIterator() {
146 Ptr<IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator> it =
147 new IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator(this);
148 return it.Detach();
149 }
150
151 // static
152 CALLER_ATTACH IndexSubTableFormat4::Builder*
CreateBuilder()153 IndexSubTableFormat4::Builder::CreateBuilder() {
154 IndexSubTableFormat4BuilderPtr output = new IndexSubTableFormat4::Builder();
155 return output.Detach();
156 }
157
158 // static
159 CALLER_ATTACH IndexSubTableFormat4::Builder*
CreateBuilder(ReadableFontData * data,int32_t index_sub_table_offset,int32_t first_glyph_index,int32_t last_glyph_index)160 IndexSubTableFormat4::Builder::CreateBuilder(ReadableFontData* data,
161 int32_t index_sub_table_offset,
162 int32_t first_glyph_index,
163 int32_t last_glyph_index) {
164 int32_t length = Builder::DataLength(data,
165 index_sub_table_offset,
166 first_glyph_index,
167 last_glyph_index);
168 ReadableFontDataPtr new_data;
169 new_data.Attach(down_cast<ReadableFontData*>(
170 data->Slice(index_sub_table_offset, length)));
171 if (new_data == NULL) {
172 return NULL;
173 }
174 IndexSubTableFormat4BuilderPtr output =
175 new IndexSubTableFormat4::Builder(new_data,
176 first_glyph_index,
177 last_glyph_index);
178 return output.Detach();
179 }
180
181 // static
182 CALLER_ATTACH IndexSubTableFormat4::Builder*
CreateBuilder(WritableFontData * data,int32_t index_sub_table_offset,int32_t first_glyph_index,int32_t last_glyph_index)183 IndexSubTableFormat4::Builder::CreateBuilder(WritableFontData* data,
184 int32_t index_sub_table_offset,
185 int32_t first_glyph_index,
186 int32_t last_glyph_index) {
187 int32_t length = Builder::DataLength(data,
188 index_sub_table_offset,
189 first_glyph_index,
190 last_glyph_index);
191 WritableFontDataPtr new_data;
192 new_data.Attach(down_cast<WritableFontData*>(
193 data->Slice(index_sub_table_offset, length)));
194 IndexSubTableFormat4BuilderPtr output =
195 new IndexSubTableFormat4::Builder(new_data,
196 first_glyph_index,
197 last_glyph_index);
198 return output.Detach();
199 }
200
SubBuildTable(ReadableFontData * data)201 CALLER_ATTACH FontDataTable* IndexSubTableFormat4::Builder::SubBuildTable(
202 ReadableFontData* data) {
203 IndexSubTableFormat4Ptr output = new IndexSubTableFormat4(
204 data, first_glyph_index(), last_glyph_index());
205 return output.Detach();
206 }
207
SubDataSet()208 void IndexSubTableFormat4::Builder::SubDataSet() {
209 Revert();
210 }
211
SubDataSizeToSerialize()212 int32_t IndexSubTableFormat4::Builder::SubDataSizeToSerialize() {
213 if (offset_pair_array_.empty()) {
214 return InternalReadData()->Length();
215 }
216 return EblcTable::Offset::kIndexSubHeaderLength + DataSize::kULONG +
217 GetOffsetArray()->size() *
218 EblcTable::Offset::kIndexSubTable4_codeOffsetPairLength;
219 }
220
SubReadyToSerialize()221 bool IndexSubTableFormat4::Builder::SubReadyToSerialize() {
222 if (!offset_pair_array_.empty()) {
223 return true;
224 }
225 return false;
226 }
227
SubSerialize(WritableFontData * new_data)228 int32_t IndexSubTableFormat4::Builder::SubSerialize(
229 WritableFontData* new_data) {
230 int32_t size = SerializeIndexSubHeader(new_data);
231 if (!model_changed()) {
232 if (InternalReadData() == NULL) {
233 return size;
234 }
235 ReadableFontDataPtr source;
236 WritableFontDataPtr target;
237 source.Attach(down_cast<ReadableFontData*>(InternalReadData()->Slice(
238 EblcTable::Offset::kIndexSubTable4_glyphArray)));
239 target.Attach(down_cast<WritableFontData*>(new_data->Slice(
240 EblcTable::Offset::kIndexSubTable4_glyphArray)));
241 size += source->CopyTo(target);
242 } else {
243 size += new_data->WriteLong(size, offset_pair_array_.size() - 1);
244 for (std::vector<CodeOffsetPairBuilder>::iterator
245 b = GetOffsetArray()->begin(), e = GetOffsetArray()->end();
246 b != e; b++) {
247 size += new_data->WriteUShort(size, b->glyph_code());
248 size += new_data->WriteUShort(size, b->offset());
249 }
250 }
251 return size;
252 }
253
Revert()254 void IndexSubTableFormat4::Builder::Revert() {
255 offset_pair_array_.clear();
256 IndexSubTable::Builder::Revert();
257 }
258
SetOffsetArray(const std::vector<CodeOffsetPairBuilder> & pair_array)259 void IndexSubTableFormat4::Builder::SetOffsetArray(
260 const std::vector<CodeOffsetPairBuilder>& pair_array) {
261 offset_pair_array_.clear();
262 offset_pair_array_ = pair_array;
263 set_model_changed();
264 }
265
Builder()266 IndexSubTableFormat4::Builder::Builder()
267 : IndexSubTable::Builder(EblcTable::Offset::kIndexSubTable4_builderDataSize,
268 Format::FORMAT_4) {
269 }
270
Builder(WritableFontData * data,int32_t first_glyph_index,int32_t last_glyph_index)271 IndexSubTableFormat4::Builder::Builder(WritableFontData* data,
272 int32_t first_glyph_index,
273 int32_t last_glyph_index)
274 : IndexSubTable::Builder(data, first_glyph_index, last_glyph_index) {
275 }
276
Builder(ReadableFontData * data,int32_t first_glyph_index,int32_t last_glyph_index)277 IndexSubTableFormat4::Builder::Builder(ReadableFontData* data,
278 int32_t first_glyph_index,
279 int32_t last_glyph_index)
280 : IndexSubTable::Builder(data, first_glyph_index, last_glyph_index) {
281 }
282
283 std::vector<IndexSubTableFormat4::CodeOffsetPairBuilder>*
GetOffsetArray()284 IndexSubTableFormat4::Builder::GetOffsetArray() {
285 if (offset_pair_array_.empty()) {
286 Initialize(InternalReadData());
287 set_model_changed();
288 }
289 return &offset_pair_array_;
290 }
291
Initialize(ReadableFontData * data)292 void IndexSubTableFormat4::Builder::Initialize(ReadableFontData* data) {
293 offset_pair_array_.clear();
294 if (data) {
295 int32_t num_pairs = IndexSubTableFormat4::NumGlyphs(data, 0) + 1;
296 int32_t offset = EblcTable::Offset::kIndexSubTable4_glyphArray;
297 for (int32_t i = 0; i < num_pairs; ++i) {
298 int32_t glyph_code = data->ReadUShort(offset +
299 EblcTable::Offset::kIndexSubTable4_codeOffsetPair_glyphCode);
300 int32_t glyph_offset = data->ReadUShort(offset +
301 EblcTable::Offset::kIndexSubTable4_codeOffsetPair_offset);
302 offset += EblcTable::Offset::kIndexSubTable4_codeOffsetPairLength;
303 CodeOffsetPairBuilder pair_builder(glyph_code, glyph_offset);
304 offset_pair_array_.push_back(pair_builder);
305 }
306 }
307 }
308
FindCodeOffsetPair(int32_t glyph_id)309 int32_t IndexSubTableFormat4::Builder::FindCodeOffsetPair(int32_t glyph_id) {
310 std::vector<CodeOffsetPairBuilder>* pair_list = GetOffsetArray();
311 int32_t location = 0;
312 int32_t bottom = 0;
313 int32_t top = pair_list->size();
314 while (top != bottom) {
315 location = (top + bottom) / 2;
316 CodeOffsetPairBuilder* pair = &(pair_list->at(location));
317 if (glyph_id < pair->glyph_code()) {
318 // location is below current location
319 top = location;
320 } else if (glyph_id > pair->glyph_code()) {
321 // location is above current location
322 bottom = location + 1;
323 } else {
324 return location;
325 }
326 }
327 return -1;
328 }
329
330 // static
DataLength(ReadableFontData * data,int32_t index_sub_table_offset,int32_t first_glyph_index,int32_t last_glyph_index)331 int32_t IndexSubTableFormat4::Builder::DataLength(
332 ReadableFontData* data,
333 int32_t index_sub_table_offset,
334 int32_t first_glyph_index,
335 int32_t last_glyph_index) {
336 int32_t num_glyphs = IndexSubTableFormat4::NumGlyphs(data,
337 index_sub_table_offset);
338 UNREFERENCED_PARAMETER(first_glyph_index);
339 UNREFERENCED_PARAMETER(last_glyph_index);
340 return EblcTable::Offset::kIndexSubTable4_glyphArray +
341 num_glyphs * EblcTable::Offset::kIndexSubTable4_codeOffsetPair_offset;
342 }
343
344
345 /******************************************************************************
346 * IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator class
347 ******************************************************************************/
BitmapGlyphInfoIterator(IndexSubTableFormat4::Builder * container)348 IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator::BitmapGlyphInfoIterator(
349 IndexSubTableFormat4::Builder* container)
350 : RefIterator<BitmapGlyphInfo, IndexSubTableFormat4::Builder,
351 IndexSubTable::Builder>(container),
352 code_offset_pair_index_(0) {
353 }
354
HasNext()355 bool IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator::HasNext() {
356 if (code_offset_pair_index_ <
357 (int32_t)(container()->GetOffsetArray()->size() - 1)) {
358 return true;
359 }
360 return false;
361 }
362
363 CALLER_ATTACH BitmapGlyphInfo*
Next()364 IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator::Next() {
365 BitmapGlyphInfoPtr output;
366 if (!HasNext()) {
367 // Note: In C++, we do not throw exception when there's no element.
368 return NULL;
369 }
370 std::vector<CodeOffsetPairBuilder>* offset_array =
371 container()->GetOffsetArray();
372 int32_t offset = offset_array->at(code_offset_pair_index_).offset();
373 int32_t next_offset = offset_array->at(code_offset_pair_index_ + 1).offset();
374 int32_t glyph_code = offset_array->at(code_offset_pair_index_).glyph_code();
375 output = new BitmapGlyphInfo(glyph_code,
376 container()->image_data_offset(),
377 offset,
378 next_offset - offset,
379 container()->image_format());
380 code_offset_pair_index_++;
381 return output.Detach();
382 }
383
384 } // namespace sfntly
385