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