LCOV - code coverage report
Current view: top level - gfx/sfntly/cpp/src/sfntly/table/core - cmap_table.cc (source / functions) Hit Total Coverage
Test: output.info Lines: 0 649 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 185 0.0 %
Legend: Lines: hit not hit

          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

Generated by: LCOV version 1.13