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  ******************************************************************************/
~Font()49 Font::~Font() {}
50 
HasTable(int32_t tag)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 
GetTable(int32_t tag)57 Table* Font::GetTable(int32_t tag) {
58   if (!HasTable(tag)) {
59     return NULL;
60   }
61   return tables_[tag];
62 }
63 
GetTableMap()64 const TableMap* Font::GetTableMap() {
65   return &tables_;
66 }
67 
Serialize(OutputStream * os,IntegerList * table_ordering)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 
Font(int32_t sfnt_version,ByteVector * digest)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 
BuildTableHeadersForSerialization(IntegerList * table_ordering,TableHeaderList * table_headers)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 
SerializeHeader(FontOutputStream * fos,TableHeaderList * table_headers)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 
SerializeTables(FontOutputStream * fos,TableHeaderList * table_headers)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 
GenerateTableOrdering(IntegerList * default_table_ordering,IntegerList * table_ordering)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 
DefaultTableOrdering(IntegerList * default_table_ordering)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  ******************************************************************************/
~Builder()213 Font::Builder::~Builder() {}
214 
GetOTFBuilder(FontFactory * factory,InputStream * is)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 
GetOTFBuilder(FontFactory * factory,WritableFontData * wfd,int32_t offset_to_offset_table)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 
GetOTFBuilder(FontFactory * factory)231 CALLER_ATTACH Font::Builder* Font::Builder::GetOTFBuilder(
232     FontFactory* factory) {
233   FontBuilderPtr builder = new Builder(factory);
234   return builder.Detach();
235 }
236 
ReadyToBuild()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 
Build()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 
SetDigest(ByteVector * digest)268 void Font::Builder::SetDigest(ByteVector* digest) {
269   digest_.clear();
270   digest_ = *digest;
271 }
272 
ClearTableBuilders()273 void Font::Builder::ClearTableBuilders() {
274   table_builders_.clear();
275 }
276 
HasTableBuilder(int32_t tag)277 bool Font::Builder::HasTableBuilder(int32_t tag) {
278   return (table_builders_.find(tag) != table_builders_.end());
279 }
280 
GetTableBuilder(int32_t tag)281 Table::Builder* Font::Builder::GetTableBuilder(int32_t tag) {
282   if (HasTableBuilder(tag))
283     return table_builders_[tag];
284   return NULL;
285 }
286 
NewTableBuilder(int32_t tag)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 
NewTableBuilder(int32_t tag,ReadableFontData * src_data)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 
RemoveTableBuilder(int32_t tag)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 
Builder(FontFactory * factory)317 Font::Builder::Builder(FontFactory* factory)
318     : factory_(factory),
319       sfnt_version_(Fixed1616::Fixed(SFNTVERSION_MAJOR, SFNTVERSION_MINOR)) {
320 }
321 
LoadFont(InputStream * is)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 
LoadFont(WritableFontData * wfd,int32_t offset_to_offset_table)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 
SfntWrapperSize()343 int32_t Font::Builder::SfntWrapperSize() {
344   return Offset::kSfntHeaderSize +
345          (Offset::kTableRecordSize * table_builders_.size());
346 }
347 
BuildAllTableBuilders(DataBlockMap * table_data,TableBuilderMap * builder_map)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
GetTableBuilder(Header * header,WritableFontData * data)361 Table::Builder* Font::Builder::GetTableBuilder(Header* header,
362                                                WritableFontData* data) {
363   return Table::Builder::GetBuilder(header, data);
364 }
365 
BuildTablesFromBuilders(Font * font,TableBuilderMap * builder_map,TableMap * table_map)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 
GetBuilder(TableBuilderMap * builder_map,int32_t tag)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 
InterRelateBuilders(TableBuilderMap * builder_map)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 
ReadHeader(FontInputStream * is,HeaderOffsetSortedSet * records)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 
ReadHeader(ReadableFontData * fd,int32_t offset,HeaderOffsetSortedSet * records)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 
LoadTableData(HeaderOffsetSortedSet * headers,FontInputStream * is,DataBlockMap * table_data)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 
LoadTableData(HeaderOffsetSortedSet * headers,WritableFontData * fd,DataBlockMap * table_data)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