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