Home | History | Annotate | Download | only in bitmap
      1 /*
      2  * Copyright 2011 Google Inc. All Rights Reserved.
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include "sfntly/table/bitmap/index_sub_table_format4.h"
     18 
     19 #include "sfntly/table/bitmap/eblc_table.h"
     20 
     21 namespace sfntly {
     22 /******************************************************************************
     23  * IndexSubTableFormat4 class
     24  ******************************************************************************/
     25 IndexSubTableFormat4::~IndexSubTableFormat4() {
     26 }
     27 
     28 int32_t IndexSubTableFormat4::NumGlyphs() {
     29   return IndexSubTableFormat4::NumGlyphs(data_, 0);
     30 }
     31 
     32 int32_t IndexSubTableFormat4::GlyphStartOffset(int32_t glyph_id) {
     33   int32_t loca = CheckGlyphRange(glyph_id);
     34   if (loca == -1) {
     35     return -1;
     36   }
     37   int32_t pair_index = FindCodeOffsetPair(glyph_id);
     38   if (pair_index < 0) {
     39     return -1;
     40   }
     41   return data_->ReadUShort(EblcTable::Offset::kIndexSubTable4_glyphArray +
     42                            pair_index *
     43                            EblcTable::Offset::kCodeOffsetPairLength +
     44                            EblcTable::Offset::kCodeOffsetPair_offset);
     45 }
     46 
     47 int32_t IndexSubTableFormat4::GlyphLength(int32_t glyph_id) {
     48   int32_t loca = CheckGlyphRange(glyph_id);
     49   if (loca == -1) {
     50     return -1;
     51   }
     52 
     53   int32_t pair_index = FindCodeOffsetPair(glyph_id);
     54   if (pair_index < 0) {
     55     return -1;
     56   }
     57   return data_->ReadUShort(
     58              EblcTable::Offset::kIndexSubTable4_glyphArray +
     59              (pair_index + 1) * EblcTable::Offset::kCodeOffsetPairLength +
     60              EblcTable::Offset::kCodeOffsetPair_offset) -
     61          data_->ReadUShort(
     62              EblcTable::Offset::kIndexSubTable4_glyphArray +
     63              (pair_index) * EblcTable::Offset::kCodeOffsetPairLength +
     64              EblcTable::Offset::kCodeOffsetPair_offset);
     65 }
     66 
     67 IndexSubTableFormat4::IndexSubTableFormat4(ReadableFontData* data,
     68                                            int32_t first,
     69                                            int32_t last)
     70     : IndexSubTable(data, first, last) {
     71 }
     72 
     73 int32_t IndexSubTableFormat4::FindCodeOffsetPair(int32_t glyph_id) {
     74   return data_->SearchUShort(EblcTable::Offset::kIndexSubTable4_glyphArray,
     75                              EblcTable::Offset::kCodeOffsetPairLength,
     76                              NumGlyphs(),
     77                              glyph_id);
     78 }
     79 
     80 int32_t IndexSubTableFormat4::NumGlyphs(ReadableFontData* data,
     81                                         int32_t table_offset) {
     82   int32_t num_glyphs = data->ReadULongAsInt(table_offset +
     83       EblcTable::Offset::kIndexSubTable4_numGlyphs);
     84   return num_glyphs;
     85 }
     86 
     87 /******************************************************************************
     88  * IndexSubTableFormat4::CodeOffsetPair related class
     89  ******************************************************************************/
     90 IndexSubTableFormat4::CodeOffsetPair::CodeOffsetPair(int32_t glyph_code,
     91                                                      int32_t offset)
     92     : glyph_code_(glyph_code), offset_(offset) {
     93 }
     94 
     95 IndexSubTableFormat4::CodeOffsetPairBuilder::CodeOffsetPairBuilder()
     96     : CodeOffsetPair(0, 0) {
     97 }
     98 
     99 IndexSubTableFormat4::CodeOffsetPairBuilder::CodeOffsetPairBuilder(
    100     int32_t glyph_code, int32_t offset)
    101     : CodeOffsetPair(glyph_code, offset) {
    102 }
    103 
    104 bool IndexSubTableFormat4::CodeOffsetPairGlyphCodeComparator::operator()(
    105     const CodeOffsetPair& lhs, const CodeOffsetPair& rhs) {
    106   return lhs.glyph_code() < rhs.glyph_code();
    107 }
    108 
    109 /******************************************************************************
    110  * IndexSubTableFormat4::Builder class
    111  ******************************************************************************/
    112 IndexSubTableFormat4::Builder::~Builder() {
    113 }
    114 
    115 int32_t IndexSubTableFormat4::Builder::NumGlyphs() {
    116   return GetOffsetArray()->size() - 1;
    117 }
    118 
    119 int32_t IndexSubTableFormat4::Builder::GlyphLength(int32_t glyph_id) {
    120   int32_t loca = CheckGlyphRange(glyph_id);
    121   if (loca == -1) {
    122     return 0;
    123   }
    124   int32_t pair_index = FindCodeOffsetPair(glyph_id);
    125   if (pair_index == -1) {
    126     return 0;
    127   }
    128   return GetOffsetArray()->at(pair_index + 1).offset() -
    129          GetOffsetArray()->at(pair_index).offset();
    130 }
    131 
    132 int32_t IndexSubTableFormat4::Builder::GlyphStartOffset(int32_t glyph_id) {
    133   int32_t loca = CheckGlyphRange(glyph_id);
    134   if (loca == -1) {
    135     return -1;
    136   }
    137   int32_t pair_index = FindCodeOffsetPair(glyph_id);
    138   if (pair_index == -1) {
    139     return -1;
    140   }
    141   return GetOffsetArray()->at(pair_index).offset();
    142 }
    143 
    144 CALLER_ATTACH IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator*
    145     IndexSubTableFormat4::Builder::GetIterator() {
    146   Ptr<IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator> it =
    147       new IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator(this);
    148   return it.Detach();
    149 }
    150 
    151 // static
    152 CALLER_ATTACH IndexSubTableFormat4::Builder*
    153 IndexSubTableFormat4::Builder::CreateBuilder() {
    154   IndexSubTableFormat4BuilderPtr output = new IndexSubTableFormat4::Builder();
    155   return output.Detach();
    156 }
    157 
    158 // static
    159 CALLER_ATTACH IndexSubTableFormat4::Builder*
    160 IndexSubTableFormat4::Builder::CreateBuilder(ReadableFontData* data,
    161                                              int32_t index_sub_table_offset,
    162                                              int32_t first_glyph_index,
    163                                              int32_t last_glyph_index) {
    164   int32_t length = Builder::DataLength(data,
    165                                        index_sub_table_offset,
    166                                        first_glyph_index,
    167                                        last_glyph_index);
    168   ReadableFontDataPtr new_data;
    169   new_data.Attach(down_cast<ReadableFontData*>(
    170       data->Slice(index_sub_table_offset, length)));
    171   if (new_data == NULL) {
    172     return NULL;
    173   }
    174   IndexSubTableFormat4BuilderPtr output =
    175       new IndexSubTableFormat4::Builder(new_data,
    176                                         first_glyph_index,
    177                                         last_glyph_index);
    178   return output.Detach();
    179 }
    180 
    181 // static
    182 CALLER_ATTACH IndexSubTableFormat4::Builder*
    183 IndexSubTableFormat4::Builder::CreateBuilder(WritableFontData* data,
    184                                              int32_t index_sub_table_offset,
    185                                              int32_t first_glyph_index,
    186                                              int32_t last_glyph_index) {
    187   int32_t length = Builder::DataLength(data,
    188                                        index_sub_table_offset,
    189                                        first_glyph_index,
    190                                        last_glyph_index);
    191   WritableFontDataPtr new_data;
    192   new_data.Attach(down_cast<WritableFontData*>(
    193       data->Slice(index_sub_table_offset, length)));
    194   IndexSubTableFormat4BuilderPtr output =
    195       new IndexSubTableFormat4::Builder(new_data,
    196                                         first_glyph_index,
    197                                         last_glyph_index);
    198   return output.Detach();
    199 }
    200 
    201 CALLER_ATTACH FontDataTable* IndexSubTableFormat4::Builder::SubBuildTable(
    202     ReadableFontData* data) {
    203   IndexSubTableFormat4Ptr output = new IndexSubTableFormat4(
    204       data, first_glyph_index(), last_glyph_index());
    205   return output.Detach();
    206 }
    207 
    208 void IndexSubTableFormat4::Builder::SubDataSet() {
    209   Revert();
    210 }
    211 
    212 int32_t IndexSubTableFormat4::Builder::SubDataSizeToSerialize() {
    213   if (offset_pair_array_.empty()) {
    214     return InternalReadData()->Length();
    215   }
    216   return EblcTable::Offset::kIndexSubHeaderLength + DataSize::kULONG +
    217          GetOffsetArray()->size() *
    218          EblcTable::Offset::kIndexSubTable4_codeOffsetPairLength;
    219 }
    220 
    221 bool IndexSubTableFormat4::Builder::SubReadyToSerialize() {
    222   if (!offset_pair_array_.empty()) {
    223     return true;
    224   }
    225   return false;
    226 }
    227 
    228 int32_t IndexSubTableFormat4::Builder::SubSerialize(
    229     WritableFontData* new_data) {
    230   int32_t size = SerializeIndexSubHeader(new_data);
    231   if (!model_changed()) {
    232     if (InternalReadData() == NULL) {
    233       return size;
    234     }
    235     ReadableFontDataPtr source;
    236     WritableFontDataPtr target;
    237     source.Attach(down_cast<ReadableFontData*>(InternalReadData()->Slice(
    238         EblcTable::Offset::kIndexSubTable4_glyphArray)));
    239     target.Attach(down_cast<WritableFontData*>(new_data->Slice(
    240         EblcTable::Offset::kIndexSubTable4_glyphArray)));
    241     size += source->CopyTo(target);
    242   } else {
    243     size += new_data->WriteLong(size, offset_pair_array_.size() - 1);
    244     for (std::vector<CodeOffsetPairBuilder>::iterator
    245              b = GetOffsetArray()->begin(), e = GetOffsetArray()->end();
    246              b != e; b++) {
    247       size += new_data->WriteUShort(size, b->glyph_code());
    248       size += new_data->WriteUShort(size, b->offset());
    249     }
    250   }
    251   return size;
    252 }
    253 
    254 void IndexSubTableFormat4::Builder::Revert() {
    255   offset_pair_array_.clear();
    256   IndexSubTable::Builder::Revert();
    257 }
    258 
    259 void IndexSubTableFormat4::Builder::SetOffsetArray(
    260     const std::vector<CodeOffsetPairBuilder>& pair_array) {
    261   offset_pair_array_.clear();
    262   offset_pair_array_ = pair_array;
    263   set_model_changed();
    264 }
    265 
    266 IndexSubTableFormat4::Builder::Builder()
    267   : IndexSubTable::Builder(EblcTable::Offset::kIndexSubTable4_builderDataSize,
    268                            Format::FORMAT_4) {
    269 }
    270 
    271 IndexSubTableFormat4::Builder::Builder(WritableFontData* data,
    272                                        int32_t first_glyph_index,
    273                                        int32_t last_glyph_index)
    274     : IndexSubTable::Builder(data, first_glyph_index, last_glyph_index) {
    275 }
    276 
    277 IndexSubTableFormat4::Builder::Builder(ReadableFontData* data,
    278                                        int32_t first_glyph_index,
    279                                        int32_t last_glyph_index)
    280     : IndexSubTable::Builder(data, first_glyph_index, last_glyph_index) {
    281 }
    282 
    283 std::vector<IndexSubTableFormat4::CodeOffsetPairBuilder>*
    284 IndexSubTableFormat4::Builder::GetOffsetArray() {
    285   if (offset_pair_array_.empty()) {
    286     Initialize(InternalReadData());
    287     set_model_changed();
    288   }
    289   return &offset_pair_array_;
    290 }
    291 
    292 void IndexSubTableFormat4::Builder::Initialize(ReadableFontData* data) {
    293   offset_pair_array_.clear();
    294   if (data) {
    295     int32_t num_pairs = IndexSubTableFormat4::NumGlyphs(data, 0) + 1;
    296     int32_t offset = EblcTable::Offset::kIndexSubTable4_glyphArray;
    297     for (int32_t i = 0; i < num_pairs; ++i) {
    298       int32_t glyph_code = data->ReadUShort(offset +
    299           EblcTable::Offset::kIndexSubTable4_codeOffsetPair_glyphCode);
    300       int32_t glyph_offset = data->ReadUShort(offset +
    301           EblcTable::Offset::kIndexSubTable4_codeOffsetPair_offset);
    302       offset += EblcTable::Offset::kIndexSubTable4_codeOffsetPairLength;
    303       CodeOffsetPairBuilder pair_builder(glyph_code, glyph_offset);
    304       offset_pair_array_.push_back(pair_builder);
    305     }
    306   }
    307 }
    308 
    309 int32_t IndexSubTableFormat4::Builder::FindCodeOffsetPair(int32_t glyph_id) {
    310   std::vector<CodeOffsetPairBuilder>* pair_list = GetOffsetArray();
    311   int32_t location = 0;
    312   int32_t bottom = 0;
    313   int32_t top = pair_list->size();
    314   while (top != bottom) {
    315     location = (top + bottom) / 2;
    316     CodeOffsetPairBuilder* pair = &(pair_list->at(location));
    317     if (glyph_id < pair->glyph_code()) {
    318       // location is below current location
    319       top = location;
    320     } else if (glyph_id > pair->glyph_code()) {
    321       // location is above current location
    322       bottom = location + 1;
    323     } else {
    324       return location;
    325     }
    326   }
    327   return -1;
    328 }
    329 
    330 // static
    331 int32_t IndexSubTableFormat4::Builder::DataLength(
    332     ReadableFontData* data,
    333     int32_t index_sub_table_offset,
    334     int32_t first_glyph_index,
    335     int32_t last_glyph_index) {
    336   int32_t num_glyphs = IndexSubTableFormat4::NumGlyphs(data,
    337                                                        index_sub_table_offset);
    338   UNREFERENCED_PARAMETER(first_glyph_index);
    339   UNREFERENCED_PARAMETER(last_glyph_index);
    340   return EblcTable::Offset::kIndexSubTable4_glyphArray +
    341          num_glyphs * EblcTable::Offset::kIndexSubTable4_codeOffsetPair_offset;
    342 }
    343 
    344 
    345 /******************************************************************************
    346  * IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator class
    347  ******************************************************************************/
    348 IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator::BitmapGlyphInfoIterator(
    349     IndexSubTableFormat4::Builder* container)
    350     : RefIterator<BitmapGlyphInfo, IndexSubTableFormat4::Builder,
    351                   IndexSubTable::Builder>(container),
    352       code_offset_pair_index_(0) {
    353 }
    354 
    355 bool IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator::HasNext() {
    356   if (code_offset_pair_index_ <
    357       (int32_t)(container()->GetOffsetArray()->size() - 1)) {
    358     return true;
    359   }
    360   return false;
    361 }
    362 
    363 CALLER_ATTACH BitmapGlyphInfo*
    364 IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator::Next() {
    365   BitmapGlyphInfoPtr output;
    366   if (!HasNext()) {
    367     // Note: In C++, we do not throw exception when there's no element.
    368     return NULL;
    369   }
    370   std::vector<CodeOffsetPairBuilder>* offset_array =
    371       container()->GetOffsetArray();
    372   int32_t offset = offset_array->at(code_offset_pair_index_).offset();
    373   int32_t next_offset = offset_array->at(code_offset_pair_index_ + 1).offset();
    374   int32_t glyph_code = offset_array->at(code_offset_pair_index_).glyph_code();
    375   output = new BitmapGlyphInfo(glyph_code,
    376                                container()->image_data_offset(),
    377                                offset,
    378                                next_offset - offset,
    379                                container()->image_format());
    380   code_offset_pair_index_++;
    381   return output.Detach();
    382 }
    383 
    384 }  // namespace sfntly
    385