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/eblc_table.h"
18
19#include <stdio.h>
20#include <stdlib.h>
21
22#include "sfntly/math/font_math.h"
23
24namespace sfntly {
25/******************************************************************************
26 * EblcTable class
27 ******************************************************************************/
28int32_t EblcTable::Version() {
29  return data_->ReadFixed(Offset::kVersion);
30}
31
32int32_t EblcTable::NumSizes() {
33  return data_->ReadULongAsInt(Offset::kNumSizes);
34}
35
36BitmapSizeTable* EblcTable::GetBitmapSizeTable(int32_t index) {
37  if (index < 0 || index > NumSizes()) {
38#if !defined (SFNTLY_NO_EXCEPTION)
39    throw IndexOutOfBoundException(
40        "Size table index is outside the range of tables.");
41#endif
42    return NULL;
43  }
44  BitmapSizeTableList* bitmap_size_table_list = GetBitmapSizeTableList();
45  if (bitmap_size_table_list) {
46    return (*bitmap_size_table_list)[index];
47  }
48  return NULL;
49}
50
51EblcTable::EblcTable(Header* header, ReadableFontData* data)
52    : SubTableContainerTable(header, data) {
53}
54
55BitmapSizeTableList* EblcTable::GetBitmapSizeTableList() {
56  AutoLock lock(bitmap_size_table_lock_);
57  if (bitmap_size_table_.empty()) {
58    CreateBitmapSizeTable(data_, NumSizes(), &bitmap_size_table_);
59  }
60  return &bitmap_size_table_;
61}
62
63// static
64void EblcTable::CreateBitmapSizeTable(ReadableFontData* data,
65                                      int32_t num_sizes,
66                                      BitmapSizeTableList* output) {
67  assert(data);
68  assert(output);
69  for (int32_t i = 0; i < num_sizes; ++i) {
70    ReadableFontDataPtr new_data;
71    new_data.Attach(down_cast<ReadableFontData*>(
72        data->Slice(Offset::kBitmapSizeTableArrayStart +
73                    i * Offset::kBitmapSizeTableLength,
74                    Offset::kBitmapSizeTableLength)));
75    BitmapSizeTableBuilderPtr size_builder;
76    size_builder.Attach(
77        BitmapSizeTable::Builder::CreateBuilder(new_data, data));
78    BitmapSizeTablePtr size;
79    size.Attach(down_cast<BitmapSizeTable*>(size_builder->Build()));
80    output->push_back(size);
81  }
82}
83
84/******************************************************************************
85 * EblcTable::Builder class
86 ******************************************************************************/
87EblcTable::Builder::Builder(Header* header, WritableFontData* data)
88    : SubTableContainerTable::Builder(header, data) {
89}
90
91EblcTable::Builder::Builder(Header* header, ReadableFontData* data)
92    : SubTableContainerTable::Builder(header, data) {
93}
94
95EblcTable::Builder::~Builder() {
96}
97
98int32_t EblcTable::Builder::SubSerialize(WritableFontData* new_data) {
99  // header
100  int32_t size = new_data->WriteFixed(0, kVersion);
101  size += new_data->WriteULong(size, size_table_builders_.size());
102
103  // calculate the offsets
104  // offset to the start of the size table array
105  int32_t size_table_start_offset = size;
106  // walking offset in the size table array
107  int32_t size_table_offset = size_table_start_offset;
108  // offset to the start of the whole index subtable block
109  int32_t sub_table_block_start_offset = size_table_offset +
110      size_table_builders_.size() * Offset::kBitmapSizeTableLength;
111  // walking offset in the index subtable
112  // points to the start of the current subtable block
113  int32_t current_sub_table_block_start_offset = sub_table_block_start_offset;
114
115#if defined (SFNTLY_DEBUG_BITMAP)
116  int32_t size_index = 0;
117#endif
118  for (BitmapSizeTableBuilderList::iterator
119           size_builder = size_table_builders_.begin(),
120           size_builder_end = size_table_builders_.end();
121       size_builder != size_builder_end; size_builder++) {
122    (*size_builder)->SetIndexSubTableArrayOffset(
123        current_sub_table_block_start_offset);
124    IndexSubTableBuilderList* index_sub_table_builder_list =
125        (*size_builder)->IndexSubTableBuilders();
126
127    // walking offset within the current subTable array
128    int32_t index_sub_table_array_offset = current_sub_table_block_start_offset;
129    // walking offset within the subTable entries
130    int32_t index_sub_table_offset = index_sub_table_array_offset +
131        index_sub_table_builder_list->size() * Offset::kIndexSubHeaderLength;
132
133#if defined (SFNTLY_DEBUG_BITMAP)
134    fprintf(stderr, "size %d: sizeTable=%x, current subTable Block=%x, ",
135            size_index, size_table_offset,
136            current_sub_table_block_start_offset);
137    fprintf(stderr, "index subTableStart=%x\n", index_sub_table_offset);
138    size_index++;
139    int32_t sub_table_index = 0;
140#endif
141    for (IndexSubTableBuilderList::iterator
142             index_sub_table_builder = index_sub_table_builder_list->begin(),
143             index_sub_table_builder_end = index_sub_table_builder_list->end();
144         index_sub_table_builder != index_sub_table_builder_end;
145         index_sub_table_builder++) {
146#if defined (SFNTLY_DEBUG_BITMAP)
147      fprintf(stderr, "\tsubTableIndex %d: format=%x, ", sub_table_index,
148              (*index_sub_table_builder)->index_format());
149      fprintf(stderr, "indexSubTableArrayOffset=%x, indexSubTableOffset=%x\n",
150              index_sub_table_array_offset, index_sub_table_offset);
151      sub_table_index++;
152#endif
153      // array entry
154      index_sub_table_array_offset += new_data->WriteUShort(
155          index_sub_table_array_offset,
156          (*index_sub_table_builder)->first_glyph_index());
157      index_sub_table_array_offset += new_data->WriteUShort(
158          index_sub_table_array_offset,
159          (*index_sub_table_builder)->last_glyph_index());
160      index_sub_table_array_offset += new_data->WriteULong(
161          index_sub_table_array_offset,
162          index_sub_table_offset - current_sub_table_block_start_offset);
163
164      // index sub table
165      WritableFontDataPtr slice_index_sub_table;
166      slice_index_sub_table.Attach(down_cast<WritableFontData*>(
167          new_data->Slice(index_sub_table_offset)));
168      int32_t current_sub_table_size =
169          (*index_sub_table_builder)->SubSerialize(slice_index_sub_table);
170      int32_t padding = FontMath::PaddingRequired(current_sub_table_size,
171                                                  DataSize::kULONG);
172#if defined (SFNTLY_DEBUG_BITMAP)
173      fprintf(stderr, "\t\tsubTableSize = %x, padding = %x\n",
174              current_sub_table_size, padding);
175#endif
176      index_sub_table_offset += current_sub_table_size;
177      index_sub_table_offset +=
178          new_data->WritePadding(index_sub_table_offset, padding);
179    }
180
181    // serialize size table
182    (*size_builder)->SetIndexTableSize(
183        index_sub_table_offset - current_sub_table_block_start_offset);
184    WritableFontDataPtr slice_size_table;
185    slice_size_table.Attach(down_cast<WritableFontData*>(
186        new_data->Slice(size_table_offset)));
187    size_table_offset += (*size_builder)->SubSerialize(slice_size_table);
188
189    current_sub_table_block_start_offset = index_sub_table_offset;
190  }
191  return size + current_sub_table_block_start_offset;
192}
193
194bool EblcTable::Builder::SubReadyToSerialize() {
195  if (size_table_builders_.empty()) {
196    return false;
197  }
198  for (BitmapSizeTableBuilderList::iterator b = size_table_builders_.begin(),
199                                            e = size_table_builders_.end();
200                                            b != e; b++) {
201    if (!(*b)->SubReadyToSerialize()) {
202      return false;
203    }
204  }
205  return true;
206}
207
208int32_t EblcTable::Builder::SubDataSizeToSerialize() {
209  if (size_table_builders_.empty()) {
210    return 0;
211  }
212  int32_t size = Offset::kHeaderLength;
213  bool variable = false;
214#if defined (SFNTLY_DEBUG_BITMAP)
215  size_t size_index = 0;
216#endif
217  for (BitmapSizeTableBuilderList::iterator b = size_table_builders_.begin(),
218                                            e = size_table_builders_.end();
219                                            b != e; b++) {
220    int32_t size_builder_size = (*b)->SubDataSizeToSerialize();
221#if defined (SFNTLY_DEBUG_BITMAP)
222    fprintf(stderr, "sizeIndex = %d, sizeBuilderSize=0x%x (%d)\n",
223            size_index++, size_builder_size, size_builder_size);
224#endif
225    variable = size_builder_size > 0 ? variable : true;
226    size += abs(size_builder_size);
227  }
228#if defined (SFNTLY_DEBUG_BITMAP)
229  fprintf(stderr, "eblc size=%d\n", size);
230#endif
231  return variable ? -size : size;
232}
233
234void EblcTable::Builder::SubDataSet() {
235  Revert();
236}
237
238BitmapSizeTableBuilderList* EblcTable::Builder::BitmapSizeBuilders() {
239  return GetSizeList();
240}
241
242void EblcTable::Builder::Revert() {
243  size_table_builders_.clear();
244  set_model_changed(false);
245}
246
247void EblcTable::Builder::GenerateLocaList(BitmapLocaList* output) {
248  assert(output);
249  BitmapSizeTableBuilderList* size_builder_list = GetSizeList();
250  output->clear();
251#if defined (SFNTLY_DEBUG_BITMAP)
252  int32_t size_index = 0;
253#endif
254  for (BitmapSizeTableBuilderList::iterator b = size_builder_list->begin(),
255                                            e = size_builder_list->end();
256                                            b != e; b++) {
257#if defined (SFNTLY_DEBUG_BITMAP)
258    fprintf(stderr, "size table = %d\n", size_index++);
259#endif
260    BitmapGlyphInfoMap loca_map;
261    (*b)->GenerateLocaMap(&loca_map);
262    output->push_back(loca_map);
263  }
264}
265
266CALLER_ATTACH
267FontDataTable* EblcTable::Builder::SubBuildTable(ReadableFontData* data) {
268  Ptr<EblcTable> new_table = new EblcTable(header(), data);
269  return new_table.Detach();
270}
271
272// static
273CALLER_ATTACH EblcTable::Builder*
274    EblcTable::Builder::CreateBuilder(Header* header, WritableFontData* data) {
275  Ptr<EblcTable::Builder> new_builder = new EblcTable::Builder(header, data);
276  return new_builder.Detach();
277}
278
279// static
280CALLER_ATTACH EblcTable::Builder*
281    EblcTable::Builder::CreateBuilder(Header* header, ReadableFontData* data) {
282  Ptr<EblcTable::Builder> new_builder = new EblcTable::Builder(header, data);
283  return new_builder.Detach();
284}
285
286BitmapSizeTableBuilderList* EblcTable::Builder::GetSizeList() {
287  if (size_table_builders_.empty()) {
288    Initialize(InternalReadData(), &size_table_builders_);
289    set_model_changed();
290  }
291  return &size_table_builders_;
292}
293
294void EblcTable::Builder::Initialize(ReadableFontData* data,
295                                    BitmapSizeTableBuilderList* output) {
296  assert(output);
297  if (data) {
298    int32_t num_sizes = data->ReadULongAsInt(Offset::kNumSizes);
299    for (int32_t i = 0; i < num_sizes; ++i) {
300      ReadableFontDataPtr new_data;
301      new_data.Attach(down_cast<ReadableFontData*>(
302          data->Slice(Offset::kBitmapSizeTableArrayStart +
303                      i * Offset::kBitmapSizeTableLength,
304                      Offset::kBitmapSizeTableLength)));
305      BitmapSizeTableBuilderPtr size_builder;
306      size_builder.Attach(BitmapSizeTable::Builder::CreateBuilder(
307          new_data, data));
308      output->push_back(size_builder);
309    }
310  }
311}
312
313}  // namespace sfntly
314