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_format5.h" 18 19#include <algorithm> 20 21#include "sfntly/table/bitmap/eblc_table.h" 22 23namespace sfntly { 24/****************************************************************************** 25 * IndexSubTableFormat5 class 26 ******************************************************************************/ 27IndexSubTableFormat5::~IndexSubTableFormat5() { 28} 29 30int32_t IndexSubTableFormat5::NumGlyphs() { 31 return NumGlyphs(data_, 0); 32} 33 34int32_t IndexSubTableFormat5::GlyphStartOffset(int32_t glyph_id) { 35 int32_t check = CheckGlyphRange(glyph_id); 36 if (check == -1) { 37 return -1; 38 } 39 int32_t loca = ReadFontData()->SearchUShort( 40 EblcTable::Offset::kIndexSubTable5_glyphArray, 41 DataSize::kUSHORT, 42 NumGlyphs(), 43 glyph_id); 44 if (loca == -1) { 45 return loca; 46 } 47 return loca * ImageSize(); 48} 49 50int32_t IndexSubTableFormat5::GlyphLength(int32_t glyph_id) { 51 int32_t check = CheckGlyphRange(glyph_id); 52 if (check == -1) { 53 return 0; 54 } 55 return image_size_; 56} 57 58int32_t IndexSubTableFormat5::ImageSize() { 59 return data_->ReadULongAsInt(EblcTable::Offset::kIndexSubTable5_imageSize); 60} 61 62CALLER_ATTACH BigGlyphMetrics* IndexSubTableFormat5::BigMetrics() { 63 ReadableFontDataPtr data; 64 data.Attach(down_cast<ReadableFontData*>(data_->Slice( 65 EblcTable::Offset::kIndexSubTable5_bigGlyphMetrics, 66 BigGlyphMetrics::Offset::kMetricsLength))); 67 BigGlyphMetricsPtr output = new BigGlyphMetrics(data); 68 return output.Detach(); 69} 70 71IndexSubTableFormat5::IndexSubTableFormat5(ReadableFontData* data, 72 int32_t first_glyph_index, 73 int32_t last_glyph_index) 74 : IndexSubTable(data, first_glyph_index, last_glyph_index) { 75 image_size_ = data_->ReadULongAsInt( 76 EblcTable::Offset::kIndexSubTable5_imageSize); 77} 78 79// static 80int32_t IndexSubTableFormat5::NumGlyphs(ReadableFontData* data, 81 int32_t table_offset) { 82 int32_t num_glyphs = data->ReadULongAsInt(table_offset + 83 EblcTable::Offset::kIndexSubTable5_numGlyphs); 84 return num_glyphs; 85} 86 87/****************************************************************************** 88 * IndexSubTableFormat5::Builder class 89 ******************************************************************************/ 90IndexSubTableFormat5::Builder::~Builder() { 91} 92 93int32_t IndexSubTableFormat5::Builder::NumGlyphs() { 94 return GetGlyphArray()->size(); 95} 96 97int32_t IndexSubTableFormat5::Builder::GlyphLength(int32_t glyph_id) { 98 UNREFERENCED_PARAMETER(glyph_id); 99 return ImageSize(); 100} 101 102int32_t IndexSubTableFormat5::Builder::GlyphStartOffset(int32_t glyph_id) { 103 int32_t check = CheckGlyphRange(glyph_id); 104 if (check == -1) { 105 return -1; 106 } 107 IntegerList* glyph_array = GetGlyphArray(); 108 IntegerList::iterator it = std::find(glyph_array->begin(), 109 glyph_array->end(), 110 glyph_id); 111 if (it == glyph_array->end()) { 112 return -1; 113 } 114 return (it - glyph_array->begin()) * ImageSize(); 115} 116 117CALLER_ATTACH IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator* 118 IndexSubTableFormat5::Builder::GetIterator() { 119 Ptr<IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator> it = 120 new IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator(this); 121 return it.Detach(); 122} 123 124// static 125CALLER_ATTACH IndexSubTableFormat5::Builder* 126IndexSubTableFormat5::Builder::CreateBuilder() { 127 IndexSubTableFormat5BuilderPtr output = new IndexSubTableFormat5::Builder(); 128 return output.Detach(); 129} 130 131// static 132CALLER_ATTACH IndexSubTableFormat5::Builder* 133IndexSubTableFormat5::Builder::CreateBuilder(ReadableFontData* data, 134 int32_t index_sub_table_offset, 135 int32_t first_glyph_index, 136 int32_t last_glyph_index) { 137 int32_t length = Builder::DataLength(data, 138 index_sub_table_offset, 139 first_glyph_index, 140 last_glyph_index); 141 ReadableFontDataPtr new_data; 142 new_data.Attach(down_cast<ReadableFontData*>( 143 data->Slice(index_sub_table_offset, length))); 144 if (new_data == NULL) { 145 return NULL; 146 } 147 IndexSubTableFormat5BuilderPtr output = 148 new IndexSubTableFormat5::Builder(new_data, 149 first_glyph_index, 150 last_glyph_index); 151 return output.Detach(); 152} 153 154// static 155CALLER_ATTACH IndexSubTableFormat5::Builder* 156IndexSubTableFormat5::Builder::CreateBuilder(WritableFontData* data, 157 int32_t index_sub_table_offset, 158 int32_t first_glyph_index, 159 int32_t last_glyph_index) { 160 int32_t length = Builder::DataLength(data, 161 index_sub_table_offset, 162 first_glyph_index, 163 last_glyph_index); 164 WritableFontDataPtr new_data; 165 new_data.Attach(down_cast<WritableFontData*>( 166 data->Slice(index_sub_table_offset, length))); 167 IndexSubTableFormat5BuilderPtr output = 168 new IndexSubTableFormat5::Builder(new_data, 169 first_glyph_index, 170 last_glyph_index); 171 return output.Detach(); 172} 173 174CALLER_ATTACH FontDataTable* IndexSubTableFormat5::Builder::SubBuildTable( 175 ReadableFontData* data) { 176 IndexSubTableFormat5Ptr output = new IndexSubTableFormat5( 177 data, first_glyph_index(), last_glyph_index()); 178 return output.Detach(); 179} 180 181void IndexSubTableFormat5::Builder::SubDataSet() { 182 Revert(); 183} 184 185int32_t IndexSubTableFormat5::Builder::SubDataSizeToSerialize() { 186 if (glyph_array_.empty()) { 187 return InternalReadData()->Length(); 188 } 189 return EblcTable::Offset::kIndexSubTable5_builderDataSize + 190 glyph_array_.size() * DataSize::kUSHORT; 191} 192 193bool IndexSubTableFormat5::Builder::SubReadyToSerialize() { 194 if (!glyph_array_.empty()) { 195 return true; 196 } 197 return false; 198} 199 200int32_t IndexSubTableFormat5::Builder::SubSerialize( 201 WritableFontData* new_data) { 202 int32_t size = SerializeIndexSubHeader(new_data); 203 if (!model_changed()) { 204 ReadableFontDataPtr source; 205 WritableFontDataPtr target; 206 source.Attach(down_cast<ReadableFontData*>(InternalReadData()->Slice( 207 EblcTable::Offset::kIndexSubTable5_imageSize))); 208 target.Attach(down_cast<WritableFontData*>(new_data->Slice( 209 EblcTable::Offset::kIndexSubTable5_imageSize))); 210 size += source->CopyTo(target); 211 } else { 212 size += new_data->WriteULong(EblcTable::Offset::kIndexSubTable5_imageSize, 213 ImageSize()); 214 WritableFontDataPtr slice; 215 slice.Attach(down_cast<WritableFontData*>(new_data->Slice(size))); 216 size += BigMetrics()->SubSerialize(slice); 217 size += new_data->WriteULong(size, glyph_array_.size()); 218 for (IntegerList::iterator b = glyph_array_.begin(), e = glyph_array_.end(); 219 b != e; b++) { 220 size += new_data->WriteUShort(size, *b); 221 } 222 } 223 return size; 224} 225 226int32_t IndexSubTableFormat5::Builder::ImageSize() { 227 return InternalReadData()->ReadULongAsInt( 228 EblcTable::Offset::kIndexSubTable5_imageSize); 229} 230 231void IndexSubTableFormat5::Builder::SetImageSize(int32_t image_size) { 232 InternalWriteData()->WriteULong( 233 EblcTable::Offset::kIndexSubTable5_imageSize, image_size); 234} 235 236BigGlyphMetrics::Builder* IndexSubTableFormat5::Builder::BigMetrics() { 237 if (metrics_ == NULL) { 238 WritableFontDataPtr data; 239 data.Attach(down_cast<WritableFontData*>(InternalWriteData()->Slice( 240 EblcTable::Offset::kIndexSubTable5_bigGlyphMetrics, 241 BigGlyphMetrics::Offset::kMetricsLength))); 242 metrics_ = new BigGlyphMetrics::Builder(data); 243 set_model_changed(); 244 } 245 return metrics_; 246} 247 248IntegerList* IndexSubTableFormat5::Builder::GlyphArray() { 249 return GetGlyphArray(); 250} 251 252void IndexSubTableFormat5::Builder::SetGlyphArray(const IntegerList& v) { 253 glyph_array_.clear(); 254 glyph_array_ = v; 255 set_model_changed(); 256} 257 258void IndexSubTableFormat5::Builder::Revert() { 259 glyph_array_.clear(); 260 IndexSubTable::Builder::Revert(); 261} 262 263IndexSubTableFormat5::Builder::Builder() 264 : IndexSubTable::Builder(EblcTable::Offset::kIndexSubTable5_builderDataSize, 265 IndexSubTable::Format::FORMAT_5) { 266} 267 268IndexSubTableFormat5::Builder::Builder(WritableFontData* data, 269 int32_t first_glyph_index, 270 int32_t last_glyph_index) 271 : IndexSubTable::Builder(data, first_glyph_index, last_glyph_index) { 272} 273 274IndexSubTableFormat5::Builder::Builder(ReadableFontData* data, 275 int32_t first_glyph_index, 276 int32_t last_glyph_index) 277 : IndexSubTable::Builder(data, first_glyph_index, last_glyph_index) { 278} 279 280IntegerList* IndexSubTableFormat5::Builder::GetGlyphArray() { 281 if (glyph_array_.empty()) { 282 Initialize(InternalReadData()); 283 set_model_changed(); 284 } 285 return &glyph_array_; 286} 287 288void IndexSubTableFormat5::Builder::Initialize(ReadableFontData* data) { 289 glyph_array_.clear(); 290 if (data) { 291 int32_t num_glyphs = IndexSubTableFormat5::NumGlyphs(data, 0); 292 for (int32_t i = 0; i < num_glyphs; ++i) { 293 glyph_array_.push_back(data->ReadUShort( 294 EblcTable::Offset::kIndexSubTable5_glyphArray + 295 i * DataSize::kUSHORT)); 296 } 297 } 298} 299 300// static 301int32_t IndexSubTableFormat5::Builder::DataLength( 302 ReadableFontData* data, 303 int32_t index_sub_table_offset, 304 int32_t first_glyph_index, 305 int32_t last_glyph_index) { 306 int32_t num_glyphs = IndexSubTableFormat5::NumGlyphs(data, 307 index_sub_table_offset); 308 UNREFERENCED_PARAMETER(first_glyph_index); 309 UNREFERENCED_PARAMETER(last_glyph_index); 310 return EblcTable::Offset::kIndexSubTable5_glyphArray + 311 num_glyphs * DataSize::kUSHORT; 312} 313 314/****************************************************************************** 315 * IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator class 316 ******************************************************************************/ 317IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator::BitmapGlyphInfoIterator( 318 IndexSubTableFormat5::Builder* container) 319 : RefIterator<BitmapGlyphInfo, IndexSubTableFormat5::Builder, 320 IndexSubTable::Builder>(container), 321 offset_index_(0) { 322} 323 324bool IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator::HasNext() { 325 if (offset_index_ < (int32_t)(container()->GetGlyphArray()->size())) { 326 return true; 327 } 328 return false; 329} 330 331CALLER_ATTACH BitmapGlyphInfo* 332IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator::Next() { 333 BitmapGlyphInfoPtr output; 334 if (!HasNext()) { 335 // Note: In C++, we do not throw exception when there's no element. 336 return NULL; 337 } 338 output = new BitmapGlyphInfo(container()->GetGlyphArray()->at(offset_index_), 339 container()->image_data_offset(), 340 offset_index_ * container()->ImageSize(), 341 container()->ImageSize(), 342 container()->image_format()); 343 offset_index_++; 344 return output.Detach(); 345} 346 347} // namespace sfntly 348