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
21namespace sfntly {
22/******************************************************************************
23 * IndexSubTableFormat4 class
24 ******************************************************************************/
25IndexSubTableFormat4::~IndexSubTableFormat4() {
26}
27
28int32_t IndexSubTableFormat4::NumGlyphs() {
29  return IndexSubTableFormat4::NumGlyphs(data_, 0);
30}
31
32int32_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
47int32_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
67IndexSubTableFormat4::IndexSubTableFormat4(ReadableFontData* data,
68                                           int32_t first,
69                                           int32_t last)
70    : IndexSubTable(data, first, last) {
71}
72
73int32_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
80int32_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 ******************************************************************************/
90IndexSubTableFormat4::CodeOffsetPair::CodeOffsetPair(int32_t glyph_code,
91                                                     int32_t offset)
92    : glyph_code_(glyph_code), offset_(offset) {
93}
94
95IndexSubTableFormat4::CodeOffsetPairBuilder::CodeOffsetPairBuilder()
96    : CodeOffsetPair(0, 0) {
97}
98
99IndexSubTableFormat4::CodeOffsetPairBuilder::CodeOffsetPairBuilder(
100    int32_t glyph_code, int32_t offset)
101    : CodeOffsetPair(glyph_code, offset) {
102}
103
104bool 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 ******************************************************************************/
112IndexSubTableFormat4::Builder::~Builder() {
113}
114
115int32_t IndexSubTableFormat4::Builder::NumGlyphs() {
116  return GetOffsetArray()->size() - 1;
117}
118
119int32_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
132int32_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
144CALLER_ATTACH IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator*
145    IndexSubTableFormat4::Builder::GetIterator() {
146  Ptr<IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator> it =
147      new IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator(this);
148  return it.Detach();
149}
150
151// static
152CALLER_ATTACH IndexSubTableFormat4::Builder*
153IndexSubTableFormat4::Builder::CreateBuilder() {
154  IndexSubTableFormat4BuilderPtr output = new IndexSubTableFormat4::Builder();
155  return output.Detach();
156}
157
158// static
159CALLER_ATTACH IndexSubTableFormat4::Builder*
160IndexSubTableFormat4::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
182CALLER_ATTACH IndexSubTableFormat4::Builder*
183IndexSubTableFormat4::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
201CALLER_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
208void IndexSubTableFormat4::Builder::SubDataSet() {
209  Revert();
210}
211
212int32_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
221bool IndexSubTableFormat4::Builder::SubReadyToSerialize() {
222  if (!offset_pair_array_.empty()) {
223    return true;
224  }
225  return false;
226}
227
228int32_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
254void IndexSubTableFormat4::Builder::Revert() {
255  offset_pair_array_.clear();
256  IndexSubTable::Builder::Revert();
257}
258
259void 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
266IndexSubTableFormat4::Builder::Builder()
267  : IndexSubTable::Builder(EblcTable::Offset::kIndexSubTable4_builderDataSize,
268                           Format::FORMAT_4) {
269}
270
271IndexSubTableFormat4::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
277IndexSubTableFormat4::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
283std::vector<IndexSubTableFormat4::CodeOffsetPairBuilder>*
284IndexSubTableFormat4::Builder::GetOffsetArray() {
285  if (offset_pair_array_.empty()) {
286    Initialize(InternalReadData());
287    set_model_changed();
288  }
289  return &offset_pair_array_;
290}
291
292void 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
309int32_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
331int32_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 ******************************************************************************/
348IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator::BitmapGlyphInfoIterator(
349    IndexSubTableFormat4::Builder* container)
350    : RefIterator<BitmapGlyphInfo, IndexSubTableFormat4::Builder,
351                  IndexSubTable::Builder>(container),
352      code_offset_pair_index_(0) {
353}
354
355bool 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
363CALLER_ATTACH BitmapGlyphInfo*
364IndexSubTableFormat4::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