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_format1.h" 18 19#include "sfntly/table/bitmap/eblc_table.h" 20 21namespace sfntly { 22/****************************************************************************** 23 * IndexSubTableFormat1 class 24 ******************************************************************************/ 25// static 26int32_t IndexSubTableFormat1::GetDataLength(ReadableFontData* data, 27 int32_t offset, 28 int32_t first, 29 int32_t last) { 30 UNREFERENCED_PARAMETER(data); 31 UNREFERENCED_PARAMETER(offset); 32 return (last - first + 1 + 1) * DataSize::kULONG; 33} 34 35IndexSubTableFormat1::~IndexSubTableFormat1() { 36} 37 38int32_t IndexSubTableFormat1::NumGlyphs() { 39 return last_glyph_index() - first_glyph_index() + 1; 40} 41 42int32_t IndexSubTableFormat1::GlyphStartOffset(int32_t glyph_id) { 43 int32_t loca = CheckGlyphRange(glyph_id); 44 if (loca == -1) { 45 return -1; 46 } 47 return Loca(loca); 48} 49 50int32_t IndexSubTableFormat1::GlyphLength(int32_t glyph_id) { 51 int32_t loca = CheckGlyphRange(glyph_id); 52 if (loca == -1) { 53 return -1; 54 } 55 return Loca(loca + 1) - Loca(loca); 56} 57 58IndexSubTableFormat1::IndexSubTableFormat1(ReadableFontData* data, 59 int32_t first_glyph_index, 60 int32_t last_glyph_index) 61 : IndexSubTable(data, first_glyph_index, last_glyph_index) { 62} 63 64int32_t IndexSubTableFormat1::Loca(int32_t loca) { 65 return image_data_offset() + 66 data_->ReadULongAsInt(EblcTable::Offset::kIndexSubTable1_offsetArray + 67 loca * DataSize::kULONG); 68} 69 70/****************************************************************************** 71 * IndexSubTableFormat1::Builder class 72 ******************************************************************************/ 73IndexSubTableFormat1::Builder::~Builder() { 74} 75 76int32_t IndexSubTableFormat1::Builder::NumGlyphs() { 77 return GetOffsetArray()->size() - 1; 78} 79 80int32_t IndexSubTableFormat1::Builder::GlyphLength(int32_t glyph_id) { 81 int32_t loca = CheckGlyphRange(glyph_id); 82 if (loca == -1) { 83 return 0; 84 } 85 IntegerList* offset_array = GetOffsetArray(); 86 return offset_array->at(loca + 1) - offset_array->at(loca); 87} 88 89int32_t IndexSubTableFormat1::Builder::GlyphStartOffset(int32_t glyph_id) { 90 int32_t loca = CheckGlyphRange(glyph_id); 91 if (loca == -1) { 92 return -1; 93 } 94 return GetOffsetArray()->at(loca); 95} 96 97CALLER_ATTACH IndexSubTableFormat1::Builder::BitmapGlyphInfoIterator* 98 IndexSubTableFormat1::Builder::GetIterator() { 99 Ptr<IndexSubTableFormat1::Builder::BitmapGlyphInfoIterator> it = 100 new IndexSubTableFormat1::Builder::BitmapGlyphInfoIterator(this); 101 return it.Detach(); 102} 103 104// static 105CALLER_ATTACH IndexSubTableFormat1::Builder* 106IndexSubTableFormat1::Builder::CreateBuilder() { 107 IndexSubTableFormat1BuilderPtr output = new IndexSubTableFormat1::Builder(); 108 return output.Detach(); 109} 110 111// static 112CALLER_ATTACH IndexSubTableFormat1::Builder* 113IndexSubTableFormat1::Builder::CreateBuilder(ReadableFontData* data, 114 int32_t index_sub_table_offset, 115 int32_t first_glyph_index, 116 int32_t last_glyph_index) { 117 int32_t length = Builder::DataLength(data, 118 index_sub_table_offset, 119 first_glyph_index, 120 last_glyph_index); 121 ReadableFontDataPtr new_data; 122 new_data.Attach(down_cast<ReadableFontData*>( 123 data->Slice(index_sub_table_offset, length))); 124 if (new_data == NULL) { 125 return NULL; 126 } 127 IndexSubTableFormat1BuilderPtr output = 128 new IndexSubTableFormat1::Builder(new_data, 129 first_glyph_index, 130 last_glyph_index); 131 return output.Detach(); 132} 133 134 135// static 136CALLER_ATTACH IndexSubTableFormat1::Builder* 137IndexSubTableFormat1::Builder::CreateBuilder(WritableFontData* data, 138 int32_t index_sub_table_offset, 139 int32_t first_glyph_index, 140 int32_t last_glyph_index) { 141 int32_t length = Builder::DataLength(data, 142 index_sub_table_offset, 143 first_glyph_index, 144 last_glyph_index); 145 WritableFontDataPtr new_data; 146 new_data.Attach(down_cast<WritableFontData*>( 147 data->Slice(index_sub_table_offset, length))); 148 IndexSubTableFormat1BuilderPtr output = 149 new IndexSubTableFormat1::Builder(new_data, 150 first_glyph_index, 151 last_glyph_index); 152 return output.Detach(); 153} 154 155CALLER_ATTACH FontDataTable* IndexSubTableFormat1::Builder::SubBuildTable( 156 ReadableFontData* data) { 157 IndexSubTableFormat1Ptr output = new IndexSubTableFormat1( 158 data, first_glyph_index(), last_glyph_index()); 159 return output.Detach(); 160} 161 162void IndexSubTableFormat1::Builder::SubDataSet() { 163 Revert(); 164} 165 166int32_t IndexSubTableFormat1::Builder::SubDataSizeToSerialize() { 167 if (offset_array_.empty()) { 168 return InternalReadData()->Length(); 169 } 170 return EblcTable::Offset::kIndexSubHeaderLength + 171 offset_array_.size() * DataSize::kULONG; 172} 173 174bool IndexSubTableFormat1::Builder::SubReadyToSerialize() { 175 if (!offset_array_.empty()) { 176 return true; 177 } 178 return false; 179} 180 181int32_t IndexSubTableFormat1::Builder::SubSerialize( 182 WritableFontData* new_data) { 183 int32_t size = SerializeIndexSubHeader(new_data); 184 if (!model_changed()) { 185 if (InternalReadData() == NULL) { 186 return size; 187 } 188 ReadableFontDataPtr source; 189 WritableFontDataPtr target; 190 source.Attach(down_cast<ReadableFontData*>(InternalReadData()->Slice( 191 EblcTable::Offset::kIndexSubTable1_offsetArray))); 192 target.Attach(down_cast<WritableFontData*>(new_data->Slice( 193 EblcTable::Offset::kIndexSubTable1_offsetArray))); 194 size += source->CopyTo(target); 195 } else { 196 for (IntegerList::iterator b = GetOffsetArray()->begin(), 197 e = GetOffsetArray()->end(); b != e; b++) { 198 size += new_data->WriteLong(size, *b); 199 } 200 } 201 return size; 202} 203 204IntegerList* IndexSubTableFormat1::Builder::OffsetArray() { 205 return GetOffsetArray(); 206} 207 208void IndexSubTableFormat1::Builder::SetOffsetArray( 209 const IntegerList& offset_array) { 210 offset_array_.clear(); 211 offset_array_ = offset_array; 212 set_model_changed(); 213} 214 215void IndexSubTableFormat1::Builder::Revert() { 216 offset_array_.clear(); 217 IndexSubTable::Builder::Revert(); 218} 219 220IndexSubTableFormat1::Builder::Builder() 221 : IndexSubTable::Builder(EblcTable::Offset::kIndexSubTable1_builderDataSize, 222 IndexSubTable::Format::FORMAT_1) { 223} 224 225IndexSubTableFormat1::Builder::Builder(WritableFontData* data, 226 int32_t first_glyph_index, 227 int32_t last_glyph_index) 228 : IndexSubTable::Builder(data, first_glyph_index, last_glyph_index) { 229} 230 231IndexSubTableFormat1::Builder::Builder(ReadableFontData* data, 232 int32_t first_glyph_index, 233 int32_t last_glyph_index) 234 : IndexSubTable::Builder(data, first_glyph_index, last_glyph_index) { 235} 236 237IntegerList* IndexSubTableFormat1::Builder::GetOffsetArray() { 238 if (offset_array_.empty()) { 239 Initialize(InternalReadData()); 240 set_model_changed(); 241 } 242 return &offset_array_; 243} 244 245void IndexSubTableFormat1::Builder::Initialize(ReadableFontData* data) { 246 offset_array_.clear(); 247 if (data) { 248 int32_t num_offsets = (last_glyph_index() - first_glyph_index() + 1) + 1; 249 for (int32_t i = 0; i < num_offsets; ++i) { 250 offset_array_.push_back(data->ReadULongAsInt( 251 EblcTable::Offset::kIndexSubTable1_offsetArray + 252 i * DataSize::kULONG)); 253 } 254 } 255} 256 257// static 258int32_t IndexSubTableFormat1::Builder::DataLength( 259 ReadableFontData* data, 260 int32_t index_sub_table_offset, 261 int32_t first_glyph_index, 262 int32_t last_glyph_index) { 263 UNREFERENCED_PARAMETER(data); 264 UNREFERENCED_PARAMETER(index_sub_table_offset); 265 return EblcTable::Offset::kIndexSubHeaderLength + 266 (last_glyph_index - first_glyph_index + 1 + 1) * DataSize::kULONG; 267} 268 269/****************************************************************************** 270 * IndexSubTableFormat1::Builder::BitmapGlyphInfoIterator class 271 ******************************************************************************/ 272IndexSubTableFormat1::Builder::BitmapGlyphInfoIterator::BitmapGlyphInfoIterator( 273 IndexSubTableFormat1::Builder* container) 274 : RefIterator<BitmapGlyphInfo, IndexSubTableFormat1::Builder, 275 IndexSubTable::Builder>(container) { 276 glyph_id_ = container->first_glyph_index(); 277} 278 279bool IndexSubTableFormat1::Builder::BitmapGlyphInfoIterator::HasNext() { 280 if (glyph_id_ <= container()->last_glyph_index()) { 281 return true; 282 } 283 return false; 284} 285 286CALLER_ATTACH BitmapGlyphInfo* 287IndexSubTableFormat1::Builder::BitmapGlyphInfoIterator::Next() { 288 BitmapGlyphInfoPtr output; 289 if (!HasNext()) { 290 // Note: In C++, we do not throw exception when there's no element. 291 return NULL; 292 } 293 output = new BitmapGlyphInfo(glyph_id_, 294 container()->image_data_offset(), 295 container()->GlyphStartOffset(glyph_id_), 296 container()->GlyphLength(glyph_id_), 297 container()->image_format()); 298 glyph_id_++; 299 return output.Detach(); 300} 301 302} // namespace sfntly 303