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 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