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