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