Home | History | Annotate | Download | only in fpdf_font
      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