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/font.h" 18 19 #include <stdio.h> 20 21 #include <functional> 22 #include <algorithm> 23 #include <map> 24 #include <string> 25 #include <typeinfo> 26 #include <iterator> 27 28 #include "sfntly/data/font_input_stream.h" 29 #include "sfntly/font_factory.h" 30 #include "sfntly/math/fixed1616.h" 31 #include "sfntly/math/font_math.h" 32 #include "sfntly/port/exception_type.h" 33 #include "sfntly/table/core/font_header_table.h" 34 #include "sfntly/table/core/horizontal_device_metrics_table.h" 35 #include "sfntly/table/core/horizontal_header_table.h" 36 #include "sfntly/table/core/horizontal_metrics_table.h" 37 #include "sfntly/table/core/maximum_profile_table.h" 38 #include "sfntly/table/truetype/loca_table.h" 39 #include "sfntly/tag.h" 40 41 namespace sfntly { 42 43 const int32_t SFNTVERSION_MAJOR = 1; 44 const int32_t SFNTVERSION_MINOR = 0; 45 46 /****************************************************************************** 47 * Font class 48 ******************************************************************************/ 49 Font::~Font() {} 50 51 bool Font::HasTable(int32_t tag) { 52 TableMap::const_iterator result = tables_.find(tag); 53 TableMap::const_iterator end = tables_.end(); 54 return (result != end); 55 } 56 57 Table* Font::GetTable(int32_t tag) { 58 if (!HasTable(tag)) { 59 return NULL; 60 } 61 return tables_[tag]; 62 } 63 64 const TableMap* Font::GetTableMap() { 65 return &tables_; 66 } 67 68 void Font::Serialize(OutputStream* os, IntegerList* table_ordering) { 69 assert(table_ordering); 70 IntegerList final_table_ordering; 71 GenerateTableOrdering(table_ordering, &final_table_ordering); 72 TableHeaderList table_records; 73 BuildTableHeadersForSerialization(&final_table_ordering, &table_records); 74 75 FontOutputStream fos(os); 76 SerializeHeader(&fos, &table_records); 77 SerializeTables(&fos, &table_records); 78 } 79 80 Font::Font(int32_t sfnt_version, ByteVector* digest) 81 : sfnt_version_(sfnt_version) { 82 // non-trivial assignments that makes debugging hard if placed in 83 // initialization list 84 digest_ = *digest; 85 } 86 87 void Font::BuildTableHeadersForSerialization(IntegerList* table_ordering, 88 TableHeaderList* table_headers) { 89 assert(table_headers); 90 assert(table_ordering); 91 92 IntegerList final_table_ordering; 93 GenerateTableOrdering(table_ordering, &final_table_ordering); 94 int32_t table_offset = Offset::kTableRecordBegin + num_tables() * 95 Offset::kTableRecordSize; 96 for (IntegerList::iterator tag = final_table_ordering.begin(), 97 tag_end = final_table_ordering.end(); 98 tag != tag_end; ++tag) { 99 if (tables_.find(*tag) == tables_.end()) { 100 continue; 101 } 102 TablePtr table = tables_[*tag]; 103 if (table != NULL) { 104 HeaderPtr header = 105 new Header(*tag, table->CalculatedChecksum(), table_offset, 106 table->header()->length()); 107 table_headers->push_back(header); 108 table_offset += (table->DataLength() + 3) & ~3; 109 } 110 } 111 } 112 113 void Font::SerializeHeader(FontOutputStream* fos, 114 TableHeaderList* table_headers) { 115 fos->WriteFixed(sfnt_version_); 116 fos->WriteUShort(table_headers->size()); 117 int32_t log2_of_max_power_of_2 = FontMath::Log2(table_headers->size()); 118 int32_t search_range = 2 << (log2_of_max_power_of_2 - 1 + 4); 119 fos->WriteUShort(search_range); 120 fos->WriteUShort(log2_of_max_power_of_2); 121 fos->WriteUShort((table_headers->size() * 16) - search_range); 122 123 HeaderTagSortedSet sorted_headers; 124 std::copy(table_headers->begin(), 125 table_headers->end(), 126 std::inserter(sorted_headers, sorted_headers.end())); 127 128 for (HeaderTagSortedSet::iterator record = sorted_headers.begin(), 129 record_end = sorted_headers.end(); 130 record != record_end; ++record) { 131 fos->WriteULong((*record)->tag()); 132 fos->WriteULong((int32_t)((*record)->checksum())); 133 fos->WriteULong((*record)->offset()); 134 fos->WriteULong((*record)->length()); 135 } 136 } 137 138 void Font::SerializeTables(FontOutputStream* fos, 139 TableHeaderList* table_headers) { 140 assert(fos); 141 assert(table_headers); 142 for (TableHeaderList::iterator record = table_headers->begin(), 143 end_of_headers = table_headers->end(); 144 record != end_of_headers; ++record) { 145 TablePtr target_table = GetTable((*record)->tag()); 146 if (target_table == NULL) { 147 #if !defined (SFNTLY_NO_EXCEPTION) 148 throw IOException("Table out of sync with font header."); 149 #endif 150 return; 151 } 152 int32_t table_size = target_table->Serialize(fos); 153 if (table_size != (*record)->length()) { 154 assert(false); 155 } 156 int32_t filler_size = ((table_size + 3) & ~3) - table_size; 157 for (int32_t i = 0; i < filler_size; ++i) { 158 fos->Write(static_cast<byte_t>(0)); 159 } 160 } 161 } 162 163 void Font::GenerateTableOrdering(IntegerList* default_table_ordering, 164 IntegerList* table_ordering) { 165 assert(default_table_ordering); 166 assert(table_ordering); 167 table_ordering->clear(); 168 if (default_table_ordering->empty()) { 169 DefaultTableOrdering(default_table_ordering); 170 } 171 172 typedef std::map<int32_t, bool> Int2Bool; 173 typedef std::pair<int32_t, bool> Int2BoolEntry; 174 Int2Bool tables_in_font; 175 for (TableMap::iterator table = tables_.begin(), table_end = tables_.end(); 176 table != table_end; ++table) { 177 tables_in_font.insert(Int2BoolEntry(table->first, false)); 178 } 179 for (IntegerList::iterator tag = default_table_ordering->begin(), 180 tag_end = default_table_ordering->end(); 181 tag != tag_end; ++tag) { 182 if (HasTable(*tag)) { 183 table_ordering->push_back(*tag); 184 tables_in_font[*tag] = true; 185 } 186 } 187 for (Int2Bool::iterator table = tables_in_font.begin(), 188 table_end = tables_in_font.end(); 189 table != table_end; ++table) { 190 if (table->second == false) 191 table_ordering->push_back(table->first); 192 } 193 } 194 195 void Font::DefaultTableOrdering(IntegerList* default_table_ordering) { 196 assert(default_table_ordering); 197 default_table_ordering->clear(); 198 if (HasTable(Tag::CFF)) { 199 default_table_ordering->resize(CFF_TABLE_ORDERING_SIZE); 200 std::copy(CFF_TABLE_ORDERING, CFF_TABLE_ORDERING + CFF_TABLE_ORDERING_SIZE, 201 default_table_ordering->begin()); 202 return; 203 } 204 default_table_ordering->resize(TRUE_TYPE_TABLE_ORDERING_SIZE); 205 std::copy(TRUE_TYPE_TABLE_ORDERING, 206 TRUE_TYPE_TABLE_ORDERING + TRUE_TYPE_TABLE_ORDERING_SIZE, 207 default_table_ordering->begin()); 208 } 209 210 /****************************************************************************** 211 * Font::Builder class 212 ******************************************************************************/ 213 Font::Builder::~Builder() {} 214 215 CALLER_ATTACH Font::Builder* Font::Builder::GetOTFBuilder(FontFactory* factory, 216 InputStream* is) { 217 FontBuilderPtr builder = new Builder(factory); 218 builder->LoadFont(is); 219 return builder.Detach(); 220 } 221 222 CALLER_ATTACH Font::Builder* Font::Builder::GetOTFBuilder( 223 FontFactory* factory, 224 WritableFontData* wfd, 225 int32_t offset_to_offset_table) { 226 FontBuilderPtr builder = new Builder(factory); 227 builder->LoadFont(wfd, offset_to_offset_table); 228 return builder.Detach(); 229 } 230 231 CALLER_ATTACH Font::Builder* Font::Builder::GetOTFBuilder( 232 FontFactory* factory) { 233 FontBuilderPtr builder = new Builder(factory); 234 return builder.Detach(); 235 } 236 237 bool Font::Builder::ReadyToBuild() { 238 // just read in data with no manipulation 239 if (table_builders_.empty() && !data_blocks_.empty()) { 240 return true; 241 } 242 243 // TODO(stuartg): font level checks - required tables etc? 244 for (TableBuilderMap::iterator table_builder = table_builders_.begin(), 245 table_builder_end = table_builders_.end(); 246 table_builder != table_builder_end; 247 ++table_builder) { 248 if (!table_builder->second->ReadyToBuild()) 249 return false; 250 } 251 return true; 252 } 253 254 CALLER_ATTACH Font* Font::Builder::Build() { 255 FontPtr font = new Font(sfnt_version_, &digest_); 256 257 if (!table_builders_.empty()) { 258 // Note: Different from Java. Directly use font->tables_ here to avoid 259 // STL container copying. 260 BuildTablesFromBuilders(font, &table_builders_, &font->tables_); 261 } 262 263 table_builders_.clear(); 264 data_blocks_.clear(); 265 return font.Detach(); 266 } 267 268 void Font::Builder::SetDigest(ByteVector* digest) { 269 digest_.clear(); 270 digest_ = *digest; 271 } 272 273 void Font::Builder::ClearTableBuilders() { 274 table_builders_.clear(); 275 } 276 277 bool Font::Builder::HasTableBuilder(int32_t tag) { 278 return (table_builders_.find(tag) != table_builders_.end()); 279 } 280 281 Table::Builder* Font::Builder::GetTableBuilder(int32_t tag) { 282 if (HasTableBuilder(tag)) 283 return table_builders_[tag]; 284 return NULL; 285 } 286 287 Table::Builder* Font::Builder::NewTableBuilder(int32_t tag) { 288 HeaderPtr header = new Header(tag); 289 TableBuilderPtr builder; 290 builder.Attach(Table::Builder::GetBuilder(header, NULL)); 291 table_builders_.insert(TableBuilderEntry(header->tag(), builder)); 292 return builder; 293 } 294 295 Table::Builder* Font::Builder::NewTableBuilder(int32_t tag, 296 ReadableFontData* src_data) { 297 assert(src_data); 298 WritableFontDataPtr data; 299 data.Attach(WritableFontData::CreateWritableFontData(src_data->Length())); 300 // TODO(stuarg): take over original data instead? 301 src_data->CopyTo(data); 302 303 HeaderPtr header = new Header(tag, data->Length()); 304 TableBuilderPtr builder; 305 builder.Attach(Table::Builder::GetBuilder(header, data)); 306 table_builders_.insert(TableBuilderEntry(tag, builder)); 307 return builder; 308 } 309 310 void Font::Builder::RemoveTableBuilder(int32_t tag) { 311 TableBuilderMap::iterator target = table_builders_.find(tag); 312 if (target != table_builders_.end()) { 313 table_builders_.erase(target); 314 } 315 } 316 317 Font::Builder::Builder(FontFactory* factory) 318 : factory_(factory), 319 sfnt_version_(Fixed1616::Fixed(SFNTVERSION_MAJOR, SFNTVERSION_MINOR)) { 320 } 321 322 void Font::Builder::LoadFont(InputStream* is) { 323 // Note: we do not throw exception here for is. This is more of an assertion. 324 assert(is); 325 FontInputStream font_is(is); 326 HeaderOffsetSortedSet records; 327 ReadHeader(&font_is, &records); 328 LoadTableData(&records, &font_is, &data_blocks_); 329 BuildAllTableBuilders(&data_blocks_, &table_builders_); 330 font_is.Close(); 331 } 332 333 void Font::Builder::LoadFont(WritableFontData* wfd, 334 int32_t offset_to_offset_table) { 335 // Note: we do not throw exception here for is. This is more of an assertion. 336 assert(wfd); 337 HeaderOffsetSortedSet records; 338 ReadHeader(wfd, offset_to_offset_table, &records); 339 LoadTableData(&records, wfd, &data_blocks_); 340 BuildAllTableBuilders(&data_blocks_, &table_builders_); 341 } 342 343 int32_t Font::Builder::SfntWrapperSize() { 344 return Offset::kSfntHeaderSize + 345 (Offset::kTableRecordSize * table_builders_.size()); 346 } 347 348 void Font::Builder::BuildAllTableBuilders(DataBlockMap* table_data, 349 TableBuilderMap* builder_map) { 350 for (DataBlockMap::iterator record = table_data->begin(), 351 record_end = table_data->end(); 352 record != record_end; ++record) { 353 TableBuilderPtr builder; 354 builder.Attach(GetTableBuilder(record->first.p_, record->second.p_)); 355 builder_map->insert(TableBuilderEntry(record->first->tag(), builder)); 356 } 357 InterRelateBuilders(&table_builders_); 358 } 359 360 CALLER_ATTACH 361 Table::Builder* Font::Builder::GetTableBuilder(Header* header, 362 WritableFontData* data) { 363 return Table::Builder::GetBuilder(header, data); 364 } 365 366 void Font::Builder::BuildTablesFromBuilders(Font* font, 367 TableBuilderMap* builder_map, 368 TableMap* table_map) { 369 UNREFERENCED_PARAMETER(font); 370 InterRelateBuilders(builder_map); 371 372 // Now build all the tables. 373 for (TableBuilderMap::iterator builder = builder_map->begin(), 374 builder_end = builder_map->end(); 375 builder != builder_end; ++builder) { 376 TablePtr table; 377 if (builder->second && builder->second->ReadyToBuild()) { 378 table.Attach(down_cast<Table*>(builder->second->Build())); 379 } 380 if (table == NULL) { 381 table_map->clear(); 382 #if !defined (SFNTLY_NO_EXCEPTION) 383 std::string builder_string = "Unable to build table - "; 384 char* table_name = TagToString(builder->first); 385 builder_string += table_name; 386 delete[] table_name; 387 throw RuntimeException(builder_string.c_str()); 388 #endif 389 return; 390 } 391 table_map->insert(TableMapEntry(table->header()->tag(), table)); 392 } 393 } 394 395 static Table::Builder* GetBuilder(TableBuilderMap* builder_map, int32_t tag) { 396 if (builder_map) { 397 TableBuilderMap::iterator target = builder_map->find(tag); 398 if (target != builder_map->end()) { 399 return target->second.p_; 400 } 401 } 402 403 return NULL; 404 } 405 406 void Font::Builder::InterRelateBuilders(TableBuilderMap* builder_map) { 407 Table::Builder* raw_head_builder = GetBuilder(builder_map, Tag::head); 408 FontHeaderTableBuilderPtr header_table_builder; 409 if (raw_head_builder != NULL) { 410 header_table_builder = 411 down_cast<FontHeaderTable::Builder*>(raw_head_builder); 412 } 413 414 Table::Builder* raw_hhea_builder = GetBuilder(builder_map, Tag::hhea); 415 HorizontalHeaderTableBuilderPtr horizontal_header_builder; 416 if (raw_head_builder != NULL) { 417 horizontal_header_builder = 418 down_cast<HorizontalHeaderTable::Builder*>(raw_hhea_builder); 419 } 420 421 Table::Builder* raw_maxp_builder = GetBuilder(builder_map, Tag::maxp); 422 MaximumProfileTableBuilderPtr max_profile_builder; 423 if (raw_maxp_builder != NULL) { 424 max_profile_builder = 425 down_cast<MaximumProfileTable::Builder*>(raw_maxp_builder); 426 } 427 428 Table::Builder* raw_loca_builder = GetBuilder(builder_map, Tag::loca); 429 LocaTableBuilderPtr loca_table_builder; 430 if (raw_loca_builder != NULL) { 431 loca_table_builder = down_cast<LocaTable::Builder*>(raw_loca_builder); 432 } 433 434 Table::Builder* raw_hmtx_builder = GetBuilder(builder_map, Tag::hmtx); 435 HorizontalMetricsTableBuilderPtr horizontal_metrics_builder; 436 if (raw_hmtx_builder != NULL) { 437 horizontal_metrics_builder = 438 down_cast<HorizontalMetricsTable::Builder*>(raw_hmtx_builder); 439 } 440 441 #if defined (SFNTLY_EXPERIMENTAL) 442 Table::Builder* raw_hdmx_builder = GetBuilder(builder_map, Tag::hdmx); 443 HorizontalDeviceMetricsTableBuilderPtr hdmx_table_builder; 444 if (raw_hdmx_builder != NULL) { 445 hdmx_table_builder = 446 down_cast<HorizontalDeviceMetricsTable::Builder*>(raw_hdmx_builder); 447 } 448 #endif 449 450 // set the inter table data required to build certain tables 451 if (horizontal_metrics_builder != NULL) { 452 if (max_profile_builder != NULL) { 453 horizontal_metrics_builder->SetNumGlyphs( 454 max_profile_builder->NumGlyphs()); 455 } 456 if (horizontal_header_builder != NULL) { 457 horizontal_metrics_builder->SetNumberOfHMetrics( 458 horizontal_header_builder->NumberOfHMetrics()); 459 } 460 } 461 462 if (loca_table_builder != NULL) { 463 if (max_profile_builder != NULL) { 464 loca_table_builder->SetNumGlyphs(max_profile_builder->NumGlyphs()); 465 } 466 if (header_table_builder != NULL) { 467 loca_table_builder->set_format_version( 468 header_table_builder->IndexToLocFormat()); 469 } 470 } 471 472 #if defined (SFNTLY_EXPERIMENTAL) 473 // Note: In C++, hdmx_table_builder can be NULL in a subsetter. 474 if (max_profile_builder != NULL && hdmx_table_builder != NULL) { 475 hdmx_table_builder->SetNumGlyphs(max_profile_builder->NumGlyphs()); 476 } 477 #endif 478 } 479 480 void Font::Builder::ReadHeader(FontInputStream* is, 481 HeaderOffsetSortedSet* records) { 482 assert(records); 483 sfnt_version_ = is->ReadFixed(); 484 num_tables_ = is->ReadUShort(); 485 search_range_ = is->ReadUShort(); 486 entry_selector_ = is->ReadUShort(); 487 range_shift_ = is->ReadUShort(); 488 489 for (int32_t table_number = 0; table_number < num_tables_; ++table_number) { 490 // Need to use temporary vars here. C++ evaluates function parameters from 491 // right to left and thus breaks the order of input stream. 492 int32_t tag = is->ReadULongAsInt(); 493 int64_t checksum = is->ReadULong(); 494 int32_t offset = is->ReadULongAsInt(); 495 int32_t length = is->ReadULongAsInt(); 496 HeaderPtr table = new Header(tag, checksum, offset, length); 497 records->insert(table); 498 } 499 } 500 501 void Font::Builder::ReadHeader(ReadableFontData* fd, 502 int32_t offset, 503 HeaderOffsetSortedSet* records) { 504 assert(records); 505 sfnt_version_ = fd->ReadFixed(offset + Offset::kSfntVersion); 506 num_tables_ = fd->ReadUShort(offset + Offset::kNumTables); 507 search_range_ = fd->ReadUShort(offset + Offset::kSearchRange); 508 entry_selector_ = fd->ReadUShort(offset + Offset::kEntrySelector); 509 range_shift_ = fd->ReadUShort(offset + Offset::kRangeShift); 510 511 int32_t table_offset = offset + Offset::kTableRecordBegin; 512 for (int32_t table_number = 0; 513 table_number < num_tables_; 514 table_number++, table_offset += Offset::kTableRecordSize) { 515 int32_t tag = fd->ReadULongAsInt(table_offset + Offset::kTableTag); 516 int64_t checksum = fd->ReadULong(table_offset + Offset::kTableCheckSum); 517 int32_t offset = fd->ReadULongAsInt(table_offset + Offset::kTableOffset); 518 int32_t length = fd->ReadULongAsInt(table_offset + Offset::kTableLength); 519 HeaderPtr table = new Header(tag, checksum, offset, length); 520 records->insert(table); 521 } 522 } 523 524 void Font::Builder::LoadTableData(HeaderOffsetSortedSet* headers, 525 FontInputStream* is, 526 DataBlockMap* table_data) { 527 assert(table_data); 528 for (HeaderOffsetSortedSet::iterator table_header = headers->begin(), 529 table_end = headers->end(); 530 table_header != table_end; 531 ++table_header) { 532 is->Skip((*table_header)->offset() - is->position()); 533 FontInputStream table_is(is, (*table_header)->length()); 534 WritableFontDataPtr data; 535 data.Attach( 536 WritableFontData::CreateWritableFontData((*table_header)->length())); 537 data->CopyFrom(&table_is, (*table_header)->length()); 538 table_data->insert(DataBlockEntry(*table_header, data)); 539 } 540 } 541 542 void Font::Builder::LoadTableData(HeaderOffsetSortedSet* headers, 543 WritableFontData* fd, 544 DataBlockMap* table_data) { 545 for (HeaderOffsetSortedSet::iterator table_header = headers->begin(), 546 table_end = headers->end(); 547 table_header != table_end; 548 ++table_header) { 549 FontDataPtr sliced_data; 550 sliced_data.Attach( 551 fd->Slice((*table_header)->offset(), (*table_header)->length())); 552 WritableFontDataPtr data = down_cast<WritableFontData*>(sliced_data.p_); 553 table_data->insert(DataBlockEntry(*table_header, data)); 554 } 555 } 556 557 } // namespace sfntly 558