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 ******************************************************************************/ 28 int32_t EblcTable::Version() { 29 return data_->ReadFixed(Offset::kVersion); 30 } 31 32 int32_t EblcTable::NumSizes() { 33 return data_->ReadULongAsInt(Offset::kNumSizes); 34 } 35 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 51 EblcTable::EblcTable(Header* header, ReadableFontData* data) 52 : SubTableContainerTable(header, data) { 53 } 54 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 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 ******************************************************************************/ 87 EblcTable::Builder::Builder(Header* header, WritableFontData* data) 88 : SubTableContainerTable::Builder(header, data) { 89 } 90 91 EblcTable::Builder::Builder(Header* header, ReadableFontData* data) 92 : SubTableContainerTable::Builder(header, data) { 93 } 94 95 EblcTable::Builder::~Builder() { 96 } 97 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 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 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 234 void EblcTable::Builder::SubDataSet() { 235 Revert(); 236 } 237 238 BitmapSizeTableBuilderList* EblcTable::Builder::BitmapSizeBuilders() { 239 return GetSizeList(); 240 } 241 242 void EblcTable::Builder::Revert() { 243 size_table_builders_.clear(); 244 set_model_changed(false); 245 } 246 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 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* 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* 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 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 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