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