font.cc revision 30d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cd
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
41namespace sfntly {
42
43const int32_t SFNTVERSION_MAJOR = 1;
44const int32_t SFNTVERSION_MINOR = 0;
45
46/******************************************************************************
47 * Font class
48 ******************************************************************************/
49Font::~Font() {}
50
51bool 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
57Table* Font::GetTable(int32_t tag) {
58  if (!HasTable(tag)) {
59    return NULL;
60  }
61  return tables_[tag];
62}
63
64const TableMap* Font::GetTableMap() {
65  return &tables_;
66}
67
68void 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
80Font::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
87void 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
113void 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
138void 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
163void 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
195void 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 ******************************************************************************/
213Font::Builder::~Builder() {}
214
215CALLER_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
222CALLER_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
231CALLER_ATTACH Font::Builder* Font::Builder::GetOTFBuilder(
232    FontFactory* factory) {
233  FontBuilderPtr builder = new Builder(factory);
234  return builder.Detach();
235}
236
237bool 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
254CALLER_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
268void Font::Builder::SetDigest(ByteVector* digest) {
269  digest_.clear();
270  digest_ = *digest;
271}
272
273void Font::Builder::ClearTableBuilders() {
274  table_builders_.clear();
275}
276
277bool Font::Builder::HasTableBuilder(int32_t tag) {
278  return (table_builders_.find(tag) != table_builders_.end());
279}
280
281Table::Builder* Font::Builder::GetTableBuilder(int32_t tag) {
282  if (HasTableBuilder(tag))
283    return table_builders_[tag];
284  return NULL;
285}
286
287Table::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
295Table::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
310void 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
317Font::Builder::Builder(FontFactory* factory)
318    : factory_(factory),
319      sfnt_version_(Fixed1616::Fixed(SFNTVERSION_MAJOR, SFNTVERSION_MINOR)) {
320}
321
322void 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
333void 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
343int32_t Font::Builder::SfntWrapperSize() {
344  return Offset::kSfntHeaderSize +
345         (Offset::kTableRecordSize * table_builders_.size());
346}
347
348void 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
360CALLER_ATTACH
361Table::Builder* Font::Builder::GetTableBuilder(Header* header,
362                                               WritableFontData* data) {
363  return Table::Builder::GetBuilder(header, data);
364}
365
366void 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
395static 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
406void 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
480void 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
501void 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
524void 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
542void 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