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 
24 namespace sfntly {
25 /******************************************************************************
26  * EblcTable class
27  ******************************************************************************/
Version()28 int32_t EblcTable::Version() {
29   return data_->ReadFixed(Offset::kVersion);
30 }
31 
NumSizes()32 int32_t EblcTable::NumSizes() {
33   return data_->ReadULongAsInt(Offset::kNumSizes);
34 }
35 
GetBitmapSizeTable(int32_t index)36 BitmapSizeTable* 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 
EblcTable(Header * header,ReadableFontData * data)51 EblcTable::EblcTable(Header* header, ReadableFontData* data)
52     : SubTableContainerTable(header, data) {
53 }
54 
GetBitmapSizeTableList()55 BitmapSizeTableList* 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
CreateBitmapSizeTable(ReadableFontData * data,int32_t num_sizes,BitmapSizeTableList * output)64 void 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  ******************************************************************************/
Builder(Header * header,WritableFontData * data)87 EblcTable::Builder::Builder(Header* header, WritableFontData* data)
88     : SubTableContainerTable::Builder(header, data) {
89 }
90 
Builder(Header * header,ReadableFontData * data)91 EblcTable::Builder::Builder(Header* header, ReadableFontData* data)
92     : SubTableContainerTable::Builder(header, data) {
93 }
94 
~Builder()95 EblcTable::Builder::~Builder() {
96 }
97 
SubSerialize(WritableFontData * new_data)98 int32_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 
SubReadyToSerialize()194 bool 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 
SubDataSizeToSerialize()208 int32_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 
SubDataSet()234 void EblcTable::Builder::SubDataSet() {
235   Revert();
236 }
237 
BitmapSizeBuilders()238 BitmapSizeTableBuilderList* EblcTable::Builder::BitmapSizeBuilders() {
239   return GetSizeList();
240 }
241 
Revert()242 void EblcTable::Builder::Revert() {
243   size_table_builders_.clear();
244   set_model_changed(false);
245 }
246 
GenerateLocaList(BitmapLocaList * output)247 void 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 
266 CALLER_ATTACH
SubBuildTable(ReadableFontData * data)267 FontDataTable* EblcTable::Builder::SubBuildTable(ReadableFontData* data) {
268   Ptr<EblcTable> new_table = new EblcTable(header(), data);
269   return new_table.Detach();
270 }
271 
272 // static
273 CALLER_ATTACH EblcTable::Builder*
CreateBuilder(Header * header,WritableFontData * data)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
280 CALLER_ATTACH EblcTable::Builder*
CreateBuilder(Header * header,ReadableFontData * data)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 
GetSizeList()286 BitmapSizeTableBuilderList* 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 
Initialize(ReadableFontData * data,BitmapSizeTableBuilderList * output)294 void 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