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