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 : // type.h needs to be included first because of building issues on Windows
18 : // Type aliases we delcare are defined in other headers and make the build
19 : // fail otherwise.
20 : #include "sfntly/port/type.h"
21 : #include "sfntly/table/core/cmap_table.h"
22 :
23 : #include <stdio.h>
24 : #include <stdlib.h>
25 :
26 : #include <utility>
27 :
28 : #include "sfntly/font.h"
29 : #include "sfntly/math/font_math.h"
30 : #include "sfntly/port/endian.h"
31 : #include "sfntly/port/exception_type.h"
32 : #include "sfntly/table/core/name_table.h"
33 :
34 : namespace sfntly {
35 :
36 : const int32_t CMapTable::NOTDEF = 0;
37 :
38 : CMapTable::CMapId CMapTable::WINDOWS_BMP = {
39 : PlatformId::kWindows,
40 : WindowsEncodingId::kUnicodeUCS2
41 : };
42 : CMapTable::CMapId CMapTable::WINDOWS_UCS4 = {
43 : PlatformId::kWindows,
44 : WindowsEncodingId::kUnicodeUCS4
45 : };
46 : CMapTable::CMapId CMapTable::MAC_ROMAN = {
47 : PlatformId::kWindows,
48 : MacintoshEncodingId::kRoman
49 : };
50 :
51 : /******************************************************************************
52 : * CMapTable class
53 : ******************************************************************************/
54 0 : CMapTable::CMapTable(Header* header, ReadableFontData* data)
55 0 : : SubTableContainerTable(header, data) {
56 0 : }
57 :
58 0 : CMapTable::~CMapTable() {}
59 :
60 0 : CALLER_ATTACH CMapTable::CMap* CMapTable::GetCMap(const int32_t index) {
61 0 : if (index < 0 || index > NumCMaps()) {
62 : #ifndef SFNTLY_NO_EXCEPTION
63 : throw IndexOutOfBoundException("Requested CMap index is out of bounds.");
64 : #else
65 0 : return NULL;
66 : #endif
67 : }
68 0 : int32_t platform_id = PlatformId(index);
69 0 : int32_t encoding_id = EncodingId(index);
70 0 : CMapId cmap_id = NewCMapId(platform_id, encoding_id);
71 0 : int32_t offset_ = Offset(index);
72 : Ptr<FontDataTable::Builder> cmap_builder =
73 0 : (CMap::Builder::GetBuilder(data_, offset_, cmap_id));
74 0 : if (!cmap_builder) {
75 : #ifndef SFNTLY_NO_EXCEPTION
76 : throw NoSuchElementException("Cannot find builder for requested CMap.");
77 : #else
78 0 : return NULL;
79 : #endif
80 : }
81 0 : return down_cast<CMapTable::CMap*>(cmap_builder->Build());
82 : }
83 :
84 0 : CALLER_ATTACH CMapTable::CMap* CMapTable::GetCMap(const int32_t platform_id,
85 : const int32_t encoding_id) {
86 0 : return GetCMap(NewCMapId(platform_id, encoding_id));
87 : }
88 :
89 : CALLER_ATTACH CMapTable::CMap*
90 0 : CMapTable::GetCMap(const CMapTable::CMapId cmap_id) {
91 0 : CMapIdFilter id_filter(cmap_id);
92 0 : CMapIterator cmap_iterator(this, &id_filter);
93 : // There can only be one cmap with a particular CMapId
94 0 : if (cmap_iterator.HasNext()) {
95 0 : Ptr<CMapTable::CMap> cmap;
96 0 : cmap.Attach(cmap_iterator.Next());
97 0 : return cmap.Detach();
98 : }
99 : #ifndef SFNTLY_NO_EXCEPTION
100 : throw NoSuchElementException();
101 : #else
102 0 : return NULL;
103 : #endif
104 : }
105 :
106 0 : int32_t CMapTable::Version() {
107 0 : return data_->ReadUShort(Offset::kVersion);
108 : }
109 :
110 0 : int32_t CMapTable::NumCMaps() {
111 0 : return data_->ReadUShort(Offset::kNumTables);
112 : }
113 :
114 0 : CMapTable::CMapId CMapTable::GetCMapId(int32_t index) {
115 0 : return NewCMapId(PlatformId(index), EncodingId(index));
116 : }
117 :
118 0 : int32_t CMapTable::PlatformId(int32_t index) {
119 0 : return data_->ReadUShort(Offset::kEncodingRecordPlatformId +
120 0 : OffsetForEncodingRecord(index));
121 : }
122 :
123 0 : int32_t CMapTable::EncodingId(int32_t index) {
124 0 : return data_->ReadUShort(Offset::kEncodingRecordEncodingId +
125 0 : OffsetForEncodingRecord(index));
126 : }
127 :
128 0 : int32_t CMapTable::Offset(int32_t index) {
129 0 : return data_->ReadULongAsInt(Offset::kEncodingRecordOffset +
130 0 : OffsetForEncodingRecord(index));
131 : }
132 :
133 0 : int32_t CMapTable::OffsetForEncodingRecord(int32_t index) {
134 0 : return Offset::kEncodingRecordStart + index * Offset::kEncodingRecordSize;
135 : }
136 :
137 0 : CMapTable::CMapId CMapTable::NewCMapId(int32_t platform_id,
138 : int32_t encoding_id) {
139 : CMapId result;
140 0 : result.platform_id = platform_id;
141 0 : result.encoding_id = encoding_id;
142 0 : return result;
143 : }
144 :
145 0 : CMapTable::CMapId CMapTable::NewCMapId(const CMapId& obj) {
146 : CMapId result;
147 0 : result.platform_id = obj.platform_id;
148 0 : result.encoding_id = obj.encoding_id;
149 0 : return result;
150 : }
151 :
152 : /******************************************************************************
153 : * CMapTable::CMapIterator class
154 : ******************************************************************************/
155 0 : CMapTable::CMapIterator::CMapIterator(CMapTable* table,
156 0 : const CMapFilter* filter)
157 0 : : table_index_(0), filter_(filter), table_(table) {
158 0 : }
159 :
160 0 : bool CMapTable::CMapIterator::HasNext() {
161 0 : if (!filter_) {
162 0 : if (table_index_ < table_->NumCMaps()) {
163 0 : return true;
164 : }
165 0 : return false;
166 : }
167 :
168 0 : for (; table_index_ < table_->NumCMaps(); ++table_index_) {
169 0 : if (filter_->accept(table_->GetCMapId(table_index_))) {
170 0 : return true;
171 : }
172 : }
173 0 : return false;
174 : }
175 :
176 0 : CALLER_ATTACH CMapTable::CMap* CMapTable::CMapIterator::Next() {
177 0 : if (!HasNext()) {
178 : #ifndef SFNTLY_NO_EXCEPTION
179 : throw NoSuchElementException();
180 : #else
181 0 : return NULL;
182 : #endif
183 : }
184 0 : CMapPtr next_cmap;
185 0 : next_cmap.Attach(table_->GetCMap(table_index_++));
186 0 : if (next_cmap == NULL) {
187 : #ifndef SFNTLY_NO_EXCEPTION
188 : throw NoSuchElementException("Error during the creation of the CMap");
189 : #else
190 0 : return NULL;
191 : #endif
192 : }
193 0 : return next_cmap.Detach();
194 : }
195 :
196 : /******************************************************************************
197 : * CMapTable::CMapId class
198 : ******************************************************************************/
199 :
200 : /******************************************************************************
201 : * CMapTable::CMapIdComparator class
202 : ******************************************************************************/
203 :
204 0 : bool CMapTable::CMapIdComparator::operator()(const CMapId& lhs,
205 : const CMapId& rhs) const {
206 0 : return ((lhs.platform_id << 8 | lhs.encoding_id) >
207 0 : (rhs.platform_id << 8 | rhs.encoding_id));
208 : }
209 :
210 : /******************************************************************************
211 : * CMapTable::CMapIdFilter class
212 : ******************************************************************************/
213 0 : CMapTable::CMapIdFilter::CMapIdFilter(const CMapId wanted_id)
214 : : wanted_id_(wanted_id),
215 0 : comparator_(NULL) {
216 0 : }
217 :
218 0 : CMapTable::CMapIdFilter::CMapIdFilter(const CMapId wanted_id,
219 0 : const CMapIdComparator* comparator)
220 : : wanted_id_(wanted_id),
221 0 : comparator_(comparator) {
222 0 : }
223 :
224 0 : bool CMapTable::CMapIdFilter::accept(const CMapId& cmap_id) const {
225 0 : if (!comparator_)
226 0 : return wanted_id_ == cmap_id;
227 0 : return (*comparator_)(wanted_id_, cmap_id);
228 : }
229 :
230 : /******************************************************************************
231 : * CMapTable::CMap class
232 : ******************************************************************************/
233 0 : CMapTable::CMap::CMap(ReadableFontData* data, int32_t format,
234 0 : const CMapId& cmap_id)
235 0 : : SubTable(data), format_(format), cmap_id_(cmap_id) {
236 0 : }
237 :
238 0 : CMapTable::CMap::~CMap() {
239 0 : }
240 :
241 : /******************************************************************************
242 : * CMapTable::CMap::Builder class
243 : ******************************************************************************/
244 0 : CMapTable::CMap::Builder::~Builder() {
245 0 : }
246 :
247 : CALLER_ATTACH CMapTable::CMap::Builder*
248 0 : CMapTable::CMap::Builder::GetBuilder(ReadableFontData* data, int32_t offset,
249 : const CMapId& cmap_id) {
250 : // NOT IMPLEMENTED: Java enum value validation
251 0 : int32_t format = data->ReadUShort(offset);
252 0 : CMapBuilderPtr builder;
253 0 : switch (format) {
254 : case CMapFormat::kFormat0:
255 0 : builder.Attach(CMapFormat0::Builder::NewInstance(data, offset, cmap_id));
256 0 : break;
257 : case CMapFormat::kFormat2:
258 : #if defined (SFNTLY_DEBUG_CMAP)
259 : fprintf(stderr, "Requesting Format2 builder, but it's unsupported; "
260 : "returning NULL\n");
261 : #endif
262 0 : break;
263 : case CMapFormat::kFormat4:
264 0 : builder.Attach(CMapFormat4::Builder::NewInstance(data, offset, cmap_id));
265 0 : break;
266 : default:
267 : #ifdef SFNTLY_DEBUG_CMAP
268 : fprintf(stderr, "Unknown builder format requested\n");
269 : #endif
270 0 : break;
271 : }
272 0 : return builder.Detach();
273 : }
274 :
275 : CALLER_ATTACH CMapTable::CMap::Builder*
276 0 : CMapTable::CMap::Builder::GetBuilder(int32_t format, const CMapId& cmap_id) {
277 0 : Ptr<CMapTable::CMap::Builder> builder;
278 0 : switch (format) {
279 : case CMapFormat::kFormat0:
280 0 : builder.Attach(CMapFormat0::Builder::NewInstance(cmap_id));
281 0 : break;
282 : case CMapFormat::kFormat2:
283 : #if defined (SFNTLY_DEBUG_CMAP)
284 : fprintf(stderr, "Requesting Format2 builder, but it's unsupported; "
285 : "returning NULL\n");
286 : #endif
287 0 : break;
288 : case CMapFormat::kFormat4:
289 0 : builder.Attach(CMapFormat4::Builder::NewInstance(cmap_id));
290 0 : break;
291 : default:
292 : #ifdef SFNTLY_DEBUG_CMAP
293 : fprintf(stderr, "Unknown builder format requested\n");
294 : #endif
295 0 : break;
296 : }
297 0 : return builder.Detach();
298 : }
299 :
300 0 : CMapTable::CMap::Builder::Builder(ReadableFontData* data,
301 : int32_t format,
302 0 : const CMapId& cmap_id)
303 : : SubTable::Builder(data),
304 : format_(format),
305 : cmap_id_(cmap_id),
306 0 : language_(0) {
307 0 : }
308 :
309 0 : CMapTable::CMap::Builder::Builder(WritableFontData* data,
310 : int32_t format,
311 0 : const CMapId& cmap_id)
312 : : SubTable::Builder(data),
313 : format_(format),
314 : cmap_id_(cmap_id),
315 0 : language_(0) {
316 0 : }
317 :
318 0 : int32_t CMapTable::CMap::Builder::SubSerialize(WritableFontData* new_data) {
319 0 : return InternalReadData()->CopyTo(new_data);
320 : }
321 :
322 0 : bool CMapTable::CMap::Builder::SubReadyToSerialize() {
323 0 : return true;
324 : }
325 :
326 0 : int32_t CMapTable::CMap::Builder::SubDataSizeToSerialize() {
327 0 : ReadableFontDataPtr read_data = InternalReadData();
328 0 : if (!read_data)
329 0 : return 0;
330 0 : return read_data->Length();
331 : }
332 :
333 0 : void CMapTable::CMap::Builder::SubDataSet() {
334 : // NOP
335 0 : }
336 :
337 : /******************************************************************************
338 : * CMapTable::CMapFormat0
339 : ******************************************************************************/
340 0 : CMapTable::CMapFormat0::~CMapFormat0() {
341 0 : }
342 :
343 0 : int32_t CMapTable::CMapFormat0::Language() {
344 0 : return 0;
345 : }
346 :
347 0 : int32_t CMapTable::CMapFormat0::GlyphId(int32_t character) {
348 0 : if (character < 0 || character > 255) {
349 0 : return CMapTable::NOTDEF;
350 : }
351 0 : return data_->ReadUByte(character + Offset::kFormat0GlyphIdArray);
352 : }
353 :
354 0 : CMapTable::CMapFormat0::CMapFormat0(ReadableFontData* data,
355 0 : const CMapId& cmap_id)
356 0 : : CMap(data, CMapFormat::kFormat0, cmap_id) {
357 0 : }
358 :
359 0 : CMapTable::CMap::CharacterIterator* CMapTable::CMapFormat0::Iterator() {
360 0 : return new CMapTable::CMapFormat0::CharacterIterator(0, 0xff);
361 : }
362 :
363 :
364 : /******************************************************************************
365 : * CMapTable::CMapFormat0::CharacterIterator
366 : ******************************************************************************/
367 0 : CMapTable::CMapFormat0::CharacterIterator::CharacterIterator(int32_t start,
368 0 : int32_t end)
369 : : character_(start),
370 0 : max_character_(end) {
371 0 : }
372 :
373 0 : CMapTable::CMapFormat0::CharacterIterator::~CharacterIterator() {}
374 :
375 0 : bool CMapTable::CMapFormat0::CharacterIterator::HasNext() {
376 0 : return character_ < max_character_;
377 : }
378 :
379 0 : int32_t CMapTable::CMapFormat0::CharacterIterator::Next() {
380 0 : if (HasNext())
381 0 : return character_++;
382 : #ifndef SFNTLY_NO_EXCEPTION
383 : throw NoSuchElementException("No more characters to iterate.");
384 : #endif
385 0 : return -1;
386 : }
387 :
388 : /******************************************************************************
389 : * CMapTable::CMapFormat0::Builder
390 : ******************************************************************************/
391 : // static
392 : CALLER_ATTACH CMapTable::CMapFormat0::Builder*
393 0 : CMapTable::CMapFormat0::Builder::NewInstance(WritableFontData* data,
394 : int32_t offset,
395 : const CMapId& cmap_id) {
396 0 : WritableFontDataPtr wdata;
397 0 : if (data) {
398 0 : wdata.Attach(down_cast<WritableFontData*>(
399 : data->Slice(offset,
400 0 : data->ReadUShort(offset + Offset::kFormat0Length))));
401 : }
402 0 : return new Builder(wdata, CMapFormat::kFormat0, cmap_id);
403 : }
404 :
405 : // static
406 : CALLER_ATTACH CMapTable::CMapFormat0::Builder*
407 0 : CMapTable::CMapFormat0::Builder::NewInstance(ReadableFontData* data,
408 : int32_t offset,
409 : const CMapId& cmap_id) {
410 0 : ReadableFontDataPtr rdata;
411 0 : if (data) {
412 0 : rdata.Attach(down_cast<ReadableFontData*>(
413 : data->Slice(offset,
414 0 : data->ReadUShort(offset + Offset::kFormat0Length))));
415 : }
416 0 : return new Builder(rdata, CMapFormat::kFormat0, cmap_id);
417 : }
418 :
419 : // static
420 : CALLER_ATTACH CMapTable::CMapFormat0::Builder*
421 0 : CMapTable::CMapFormat0::Builder::NewInstance(const CMapId& cmap_id) {
422 0 : return new Builder(cmap_id);
423 : }
424 :
425 : // Always call NewInstance instead of the constructor for creating a new builder
426 : // object! This refactoring avoids memory leaks when slicing the font data.
427 0 : CMapTable::CMapFormat0::Builder::Builder(WritableFontData* data, int32_t offset,
428 0 : const CMapId& cmap_id)
429 0 : : CMapTable::CMap::Builder(data, CMapFormat::kFormat0, cmap_id) {
430 : UNREFERENCED_PARAMETER(offset);
431 0 : }
432 :
433 0 : CMapTable::CMapFormat0::Builder::Builder(
434 : ReadableFontData* data,
435 : int32_t offset,
436 0 : const CMapId& cmap_id)
437 0 : : CMapTable::CMap::Builder(data, CMapFormat::kFormat0, cmap_id) {
438 : UNREFERENCED_PARAMETER(offset);
439 0 : }
440 :
441 0 : CMapTable::CMapFormat0::Builder::Builder(const CMapId& cmap_id)
442 : : CMap::Builder(static_cast<ReadableFontData*>(NULL),
443 : CMapFormat::kFormat0,
444 0 : cmap_id) {
445 0 : }
446 :
447 0 : CMapTable::CMapFormat0::Builder::~Builder() {
448 0 : }
449 :
450 : CALLER_ATTACH FontDataTable*
451 0 : CMapTable::CMapFormat0::Builder::SubBuildTable(ReadableFontData* data) {
452 0 : FontDataTablePtr table = new CMapFormat0(data, cmap_id());
453 0 : return table.Detach();
454 : }
455 :
456 : /******************************************************************************
457 : * CMapTable::CMapFormat2
458 : ******************************************************************************/
459 0 : CMapTable::CMapFormat2::~CMapFormat2() {
460 0 : }
461 :
462 0 : int32_t CMapTable::CMapFormat2::Language() {
463 0 : return 0;
464 : }
465 :
466 0 : int32_t CMapTable::CMapFormat2::GlyphId(int32_t character) {
467 0 : if (character > 0xffff) {
468 0 : return CMapTable::NOTDEF;
469 : }
470 :
471 0 : uint32_t c = ToBE32(character);
472 0 : byte_t high_byte = (c >> 8) & 0xff;
473 0 : byte_t low_byte = c & 0xff;
474 0 : int32_t offset = SubHeaderOffset(high_byte);
475 :
476 0 : if (offset == 0) {
477 0 : low_byte = high_byte;
478 0 : high_byte = 0;
479 : }
480 :
481 0 : int32_t first_code = FirstCode(high_byte);
482 0 : int32_t entry_count = EntryCount(high_byte);
483 :
484 0 : if (low_byte < first_code || low_byte >= first_code + entry_count) {
485 0 : return CMapTable::NOTDEF;
486 : }
487 :
488 0 : int32_t id_range_offset = IdRangeOffset(high_byte);
489 :
490 : // position of idRangeOffset + value of idRangeOffset + index for low byte
491 : // = firstcode
492 0 : int32_t p_location = (offset + Offset::kFormat2SubHeader_idRangeOffset) +
493 : id_range_offset +
494 0 : (low_byte - first_code) * DataSize::kUSHORT;
495 0 : int p = data_->ReadUShort(p_location);
496 0 : if (p == 0) {
497 0 : return CMapTable::NOTDEF;
498 : }
499 :
500 0 : if (offset == 0) {
501 0 : return p;
502 : }
503 0 : int id_delta = IdDelta(high_byte);
504 0 : return (p + id_delta) % 65536;
505 : }
506 :
507 0 : int32_t CMapTable::CMapFormat2::BytesConsumed(int32_t character) {
508 0 : uint32_t c = ToBE32(character);
509 0 : int32_t high_byte = (c >> 8) & 0xff;
510 0 : int32_t offset = SubHeaderOffset(high_byte);
511 0 : return (offset == 0) ? 1 : 2;
512 : }
513 :
514 0 : CMapTable::CMapFormat2::CMapFormat2(ReadableFontData* data,
515 0 : const CMapId& cmap_id)
516 0 : : CMap(data, CMapFormat::kFormat2, cmap_id) {
517 0 : }
518 :
519 0 : int32_t CMapTable::CMapFormat2::SubHeaderOffset(int32_t sub_header_index) {
520 0 : return data_->ReadUShort(Offset::kFormat2SubHeaderKeys +
521 0 : sub_header_index * DataSize::kUSHORT);
522 : }
523 :
524 0 : int32_t CMapTable::CMapFormat2::FirstCode(int32_t sub_header_index) {
525 0 : int32_t sub_header_offset = SubHeaderOffset(sub_header_index);
526 0 : return data_->ReadUShort(sub_header_offset +
527 : Offset::kFormat2SubHeaderKeys +
528 0 : Offset::kFormat2SubHeader_firstCode);
529 : }
530 :
531 0 : int32_t CMapTable::CMapFormat2::EntryCount(int32_t sub_header_index) {
532 0 : int32_t sub_header_offset = SubHeaderOffset(sub_header_index);
533 0 : return data_->ReadUShort(sub_header_offset +
534 : Offset::kFormat2SubHeaderKeys +
535 0 : Offset::kFormat2SubHeader_entryCount);
536 : }
537 :
538 0 : int32_t CMapTable::CMapFormat2::IdRangeOffset(int32_t sub_header_index) {
539 0 : int32_t sub_header_offset = SubHeaderOffset(sub_header_index);
540 0 : return data_->ReadUShort(sub_header_offset +
541 : Offset::kFormat2SubHeaderKeys +
542 0 : Offset::kFormat2SubHeader_idRangeOffset);
543 : }
544 :
545 0 : int32_t CMapTable::CMapFormat2::IdDelta(int32_t sub_header_index) {
546 0 : int32_t sub_header_offset = SubHeaderOffset(sub_header_index);
547 0 : return data_->ReadUShort(sub_header_offset +
548 : Offset::kFormat2SubHeaderKeys +
549 0 : Offset::kFormat2SubHeader_idDelta);
550 : }
551 :
552 0 : CMapTable::CMap::CharacterIterator* CMapTable::CMapFormat2::Iterator() {
553 : // UNIMPLEMENTED
554 0 : return NULL;
555 : }
556 :
557 : /******************************************************************************
558 : * CMapTable::CMapFormat2::Builder
559 : ******************************************************************************/
560 0 : CMapTable::CMapFormat2::Builder::Builder(WritableFontData* data,
561 : int32_t offset,
562 0 : const CMapId& cmap_id)
563 0 : : CMapTable::CMap::Builder(data ? down_cast<WritableFontData*>(
564 : data->Slice(offset, data->ReadUShort(
565 0 : offset + Offset::kFormat0Length)))
566 : : static_cast<WritableFontData*>(NULL),
567 0 : CMapFormat::kFormat2, cmap_id) {
568 : // TODO(arthurhsu): FIXIT: heavy lifting and leak, need fix.
569 0 : }
570 :
571 0 : CMapTable::CMapFormat2::Builder::Builder(ReadableFontData* data,
572 : int32_t offset,
573 0 : const CMapId& cmap_id)
574 0 : : CMapTable::CMap::Builder(data ? down_cast<ReadableFontData*>(
575 : data->Slice(offset, data->ReadUShort(
576 0 : offset + Offset::kFormat0Length)))
577 : : static_cast<ReadableFontData*>(NULL),
578 0 : CMapFormat::kFormat2, cmap_id) {
579 : // TODO(arthurhsu): FIXIT: heavy lifting and leak, need fix.
580 0 : }
581 :
582 0 : CMapTable::CMapFormat2::Builder::~Builder() {
583 0 : }
584 :
585 : CALLER_ATTACH FontDataTable*
586 0 : CMapTable::CMapFormat2::Builder::SubBuildTable(ReadableFontData* data) {
587 0 : FontDataTablePtr table = new CMapFormat2(data, cmap_id());
588 0 : return table.Detach();
589 : }
590 :
591 : /******************************************************************************
592 : * CMapTable::CMapFormat4
593 : ******************************************************************************/
594 0 : CMapTable::CMapFormat4::CMapFormat4(ReadableFontData* data,
595 0 : const CMapId& cmap_id)
596 : : CMap(data, CMapFormat::kFormat4, cmap_id),
597 0 : seg_count_(SegCount(data)),
598 0 : start_code_offset_(StartCodeOffset(seg_count_)),
599 0 : id_delta_offset_(IdDeltaOffset(seg_count_)),
600 0 : glyph_id_array_offset_(GlyphIdArrayOffset(seg_count_)) {
601 0 : }
602 :
603 0 : CMapTable::CMapFormat4::~CMapFormat4() {
604 0 : }
605 :
606 0 : int32_t CMapTable::CMapFormat4::GlyphId(int32_t character) {
607 0 : int32_t segment = data_->SearchUShort(StartCodeOffset(seg_count_),
608 : DataSize::kUSHORT,
609 : Offset::kFormat4EndCount,
610 : DataSize::kUSHORT,
611 : seg_count_,
612 0 : character);
613 0 : if (segment == -1) {
614 0 : return CMapTable::NOTDEF;
615 : }
616 0 : int32_t start_code = StartCode(segment);
617 0 : return RetrieveGlyphId(segment, start_code, character);
618 : }
619 :
620 0 : int32_t CMapTable::CMapFormat4::RetrieveGlyphId(int32_t segment,
621 : int32_t start_code,
622 : int32_t character) {
623 0 : if (character < start_code) {
624 0 : return CMapTable::NOTDEF;
625 : }
626 0 : int32_t id_range_offset = IdRangeOffset(segment);
627 0 : if (id_range_offset == 0) {
628 0 : return (character + IdDelta(segment)) % 65536;
629 : }
630 0 : return data_->ReadUShort(id_range_offset +
631 0 : IdRangeOffsetLocation(segment) +
632 0 : 2 * (character - start_code));
633 : }
634 :
635 0 : int32_t CMapTable::CMapFormat4::seg_count() {
636 0 : return seg_count_;
637 : }
638 :
639 0 : int32_t CMapTable::CMapFormat4::Length() {
640 0 : return Length(data_);
641 : }
642 :
643 0 : int32_t CMapTable::CMapFormat4::StartCode(int32_t segment) {
644 0 : if (!IsValidIndex(segment)) {
645 0 : return -1;
646 : }
647 0 : return StartCode(data_.p_, seg_count_, segment);
648 : }
649 :
650 : // static
651 0 : int32_t CMapTable::CMapFormat4::Language(ReadableFontData* data) {
652 0 : int32_t language = data->ReadUShort(Offset::kFormat4Language);
653 0 : return language;
654 : }
655 :
656 : // static
657 0 : int32_t CMapTable::CMapFormat4::Length(ReadableFontData* data) {
658 0 : int32_t length = data->ReadUShort(Offset::kFormat4Length);
659 0 : return length;
660 : }
661 :
662 : // static
663 0 : int32_t CMapTable::CMapFormat4::SegCount(ReadableFontData* data) {
664 0 : int32_t seg_count = data->ReadUShort(Offset::kFormat4SegCountX2) / 2;
665 0 : return seg_count;
666 : }
667 :
668 : // static
669 0 : int32_t CMapTable::CMapFormat4::StartCode(ReadableFontData* data,
670 : int32_t seg_count,
671 : int32_t index) {
672 0 : int32_t start_code = data->ReadUShort(StartCodeOffset(seg_count) +
673 0 : index * DataSize::kUSHORT);
674 0 : return start_code;
675 : }
676 :
677 : // static
678 0 : int32_t CMapTable::CMapFormat4::StartCodeOffset(int32_t seg_count) {
679 0 : int32_t start_code_offset = Offset::kFormat4EndCount +
680 0 : (seg_count + 1) * DataSize::kUSHORT;
681 0 : return start_code_offset;
682 : }
683 :
684 : // static
685 0 : int32_t CMapTable::CMapFormat4::EndCode(ReadableFontData* data,
686 : int32_t seg_count,
687 : int32_t index) {
688 : UNREFERENCED_PARAMETER(seg_count);
689 0 : int32_t end_code = data->ReadUShort(Offset::kFormat4EndCount +
690 0 : index * DataSize::kUSHORT);
691 0 : return end_code;
692 : }
693 :
694 : // static
695 0 : int32_t CMapTable::CMapFormat4::IdDelta(ReadableFontData* data,
696 : int32_t seg_count,
697 : int32_t index) {
698 0 : int32_t id_delta = data->ReadUShort(IdDeltaOffset(seg_count) +
699 0 : index * DataSize::kUSHORT);
700 0 : return id_delta;
701 : }
702 :
703 : // static
704 0 : int32_t CMapTable::CMapFormat4::IdDeltaOffset(int32_t seg_count) {
705 : int32_t id_delta_offset =
706 0 : Offset::kFormat4EndCount + (2 * seg_count + 1) * DataSize::kUSHORT;
707 0 : return id_delta_offset;
708 : }
709 :
710 : // static
711 0 : int32_t CMapTable::CMapFormat4::IdRangeOffset(ReadableFontData* data,
712 : int32_t seg_count,
713 : int32_t index) {
714 : int32_t id_range_offset =
715 0 : data->ReadUShort(IdRangeOffsetOffset(seg_count)
716 0 : + index * DataSize::kUSHORT);
717 0 : return id_range_offset;
718 : }
719 :
720 : // static
721 0 : int32_t CMapTable::CMapFormat4::IdRangeOffsetOffset(int32_t seg_count) {
722 : int32_t id_range_offset_offset =
723 0 : Offset::kFormat4EndCount + (2 * seg_count + 1) * DataSize::kUSHORT +
724 0 : seg_count * DataSize::kSHORT;
725 0 : return id_range_offset_offset;
726 : }
727 :
728 : // static
729 0 : int32_t CMapTable::CMapFormat4::GlyphIdArrayOffset(int32_t seg_count) {
730 : int32_t glyph_id_array_offset =
731 0 : Offset::kFormat4EndCount + (3 * seg_count + 1) * DataSize::kUSHORT +
732 0 : seg_count * DataSize::kSHORT;
733 0 : return glyph_id_array_offset;
734 : }
735 :
736 0 : int32_t CMapTable::CMapFormat4::EndCode(int32_t segment) {
737 0 : if (IsValidIndex(segment)) {
738 0 : return EndCode(data_, seg_count_, segment);
739 : }
740 : #if defined (SFNTLY_NO_EXCEPTION)
741 0 : return -1;
742 : #else
743 : throw IllegalArgumentException();
744 : #endif
745 : }
746 :
747 0 : bool CMapTable::CMapFormat4::IsValidIndex(int32_t segment) {
748 0 : if (segment < 0 || segment >= seg_count_) {
749 : #if defined (SFNTLY_NO_EXCEPTION)
750 0 : return false;
751 : #else
752 : throw IllegalArgumentException();
753 : #endif
754 : }
755 0 : return true;
756 : }
757 :
758 0 : int32_t CMapTable::CMapFormat4::IdDelta(int32_t segment) {
759 0 : if (IsValidIndex(segment))
760 0 : return IdDelta(data_, seg_count_, segment);
761 0 : return -1;
762 : }
763 :
764 0 : int32_t CMapTable::CMapFormat4::IdRangeOffset(int32_t segment) {
765 0 : if (IsValidIndex(segment))
766 0 : return data_->ReadUShort(IdRangeOffsetLocation(segment));
767 0 : return -1;
768 : }
769 :
770 0 : int32_t CMapTable::CMapFormat4::IdRangeOffsetLocation(int32_t segment) {
771 0 : if (IsValidIndex(segment))
772 0 : return IdRangeOffsetOffset(seg_count_) + segment * DataSize::kUSHORT;
773 0 : return -1;
774 : }
775 :
776 0 : int32_t CMapTable::CMapFormat4::GlyphIdArray(int32_t index) {
777 0 : return data_->ReadUShort(glyph_id_array_offset_ + index * DataSize::kUSHORT);
778 : }
779 :
780 0 : int32_t CMapTable::CMapFormat4::Language() {
781 0 : return Language(data_);
782 : }
783 :
784 :
785 0 : CMapTable::CMap::CharacterIterator* CMapTable::CMapFormat4::Iterator() {
786 0 : return new CharacterIterator(this);
787 : }
788 :
789 : /******************************************************************************
790 : * CMapTable::CMapFormat4::CharacterIterator class
791 : ******************************************************************************/
792 0 : CMapTable::CMapFormat4::CharacterIterator::CharacterIterator(
793 0 : CMapFormat4* parent)
794 : : parent_(parent),
795 : segment_index_(0),
796 : first_char_in_segment_(-1),
797 : last_char_in_segment_(-1),
798 : next_char_(-1),
799 0 : next_char_set_(false) {
800 0 : }
801 :
802 0 : bool CMapTable::CMapFormat4::CharacterIterator::HasNext() {
803 0 : if (next_char_set_)
804 0 : return true;
805 0 : while (segment_index_ < parent_->seg_count_) {
806 0 : if (first_char_in_segment_ < 0) {
807 0 : first_char_in_segment_ = parent_->StartCode(segment_index_);
808 0 : last_char_in_segment_ = parent_->EndCode(segment_index_);
809 0 : next_char_ = first_char_in_segment_;
810 0 : next_char_set_ = true;
811 0 : return true;
812 : }
813 0 : if (next_char_ < last_char_in_segment_) {
814 0 : next_char_++;
815 0 : next_char_set_ = true;
816 0 : return true;
817 : }
818 0 : segment_index_++;
819 0 : first_char_in_segment_ = -1;
820 : }
821 0 : return false;
822 : }
823 :
824 0 : int32_t CMapTable::CMapFormat4::CharacterIterator::Next() {
825 0 : if (!next_char_set_) {
826 0 : if (!HasNext()) {
827 : #if defined (SFNTLY_NO_EXCEPTION)
828 0 : return -1;
829 : #else
830 : throw NoSuchElementException("No more characters to iterate.");
831 : #endif
832 : }
833 : }
834 0 : next_char_set_ = false;
835 0 : return next_char_;
836 : }
837 :
838 : /******************************************************************************
839 : * CMapTable::CMapFormat4::Builder::Segment class
840 : ******************************************************************************/
841 0 : CMapTable::CMapFormat4::Builder::Segment::Segment() {}
842 :
843 0 : CMapTable::CMapFormat4::Builder::Segment::Segment(Segment* other)
844 0 : : start_count_(other->start_count_),
845 0 : end_count_(other->end_count_),
846 0 : id_delta_(other->id_delta_),
847 0 : id_range_offset_(other->id_range_offset_) {
848 0 : }
849 :
850 0 : CMapTable::CMapFormat4::Builder::Segment::Segment(int32_t start_count,
851 : int32_t end_count,
852 : int32_t id_delta,
853 0 : int32_t id_range_offset)
854 : : start_count_(start_count),
855 : end_count_(end_count),
856 : id_delta_(id_delta),
857 0 : id_range_offset_(id_range_offset) {
858 0 : }
859 :
860 0 : CMapTable::CMapFormat4::Builder::Segment::~Segment() {}
861 :
862 0 : int32_t CMapTable::CMapFormat4::Builder::Segment::start_count() {
863 0 : return start_count_;
864 : }
865 :
866 : void
867 0 : CMapTable::CMapFormat4::Builder::Segment::set_start_count(int32_t start_count) {
868 0 : start_count_ = start_count;
869 0 : }
870 :
871 0 : int32_t CMapTable::CMapFormat4::Builder::Segment::end_count() {
872 0 : return end_count_;
873 : }
874 :
875 : void
876 0 : CMapTable::CMapFormat4::Builder::Segment::set_end_count(int32_t end_count) {
877 0 : end_count_ = end_count;
878 0 : }
879 :
880 0 : int32_t CMapTable::CMapFormat4::Builder::Segment::id_delta() {
881 0 : return id_delta_;
882 : }
883 :
884 : void
885 0 : CMapTable::CMapFormat4::Builder::Segment::set_id_delta(int32_t id_delta) {
886 0 : id_delta_ = id_delta;
887 0 : }
888 :
889 0 : int32_t CMapTable::CMapFormat4::Builder::Segment::id_range_offset() {
890 0 : return id_range_offset_;
891 : }
892 :
893 : void
894 0 : CMapTable::CMapFormat4::Builder::Segment::
895 : set_id_range_offset(int32_t id_range_offset) {
896 0 : id_range_offset_ = id_range_offset;
897 0 : }
898 :
899 : // static
900 : CALLER_ATTACH SegmentList*
901 0 : CMapTable::CMapFormat4::Builder::Segment::DeepCopy(SegmentList* original) {
902 0 : SegmentList* list = new SegmentList;
903 0 : for (SegmentList::iterator it = original->begin(),
904 0 : e = original->end(); it != e; ++it) {
905 0 : list->push_back(*it);
906 : }
907 0 : return list;
908 : }
909 :
910 : /******************************************************************************
911 : * CMapTable::CMapFormat4::Builder class
912 : ******************************************************************************/
913 : CALLER_ATTACH CMapTable::CMapFormat4::Builder*
914 0 : CMapTable::CMapFormat4::Builder::NewInstance(ReadableFontData* data,
915 : int32_t offset,
916 : const CMapId& cmap_id) {
917 0 : ReadableFontDataPtr rdata;
918 0 : if (data) {
919 : rdata.Attach
920 0 : (down_cast<ReadableFontData*>
921 : (data->Slice(offset,
922 0 : data->ReadUShort(offset + Offset::kFormat4Length))));
923 : }
924 0 : return new Builder(rdata, CMapFormat::kFormat4, cmap_id);
925 : }
926 :
927 : CALLER_ATTACH CMapTable::CMapFormat4::Builder*
928 0 : CMapTable::CMapFormat4::Builder::NewInstance(WritableFontData* data,
929 : int32_t offset,
930 : const CMapId& cmap_id) {
931 0 : WritableFontDataPtr wdata;
932 0 : if (data) {
933 : wdata.Attach
934 0 : (down_cast<WritableFontData*>
935 : (data->Slice(offset,
936 0 : data->ReadUShort(offset + Offset::kFormat4Length))));
937 : }
938 0 : return new Builder(wdata, CMapFormat::kFormat4, cmap_id);
939 : }
940 :
941 : CALLER_ATTACH CMapTable::CMapFormat4::Builder*
942 0 : CMapTable::CMapFormat4::Builder::NewInstance(const CMapId& cmap_id) {
943 0 : return new Builder(cmap_id);
944 : }
945 :
946 0 : CMapTable::CMapFormat4::Builder::Builder(ReadableFontData* data, int32_t offset,
947 0 : const CMapId& cmap_id)
948 0 : : CMap::Builder(data, CMapFormat::kFormat4, cmap_id) {
949 : UNREFERENCED_PARAMETER(offset);
950 0 : }
951 :
952 0 : CMapTable::CMapFormat4::Builder::Builder(WritableFontData* data, int32_t offset,
953 0 : const CMapId& cmap_id)
954 0 : : CMap::Builder(data, CMapFormat::kFormat4, cmap_id) {
955 : UNREFERENCED_PARAMETER(offset);
956 0 : }
957 :
958 0 : CMapTable::CMapFormat4::Builder::Builder(SegmentList* segments,
959 : IntegerList* glyph_id_array,
960 0 : const CMapId& cmap_id)
961 : : CMap::Builder(static_cast<ReadableFontData*>(NULL),
962 : CMapFormat::kFormat4, cmap_id),
963 : segments_(segments->begin(), segments->end()),
964 0 : glyph_id_array_(glyph_id_array->begin(), glyph_id_array->end()) {
965 0 : set_model_changed();
966 0 : }
967 :
968 0 : CMapTable::CMapFormat4::Builder::Builder(const CMapId& cmap_id)
969 : : CMap::Builder(static_cast<ReadableFontData*>(NULL),
970 0 : CMapFormat::kFormat4, cmap_id) {
971 0 : }
972 :
973 0 : CMapTable::CMapFormat4::Builder::~Builder() {}
974 :
975 0 : void CMapTable::CMapFormat4::Builder::Initialize(ReadableFontData* data) {
976 0 : if (data == NULL || data->Length() == 0)
977 0 : return;
978 :
979 : // build segments
980 0 : int32_t seg_count = CMapFormat4::SegCount(data);
981 0 : for (int32_t index = 0; index < seg_count; ++index) {
982 0 : Ptr<Segment> segment = new Segment;
983 0 : segment->set_start_count(CMapFormat4::StartCode(data, seg_count, index));
984 : #if defined SFNTLY_DEBUG_CMAP
985 : fprintf(stderr, "Segment %d; start %d\n", index, segment->start_count());
986 : #endif
987 0 : segment->set_end_count(CMapFormat4::EndCode(data, seg_count, index));
988 0 : segment->set_id_delta(CMapFormat4::IdDelta(data, seg_count, index));
989 0 : segment->set_id_range_offset(CMapFormat4::IdRangeOffset(data,
990 : seg_count,
991 0 : index));
992 0 : segments_.push_back(segment);
993 : }
994 :
995 : // build glyph id array
996 0 : int32_t glyph_id_array_offset = CMapFormat4::GlyphIdArrayOffset(seg_count);
997 : int32_t glyph_id_array_length =
998 0 : (CMapFormat4::Length(data) - glyph_id_array_offset)
999 0 : / DataSize::kUSHORT;
1000 0 : fprintf(stderr, "id array size %d\n", glyph_id_array_length);
1001 0 : for (int32_t i = 0; i < glyph_id_array_length; i += DataSize::kUSHORT) {
1002 0 : glyph_id_array_.push_back(data->ReadUShort(glyph_id_array_offset + i));
1003 : }
1004 : }
1005 :
1006 0 : SegmentList* CMapTable::CMapFormat4::Builder::segments() {
1007 0 : if (segments_.empty()) {
1008 0 : Initialize(InternalReadData());
1009 0 : set_model_changed();
1010 : }
1011 0 : return &segments_;
1012 : }
1013 :
1014 0 : void CMapTable::CMapFormat4::Builder::set_segments(SegmentList* segments) {
1015 0 : segments_.assign(segments->begin(), segments->end());
1016 0 : set_model_changed();
1017 0 : }
1018 :
1019 0 : IntegerList* CMapTable::CMapFormat4::Builder::glyph_id_array() {
1020 0 : if (glyph_id_array_.empty()) {
1021 0 : Initialize(InternalReadData());
1022 0 : set_model_changed();
1023 : }
1024 0 : return &glyph_id_array_;
1025 : }
1026 :
1027 0 : void CMapTable::CMapFormat4::Builder::
1028 : set_glyph_id_array(IntegerList* glyph_id_array) {
1029 0 : glyph_id_array_.assign(glyph_id_array->begin(), glyph_id_array->end());
1030 0 : set_model_changed();
1031 0 : }
1032 :
1033 : CALLER_ATTACH FontDataTable*
1034 0 : CMapTable::CMapFormat4::Builder::SubBuildTable(ReadableFontData* data) {
1035 0 : FontDataTablePtr table = new CMapFormat4(data, cmap_id());
1036 0 : return table.Detach();
1037 : }
1038 :
1039 0 : void CMapTable::CMapFormat4::Builder::SubDataSet() {
1040 0 : segments_.clear();
1041 0 : glyph_id_array_.clear();
1042 0 : set_model_changed();
1043 0 : }
1044 :
1045 0 : int32_t CMapTable::CMapFormat4::Builder::SubDataSizeToSerialize() {
1046 0 : if (!model_changed()) {
1047 0 : return CMap::Builder::SubDataSizeToSerialize();
1048 : }
1049 0 : int32_t size = Offset::kFormat4FixedSize + segments_.size()
1050 : * (3 * DataSize::kUSHORT + DataSize::kSHORT)
1051 0 : + glyph_id_array_.size() * DataSize::kSHORT;
1052 0 : return size;
1053 : }
1054 :
1055 0 : bool CMapTable::CMapFormat4::Builder::SubReadyToSerialize() {
1056 0 : if (!model_changed()) {
1057 0 : return CMap::Builder::SubReadyToSerialize();
1058 : }
1059 0 : if (!segments()->empty()) {
1060 0 : return true;
1061 : }
1062 0 : return false;
1063 : }
1064 :
1065 : int32_t
1066 0 : CMapTable::CMapFormat4::Builder::SubSerialize(WritableFontData* new_data) {
1067 0 : if (!model_changed()) {
1068 0 : return CMap::Builder::SubSerialize(new_data);
1069 : }
1070 0 : int32_t index = 0;
1071 0 : index += new_data->WriteUShort(index, CMapFormat::kFormat4);
1072 0 : index += DataSize::kUSHORT; // length - write this at the end
1073 0 : index += new_data->WriteUShort(index, language());
1074 :
1075 0 : int32_t seg_count = segments_.size();
1076 0 : index += new_data->WriteUShort(index, seg_count * 2);
1077 0 : int32_t log2_seg_count = FontMath::Log2(seg_count);
1078 0 : int32_t search_range = 1 << (log2_seg_count + 1);
1079 0 : index += new_data->WriteUShort(index, search_range);
1080 0 : int32_t entry_selector = log2_seg_count;
1081 0 : index += new_data->WriteUShort(index, entry_selector);
1082 0 : int32_t range_shift = 2 * seg_count - search_range;
1083 0 : index += new_data->WriteUShort(index, range_shift);
1084 :
1085 0 : for (int32_t i = 0; i < seg_count; ++i) {
1086 0 : index += new_data->WriteUShort(index, segments_[i]->end_count());
1087 : }
1088 0 : index += new_data->WriteUShort(index, 0); // reserved ushort
1089 0 : for (int32_t i = 0; i < seg_count; ++i) {
1090 : #if defined SFNTLY_DEBUG_CMAP
1091 : fprintf(stderr, "Segment %d; start %d\n", i, segments_[i]->start_count());
1092 : #endif
1093 0 : index += new_data->WriteUShort(index, segments_[i]->start_count());
1094 : }
1095 0 : for (int32_t i = 0; i < seg_count; ++i) {
1096 0 : index += new_data->WriteShort(index, segments_[i]->id_delta());
1097 : }
1098 0 : for (int32_t i = 0; i < seg_count; ++i) {
1099 0 : index += new_data->WriteUShort(index, segments_[i]->id_range_offset());
1100 : }
1101 :
1102 : #if defined SFNTLY_DEBUG_CMAP
1103 : fprintf(stderr, "Glyph id array size %lu\n", glyph_id_array_.size());
1104 : #endif
1105 0 : for (size_t i = 0; i < glyph_id_array_.size(); ++i) {
1106 0 : index += new_data->WriteUShort(index, glyph_id_array_[i]);
1107 : }
1108 :
1109 0 : new_data->WriteUShort(Offset::kFormat4Length, index);
1110 0 : return index;
1111 : }
1112 :
1113 : /******************************************************************************
1114 : * CMapTable::Builder class
1115 : ******************************************************************************/
1116 0 : CMapTable::Builder::Builder(Header* header, WritableFontData* data)
1117 0 : : SubTableContainerTable::Builder(header, data), version_(0) {
1118 0 : }
1119 :
1120 0 : CMapTable::Builder::Builder(Header* header, ReadableFontData* data)
1121 0 : : SubTableContainerTable::Builder(header, data), version_(0) {
1122 0 : }
1123 :
1124 0 : CMapTable::Builder::~Builder() {
1125 0 : }
1126 :
1127 0 : int32_t CMapTable::Builder::SubSerialize(WritableFontData* new_data) {
1128 0 : int32_t size = new_data->WriteUShort(CMapTable::Offset::kVersion,
1129 0 : version_);
1130 0 : size += new_data->WriteUShort(CMapTable::Offset::kNumTables,
1131 0 : GetCMapBuilders()->size());
1132 :
1133 0 : int32_t index_offset = size;
1134 0 : size += GetCMapBuilders()->size() * CMapTable::Offset::kEncodingRecordSize;
1135 0 : for (CMapBuilderMap::iterator it = GetCMapBuilders()->begin(),
1136 0 : e = GetCMapBuilders()->end(); it != e; ++it) {
1137 0 : CMapBuilderPtr b = it->second;
1138 : // header entry
1139 0 : index_offset += new_data->WriteUShort(index_offset, b->platform_id());
1140 0 : index_offset += new_data->WriteUShort(index_offset, b->encoding_id());
1141 0 : index_offset += new_data->WriteULong(index_offset, size);
1142 :
1143 : // cmap
1144 0 : FontDataPtr slice;
1145 0 : slice.Attach(new_data->Slice(size));
1146 0 : size += b->SubSerialize(down_cast<WritableFontData*>(slice.p_));
1147 : }
1148 0 : return size;
1149 : }
1150 :
1151 0 : bool CMapTable::Builder::SubReadyToSerialize() {
1152 0 : if (GetCMapBuilders()->empty())
1153 0 : return false;
1154 :
1155 : // check each table
1156 0 : for (CMapBuilderMap::iterator it = GetCMapBuilders()->begin(),
1157 0 : e = GetCMapBuilders()->end(); it != e; ++it) {
1158 0 : if (!it->second->SubReadyToSerialize())
1159 0 : return false;
1160 : }
1161 0 : return true;
1162 : }
1163 :
1164 0 : int32_t CMapTable::Builder::SubDataSizeToSerialize() {
1165 0 : if (GetCMapBuilders()->empty())
1166 0 : return 0;
1167 :
1168 0 : bool variable = false;
1169 0 : int32_t size = CMapTable::Offset::kEncodingRecordStart +
1170 0 : GetCMapBuilders()->size() * CMapTable::Offset::kEncodingRecordSize;
1171 :
1172 : // calculate size of each table
1173 0 : for (CMapBuilderMap::iterator it = GetCMapBuilders()->begin(),
1174 0 : e = GetCMapBuilders()->end(); it != e; ++it) {
1175 0 : int32_t cmap_size = it->second->SubDataSizeToSerialize();
1176 0 : size += abs(cmap_size);
1177 0 : variable |= cmap_size <= 0;
1178 : }
1179 0 : return variable ? -size : size;
1180 : }
1181 :
1182 0 : void CMapTable::Builder::SubDataSet() {
1183 0 : GetCMapBuilders()->clear();
1184 0 : Table::Builder::set_model_changed();
1185 0 : }
1186 :
1187 : CALLER_ATTACH FontDataTable*
1188 0 : CMapTable::Builder::SubBuildTable(ReadableFontData* data) {
1189 0 : FontDataTablePtr table = new CMapTable(header(), data);
1190 0 : return table.Detach();
1191 : }
1192 :
1193 : CALLER_ATTACH CMapTable::Builder*
1194 0 : CMapTable::Builder::CreateBuilder(Header* header,
1195 : WritableFontData* data) {
1196 0 : Ptr<CMapTable::Builder> builder;
1197 0 : builder = new CMapTable::Builder(header, data);
1198 0 : return builder.Detach();
1199 : }
1200 :
1201 : // static
1202 : CALLER_ATTACH CMapTable::CMap::Builder*
1203 0 : CMapTable::Builder::CMapBuilder(ReadableFontData* data, int32_t index) {
1204 0 : if (index < 0 || index > NumCMaps(data)) {
1205 : #if !defined (SFNTLY_NO_EXCEPTION)
1206 : throw IndexOutOfBoundException(
1207 : "CMap table is outside of the bounds of the known tables.");
1208 : #endif
1209 0 : return NULL;
1210 : }
1211 :
1212 0 : int32_t platform_id = data->ReadUShort(Offset::kEncodingRecordPlatformId +
1213 0 : OffsetForEncodingRecord(index));
1214 0 : int32_t encoding_id = data->ReadUShort(Offset::kEncodingRecordEncodingId +
1215 0 : OffsetForEncodingRecord(index));
1216 0 : int32_t offset = data->ReadULongAsInt(Offset::kEncodingRecordOffset +
1217 0 : OffsetForEncodingRecord(index));
1218 : return CMap::Builder::GetBuilder(data, offset,
1219 0 : NewCMapId(platform_id, encoding_id));
1220 : }
1221 :
1222 : // static
1223 0 : int32_t CMapTable::Builder::NumCMaps(ReadableFontData* data) {
1224 0 : if (data == NULL) {
1225 0 : return 0;
1226 : }
1227 0 : return data->ReadUShort(Offset::kNumTables);
1228 : }
1229 :
1230 0 : int32_t CMapTable::Builder::NumCMaps() {
1231 0 : return GetCMapBuilders()->size();
1232 : }
1233 :
1234 0 : void CMapTable::Builder::Initialize(ReadableFontData* data) {
1235 0 : int32_t num_cmaps = NumCMaps(data);
1236 0 : for (int32_t i = 0; i < num_cmaps; ++i) {
1237 0 : CMapTable::CMap::Builder* cmap_builder = CMapBuilder(data, i);
1238 0 : if (!cmap_builder)
1239 0 : continue;
1240 0 : cmap_builders_[cmap_builder->cmap_id()] = cmap_builder;
1241 : }
1242 0 : }
1243 :
1244 0 : CMapTable::CMap::Builder* CMapTable::Builder::NewCMapBuilder(
1245 : const CMapId& cmap_id,
1246 : ReadableFontData* data) {
1247 0 : Ptr<WritableFontData> wfd;
1248 0 : wfd.Attach(WritableFontData::CreateWritableFontData(data->Size()));
1249 0 : data->CopyTo(wfd.p_);
1250 0 : CMapTable::CMapBuilderPtr builder;
1251 0 : builder.Attach(CMap::Builder::GetBuilder(wfd.p_, 0, cmap_id));
1252 0 : CMapBuilderMap* cmap_builders = CMapTable::Builder::GetCMapBuilders();
1253 0 : cmap_builders->insert(std::make_pair(cmap_id, builder.p_));
1254 0 : return builder.Detach();
1255 : }
1256 :
1257 : CMapTable::CMap::Builder*
1258 0 : CMapTable::Builder::NewCMapBuilder(int32_t format, const CMapId& cmap_id) {
1259 0 : Ptr<CMapTable::CMap::Builder> cmap_builder;
1260 0 : cmap_builder.Attach(CMap::Builder::GetBuilder(format, cmap_id));
1261 0 : CMapBuilderMap* cmap_builders = CMapTable::Builder::GetCMapBuilders();
1262 0 : cmap_builders->insert(std::make_pair(cmap_id, cmap_builder.p_));
1263 0 : return cmap_builder.Detach();
1264 : }
1265 :
1266 : CMapTable::CMap::Builder*
1267 0 : CMapTable::Builder::CMapBuilder(const CMapId& cmap_id) {
1268 0 : CMapBuilderMap* cmap_builders = this->GetCMapBuilders();
1269 0 : CMapBuilderMap::iterator builder = cmap_builders->find(cmap_id);
1270 0 : if (builder != cmap_builders->end())
1271 0 : return builder->second;
1272 : #ifndef SFNTLY_NO_EXCEPTION
1273 : throw NoSuchElementException("No builder found for cmap_id");
1274 : #else
1275 0 : return NULL;
1276 : #endif
1277 : }
1278 :
1279 0 : CMapTable::CMapBuilderMap* CMapTable::Builder::GetCMapBuilders() {
1280 0 : if (cmap_builders_.empty()) {
1281 0 : Initialize(InternalReadData());
1282 0 : set_model_changed();
1283 : }
1284 0 : return &cmap_builders_;
1285 : }
1286 :
1287 : } // namespace sfntly
|