Home | History | Annotate | Download | only in sfntly
      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