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