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 <algorithm>
22 #include <functional>
23 #include <iterator>
24 #include <limits>
25 #include <map>
26 #include <string>
27 #include <typeinfo>
28 
29 #include "sfntly/data/font_input_stream.h"
30 #include "sfntly/font_factory.h"
31 #include "sfntly/math/fixed1616.h"
32 #include "sfntly/math/font_math.h"
33 #include "sfntly/port/exception_type.h"
34 #include "sfntly/table/core/font_header_table.h"
35 #include "sfntly/table/core/horizontal_device_metrics_table.h"
36 #include "sfntly/table/core/horizontal_header_table.h"
37 #include "sfntly/table/core/horizontal_metrics_table.h"
38 #include "sfntly/table/core/maximum_profile_table.h"
39 #include "sfntly/table/truetype/loca_table.h"
40 #include "sfntly/tag.h"
41 
42 namespace sfntly {
43 
44 namespace {
45 
46 const int32_t kSFNTVersionMajor = 1;
47 const int32_t kSFNTVersionMinor = 0;
48 
49 const int32_t kMaxTableSize = 200 * 1024 * 1024;
50 
IsValidHeaderRegion(int32_t data_length,int32_t offset,int32_t length)51 bool IsValidHeaderRegion(int32_t data_length, int32_t offset, int32_t length) {
52   return offset >= 0 && length >= 0 &&
53          offset <= std::numeric_limits<int32_t>::max() - length &&
54          offset + length <= data_length;
55 }
56 
57 }  // namespace
58 
59 /******************************************************************************
60  * Font class
61  ******************************************************************************/
~Font()62 Font::~Font() {}
63 
HasTable(int32_t tag) const64 bool Font::HasTable(int32_t tag) const {
65   return tables_.find(tag) != tables_.end();
66 }
67 
GetTable(int32_t tag)68 Table* Font::GetTable(int32_t tag) {
69   if (!HasTable(tag))
70     return NULL;
71   return tables_[tag];
72 }
73 
GetTableMap()74 const TableMap* Font::GetTableMap() {
75   return &tables_;
76 }
77 
Serialize(OutputStream * os,std::vector<int32_t> * table_ordering)78 void Font::Serialize(OutputStream* os, std::vector<int32_t>* table_ordering) {
79   assert(table_ordering);
80   std::vector<int32_t> final_table_ordering;
81   GenerateTableOrdering(table_ordering, &final_table_ordering);
82   TableHeaderList table_records;
83   BuildTableHeadersForSerialization(&final_table_ordering, &table_records);
84 
85   FontOutputStream fos(os);
86   SerializeHeader(&fos, &table_records);
87   SerializeTables(&fos, &table_records);
88 }
89 
Font(int32_t sfnt_version,std::vector<uint8_t> * digest)90 Font::Font(int32_t sfnt_version, std::vector<uint8_t>* digest)
91     : sfnt_version_(sfnt_version) {
92   // non-trivial assignments that makes debugging hard if placed in
93   // initialization list
94   digest_ = *digest;
95 }
96 
BuildTableHeadersForSerialization(std::vector<int32_t> * table_ordering,TableHeaderList * table_headers)97 void Font::BuildTableHeadersForSerialization(std::vector<int32_t>* table_ordering,
98                                              TableHeaderList* table_headers) {
99   assert(table_headers);
100   assert(table_ordering);
101 
102   std::vector<int32_t> final_table_ordering;
103   GenerateTableOrdering(table_ordering, &final_table_ordering);
104   int32_t table_offset = Offset::kTableRecordBegin + num_tables() *
105                          Offset::kTableRecordSize;
106   for (size_t i = 0; i < final_table_ordering.size(); ++i) {
107     int32_t tag = final_table_ordering[i];
108     TablePtr table = GetTable(tag);
109     if (table == NULL)
110       continue;
111 
112     HeaderPtr header = new Header(tag, table->CalculatedChecksum(),
113                                   table_offset, table->header()->length());
114     table_headers->push_back(header);
115     table_offset += (table->DataLength() + 3) & ~3;
116   }
117 }
118 
SerializeHeader(FontOutputStream * fos,TableHeaderList * table_headers)119 void Font::SerializeHeader(FontOutputStream* fos,
120                            TableHeaderList* table_headers) {
121   fos->WriteFixed(sfnt_version_);
122   fos->WriteUShort(table_headers->size());
123   int32_t log2_of_max_power_of_2 = FontMath::Log2(table_headers->size());
124   int32_t search_range = 2 << (log2_of_max_power_of_2 - 1 + 4);
125   fos->WriteUShort(search_range);
126   fos->WriteUShort(log2_of_max_power_of_2);
127   fos->WriteUShort((table_headers->size() * 16) - search_range);
128 
129   HeaderTagSortedSet sorted_headers;
130   std::copy(table_headers->begin(),
131             table_headers->end(),
132             std::inserter(sorted_headers, sorted_headers.end()));
133 
134   for (HeaderTagSortedSet::iterator record = sorted_headers.begin(),
135                                     record_end = sorted_headers.end();
136                                     record != record_end; ++record) {
137     fos->WriteULong((*record)->tag());
138     fos->WriteULong((int32_t)((*record)->checksum()));
139     fos->WriteULong((*record)->offset());
140     fos->WriteULong((*record)->length());
141   }
142 }
143 
SerializeTables(FontOutputStream * fos,TableHeaderList * table_headers)144 void Font::SerializeTables(FontOutputStream* fos,
145                            TableHeaderList* table_headers) {
146   assert(fos);
147   assert(table_headers);
148   for (size_t i = 0; i < table_headers->size(); ++i) {
149     const HeaderPtr& record = (*table_headers)[i];
150     TablePtr target_table = GetTable(record->tag());
151     if (target_table == NULL) {
152 #if !defined (SFNTLY_NO_EXCEPTION)
153       throw IOException("Table out of sync with font header.");
154 #endif
155       return;
156     }
157     int32_t table_size = target_table->Serialize(fos);
158     assert(table_size == record->length());
159 
160     int32_t filler_size = ((table_size + 3) & ~3) - table_size;
161     for (int32_t i = 0; i < filler_size; ++i) {
162       fos->Write(static_cast<uint8_t>(0));
163     }
164   }
165 }
166 
GenerateTableOrdering(std::vector<int32_t> * default_table_ordering,std::vector<int32_t> * table_ordering)167 void Font::GenerateTableOrdering(std::vector<int32_t>* default_table_ordering,
168                                  std::vector<int32_t>* table_ordering) {
169   assert(default_table_ordering);
170   assert(table_ordering);
171   table_ordering->clear();
172   if (default_table_ordering->empty()) {
173     DefaultTableOrdering(default_table_ordering);
174   }
175 
176   typedef std::map<int32_t, bool> Int2Bool;
177   typedef std::pair<int32_t, bool> Int2BoolEntry;
178   Int2Bool tables_in_font;
179   for (TableMap::iterator table = tables_.begin(), table_end = tables_.end();
180                           table != table_end; ++table) {
181     tables_in_font.insert(Int2BoolEntry(table->first, false));
182   }
183   for (std::vector<int32_t>::iterator tag = default_table_ordering->begin(),
184                              tag_end = default_table_ordering->end();
185                              tag != tag_end; ++tag) {
186     if (HasTable(*tag)) {
187       table_ordering->push_back(*tag);
188       tables_in_font[*tag] = true;
189     }
190   }
191   for (Int2Bool::iterator table = tables_in_font.begin(),
192                           table_end = tables_in_font.end();
193                           table != table_end; ++table) {
194     if (table->second == false)
195       table_ordering->push_back(table->first);
196   }
197 }
198 
DefaultTableOrdering(std::vector<int32_t> * default_table_ordering)199 void Font::DefaultTableOrdering(std::vector<int32_t>* default_table_ordering) {
200   assert(default_table_ordering);
201   default_table_ordering->clear();
202   if (HasTable(Tag::CFF)) {
203     default_table_ordering->resize(CFF_TABLE_ORDERING_SIZE);
204     std::copy(CFF_TABLE_ORDERING, CFF_TABLE_ORDERING + CFF_TABLE_ORDERING_SIZE,
205               default_table_ordering->begin());
206     return;
207   }
208   default_table_ordering->resize(TRUE_TYPE_TABLE_ORDERING_SIZE);
209   std::copy(TRUE_TYPE_TABLE_ORDERING,
210             TRUE_TYPE_TABLE_ORDERING + TRUE_TYPE_TABLE_ORDERING_SIZE,
211             default_table_ordering->begin());
212 }
213 
214 /******************************************************************************
215  * Font::Builder class
216  ******************************************************************************/
~Builder()217 Font::Builder::~Builder() {}
218 
GetOTFBuilder(FontFactory * factory,InputStream * is)219 CALLER_ATTACH Font::Builder* Font::Builder::GetOTFBuilder(FontFactory* factory,
220                                                           InputStream* is) {
221   FontBuilderPtr builder = new Builder(factory);
222   builder->LoadFont(is);
223   return builder.Detach();
224 }
225 
GetOTFBuilder(FontFactory * factory,WritableFontData * wfd,int32_t offset_to_offset_table)226 CALLER_ATTACH Font::Builder* Font::Builder::GetOTFBuilder(
227     FontFactory* factory,
228     WritableFontData* wfd,
229     int32_t offset_to_offset_table) {
230   FontBuilderPtr builder = new Builder(factory);
231   builder->LoadFont(wfd, offset_to_offset_table);
232   return builder.Detach();
233 }
234 
GetOTFBuilder(FontFactory * factory)235 CALLER_ATTACH Font::Builder* Font::Builder::GetOTFBuilder(
236     FontFactory* factory) {
237   FontBuilderPtr builder = new Builder(factory);
238   return builder.Detach();
239 }
240 
ReadyToBuild()241 bool Font::Builder::ReadyToBuild() {
242   // just read in data with no manipulation
243   if (table_builders_.empty() && !data_blocks_.empty()) {
244     return true;
245   }
246 
247   // TODO(stuartg): font level checks - required tables etc?
248   for (TableBuilderMap::iterator table_builder = table_builders_.begin(),
249                                  table_builder_end = table_builders_.end();
250                                  table_builder != table_builder_end;
251                                  ++table_builder) {
252     if (!table_builder->second->ReadyToBuild())
253       return false;
254   }
255   return true;
256 }
257 
Build()258 CALLER_ATTACH Font* Font::Builder::Build() {
259   FontPtr font = new Font(sfnt_version_, &digest_);
260 
261   if (!table_builders_.empty()) {
262     // Note: Different from Java. Directly use font->tables_ here to avoid
263     //       STL container copying.
264     BuildTablesFromBuilders(font, &table_builders_, &font->tables_);
265   }
266 
267   table_builders_.clear();
268   data_blocks_.clear();
269   return font.Detach();
270 }
271 
SetDigest(std::vector<uint8_t> * digest)272 void Font::Builder::SetDigest(std::vector<uint8_t>* digest) {
273   digest_.clear();
274   digest_ = *digest;
275 }
276 
ClearTableBuilders()277 void Font::Builder::ClearTableBuilders() {
278   table_builders_.clear();
279 }
280 
HasTableBuilder(int32_t tag)281 bool Font::Builder::HasTableBuilder(int32_t tag) {
282   return (table_builders_.find(tag) != table_builders_.end());
283 }
284 
GetTableBuilder(int32_t tag)285 Table::Builder* Font::Builder::GetTableBuilder(int32_t tag) {
286   if (HasTableBuilder(tag))
287     return table_builders_[tag];
288   return NULL;
289 }
290 
NewTableBuilder(int32_t tag)291 Table::Builder* Font::Builder::NewTableBuilder(int32_t tag) {
292   HeaderPtr header = new Header(tag);
293   TableBuilderPtr builder;
294   builder.Attach(Table::Builder::GetBuilder(header, NULL));
295   table_builders_.insert(TableBuilderEntry(header->tag(), builder));
296   return builder;
297 }
298 
NewTableBuilder(int32_t tag,ReadableFontData * src_data)299 Table::Builder* Font::Builder::NewTableBuilder(int32_t tag,
300                                                ReadableFontData* src_data) {
301   assert(src_data);
302   WritableFontDataPtr data;
303   data.Attach(WritableFontData::CreateWritableFontData(src_data->Length()));
304   // TODO(stuarg): take over original data instead?
305   src_data->CopyTo(data);
306 
307   HeaderPtr header = new Header(tag, data->Length());
308   TableBuilderPtr builder;
309   builder.Attach(Table::Builder::GetBuilder(header, data));
310   table_builders_.insert(TableBuilderEntry(tag, builder));
311   return builder;
312 }
313 
RemoveTableBuilder(int32_t tag)314 void Font::Builder::RemoveTableBuilder(int32_t tag) {
315   table_builders_.erase(tag);
316 }
317 
Builder(FontFactory * factory)318 Font::Builder::Builder(FontFactory* factory)
319     : factory_(factory),
320       sfnt_version_(Fixed1616::Fixed(kSFNTVersionMajor, kSFNTVersionMinor)) {
321 }
322 
LoadFont(InputStream * is)323 void Font::Builder::LoadFont(InputStream* is) {
324   // Note: we do not throw exception here for is.  This is more of an assertion.
325   assert(is);
326   FontInputStream font_is(is);
327   HeaderOffsetSortedSet records;
328   ReadHeader(&font_is, &records);
329   LoadTableData(&records, &font_is, &data_blocks_);
330   BuildAllTableBuilders(&data_blocks_, &table_builders_);
331   font_is.Close();
332 }
333 
LoadFont(WritableFontData * wfd,int32_t offset_to_offset_table)334 void Font::Builder::LoadFont(WritableFontData* wfd,
335                              int32_t offset_to_offset_table) {
336   // Note: we do not throw exception here for is.  This is more of an assertion.
337   assert(wfd);
338   HeaderOffsetSortedSet records;
339   ReadHeader(wfd, offset_to_offset_table, &records);
340   LoadTableData(&records, wfd, &data_blocks_);
341   BuildAllTableBuilders(&data_blocks_, &table_builders_);
342 }
343 
SfntWrapperSize()344 int32_t Font::Builder::SfntWrapperSize() {
345   return Offset::kSfntHeaderSize +
346          (Offset::kTableRecordSize * table_builders_.size());
347 }
348 
BuildAllTableBuilders(DataBlockMap * table_data,TableBuilderMap * builder_map)349 void Font::Builder::BuildAllTableBuilders(DataBlockMap* table_data,
350                                           TableBuilderMap* builder_map) {
351   for (DataBlockMap::iterator record = table_data->begin(),
352                               record_end = table_data->end();
353                               record != record_end; ++record) {
354     TableBuilderPtr builder;
355     builder.Attach(GetTableBuilder(record->first.p_, record->second.p_));
356     builder_map->insert(TableBuilderEntry(record->first->tag(), builder));
357   }
358   InterRelateBuilders(&table_builders_);
359 }
360 
361 CALLER_ATTACH
GetTableBuilder(Header * header,WritableFontData * data)362 Table::Builder* Font::Builder::GetTableBuilder(Header* header,
363                                                WritableFontData* data) {
364   return Table::Builder::GetBuilder(header, data);
365 }
366 
BuildTablesFromBuilders(Font * font,TableBuilderMap * builder_map,TableMap * table_map)367 void Font::Builder::BuildTablesFromBuilders(Font* font,
368                                             TableBuilderMap* builder_map,
369                                             TableMap* table_map) {
370   UNREFERENCED_PARAMETER(font);
371   InterRelateBuilders(builder_map);
372 
373   // Now build all the tables.
374   for (TableBuilderMap::iterator builder = builder_map->begin(),
375                                  builder_end = builder_map->end();
376                                  builder != builder_end; ++builder) {
377     TablePtr table;
378     if (builder->second && builder->second->ReadyToBuild()) {
379       table.Attach(down_cast<Table*>(builder->second->Build()));
380     }
381     if (table == NULL) {
382       table_map->clear();
383 #if !defined (SFNTLY_NO_EXCEPTION)
384       std::string builder_string = "Unable to build table - ";
385       char* table_name = TagToString(builder->first);
386       builder_string += table_name;
387       delete[] table_name;
388       throw RuntimeException(builder_string.c_str());
389 #endif
390       return;
391     }
392     table_map->insert(TableMapEntry(table->header()->tag(), table));
393   }
394 }
395 
GetBuilder(TableBuilderMap * builder_map,int32_t tag)396 static Table::Builder* GetBuilder(TableBuilderMap* builder_map, int32_t tag) {
397   if (!builder_map)
398     return NULL;
399 
400   TableBuilderMap::iterator target = builder_map->find(tag);
401   if (target == builder_map->end())
402     return NULL;
403 
404   return target->second.p_;
405 }
406 
407 // Like GetBuilder(), but the returned Builder must be able to support reads.
GetReadBuilder(TableBuilderMap * builder_map,int32_t tag)408 static Table::Builder* GetReadBuilder(TableBuilderMap* builder_map, int32_t tag) {
409   Table::Builder* builder = GetBuilder(builder_map, tag);
410   if (!builder || !builder->InternalReadData())
411     return NULL;
412 
413   return builder;
414 }
415 
InterRelateBuilders(TableBuilderMap * builder_map)416 void Font::Builder::InterRelateBuilders(TableBuilderMap* builder_map) {
417   Table::Builder* raw_head_builder = GetReadBuilder(builder_map, Tag::head);
418   FontHeaderTableBuilderPtr header_table_builder;
419   if (raw_head_builder != NULL) {
420     header_table_builder =
421         down_cast<FontHeaderTable::Builder*>(raw_head_builder);
422   }
423 
424   Table::Builder* raw_hhea_builder = GetReadBuilder(builder_map, Tag::hhea);
425   HorizontalHeaderTableBuilderPtr horizontal_header_builder;
426   if (raw_head_builder != NULL) {
427     horizontal_header_builder =
428         down_cast<HorizontalHeaderTable::Builder*>(raw_hhea_builder);
429   }
430 
431   Table::Builder* raw_maxp_builder = GetReadBuilder(builder_map, Tag::maxp);
432   MaximumProfileTableBuilderPtr max_profile_builder;
433   if (raw_maxp_builder != NULL) {
434     max_profile_builder =
435         down_cast<MaximumProfileTable::Builder*>(raw_maxp_builder);
436   }
437 
438   Table::Builder* raw_loca_builder = GetBuilder(builder_map, Tag::loca);
439   LocaTableBuilderPtr loca_table_builder;
440   if (raw_loca_builder != NULL) {
441     loca_table_builder = down_cast<LocaTable::Builder*>(raw_loca_builder);
442   }
443 
444   Table::Builder* raw_hmtx_builder = GetReadBuilder(builder_map, Tag::hmtx);
445   HorizontalMetricsTableBuilderPtr horizontal_metrics_builder;
446   if (raw_hmtx_builder != NULL) {
447     horizontal_metrics_builder =
448         down_cast<HorizontalMetricsTable::Builder*>(raw_hmtx_builder);
449   }
450 
451 #if defined (SFNTLY_EXPERIMENTAL)
452   Table::Builder* raw_hdmx_builder = GetBuilder(builder_map, Tag::hdmx);
453   HorizontalDeviceMetricsTableBuilderPtr hdmx_table_builder;
454   if (raw_hdmx_builder != NULL) {
455     hdmx_table_builder =
456         down_cast<HorizontalDeviceMetricsTable::Builder*>(raw_hdmx_builder);
457   }
458 #endif
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       int32_t num_glyphs = max_profile_builder->NumGlyphs();
464       if (num_glyphs >= 0)
465         horizontal_metrics_builder->SetNumGlyphs(num_glyphs);
466     }
467     if (horizontal_header_builder != NULL) {
468       int32_t num_hmetrics = horizontal_header_builder->NumberOfHMetrics();
469       if (num_hmetrics >= 0)
470         horizontal_metrics_builder->SetNumberOfHMetrics(num_hmetrics);
471     }
472   }
473 
474   if (loca_table_builder != NULL) {
475     if (max_profile_builder != NULL) {
476       int32_t num_glyphs = max_profile_builder->NumGlyphs();
477       if (num_glyphs >= 0)
478         loca_table_builder->SetNumGlyphs(num_glyphs);
479     }
480     if (header_table_builder != NULL) {
481       loca_table_builder->set_format_version(
482           header_table_builder->IndexToLocFormat());
483     }
484   }
485 
486 #if defined (SFNTLY_EXPERIMENTAL)
487   // Note: In C++, hdmx_table_builder can be NULL in a subsetter.
488   if (max_profile_builder != NULL && hdmx_table_builder != NULL) {
489     hdmx_table_builder->SetNumGlyphs(max_profile_builder->NumGlyphs());
490   }
491 #endif
492 }
493 
ReadHeader(FontInputStream * is,HeaderOffsetSortedSet * records)494 void Font::Builder::ReadHeader(FontInputStream* is,
495                                HeaderOffsetSortedSet* records) {
496   assert(records);
497   sfnt_version_ = is->ReadFixed();
498   num_tables_ = is->ReadUShort();
499   search_range_ = is->ReadUShort();
500   entry_selector_ = is->ReadUShort();
501   range_shift_ = is->ReadUShort();
502 
503   for (int32_t table_number = 0; table_number < num_tables_; ++table_number) {
504     // Need to use temporary vars here.  C++ evaluates function parameters from
505     // right to left and thus breaks the order of input stream.
506     int32_t tag = is->ReadULongAsInt();
507     int64_t checksum = is->ReadULong();
508     int32_t offset = is->ReadULongAsInt();
509     int32_t length = is->ReadULongAsInt();
510     if (!IsValidHeaderRegion(is->Length(), offset, length))
511       continue;
512 
513     HeaderPtr table = new Header(tag, checksum, offset, length);
514     records->insert(table);
515   }
516 }
517 
ReadHeader(ReadableFontData * fd,int32_t offset,HeaderOffsetSortedSet * records)518 void Font::Builder::ReadHeader(ReadableFontData* fd,
519                                int32_t offset,
520                                HeaderOffsetSortedSet* records) {
521   assert(records);
522   sfnt_version_ = fd->ReadFixed(offset + Offset::kSfntVersion);
523   num_tables_ = fd->ReadUShort(offset + Offset::kNumTables);
524   search_range_ = fd->ReadUShort(offset + Offset::kSearchRange);
525   entry_selector_ = fd->ReadUShort(offset + Offset::kEntrySelector);
526   range_shift_ = fd->ReadUShort(offset + Offset::kRangeShift);
527 
528   if (num_tables_ > fd->Size() / Offset::kTableRecordSize)
529     return;
530 
531   int32_t table_offset = offset + Offset::kTableRecordBegin;
532   for (int32_t table_number = 0;
533        table_number < num_tables_;
534        table_number++, table_offset += Offset::kTableRecordSize) {
535     int32_t tag = fd->ReadULongAsInt(table_offset + Offset::kTableTag);
536     int64_t checksum = fd->ReadULong(table_offset + Offset::kTableCheckSum);
537     int32_t offset = fd->ReadULongAsInt(table_offset + Offset::kTableOffset);
538     int32_t length = fd->ReadULongAsInt(table_offset + Offset::kTableLength);
539     if (!IsValidHeaderRegion(fd->Size(), offset, length))
540       continue;
541 
542     HeaderPtr table = new Header(tag, checksum, offset, length);
543     records->insert(table);
544   }
545 }
546 
LoadTableData(HeaderOffsetSortedSet * headers,FontInputStream * is,DataBlockMap * table_data)547 void Font::Builder::LoadTableData(HeaderOffsetSortedSet* headers,
548                                   FontInputStream* is,
549                                   DataBlockMap* table_data) {
550   assert(table_data);
551   for (HeaderOffsetSortedSet::iterator it = headers->begin(),
552                                        table_end = headers->end();
553                                        it != table_end;
554                                        ++it) {
555     const Ptr<Header> header = *it;
556     is->Skip(header->offset() - is->position());
557     if (header->length() > kMaxTableSize)
558       continue;
559 
560     FontInputStream table_is(is, header->length());
561     WritableFontDataPtr data;
562     data.Attach(WritableFontData::CreateWritableFontData(header->length()));
563     data->CopyFrom(&table_is, header->length());
564     table_data->insert(DataBlockEntry(header, data));
565   }
566 }
567 
LoadTableData(HeaderOffsetSortedSet * headers,WritableFontData * fd,DataBlockMap * table_data)568 void Font::Builder::LoadTableData(HeaderOffsetSortedSet* headers,
569                                   WritableFontData* fd,
570                                   DataBlockMap* table_data) {
571   for (HeaderOffsetSortedSet::iterator it = headers->begin(),
572                                        table_end = headers->end();
573                                        it != table_end;
574                                        ++it) {
575     const Ptr<Header> header = *it;
576     if (header->length() > kMaxTableSize)
577       continue;
578 
579     FontDataPtr sliced_data;
580     sliced_data.Attach(fd->Slice(header->offset(), header->length()));
581     WritableFontDataPtr data = down_cast<WritableFontData*>(sliced_data.p_);
582     table_data->insert(DataBlockEntry(header, data));
583   }
584 }
585 
586 }  // namespace sfntly
587