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