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