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_format5.h"
18
19#include <algorithm>
20
21#include "sfntly/table/bitmap/eblc_table.h"
22
23namespace sfntly {
24/******************************************************************************
25 * IndexSubTableFormat5 class
26 ******************************************************************************/
27IndexSubTableFormat5::~IndexSubTableFormat5() {
28}
29
30int32_t IndexSubTableFormat5::NumGlyphs() {
31  return NumGlyphs(data_, 0);
32}
33
34int32_t IndexSubTableFormat5::GlyphStartOffset(int32_t glyph_id) {
35  int32_t check = CheckGlyphRange(glyph_id);
36  if (check == -1) {
37    return -1;
38  }
39  int32_t loca = ReadFontData()->SearchUShort(
40      EblcTable::Offset::kIndexSubTable5_glyphArray,
41      DataSize::kUSHORT,
42      NumGlyphs(),
43      glyph_id);
44  if (loca == -1) {
45    return loca;
46  }
47  return loca * ImageSize();
48}
49
50int32_t IndexSubTableFormat5::GlyphLength(int32_t glyph_id) {
51  int32_t check = CheckGlyphRange(glyph_id);
52  if (check == -1) {
53    return 0;
54  }
55  return image_size_;
56}
57
58int32_t IndexSubTableFormat5::ImageSize() {
59  return data_->ReadULongAsInt(EblcTable::Offset::kIndexSubTable5_imageSize);
60}
61
62CALLER_ATTACH BigGlyphMetrics* IndexSubTableFormat5::BigMetrics() {
63  ReadableFontDataPtr data;
64  data.Attach(down_cast<ReadableFontData*>(data_->Slice(
65      EblcTable::Offset::kIndexSubTable5_bigGlyphMetrics,
66      BigGlyphMetrics::Offset::kMetricsLength)));
67  BigGlyphMetricsPtr output = new BigGlyphMetrics(data);
68  return output.Detach();
69}
70
71IndexSubTableFormat5::IndexSubTableFormat5(ReadableFontData* data,
72                                           int32_t first_glyph_index,
73                                           int32_t last_glyph_index)
74    : IndexSubTable(data, first_glyph_index, last_glyph_index) {
75  image_size_ = data_->ReadULongAsInt(
76      EblcTable::Offset::kIndexSubTable5_imageSize);
77}
78
79// static
80int32_t IndexSubTableFormat5::NumGlyphs(ReadableFontData* data,
81                                        int32_t table_offset) {
82  int32_t num_glyphs = data->ReadULongAsInt(table_offset +
83      EblcTable::Offset::kIndexSubTable5_numGlyphs);
84  return num_glyphs;
85}
86
87/******************************************************************************
88 * IndexSubTableFormat5::Builder class
89 ******************************************************************************/
90IndexSubTableFormat5::Builder::~Builder() {
91}
92
93int32_t IndexSubTableFormat5::Builder::NumGlyphs() {
94  return GetGlyphArray()->size();
95}
96
97int32_t IndexSubTableFormat5::Builder::GlyphLength(int32_t glyph_id) {
98  UNREFERENCED_PARAMETER(glyph_id);
99  return ImageSize();
100}
101
102int32_t IndexSubTableFormat5::Builder::GlyphStartOffset(int32_t glyph_id) {
103  int32_t check = CheckGlyphRange(glyph_id);
104  if (check == -1) {
105    return -1;
106  }
107  IntegerList* glyph_array = GetGlyphArray();
108  IntegerList::iterator it = std::find(glyph_array->begin(),
109                                       glyph_array->end(),
110                                       glyph_id);
111  if (it == glyph_array->end()) {
112    return -1;
113  }
114  return (it - glyph_array->begin()) * ImageSize();
115}
116
117CALLER_ATTACH IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator*
118    IndexSubTableFormat5::Builder::GetIterator() {
119  Ptr<IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator> it =
120      new IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator(this);
121  return it.Detach();
122}
123
124// static
125CALLER_ATTACH IndexSubTableFormat5::Builder*
126IndexSubTableFormat5::Builder::CreateBuilder() {
127  IndexSubTableFormat5BuilderPtr output = new IndexSubTableFormat5::Builder();
128  return output.Detach();
129}
130
131// static
132CALLER_ATTACH IndexSubTableFormat5::Builder*
133IndexSubTableFormat5::Builder::CreateBuilder(ReadableFontData* data,
134                                             int32_t index_sub_table_offset,
135                                             int32_t first_glyph_index,
136                                             int32_t last_glyph_index) {
137  int32_t length = Builder::DataLength(data,
138                                       index_sub_table_offset,
139                                       first_glyph_index,
140                                       last_glyph_index);
141  ReadableFontDataPtr new_data;
142  new_data.Attach(down_cast<ReadableFontData*>(
143      data->Slice(index_sub_table_offset, length)));
144  if (new_data == NULL) {
145    return NULL;
146  }
147  IndexSubTableFormat5BuilderPtr output =
148      new IndexSubTableFormat5::Builder(new_data,
149                                        first_glyph_index,
150                                        last_glyph_index);
151  return output.Detach();
152}
153
154// static
155CALLER_ATTACH IndexSubTableFormat5::Builder*
156IndexSubTableFormat5::Builder::CreateBuilder(WritableFontData* data,
157                                             int32_t index_sub_table_offset,
158                                             int32_t first_glyph_index,
159                                             int32_t last_glyph_index) {
160  int32_t length = Builder::DataLength(data,
161                                       index_sub_table_offset,
162                                       first_glyph_index,
163                                       last_glyph_index);
164  WritableFontDataPtr new_data;
165  new_data.Attach(down_cast<WritableFontData*>(
166      data->Slice(index_sub_table_offset, length)));
167  IndexSubTableFormat5BuilderPtr output =
168      new IndexSubTableFormat5::Builder(new_data,
169                                        first_glyph_index,
170                                        last_glyph_index);
171  return output.Detach();
172}
173
174CALLER_ATTACH FontDataTable* IndexSubTableFormat5::Builder::SubBuildTable(
175    ReadableFontData* data) {
176  IndexSubTableFormat5Ptr output = new IndexSubTableFormat5(
177      data, first_glyph_index(), last_glyph_index());
178  return output.Detach();
179}
180
181void IndexSubTableFormat5::Builder::SubDataSet() {
182  Revert();
183}
184
185int32_t IndexSubTableFormat5::Builder::SubDataSizeToSerialize() {
186  if (glyph_array_.empty()) {
187    return InternalReadData()->Length();
188  }
189  return EblcTable::Offset::kIndexSubTable5_builderDataSize +
190         glyph_array_.size() * DataSize::kUSHORT;
191}
192
193bool IndexSubTableFormat5::Builder::SubReadyToSerialize() {
194  if (!glyph_array_.empty()) {
195    return true;
196  }
197  return false;
198}
199
200int32_t IndexSubTableFormat5::Builder::SubSerialize(
201    WritableFontData* new_data) {
202  int32_t size = SerializeIndexSubHeader(new_data);
203  if (!model_changed()) {
204    ReadableFontDataPtr source;
205    WritableFontDataPtr target;
206    source.Attach(down_cast<ReadableFontData*>(InternalReadData()->Slice(
207        EblcTable::Offset::kIndexSubTable5_imageSize)));
208    target.Attach(down_cast<WritableFontData*>(new_data->Slice(
209        EblcTable::Offset::kIndexSubTable5_imageSize)));
210    size += source->CopyTo(target);
211  } else {
212    size += new_data->WriteULong(EblcTable::Offset::kIndexSubTable5_imageSize,
213                                 ImageSize());
214    WritableFontDataPtr slice;
215    slice.Attach(down_cast<WritableFontData*>(new_data->Slice(size)));
216    size += BigMetrics()->SubSerialize(slice);
217    size += new_data->WriteULong(size, glyph_array_.size());
218    for (IntegerList::iterator b = glyph_array_.begin(), e = glyph_array_.end();
219                               b != e; b++) {
220      size += new_data->WriteUShort(size, *b);
221    }
222  }
223  return size;
224}
225
226int32_t IndexSubTableFormat5::Builder::ImageSize() {
227  return InternalReadData()->ReadULongAsInt(
228      EblcTable::Offset::kIndexSubTable5_imageSize);
229}
230
231void IndexSubTableFormat5::Builder::SetImageSize(int32_t image_size) {
232  InternalWriteData()->WriteULong(
233      EblcTable::Offset::kIndexSubTable5_imageSize, image_size);
234}
235
236BigGlyphMetrics::Builder* IndexSubTableFormat5::Builder::BigMetrics() {
237  if (metrics_ == NULL) {
238    WritableFontDataPtr data;
239    data.Attach(down_cast<WritableFontData*>(InternalWriteData()->Slice(
240        EblcTable::Offset::kIndexSubTable5_bigGlyphMetrics,
241        BigGlyphMetrics::Offset::kMetricsLength)));
242    metrics_ = new BigGlyphMetrics::Builder(data);
243    set_model_changed();
244  }
245  return metrics_;
246}
247
248IntegerList* IndexSubTableFormat5::Builder::GlyphArray() {
249  return GetGlyphArray();
250}
251
252void IndexSubTableFormat5::Builder::SetGlyphArray(const IntegerList& v) {
253  glyph_array_.clear();
254  glyph_array_ = v;
255  set_model_changed();
256}
257
258void IndexSubTableFormat5::Builder::Revert() {
259  glyph_array_.clear();
260  IndexSubTable::Builder::Revert();
261}
262
263IndexSubTableFormat5::Builder::Builder()
264    : IndexSubTable::Builder(EblcTable::Offset::kIndexSubTable5_builderDataSize,
265                             IndexSubTable::Format::FORMAT_5) {
266}
267
268IndexSubTableFormat5::Builder::Builder(WritableFontData* data,
269                                       int32_t first_glyph_index,
270                                       int32_t last_glyph_index)
271    : IndexSubTable::Builder(data, first_glyph_index, last_glyph_index) {
272}
273
274IndexSubTableFormat5::Builder::Builder(ReadableFontData* data,
275                                       int32_t first_glyph_index,
276                                       int32_t last_glyph_index)
277    : IndexSubTable::Builder(data, first_glyph_index, last_glyph_index) {
278}
279
280IntegerList* IndexSubTableFormat5::Builder::GetGlyphArray() {
281  if (glyph_array_.empty()) {
282    Initialize(InternalReadData());
283    set_model_changed();
284  }
285  return &glyph_array_;
286}
287
288void IndexSubTableFormat5::Builder::Initialize(ReadableFontData* data) {
289  glyph_array_.clear();
290  if (data) {
291    int32_t num_glyphs = IndexSubTableFormat5::NumGlyphs(data, 0);
292    for (int32_t i = 0; i < num_glyphs; ++i) {
293      glyph_array_.push_back(data->ReadUShort(
294          EblcTable::Offset::kIndexSubTable5_glyphArray +
295          i * DataSize::kUSHORT));
296    }
297  }
298}
299
300// static
301int32_t IndexSubTableFormat5::Builder::DataLength(
302    ReadableFontData* data,
303    int32_t index_sub_table_offset,
304    int32_t first_glyph_index,
305    int32_t last_glyph_index) {
306  int32_t num_glyphs = IndexSubTableFormat5::NumGlyphs(data,
307                                                       index_sub_table_offset);
308  UNREFERENCED_PARAMETER(first_glyph_index);
309  UNREFERENCED_PARAMETER(last_glyph_index);
310  return EblcTable::Offset::kIndexSubTable5_glyphArray +
311         num_glyphs * DataSize::kUSHORT;
312}
313
314/******************************************************************************
315 * IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator class
316 ******************************************************************************/
317IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator::BitmapGlyphInfoIterator(
318    IndexSubTableFormat5::Builder* container)
319    : RefIterator<BitmapGlyphInfo, IndexSubTableFormat5::Builder,
320                  IndexSubTable::Builder>(container),
321      offset_index_(0) {
322}
323
324bool IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator::HasNext() {
325  if (offset_index_ < (int32_t)(container()->GetGlyphArray()->size())) {
326    return true;
327  }
328  return false;
329}
330
331CALLER_ATTACH BitmapGlyphInfo*
332IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator::Next() {
333  BitmapGlyphInfoPtr output;
334  if (!HasNext()) {
335    // Note: In C++, we do not throw exception when there's no element.
336    return NULL;
337  }
338  output = new BitmapGlyphInfo(container()->GetGlyphArray()->at(offset_index_),
339                               container()->image_data_offset(),
340                               offset_index_ * container()->ImageSize(),
341                               container()->ImageSize(),
342                               container()->image_format());
343  offset_index_++;
344  return output.Detach();
345}
346
347}  // namespace sfntly
348