1 // Copyright 2014 PDFium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com 6 7 #include "ttgsubtable.h" 8 9 #include <memory> 10 11 #include "core/include/fxge/fx_freetype.h" 12 #include "core/include/fxge/fx_ge.h" 13 #include "third_party/base/stl_util.h" 14 15 CFX_GlyphMap::CFX_GlyphMap() {} 16 CFX_GlyphMap::~CFX_GlyphMap() {} 17 extern "C" { 18 static int _CompareInt(const void* p1, const void* p2) { 19 return (*(FX_DWORD*)p1) - (*(FX_DWORD*)p2); 20 } 21 }; 22 struct _IntPair { 23 int32_t key; 24 int32_t value; 25 }; 26 void CFX_GlyphMap::SetAt(int key, int value) { 27 FX_DWORD count = m_Buffer.GetSize() / sizeof(_IntPair); 28 _IntPair* buf = (_IntPair*)m_Buffer.GetBuffer(); 29 _IntPair pair = {key, value}; 30 if (count == 0 || key > buf[count - 1].key) { 31 m_Buffer.AppendBlock(&pair, sizeof(_IntPair)); 32 return; 33 } 34 int low = 0, high = count - 1; 35 while (low <= high) { 36 int mid = (low + high) / 2; 37 if (buf[mid].key < key) { 38 low = mid + 1; 39 } else if (buf[mid].key > key) { 40 high = mid - 1; 41 } else { 42 buf[mid].value = value; 43 return; 44 } 45 } 46 m_Buffer.InsertBlock(low * sizeof(_IntPair), &pair, sizeof(_IntPair)); 47 } 48 FX_BOOL CFX_GlyphMap::Lookup(int key, int& value) { 49 void* pResult = FXSYS_bsearch(&key, m_Buffer.GetBuffer(), 50 m_Buffer.GetSize() / sizeof(_IntPair), 51 sizeof(_IntPair), _CompareInt); 52 if (!pResult) { 53 return FALSE; 54 } 55 value = ((FX_DWORD*)pResult)[1]; 56 return TRUE; 57 } 58 bool CFX_CTTGSUBTable::LoadGSUBTable(FT_Bytes gsub) { 59 header.Version = gsub[0] << 24 | gsub[1] << 16 | gsub[2] << 8 | gsub[3]; 60 if (header.Version != 0x00010000) { 61 return false; 62 } 63 header.ScriptList = gsub[4] << 8 | gsub[5]; 64 header.FeatureList = gsub[6] << 8 | gsub[7]; 65 header.LookupList = gsub[8] << 8 | gsub[9]; 66 return Parse(&gsub[header.ScriptList], &gsub[header.FeatureList], 67 &gsub[header.LookupList]); 68 } 69 bool CFX_CTTGSUBTable::GetVerticalGlyph(uint32_t glyphnum, 70 uint32_t* vglyphnum) { 71 uint32_t tag[] = { 72 (uint8_t)'v' << 24 | (uint8_t)'r' << 16 | (uint8_t)'t' << 8 | 73 (uint8_t)'2', 74 (uint8_t)'v' << 24 | (uint8_t)'e' << 16 | (uint8_t)'r' << 8 | 75 (uint8_t)'t', 76 }; 77 if (!m_bFeautureMapLoad) { 78 for (int i = 0; i < ScriptList.ScriptCount; i++) { 79 for (int j = 0; j < (ScriptList.ScriptRecord + i)->Script.LangSysCount; 80 ++j) { 81 for (int k = 0; 82 k < ((ScriptList.ScriptRecord + i)->Script.LangSysRecord + j) 83 ->LangSys.FeatureCount; 84 ++k) { 85 FX_DWORD index = 86 *(((ScriptList.ScriptRecord + i)->Script.LangSysRecord + j) 87 ->LangSys.FeatureIndex + 88 k); 89 if (FeatureList.FeatureRecord[index].FeatureTag == tag[0] || 90 FeatureList.FeatureRecord[index].FeatureTag == tag[1]) { 91 if (!pdfium::ContainsKey(m_featureMap, index)) { 92 m_featureMap[index] = index; 93 } 94 } 95 } 96 } 97 } 98 if (m_featureMap.empty()) { 99 for (int i = 0; i < FeatureList.FeatureCount; i++) { 100 if (FeatureList.FeatureRecord[i].FeatureTag == tag[0] || 101 FeatureList.FeatureRecord[i].FeatureTag == tag[1]) { 102 m_featureMap[i] = i; 103 } 104 } 105 } 106 m_bFeautureMapLoad = TRUE; 107 } 108 for (const auto& pair : m_featureMap) { 109 if (GetVerticalGlyphSub(glyphnum, vglyphnum, 110 &FeatureList.FeatureRecord[pair.second].Feature)) { 111 return true; 112 } 113 } 114 return false; 115 } 116 bool CFX_CTTGSUBTable::GetVerticalGlyphSub(uint32_t glyphnum, 117 uint32_t* vglyphnum, 118 struct TFeature* Feature) { 119 for (int i = 0; i < Feature->LookupCount; i++) { 120 int index = Feature->LookupListIndex[i]; 121 if (index < 0 || LookupList.LookupCount < index) { 122 continue; 123 } 124 if (LookupList.Lookup[index].LookupType == 1) { 125 if (GetVerticalGlyphSub2(glyphnum, vglyphnum, 126 &LookupList.Lookup[index])) { 127 return true; 128 } 129 } 130 } 131 return false; 132 } 133 bool CFX_CTTGSUBTable::GetVerticalGlyphSub2(uint32_t glyphnum, 134 uint32_t* vglyphnum, 135 struct TLookup* Lookup) { 136 for (int i = 0; i < Lookup->SubTableCount; i++) { 137 switch (Lookup->SubTable[i]->SubstFormat) { 138 case 1: { 139 TSingleSubstFormat1* tbl1 = (TSingleSubstFormat1*)Lookup->SubTable[i]; 140 if (GetCoverageIndex(tbl1->Coverage, glyphnum) >= 0) { 141 *vglyphnum = glyphnum + tbl1->DeltaGlyphID; 142 return true; 143 } 144 break; 145 } 146 case 2: { 147 TSingleSubstFormat2* tbl2 = (TSingleSubstFormat2*)Lookup->SubTable[i]; 148 int index = -1; 149 index = GetCoverageIndex(tbl2->Coverage, glyphnum); 150 if (0 <= index && index < tbl2->GlyphCount) { 151 *vglyphnum = tbl2->Substitute[index]; 152 return true; 153 } 154 break; 155 } 156 } 157 } 158 return false; 159 } 160 int CFX_CTTGSUBTable::GetCoverageIndex(struct TCoverageFormatBase* Coverage, 161 uint32_t g) { 162 int i = 0; 163 if (!Coverage) { 164 return -1; 165 } 166 switch (Coverage->CoverageFormat) { 167 case 1: { 168 TCoverageFormat1* c1 = (TCoverageFormat1*)Coverage; 169 for (i = 0; i < c1->GlyphCount; i++) { 170 if ((uint32_t)c1->GlyphArray[i] == g) { 171 return i; 172 } 173 } 174 return -1; 175 } 176 case 2: { 177 TCoverageFormat2* c2 = (TCoverageFormat2*)Coverage; 178 for (i = 0; i < c2->RangeCount; i++) { 179 uint32_t s = c2->RangeRecord[i].Start; 180 uint32_t e = c2->RangeRecord[i].End; 181 uint32_t si = c2->RangeRecord[i].StartCoverageIndex; 182 if (s <= g && g <= e) { 183 return si + g - s; 184 } 185 } 186 return -1; 187 } 188 } 189 return -1; 190 } 191 bool CFX_CTTGSUBTable::Parse(FT_Bytes scriptlist, 192 FT_Bytes featurelist, 193 FT_Bytes lookuplist) { 194 ParseScriptList(scriptlist, &ScriptList); 195 ParseFeatureList(featurelist, &FeatureList); 196 ParseLookupList(lookuplist, &LookupList); 197 return true; 198 } 199 void CFX_CTTGSUBTable::ParseScriptList(FT_Bytes raw, struct TScriptList* rec) { 200 int i; 201 FT_Bytes sp = raw; 202 rec->ScriptCount = GetUInt16(sp); 203 if (rec->ScriptCount <= 0) { 204 return; 205 } 206 rec->ScriptRecord = new struct TScriptRecord[rec->ScriptCount]; 207 for (i = 0; i < rec->ScriptCount; i++) { 208 rec->ScriptRecord[i].ScriptTag = GetUInt32(sp); 209 uint16_t offset = GetUInt16(sp); 210 ParseScript(&raw[offset], &rec->ScriptRecord[i].Script); 211 } 212 } 213 void CFX_CTTGSUBTable::ParseScript(FT_Bytes raw, struct TScript* rec) { 214 int i; 215 FT_Bytes sp = raw; 216 rec->DefaultLangSys = GetUInt16(sp); 217 rec->LangSysCount = GetUInt16(sp); 218 if (rec->LangSysCount <= 0) { 219 return; 220 } 221 rec->LangSysRecord = new struct TLangSysRecord[rec->LangSysCount]; 222 for (i = 0; i < rec->LangSysCount; i++) { 223 rec->LangSysRecord[i].LangSysTag = GetUInt32(sp); 224 uint16_t offset = GetUInt16(sp); 225 ParseLangSys(&raw[offset], &rec->LangSysRecord[i].LangSys); 226 } 227 } 228 void CFX_CTTGSUBTable::ParseLangSys(FT_Bytes raw, struct TLangSys* rec) { 229 FT_Bytes sp = raw; 230 rec->LookupOrder = GetUInt16(sp); 231 rec->ReqFeatureIndex = GetUInt16(sp); 232 rec->FeatureCount = GetUInt16(sp); 233 if (rec->FeatureCount <= 0) { 234 return; 235 } 236 rec->FeatureIndex = new uint16_t[rec->FeatureCount]; 237 FXSYS_memset(rec->FeatureIndex, 0, sizeof(uint16_t) * rec->FeatureCount); 238 for (int i = 0; i < rec->FeatureCount; ++i) { 239 rec->FeatureIndex[i] = GetUInt16(sp); 240 } 241 } 242 void CFX_CTTGSUBTable::ParseFeatureList(FT_Bytes raw, TFeatureList* rec) { 243 int i; 244 FT_Bytes sp = raw; 245 rec->FeatureCount = GetUInt16(sp); 246 if (rec->FeatureCount <= 0) { 247 return; 248 } 249 rec->FeatureRecord = new struct TFeatureRecord[rec->FeatureCount]; 250 for (i = 0; i < rec->FeatureCount; i++) { 251 rec->FeatureRecord[i].FeatureTag = GetUInt32(sp); 252 uint16_t offset = GetUInt16(sp); 253 ParseFeature(&raw[offset], &rec->FeatureRecord[i].Feature); 254 } 255 } 256 void CFX_CTTGSUBTable::ParseFeature(FT_Bytes raw, TFeature* rec) { 257 int i; 258 FT_Bytes sp = raw; 259 rec->FeatureParams = GetUInt16(sp); 260 rec->LookupCount = GetUInt16(sp); 261 if (rec->LookupCount <= 0) { 262 return; 263 } 264 rec->LookupListIndex = new uint16_t[rec->LookupCount]; 265 for (i = 0; i < rec->LookupCount; i++) { 266 rec->LookupListIndex[i] = GetUInt16(sp); 267 } 268 } 269 void CFX_CTTGSUBTable::ParseLookupList(FT_Bytes raw, TLookupList* rec) { 270 int i; 271 FT_Bytes sp = raw; 272 rec->LookupCount = GetUInt16(sp); 273 if (rec->LookupCount <= 0) { 274 return; 275 } 276 rec->Lookup = new struct TLookup[rec->LookupCount]; 277 for (i = 0; i < rec->LookupCount; i++) { 278 uint16_t offset = GetUInt16(sp); 279 ParseLookup(&raw[offset], &rec->Lookup[i]); 280 } 281 } 282 void CFX_CTTGSUBTable::ParseLookup(FT_Bytes raw, TLookup* rec) { 283 int i; 284 FT_Bytes sp = raw; 285 rec->LookupType = GetUInt16(sp); 286 rec->LookupFlag = GetUInt16(sp); 287 rec->SubTableCount = GetUInt16(sp); 288 if (rec->SubTableCount <= 0) { 289 return; 290 } 291 rec->SubTable = new struct TSubTableBase*[rec->SubTableCount]; 292 for (i = 0; i < rec->SubTableCount; i++) { 293 rec->SubTable[i] = NULL; 294 } 295 if (rec->LookupType != 1) { 296 return; 297 } 298 for (i = 0; i < rec->SubTableCount; i++) { 299 uint16_t offset = GetUInt16(sp); 300 ParseSingleSubst(&raw[offset], &rec->SubTable[i]); 301 } 302 } 303 void CFX_CTTGSUBTable::ParseCoverage(FT_Bytes raw, TCoverageFormatBase** rec) { 304 FT_Bytes sp = raw; 305 uint16_t Format = GetUInt16(sp); 306 switch (Format) { 307 case 1: 308 *rec = new TCoverageFormat1(); 309 ParseCoverageFormat1(raw, (TCoverageFormat1*)*rec); 310 break; 311 case 2: 312 *rec = new TCoverageFormat2(); 313 ParseCoverageFormat2(raw, (TCoverageFormat2*)*rec); 314 break; 315 } 316 } 317 void CFX_CTTGSUBTable::ParseCoverageFormat1(FT_Bytes raw, 318 TCoverageFormat1* rec) { 319 int i; 320 FT_Bytes sp = raw; 321 GetUInt16(sp); 322 rec->GlyphCount = GetUInt16(sp); 323 if (rec->GlyphCount <= 0) { 324 return; 325 } 326 rec->GlyphArray = new uint16_t[rec->GlyphCount]; 327 for (i = 0; i < rec->GlyphCount; i++) { 328 rec->GlyphArray[i] = GetUInt16(sp); 329 } 330 } 331 void CFX_CTTGSUBTable::ParseCoverageFormat2(FT_Bytes raw, 332 TCoverageFormat2* rec) { 333 int i; 334 FT_Bytes sp = raw; 335 GetUInt16(sp); 336 rec->RangeCount = GetUInt16(sp); 337 if (rec->RangeCount <= 0) { 338 return; 339 } 340 rec->RangeRecord = new TRangeRecord[rec->RangeCount]; 341 for (i = 0; i < rec->RangeCount; i++) { 342 rec->RangeRecord[i].Start = GetUInt16(sp); 343 rec->RangeRecord[i].End = GetUInt16(sp); 344 rec->RangeRecord[i].StartCoverageIndex = GetUInt16(sp); 345 } 346 } 347 void CFX_CTTGSUBTable::ParseSingleSubst(FT_Bytes raw, TSubTableBase** rec) { 348 FT_Bytes sp = raw; 349 uint16_t Format = GetUInt16(sp); 350 switch (Format) { 351 case 1: 352 *rec = new TSingleSubstFormat1(); 353 ParseSingleSubstFormat1(raw, (TSingleSubstFormat1*)*rec); 354 break; 355 case 2: 356 *rec = new TSingleSubstFormat2(); 357 ParseSingleSubstFormat2(raw, (TSingleSubstFormat2*)*rec); 358 break; 359 } 360 } 361 void CFX_CTTGSUBTable::ParseSingleSubstFormat1(FT_Bytes raw, 362 TSingleSubstFormat1* rec) { 363 FT_Bytes sp = raw; 364 GetUInt16(sp); 365 uint16_t offset = GetUInt16(sp); 366 ParseCoverage(&raw[offset], &rec->Coverage); 367 rec->DeltaGlyphID = GetInt16(sp); 368 } 369 void CFX_CTTGSUBTable::ParseSingleSubstFormat2(FT_Bytes raw, 370 TSingleSubstFormat2* rec) { 371 int i; 372 FT_Bytes sp = raw; 373 GetUInt16(sp); 374 uint16_t offset = GetUInt16(sp); 375 ParseCoverage(&raw[offset], &rec->Coverage); 376 rec->GlyphCount = GetUInt16(sp); 377 if (rec->GlyphCount <= 0) { 378 return; 379 } 380 rec->Substitute = new uint16_t[rec->GlyphCount]; 381 for (i = 0; i < rec->GlyphCount; i++) { 382 rec->Substitute[i] = GetUInt16(sp); 383 } 384 } 385 FX_BOOL CFX_GSUBTable::GetVerticalGlyph(FX_DWORD glyphnum, 386 FX_DWORD* vglyphnum) { 387 return m_GsubImp.GetVerticalGlyph(glyphnum, vglyphnum); 388 } 389 // static 390 IFX_GSUBTable* IFX_GSUBTable::Create(CFX_Font* pFont) { 391 if (!pFont) { 392 return NULL; 393 } 394 if (!pFont->GetSubData()) { 395 unsigned long length = 0; 396 int error = FXFT_Load_Sfnt_Table( 397 pFont->GetFace(), FT_MAKE_TAG('G', 'S', 'U', 'B'), 0, NULL, &length); 398 if (!error) { 399 pFont->SetSubData(FX_Alloc(uint8_t, length)); 400 } 401 if (!pFont->GetSubData()) { 402 return NULL; 403 } 404 } 405 int error = 406 FXFT_Load_Sfnt_Table(pFont->GetFace(), FT_MAKE_TAG('G', 'S', 'U', 'B'), 0, 407 pFont->GetSubData(), NULL); 408 if (!error && pFont->GetSubData()) { 409 std::unique_ptr<CFX_GSUBTable> pGsubTable(new CFX_GSUBTable); 410 if (pGsubTable->m_GsubImp.LoadGSUBTable((FT_Bytes)pFont->GetSubData())) { 411 return pGsubTable.release(); 412 } 413 } 414 return NULL; 415 } 416