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