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_format3.h"
18
19#include "sfntly/table/bitmap/eblc_table.h"
20
21namespace sfntly {
22/******************************************************************************
23 * IndexSubTableFormat3 class
24 ******************************************************************************/
25IndexSubTableFormat3::~IndexSubTableFormat3() {
26}
27
28int32_t IndexSubTableFormat3::NumGlyphs() {
29  return last_glyph_index() - first_glyph_index() + 1;
30}
31
32int32_t IndexSubTableFormat3::GlyphStartOffset(int32_t glyph_id) {
33  int32_t loca = CheckGlyphRange(glyph_id);
34  if (loca != -1) {
35    return Loca(loca);
36  }
37  return -1;
38}
39
40int32_t IndexSubTableFormat3::GlyphLength(int32_t glyph_id) {
41  int32_t loca = CheckGlyphRange(glyph_id);
42  if (loca != -1) {
43    return Loca(glyph_id + 1) - Loca(glyph_id);
44  }
45  return 0;
46}
47
48// static
49int32_t IndexSubTableFormat3::GetDataLength(ReadableFontData* data,
50                                            int32_t offset,
51                                            int32_t first,
52                                            int32_t last) {
53  UNREFERENCED_PARAMETER(data);
54  UNREFERENCED_PARAMETER(offset);
55  return (last - first + 1 + 1) * DataSize::kUSHORT;
56}
57
58IndexSubTableFormat3::IndexSubTableFormat3(ReadableFontData* data,
59                                           int32_t first_glyph_index,
60                                           int32_t last_glyph_index)
61    : IndexSubTable(data, first_glyph_index, last_glyph_index) {
62}
63
64int32_t IndexSubTableFormat3::Loca(int32_t loca) {
65  int32_t read_offset =
66      data_->ReadUShort(EblcTable::Offset::kIndexSubTable3_offsetArray +
67                        loca * DataSize::kUSHORT);
68  return read_offset;
69}
70
71/******************************************************************************
72 * IndexSubTableFormat3::Builder class
73 ******************************************************************************/
74IndexSubTableFormat3::Builder::~Builder() {
75}
76
77int32_t IndexSubTableFormat3::Builder::NumGlyphs() {
78  return GetOffsetArray()->size() - 1;
79}
80
81int32_t IndexSubTableFormat3::Builder::GlyphStartOffset(int32_t glyph_id) {
82  int32_t loca = CheckGlyphRange(glyph_id);
83  if (loca == -1) {
84    return -1;
85  }
86  return GetOffsetArray()->at(loca);
87}
88
89int32_t IndexSubTableFormat3::Builder::GlyphLength(int32_t glyph_id) {
90  int32_t loca = CheckGlyphRange(glyph_id);
91  if (loca == -1) {
92    return 0;
93  }
94  IntegerList* offset_array = GetOffsetArray();
95  return offset_array->at(loca + 1) - offset_array->at(loca);
96}
97
98CALLER_ATTACH IndexSubTableFormat3::Builder::BitmapGlyphInfoIterator*
99    IndexSubTableFormat3::Builder::GetIterator() {
100  Ptr<IndexSubTableFormat3::Builder::BitmapGlyphInfoIterator> it =
101      new IndexSubTableFormat3::Builder::BitmapGlyphInfoIterator(this);
102  return it.Detach();
103}
104
105void IndexSubTableFormat3::Builder::Revert() {
106  offset_array_.clear();
107  IndexSubTable::Builder::Revert();
108}
109
110void IndexSubTableFormat3::Builder::SetOffsetArray(
111    const IntegerList& offset_array) {
112  offset_array_.clear();
113  offset_array_ = offset_array;
114  set_model_changed();
115}
116
117// static
118CALLER_ATTACH IndexSubTableFormat3::Builder*
119IndexSubTableFormat3::Builder::CreateBuilder() {
120  IndexSubTableFormat3BuilderPtr output = new IndexSubTableFormat3::Builder();
121  return output.Detach();
122}
123
124// static
125CALLER_ATTACH IndexSubTableFormat3::Builder*
126IndexSubTableFormat3::Builder::CreateBuilder(ReadableFontData* data,
127                                             int32_t index_sub_table_offset,
128                                             int32_t first_glyph_index,
129                                             int32_t last_glyph_index) {
130  int32_t length = Builder::DataLength(data,
131                                       index_sub_table_offset,
132                                       first_glyph_index,
133                                       last_glyph_index);
134  ReadableFontDataPtr new_data;
135  new_data.Attach(down_cast<ReadableFontData*>(
136      data->Slice(index_sub_table_offset, length)));
137  if (new_data == NULL) {
138    return NULL;
139  }
140  IndexSubTableFormat3BuilderPtr output =
141      new IndexSubTableFormat3::Builder(new_data,
142                                        first_glyph_index,
143                                        last_glyph_index);
144  return output.Detach();
145}
146
147// static
148CALLER_ATTACH IndexSubTableFormat3::Builder*
149IndexSubTableFormat3::Builder::CreateBuilder(WritableFontData* data,
150                                             int32_t index_sub_table_offset,
151                                             int32_t first_glyph_index,
152                                             int32_t last_glyph_index) {
153  int32_t length = Builder::DataLength(data,
154                                       index_sub_table_offset,
155                                       first_glyph_index,
156                                       last_glyph_index);
157  WritableFontDataPtr new_data;
158  new_data.Attach(down_cast<WritableFontData*>(
159      data->Slice(index_sub_table_offset, length)));
160  IndexSubTableFormat3BuilderPtr output =
161      new IndexSubTableFormat3::Builder(new_data,
162                                        first_glyph_index,
163                                        last_glyph_index);
164  return output.Detach();
165}
166
167CALLER_ATTACH FontDataTable* IndexSubTableFormat3::Builder::SubBuildTable(
168    ReadableFontData* data) {
169  IndexSubTableFormat3Ptr output = new IndexSubTableFormat3(
170      data, first_glyph_index(), last_glyph_index());
171  return output.Detach();
172}
173
174void IndexSubTableFormat3::Builder::SubDataSet() {
175  Revert();
176}
177
178int32_t IndexSubTableFormat3::Builder::SubDataSizeToSerialize() {
179  if (offset_array_.empty()) {
180    return InternalReadData()->Length();
181  }
182  return EblcTable::Offset::kIndexSubHeaderLength +
183         offset_array_.size() * DataSize::kULONG;
184}
185
186bool IndexSubTableFormat3::Builder::SubReadyToSerialize() {
187  if (!offset_array_.empty()) {
188    return true;
189  }
190  return false;
191}
192
193int32_t IndexSubTableFormat3::Builder::SubSerialize(
194    WritableFontData* new_data) {
195  int32_t size = SerializeIndexSubHeader(new_data);
196  if (!model_changed()) {
197    if (InternalReadData() == NULL) {
198      return size;
199    }
200    ReadableFontDataPtr source;
201    WritableFontDataPtr target;
202    source.Attach(down_cast<ReadableFontData*>(InternalReadData()->Slice(
203        EblcTable::Offset::kIndexSubTable3_offsetArray)));
204    target.Attach(down_cast<WritableFontData*>(new_data->Slice(
205        EblcTable::Offset::kIndexSubTable3_offsetArray)));
206    size += source->CopyTo(target);
207  } else {
208    for (IntegerList::iterator b = GetOffsetArray()->begin(),
209                               e = GetOffsetArray()->end(); b != e; b++) {
210      size += new_data->WriteUShort(size, *b);
211    }
212  }
213  return size;
214}
215
216IndexSubTableFormat3::Builder::Builder()
217    : IndexSubTable::Builder(EblcTable::Offset::kIndexSubTable3_builderDataSize,
218                             IndexSubTable::Format::FORMAT_3) {
219}
220
221IndexSubTableFormat3::Builder::Builder(WritableFontData* data,
222                                       int32_t first_glyph_index,
223                                       int32_t last_glyph_index)
224    : IndexSubTable::Builder(data, first_glyph_index, last_glyph_index) {
225}
226
227IndexSubTableFormat3::Builder::Builder(ReadableFontData* data,
228                                       int32_t first_glyph_index,
229                                       int32_t last_glyph_index)
230    : IndexSubTable::Builder(data, first_glyph_index, last_glyph_index) {
231}
232
233IntegerList* IndexSubTableFormat3::Builder::GetOffsetArray() {
234  if (offset_array_.empty()) {
235    Initialize(InternalReadData());
236    set_model_changed();
237  }
238  return &offset_array_;
239}
240
241void IndexSubTableFormat3::Builder::Initialize(ReadableFontData* data) {
242  offset_array_.clear();
243  if (data) {
244    int32_t num_offsets = (last_glyph_index() - first_glyph_index() + 1) + 1;
245    for (int32_t i = 0; i < num_offsets; ++i) {
246      offset_array_.push_back(data->ReadUShort(
247         EblcTable::Offset::kIndexSubTable3_offsetArray +
248         i * DataSize::kUSHORT));
249    }
250  }
251}
252
253// static
254int32_t IndexSubTableFormat3::Builder::DataLength(
255    ReadableFontData* data,
256    int32_t index_sub_table_offset,
257    int32_t first_glyph_index,
258    int32_t last_glyph_index) {
259  UNREFERENCED_PARAMETER(data);
260  UNREFERENCED_PARAMETER(index_sub_table_offset);
261  return EblcTable::Offset::kIndexSubHeaderLength +
262         (last_glyph_index - first_glyph_index + 1 + 1) * DataSize::kUSHORT;
263}
264
265/******************************************************************************
266 * IndexSubTableFormat3::Builder::BitmapGlyphInfoIterator class
267 ******************************************************************************/
268IndexSubTableFormat3::Builder::BitmapGlyphInfoIterator::BitmapGlyphInfoIterator(
269    IndexSubTableFormat3::Builder* container)
270    : RefIterator<BitmapGlyphInfo, IndexSubTableFormat3::Builder,
271                  IndexSubTable::Builder>(container) {
272  glyph_id_ = container->first_glyph_index();
273}
274
275bool IndexSubTableFormat3::Builder::BitmapGlyphInfoIterator::HasNext() {
276  if (glyph_id_ <= container()->last_glyph_index()) {
277    return true;
278  }
279  return false;
280}
281
282CALLER_ATTACH BitmapGlyphInfo*
283IndexSubTableFormat3::Builder::BitmapGlyphInfoIterator::Next() {
284  BitmapGlyphInfoPtr output;
285  if (!HasNext()) {
286    // Note: In C++, we do not throw exception when there's no element.
287    return NULL;
288  }
289  output = new BitmapGlyphInfo(glyph_id_,
290                               container()->image_data_offset(),
291                               container()->GlyphStartOffset(glyph_id_),
292                               container()->GlyphLength(glyph_id_),
293                               container()->image_format());
294  glyph_id_++;
295  return output.Detach();
296}
297
298}  // namespace sfntly
299