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