ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

opentype.c
Go to the documentation of this file.
00001 /*
00002  * Opentype font interfaces for the Uniscribe Script Processor (usp10.dll)
00003  *
00004  * Copyright 2012 CodeWeavers, Aric Stewart
00005  *
00006  * This library is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU Lesser General Public
00008  * License as published by the Free Software Foundation; either
00009  * version 2.1 of the License, or (at your option) any later version.
00010  *
00011  * This library is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  * Lesser General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU Lesser General Public
00017  * License along with this library; if not, write to the Free Software
00018  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
00019  *
00020  */
00021 #include <stdarg.h>
00022 #include <stdlib.h>
00023 
00024 #include "windef.h"
00025 #include "winbase.h"
00026 #include "wingdi.h"
00027 #include "winuser.h"
00028 #include "winnls.h"
00029 #include "usp10.h"
00030 #include "winternl.h"
00031 
00032 #include "usp10_internal.h"
00033 
00034 #include "wine/debug.h"
00035 
00036 WINE_DEFAULT_DEBUG_CHANNEL(uniscribe);
00037 
00038 #ifdef WORDS_BIGENDIAN
00039 #define GET_BE_WORD(x) (x)
00040 #define GET_BE_DWORD(x) (x)
00041 #else
00042 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
00043 #define GET_BE_DWORD(x) RtlUlongByteSwap(x)
00044 #endif
00045 
00046 /* These are all structures needed for the cmap format 12 table */
00047 #define CMAP_TAG MS_MAKE_TAG('c', 'm', 'a', 'p')
00048 
00049 typedef struct {
00050     WORD platformID;
00051     WORD encodingID;
00052     DWORD offset;
00053 } CMAP_EncodingRecord;
00054 
00055 typedef struct {
00056     WORD version;
00057     WORD numTables;
00058     CMAP_EncodingRecord tables[1];
00059 } CMAP_Header;
00060 
00061 typedef struct {
00062     DWORD startCharCode;
00063     DWORD endCharCode;
00064     DWORD startGlyphID;
00065 } CMAP_SegmentedCoverage_group;
00066 
00067 typedef struct {
00068     WORD format;
00069     WORD reserved;
00070     DWORD length;
00071     DWORD language;
00072     DWORD nGroups;
00073     CMAP_SegmentedCoverage_group groups[1];
00074 } CMAP_SegmentedCoverage;
00075 
00076 /* These are all structures needed for the GDEF table */
00077 #define GDEF_TAG MS_MAKE_TAG('G', 'D', 'E', 'F')
00078 
00079 enum {BaseGlyph=1, LigatureGlyph, MarkGlyph, ComponentGlyph};
00080 
00081 typedef struct {
00082     DWORD Version;
00083     WORD GlyphClassDef;
00084     WORD AttachList;
00085     WORD LigCaretList;
00086     WORD MarkAttachClassDef;
00087 } GDEF_Header;
00088 
00089 typedef struct {
00090     WORD ClassFormat;
00091     WORD StartGlyph;
00092     WORD GlyphCount;
00093     WORD ClassValueArray[1];
00094 } GDEF_ClassDefFormat1;
00095 
00096 typedef struct {
00097     WORD Start;
00098     WORD End;
00099     WORD Class;
00100 } GDEF_ClassRangeRecord;
00101 
00102 typedef struct {
00103     WORD ClassFormat;
00104     WORD ClassRangeCount;
00105     GDEF_ClassRangeRecord ClassRangeRecord[1];
00106 } GDEF_ClassDefFormat2;
00107 
00108 /* These are all structures needed for the GSUB table */
00109 
00110 typedef struct {
00111     DWORD version;
00112     WORD ScriptList;
00113     WORD FeatureList;
00114     WORD LookupList;
00115 } GSUB_Header;
00116 
00117 typedef struct {
00118     CHAR ScriptTag[4];
00119     WORD Script;
00120 } GSUB_ScriptRecord;
00121 
00122 typedef struct {
00123     WORD ScriptCount;
00124     GSUB_ScriptRecord ScriptRecord[1];
00125 } GSUB_ScriptList;
00126 
00127 typedef struct {
00128     CHAR LangSysTag[4];
00129     WORD LangSys;
00130 } GSUB_LangSysRecord;
00131 
00132 typedef struct {
00133     WORD DefaultLangSys;
00134     WORD LangSysCount;
00135     GSUB_LangSysRecord LangSysRecord[1];
00136 } GSUB_Script;
00137 
00138 typedef struct {
00139     WORD LookupOrder; /* Reserved */
00140     WORD ReqFeatureIndex;
00141     WORD FeatureCount;
00142     WORD FeatureIndex[1];
00143 } GSUB_LangSys;
00144 
00145 typedef struct {
00146     CHAR FeatureTag[4];
00147     WORD Feature;
00148 } GSUB_FeatureRecord;
00149 
00150 typedef struct {
00151     WORD FeatureCount;
00152     GSUB_FeatureRecord FeatureRecord[1];
00153 } GSUB_FeatureList;
00154 
00155 typedef struct {
00156     WORD FeatureParams; /* Reserved */
00157     WORD LookupCount;
00158     WORD LookupListIndex[1];
00159 } GSUB_Feature;
00160 
00161 typedef struct {
00162     WORD LookupCount;
00163     WORD Lookup[1];
00164 } GSUB_LookupList;
00165 
00166 typedef struct {
00167     WORD LookupType;
00168     WORD LookupFlag;
00169     WORD SubTableCount;
00170     WORD SubTable[1];
00171 } GSUB_LookupTable;
00172 
00173 typedef struct {
00174     WORD CoverageFormat;
00175     WORD GlyphCount;
00176     WORD GlyphArray[1];
00177 } GSUB_CoverageFormat1;
00178 
00179 typedef struct {
00180     WORD Start;
00181     WORD End;
00182     WORD StartCoverageIndex;
00183 } GSUB_RangeRecord;
00184 
00185 typedef struct {
00186     WORD CoverageFormat;
00187     WORD RangeCount;
00188     GSUB_RangeRecord RangeRecord[1];
00189 } GSUB_CoverageFormat2;
00190 
00191 typedef struct {
00192     WORD SubstFormat; /* = 1 */
00193     WORD Coverage;
00194     WORD DeltaGlyphID;
00195 } GSUB_SingleSubstFormat1;
00196 
00197 typedef struct {
00198     WORD SubstFormat; /* = 2 */
00199     WORD Coverage;
00200     WORD GlyphCount;
00201     WORD Substitute[1];
00202 }GSUB_SingleSubstFormat2;
00203 
00204 typedef struct {
00205     WORD SubstFormat; /* = 1 */
00206     WORD Coverage;
00207     WORD SequenceCount;
00208     WORD Sequence[1];
00209 }GSUB_MultipleSubstFormat1;
00210 
00211 typedef struct {
00212     WORD GlyphCount;
00213     WORD Substitute[1];
00214 }GSUB_Sequence;
00215 
00216 typedef struct {
00217     WORD SubstFormat; /* = 1 */
00218     WORD Coverage;
00219     WORD LigSetCount;
00220     WORD LigatureSet[1];
00221 }GSUB_LigatureSubstFormat1;
00222 
00223 typedef struct {
00224     WORD LigatureCount;
00225     WORD Ligature[1];
00226 }GSUB_LigatureSet;
00227 
00228 typedef struct{
00229     WORD LigGlyph;
00230     WORD CompCount;
00231     WORD Component[1];
00232 }GSUB_Ligature;
00233 
00234 typedef struct{
00235     WORD SequenceIndex;
00236     WORD LookupListIndex;
00237 
00238 }GSUB_SubstLookupRecord;
00239 
00240 typedef struct{
00241     WORD SubstFormat; /* = 1 */
00242     WORD Coverage;
00243     WORD ChainSubRuleSetCount;
00244     WORD ChainSubRuleSet[1];
00245 }GSUB_ChainContextSubstFormat1;
00246 
00247 typedef struct {
00248     WORD SubstFormat; /* = 3 */
00249     WORD BacktrackGlyphCount;
00250     WORD Coverage[1];
00251 }GSUB_ChainContextSubstFormat3_1;
00252 
00253 typedef struct{
00254     WORD InputGlyphCount;
00255     WORD Coverage[1];
00256 }GSUB_ChainContextSubstFormat3_2;
00257 
00258 typedef struct{
00259     WORD LookaheadGlyphCount;
00260     WORD Coverage[1];
00261 }GSUB_ChainContextSubstFormat3_3;
00262 
00263 typedef struct{
00264     WORD SubstCount;
00265     GSUB_SubstLookupRecord SubstLookupRecord[1];
00266 }GSUB_ChainContextSubstFormat3_4;
00267 
00268 typedef struct {
00269     WORD SubstFormat; /* = 1 */
00270     WORD Coverage;
00271     WORD AlternateSetCount;
00272     WORD AlternateSet[1];
00273 } GSUB_AlternateSubstFormat1;
00274 
00275 typedef struct{
00276     WORD GlyphCount;
00277     WORD Alternate[1];
00278 } GSUB_AlternateSet;
00279 
00280 /**********
00281  * CMAP
00282  **********/
00283 
00284 static VOID *load_CMAP_format12_table(HDC hdc, ScriptCache *psc)
00285 {
00286     CMAP_Header *CMAP_Table = NULL;
00287     int length;
00288     int i;
00289 
00290     if (!psc->CMAP_Table)
00291     {
00292         length = GetFontData(hdc, CMAP_TAG , 0, NULL, 0);
00293         if (length != GDI_ERROR)
00294         {
00295             psc->CMAP_Table = HeapAlloc(GetProcessHeap(),0,length);
00296             GetFontData(hdc, CMAP_TAG , 0, psc->CMAP_Table, length);
00297             TRACE("Loaded cmap table of %i bytes\n",length);
00298         }
00299         else
00300             return NULL;
00301     }
00302 
00303     CMAP_Table = psc->CMAP_Table;
00304 
00305     for (i = 0; i < GET_BE_WORD(CMAP_Table->numTables); i++)
00306     {
00307         if ( (GET_BE_WORD(CMAP_Table->tables[i].platformID) == 3) &&
00308              (GET_BE_WORD(CMAP_Table->tables[i].encodingID) == 10) )
00309         {
00310             CMAP_SegmentedCoverage *format = (CMAP_SegmentedCoverage*)(((BYTE*)CMAP_Table) + GET_BE_DWORD(CMAP_Table->tables[i].offset));
00311             if (GET_BE_WORD(format->format) == 12)
00312                 return format;
00313         }
00314     }
00315     return NULL;
00316 }
00317 
00318 static int compare_group(const void *a, const void* b)
00319 {
00320     const DWORD *chr = a;
00321     const CMAP_SegmentedCoverage_group *group = b;
00322 
00323     if (*chr < GET_BE_DWORD(group->startCharCode))
00324         return -1;
00325     if (*chr > GET_BE_DWORD(group->endCharCode))
00326         return 1;
00327     return 0;
00328 }
00329 
00330 DWORD OpenType_CMAP_GetGlyphIndex(HDC hdc, ScriptCache *psc, DWORD utf32c, LPWORD pgi, DWORD flags)
00331 {
00332     /* BMP: use gdi32 for ease */
00333     if (utf32c < 0x10000)
00334     {
00335         WCHAR ch = utf32c;
00336         return GetGlyphIndicesW(hdc,&ch, 1, pgi, flags);
00337     }
00338 
00339     if (!psc->CMAP_format12_Table)
00340         psc->CMAP_format12_Table = load_CMAP_format12_table(hdc, psc);
00341 
00342     if (flags & GGI_MARK_NONEXISTING_GLYPHS)
00343         *pgi = 0xffff;
00344     else
00345         *pgi = 0;
00346 
00347     if (psc->CMAP_format12_Table)
00348     {
00349         CMAP_SegmentedCoverage *format = NULL;
00350         CMAP_SegmentedCoverage_group *group = NULL;
00351 
00352         format = (CMAP_SegmentedCoverage *)psc->CMAP_format12_Table;
00353 
00354         group = bsearch(&utf32c, format->groups, GET_BE_DWORD(format->nGroups),
00355                         sizeof(CMAP_SegmentedCoverage_group), compare_group);
00356 
00357         if (group)
00358         {
00359             DWORD offset = utf32c - GET_BE_DWORD(group->startCharCode);
00360             *pgi = GET_BE_DWORD(group->startGlyphID) + offset;
00361             return 0;
00362         }
00363     }
00364     return 0;
00365 }
00366 
00367 /**********
00368  * GDEF
00369  **********/
00370 
00371 static WORD GDEF_get_glyph_class(const GDEF_Header *header, WORD glyph)
00372 {
00373     int offset;
00374     WORD class = 0;
00375     const GDEF_ClassDefFormat1 *cf1;
00376 
00377     if (!header)
00378         return 0;
00379 
00380     offset = GET_BE_WORD(header->GlyphClassDef);
00381     if (!offset)
00382         return 0;
00383 
00384     cf1 = (GDEF_ClassDefFormat1*)(((BYTE*)header)+offset);
00385     if (GET_BE_WORD(cf1->ClassFormat) == 1)
00386     {
00387         if (glyph >= GET_BE_WORD(cf1->StartGlyph))
00388         {
00389             int index = glyph - GET_BE_WORD(cf1->StartGlyph);
00390             if (index < GET_BE_WORD(cf1->GlyphCount))
00391                 class = GET_BE_WORD(cf1->ClassValueArray[index]);
00392         }
00393     }
00394     else if (GET_BE_WORD(cf1->ClassFormat) == 2)
00395     {
00396         const GDEF_ClassDefFormat2 *cf2 = (GDEF_ClassDefFormat2*)cf1;
00397         int i, top;
00398         top = GET_BE_WORD(cf2->ClassRangeCount);
00399         for (i = 0; i < top; i++)
00400         {
00401             if (glyph >= GET_BE_WORD(cf2->ClassRangeRecord[i].Start) &&
00402                 glyph <= GET_BE_WORD(cf2->ClassRangeRecord[i].End))
00403             {
00404                 class = GET_BE_WORD(cf2->ClassRangeRecord[i].Class);
00405                 break;
00406             }
00407         }
00408     }
00409     else
00410         ERR("Unknown Class Format %i\n",GET_BE_WORD(cf1->ClassFormat));
00411 
00412     return class;
00413 }
00414 
00415 static VOID *load_gdef_table(HDC hdc)
00416 {
00417     VOID* GDEF_Table = NULL;
00418     int length = GetFontData(hdc, GDEF_TAG , 0, NULL, 0);
00419     if (length != GDI_ERROR)
00420     {
00421         GDEF_Table = HeapAlloc(GetProcessHeap(),0,length);
00422         GetFontData(hdc, GDEF_TAG , 0, GDEF_Table, length);
00423         TRACE("Loaded GDEF table of %i bytes\n",length);
00424     }
00425     return GDEF_Table;
00426 }
00427 
00428 void OpenType_GDEF_UpdateGlyphProps(HDC hdc, ScriptCache *psc, const WORD *pwGlyphs, const WORD cGlyphs, WORD* pwLogClust, const WORD cChars, SCRIPT_GLYPHPROP *pGlyphProp)
00429 {
00430     int i;
00431 
00432     if (!psc->GDEF_Table)
00433         psc->GDEF_Table = load_gdef_table(hdc);
00434 
00435     for (i = 0; i < cGlyphs; i++)
00436     {
00437         WORD class;
00438         int char_count = 0;
00439         int k;
00440 
00441         k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
00442         if (k >= 0)
00443         {
00444             for (; k < cChars && pwLogClust[k] == i; k++)
00445                 char_count++;
00446         }
00447 
00448         class = GDEF_get_glyph_class(psc->GDEF_Table, pwGlyphs[i]);
00449 
00450         switch (class)
00451         {
00452             case 0:
00453             case BaseGlyph:
00454                 pGlyphProp[i].sva.fClusterStart = 1;
00455                 pGlyphProp[i].sva.fDiacritic = 0;
00456                 pGlyphProp[i].sva.fZeroWidth = 0;
00457                 break;
00458             case LigatureGlyph:
00459                 pGlyphProp[i].sva.fClusterStart = 1;
00460                 pGlyphProp[i].sva.fDiacritic = 0;
00461                 pGlyphProp[i].sva.fZeroWidth = 0;
00462                 break;
00463             case MarkGlyph:
00464                 pGlyphProp[i].sva.fClusterStart = 0;
00465                 pGlyphProp[i].sva.fDiacritic = 1;
00466                 pGlyphProp[i].sva.fZeroWidth = 1;
00467                 break;
00468             case ComponentGlyph:
00469                 pGlyphProp[i].sva.fClusterStart = 0;
00470                 pGlyphProp[i].sva.fDiacritic = 0;
00471                 pGlyphProp[i].sva.fZeroWidth = 0;
00472                 break;
00473             default:
00474                 ERR("Unknown glyph class %i\n",class);
00475                 pGlyphProp[i].sva.fClusterStart = 1;
00476                 pGlyphProp[i].sva.fDiacritic = 0;
00477                 pGlyphProp[i].sva.fZeroWidth = 0;
00478         }
00479 
00480         if (char_count == 0)
00481             pGlyphProp[i].sva.fClusterStart = 0;
00482     }
00483 }
00484 
00485 /**********
00486  * GSUB
00487  **********/
00488 static INT GSUB_apply_lookup(const GSUB_LookupList* lookup, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count);
00489 
00490 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
00491 {
00492     const GSUB_CoverageFormat1* cf1;
00493 
00494     cf1 = table;
00495 
00496     if (GET_BE_WORD(cf1->CoverageFormat) == 1)
00497     {
00498         int count = GET_BE_WORD(cf1->GlyphCount);
00499         int i;
00500         TRACE("Coverage Format 1, %i glyphs\n",count);
00501         for (i = 0; i < count; i++)
00502             if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
00503                 return i;
00504         return -1;
00505     }
00506     else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
00507     {
00508         const GSUB_CoverageFormat2* cf2;
00509         int i;
00510         int count;
00511         cf2 = (const GSUB_CoverageFormat2*)cf1;
00512 
00513         count = GET_BE_WORD(cf2->RangeCount);
00514         TRACE("Coverage Format 2, %i ranges\n",count);
00515         for (i = 0; i < count; i++)
00516         {
00517             if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
00518                 return -1;
00519             if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
00520                 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
00521             {
00522                 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
00523                     glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
00524             }
00525         }
00526         return -1;
00527     }
00528     else
00529         ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
00530 
00531     return -1;
00532 }
00533 
00534 static INT GSUB_apply_SingleSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
00535 {
00536     int j;
00537     TRACE("Single Substitution Subtable\n");
00538 
00539     for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
00540     {
00541         int offset;
00542         const GSUB_SingleSubstFormat1 *ssf1;
00543         offset = GET_BE_WORD(look->SubTable[j]);
00544         ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
00545         if (GET_BE_WORD(ssf1->SubstFormat) == 1)
00546         {
00547             int offset = GET_BE_WORD(ssf1->Coverage);
00548             TRACE("  subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
00549             if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyphs[glyph_index]) != -1)
00550             {
00551                 TRACE("  Glyph 0x%x ->",glyphs[glyph_index]);
00552                 glyphs[glyph_index] = glyphs[glyph_index] + GET_BE_WORD(ssf1->DeltaGlyphID);
00553                 TRACE(" 0x%x\n",glyphs[glyph_index]);
00554                 return glyph_index + write_dir;
00555             }
00556         }
00557         else
00558         {
00559             const GSUB_SingleSubstFormat2 *ssf2;
00560             INT index;
00561             INT offset;
00562 
00563             ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
00564             offset = GET_BE_WORD(ssf1->Coverage);
00565             TRACE("  subtype 2,  glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
00566             index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyphs[glyph_index]);
00567             TRACE("  Coverage index %i\n",index);
00568             if (index != -1)
00569             {
00570                 if (glyphs[glyph_index] == GET_BE_WORD(ssf2->Substitute[index]))
00571                     return GSUB_E_NOGLYPH;
00572 
00573                 TRACE("    Glyph is 0x%x ->",glyphs[glyph_index]);
00574                 glyphs[glyph_index] = GET_BE_WORD(ssf2->Substitute[index]);
00575                 TRACE("0x%x\n",glyphs[glyph_index]);
00576                 return glyph_index + write_dir;
00577             }
00578         }
00579     }
00580     return GSUB_E_NOGLYPH;
00581 }
00582 
00583 static INT GSUB_apply_MultipleSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
00584 {
00585     int j;
00586     TRACE("Multiple Substitution Subtable\n");
00587 
00588     for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
00589     {
00590         int offset, index;
00591         const GSUB_MultipleSubstFormat1 *msf1;
00592         offset = GET_BE_WORD(look->SubTable[j]);
00593         msf1 = (const GSUB_MultipleSubstFormat1*)((const BYTE*)look+offset);
00594 
00595         offset = GET_BE_WORD(msf1->Coverage);
00596         index = GSUB_is_glyph_covered((const BYTE*)msf1+offset, glyphs[glyph_index]);
00597         if (index != -1)
00598         {
00599             const GSUB_Sequence *seq;
00600             int sub_count;
00601             int j;
00602             offset = GET_BE_WORD(msf1->Sequence[index]);
00603             seq = (const GSUB_Sequence*)((const BYTE*)msf1+offset);
00604             sub_count = GET_BE_WORD(seq->GlyphCount);
00605             TRACE("  Glyph 0x%x (+%i)->",glyphs[glyph_index],(sub_count-1));
00606 
00607             for (j = (*glyph_count)+(sub_count-1); j > glyph_index; j--)
00608                     glyphs[j] =glyphs[j-(sub_count-1)];
00609 
00610             for (j = 0; j < sub_count; j++)
00611                     if (write_dir < 0)
00612                         glyphs[glyph_index + (sub_count-1) - j] = GET_BE_WORD(seq->Substitute[j]);
00613                     else
00614                         glyphs[glyph_index + j] = GET_BE_WORD(seq->Substitute[j]);
00615 
00616             *glyph_count = *glyph_count + (sub_count - 1);
00617 
00618             if (TRACE_ON(uniscribe))
00619             {
00620                 for (j = 0; j < sub_count; j++)
00621                     TRACE(" 0x%x",glyphs[glyph_index+j]);
00622                 TRACE("\n");
00623             }
00624 
00625             return glyph_index + (sub_count * write_dir);
00626         }
00627     }
00628     return GSUB_E_NOGLYPH;
00629 }
00630 
00631 static INT GSUB_apply_AlternateSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
00632 {
00633     int j;
00634     TRACE("Alternate Substitution Subtable\n");
00635 
00636     for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
00637     {
00638         int offset;
00639         const GSUB_AlternateSubstFormat1 *asf1;
00640         INT index;
00641 
00642         offset = GET_BE_WORD(look->SubTable[j]);
00643         asf1 = (const GSUB_AlternateSubstFormat1*)((const BYTE*)look+offset);
00644         offset = GET_BE_WORD(asf1->Coverage);
00645 
00646         index = GSUB_is_glyph_covered((const BYTE*)asf1+offset, glyphs[glyph_index]);
00647         if (index != -1)
00648         {
00649             const GSUB_AlternateSet *as;
00650             offset =  GET_BE_WORD(asf1->AlternateSet[index]);
00651             as = (const GSUB_AlternateSet*)((const BYTE*)asf1+offset);
00652             FIXME("%i alternates, picking index 0\n",GET_BE_WORD(as->GlyphCount));
00653             if (glyphs[glyph_index] == GET_BE_WORD(as->Alternate[0]))
00654                 return GSUB_E_NOGLYPH;
00655 
00656             TRACE("  Glyph 0x%x ->",glyphs[glyph_index]);
00657             glyphs[glyph_index] = GET_BE_WORD(as->Alternate[0]);
00658             TRACE(" 0x%x\n",glyphs[glyph_index]);
00659             return glyph_index + write_dir;
00660         }
00661     }
00662     return GSUB_E_NOGLYPH;
00663 }
00664 
00665 static INT GSUB_apply_LigatureSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
00666 {
00667     int j;
00668 
00669     TRACE("Ligature Substitution Subtable\n");
00670     for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
00671     {
00672         const GSUB_LigatureSubstFormat1 *lsf1;
00673         int offset,index;
00674 
00675         offset = GET_BE_WORD(look->SubTable[j]);
00676         lsf1 = (const GSUB_LigatureSubstFormat1*)((const BYTE*)look+offset);
00677         offset = GET_BE_WORD(lsf1->Coverage);
00678         index = GSUB_is_glyph_covered((const BYTE*)lsf1+offset, glyphs[glyph_index]);
00679         TRACE("  Coverage index %i\n",index);
00680         if (index != -1)
00681         {
00682             const GSUB_LigatureSet *ls;
00683             int k, count;
00684 
00685             offset = GET_BE_WORD(lsf1->LigatureSet[index]);
00686             ls = (const GSUB_LigatureSet*)((const BYTE*)lsf1+offset);
00687             count = GET_BE_WORD(ls->LigatureCount);
00688             TRACE("  LigatureSet has %i members\n",count);
00689             for (k = 0; k < count; k++)
00690             {
00691                 const GSUB_Ligature *lig;
00692                 int CompCount,l,CompIndex;
00693 
00694                 offset = GET_BE_WORD(ls->Ligature[k]);
00695                 lig = (const GSUB_Ligature*)((const BYTE*)ls+offset);
00696                 CompCount = GET_BE_WORD(lig->CompCount) - 1;
00697                 CompIndex = glyph_index+write_dir;
00698                 for (l = 0; l < CompCount && CompIndex >= 0 && CompIndex < *glyph_count; l++)
00699                 {
00700                     int CompGlyph;
00701                     CompGlyph = GET_BE_WORD(lig->Component[l]);
00702                     if (CompGlyph != glyphs[CompIndex])
00703                         break;
00704                     CompIndex += write_dir;
00705                 }
00706                 if (l == CompCount)
00707                 {
00708                     int replaceIdx = glyph_index;
00709                     if (write_dir < 0)
00710                         replaceIdx = glyph_index - CompCount;
00711 
00712                     TRACE("    Glyph is 0x%x (+%i) ->",glyphs[glyph_index],CompCount);
00713                     glyphs[replaceIdx] = GET_BE_WORD(lig->LigGlyph);
00714                     TRACE("0x%x\n",glyphs[replaceIdx]);
00715                     if (CompCount > 0)
00716                     {
00717                         int j;
00718                         for (j = replaceIdx + 1; j < *glyph_count; j++)
00719                             glyphs[j] =glyphs[j+CompCount];
00720                         *glyph_count = *glyph_count - CompCount;
00721                     }
00722                     return replaceIdx + write_dir;
00723                 }
00724             }
00725         }
00726     }
00727     return GSUB_E_NOGLYPH;
00728 }
00729 
00730 static INT GSUB_apply_ChainContextSubst(const GSUB_LookupList* lookup, const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
00731 {
00732     int j;
00733     BOOL done = FALSE;
00734 
00735     TRACE("Chaining Contextual Substitution Subtable\n");
00736     for (j = 0; j < GET_BE_WORD(look->SubTableCount) && !done; j++)
00737     {
00738         const GSUB_ChainContextSubstFormat1 *ccsf1;
00739         int offset;
00740         int dirLookahead = write_dir;
00741         int dirBacktrack = -1 * write_dir;
00742 
00743         offset = GET_BE_WORD(look->SubTable[j]);
00744         ccsf1 = (const GSUB_ChainContextSubstFormat1*)((const BYTE*)look+offset);
00745         if (GET_BE_WORD(ccsf1->SubstFormat) == 1)
00746         {
00747             FIXME("  TODO: subtype 1 (Simple context glyph substitution)\n");
00748             continue;
00749         }
00750         else if (GET_BE_WORD(ccsf1->SubstFormat) == 2)
00751         {
00752             FIXME("  TODO: subtype 2 (Class-based Chaining Context Glyph Substitution)\n");
00753             continue;
00754         }
00755         else if (GET_BE_WORD(ccsf1->SubstFormat) == 3)
00756         {
00757             int k;
00758             int indexGlyphs;
00759             const GSUB_ChainContextSubstFormat3_1 *ccsf3_1;
00760             const GSUB_ChainContextSubstFormat3_2 *ccsf3_2;
00761             const GSUB_ChainContextSubstFormat3_3 *ccsf3_3;
00762             const GSUB_ChainContextSubstFormat3_4 *ccsf3_4;
00763             int newIndex = glyph_index;
00764 
00765             ccsf3_1 = (const GSUB_ChainContextSubstFormat3_1 *)ccsf1;
00766 
00767             TRACE("  subtype 3 (Coverage-based Chaining Context Glyph Substitution)\n");
00768 
00769             for (k = 0; k < GET_BE_WORD(ccsf3_1->BacktrackGlyphCount); k++)
00770             {
00771                 offset = GET_BE_WORD(ccsf3_1->Coverage[k]);
00772                 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (dirBacktrack * (k+1))]) == -1)
00773                     break;
00774             }
00775             if (k != GET_BE_WORD(ccsf3_1->BacktrackGlyphCount))
00776                 continue;
00777             TRACE("Matched Backtrack\n");
00778 
00779             ccsf3_2 = (const GSUB_ChainContextSubstFormat3_2 *)(((LPBYTE)ccsf1)+sizeof(GSUB_ChainContextSubstFormat3_1) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_1->BacktrackGlyphCount)-1)));
00780 
00781             indexGlyphs = GET_BE_WORD(ccsf3_2->InputGlyphCount);
00782             for (k = 0; k < indexGlyphs; k++)
00783             {
00784                 offset = GET_BE_WORD(ccsf3_2->Coverage[k]);
00785                 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (write_dir * k)]) == -1)
00786                     break;
00787             }
00788             if (k != indexGlyphs)
00789                 continue;
00790             TRACE("Matched IndexGlyphs\n");
00791 
00792             ccsf3_3 = (const GSUB_ChainContextSubstFormat3_3 *)(((LPBYTE)ccsf3_2)+sizeof(GSUB_ChainContextSubstFormat3_2) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_2->InputGlyphCount)-1)));
00793 
00794             for (k = 0; k < GET_BE_WORD(ccsf3_3->LookaheadGlyphCount); k++)
00795             {
00796                 offset = GET_BE_WORD(ccsf3_3->Coverage[k]);
00797                 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (dirLookahead * (indexGlyphs + k))]) == -1)
00798                     break;
00799             }
00800             if (k != GET_BE_WORD(ccsf3_3->LookaheadGlyphCount))
00801                 continue;
00802             TRACE("Matched LookAhead\n");
00803 
00804             ccsf3_4 = (const GSUB_ChainContextSubstFormat3_4 *)(((LPBYTE)ccsf3_3)+sizeof(GSUB_ChainContextSubstFormat3_3) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_3->LookaheadGlyphCount)-1)));
00805 
00806             if (GET_BE_WORD(ccsf3_4->SubstCount))
00807             {
00808                 for (k = 0; k < GET_BE_WORD(ccsf3_4->SubstCount); k++)
00809                 {
00810                     int lookupIndex = GET_BE_WORD(ccsf3_4->SubstLookupRecord[k].LookupListIndex);
00811                     int SequenceIndex = GET_BE_WORD(ccsf3_4->SubstLookupRecord[k].SequenceIndex) * write_dir;
00812 
00813                     TRACE("SUBST: %i -> %i %i\n",k, SequenceIndex, lookupIndex);
00814                     newIndex = GSUB_apply_lookup(lookup, lookupIndex, glyphs, glyph_index + SequenceIndex, write_dir, glyph_count);
00815                     if (newIndex == -1)
00816                     {
00817                         ERR("Chain failed to generate a glyph\n");
00818                         continue;
00819                     }
00820                 }
00821                 return newIndex;
00822             }
00823             else return GSUB_E_NOGLYPH;
00824         }
00825     }
00826     return -1;
00827 }
00828 
00829 static INT GSUB_apply_lookup(const GSUB_LookupList* lookup, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
00830 {
00831     int offset;
00832     const GSUB_LookupTable *look;
00833 
00834     offset = GET_BE_WORD(lookup->Lookup[lookup_index]);
00835     look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
00836     TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
00837     switch(GET_BE_WORD(look->LookupType))
00838     {
00839         case 1:
00840             return GSUB_apply_SingleSubst(look, glyphs, glyph_index, write_dir, glyph_count);
00841         case 2:
00842             return GSUB_apply_MultipleSubst(look, glyphs, glyph_index, write_dir, glyph_count);
00843         case 3:
00844             return GSUB_apply_AlternateSubst(look, glyphs, glyph_index, write_dir, glyph_count);
00845         case 4:
00846             return GSUB_apply_LigatureSubst(look, glyphs, glyph_index, write_dir, glyph_count);
00847         case 6:
00848             return GSUB_apply_ChainContextSubst(lookup, look, glyphs, glyph_index, write_dir, glyph_count);
00849         default:
00850             FIXME("We do not handle SubType %i\n",GET_BE_WORD(look->LookupType));
00851     }
00852     return GSUB_E_NOGLYPH;
00853 }
00854 
00855 INT OpenType_apply_GSUB_lookup(LPCVOID table, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
00856 {
00857     const GSUB_Header *header = (const GSUB_Header *)table;
00858     const GSUB_LookupList *lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
00859 
00860     return GSUB_apply_lookup(lookup, lookup_index, glyphs, glyph_index, write_dir, glyph_count);
00861 }
00862 
00863 static void GSUB_initialize_script_cache(ScriptCache *psc)
00864 {
00865     int i;
00866 
00867     if (!psc->script_count)
00868     {
00869         const GSUB_ScriptList *script;
00870         const GSUB_Header* header = (const GSUB_Header*)psc->GSUB_Table;
00871         script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
00872         psc->script_count = GET_BE_WORD(script->ScriptCount);
00873         TRACE("initializing %i scripts in this font\n",psc->script_count);
00874         if (psc->script_count)
00875         {
00876             psc->scripts = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(LoadedScript) * psc->script_count);
00877             for (i = 0; i < psc->script_count; i++)
00878             {
00879                 int offset = GET_BE_WORD(script->ScriptRecord[i].Script);
00880                 psc->scripts[i].tag = MS_MAKE_TAG(script->ScriptRecord[i].ScriptTag[0], script->ScriptRecord[i].ScriptTag[1], script->ScriptRecord[i].ScriptTag[2], script->ScriptRecord[i].ScriptTag[3]);
00881                 psc->scripts[i].table = ((const BYTE*)script + offset);
00882             }
00883         }
00884     }
00885 }
00886 
00887 HRESULT OpenType_GSUB_GetFontScriptTags(ScriptCache *psc, OPENTYPE_TAG searchingFor, int cMaxTags, OPENTYPE_TAG *pScriptTags, int *pcTags, LPCVOID* script_table)
00888 {
00889     int i;
00890     HRESULT rc = S_OK;
00891 
00892     GSUB_initialize_script_cache(psc);
00893     *pcTags = psc->script_count;
00894 
00895     if (!searchingFor && cMaxTags < *pcTags)
00896         rc = E_OUTOFMEMORY;
00897     else if (searchingFor)
00898         rc = USP_E_SCRIPT_NOT_IN_FONT;
00899 
00900     for (i = 0; i < psc->script_count; i++)
00901     {
00902         if (i < cMaxTags)
00903             pScriptTags[i] = psc->scripts[i].tag;
00904 
00905         if (searchingFor)
00906         {
00907             if (searchingFor == psc->scripts[i].tag)
00908             {
00909                 pScriptTags[0] = psc->scripts[i].tag;
00910                 *pcTags = 1;
00911                 if (script_table)
00912                     *script_table = psc->scripts[i].table;
00913                 rc = S_OK;
00914                 break;
00915             }
00916         }
00917     }
00918     return rc;
00919 }
00920 
00921 static void GSUB_initialize_language_cache(LoadedScript *script)
00922 {
00923     int i;
00924 
00925     if (!script->language_count)
00926     {
00927         const GSUB_Script* table = script->table;
00928         script->language_count = GET_BE_WORD(table->LangSysCount);
00929         script->default_language.tag = MS_MAKE_TAG('d','f','l','t');
00930         script->default_language.table = (const BYTE*)table + GET_BE_WORD(table->DefaultLangSys);
00931 
00932         if (script->language_count)
00933         {
00934             TRACE("Deflang %p, LangCount %i\n",script->default_language.table, script->language_count);
00935 
00936             script->languages = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(LoadedLanguage) * script->language_count);
00937 
00938             for (i = 0; i < script->language_count; i++)
00939             {
00940                 int offset = GET_BE_WORD(table->LangSysRecord[i].LangSys);
00941                 script->languages[i].tag = MS_MAKE_TAG(table->LangSysRecord[i].LangSysTag[0], table->LangSysRecord[i].LangSysTag[1], table->LangSysRecord[i].LangSysTag[2], table->LangSysRecord[i].LangSysTag[3]);
00942                 script->languages[i].table = ((const BYTE*)table + offset);
00943             }
00944         }
00945     }
00946 }
00947 
00948 HRESULT OpenType_GSUB_GetFontLanguageTags(ScriptCache *psc, OPENTYPE_TAG script_tag, OPENTYPE_TAG searchingFor, int cMaxTags, OPENTYPE_TAG *pLanguageTags, int *pcTags, LPCVOID* language_table)
00949 {
00950     int i;
00951     HRESULT rc = S_OK;
00952     LoadedScript *script = NULL;
00953 
00954     GSUB_initialize_script_cache(psc);
00955 
00956     for (i = 0; i < psc->script_count; i++)
00957     {
00958          if (psc->scripts[i].tag == script_tag)
00959          {
00960             script = &psc->scripts[i];
00961             break;
00962          }
00963     }
00964 
00965     if (!script)
00966         return E_INVALIDARG;
00967 
00968     GSUB_initialize_language_cache(script);
00969 
00970     if (!searchingFor && cMaxTags < script->language_count)
00971         rc = E_OUTOFMEMORY;
00972     else if (searchingFor)
00973         rc = E_INVALIDARG;
00974 
00975     *pcTags = script->language_count;
00976 
00977     for (i = 0; i < script->language_count; i++)
00978     {
00979         if (i < cMaxTags)
00980             pLanguageTags[i] = script->languages[i].tag;
00981 
00982         if (searchingFor)
00983         {
00984             if (searchingFor == script->languages[i].tag)
00985             {
00986                 pLanguageTags[0] = script->languages[i].tag;
00987                 *pcTags = 1;
00988                 if (language_table)
00989                     *language_table = script->languages[i].table;
00990                 rc = S_OK;
00991                 break;
00992             }
00993         }
00994     }
00995 
00996     if (script->default_language.table)
00997     {
00998         if (i < cMaxTags)
00999             pLanguageTags[i] = script->default_language.tag;
01000 
01001         if (searchingFor  && FAILED(rc))
01002         {
01003             pLanguageTags[0] = script->default_language.tag;
01004             if (language_table)
01005                 *language_table = script->default_language.table;
01006         }
01007         i++;
01008         *pcTags = (*pcTags) + 1;
01009     }
01010 
01011     return rc;
01012 }
01013 
01014 
01015 static void GSUB_initialize_feature_cache(LPCVOID table, LoadedLanguage *language)
01016 {
01017     int i;
01018 
01019     if (!language->feature_count)
01020     {
01021         const GSUB_LangSys *lang= language->table;
01022         const GSUB_Header *header = (const GSUB_Header *)table;
01023         const GSUB_FeatureList *feature_list;
01024 
01025         language->feature_count = GET_BE_WORD(lang->FeatureCount);
01026         TRACE("%i features\n",language->feature_count);
01027 
01028         if (language->feature_count)
01029         {
01030             language->features = HeapAlloc(GetProcessHeap(),0,sizeof(LoadedFeature)*language->feature_count);
01031 
01032             feature_list = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
01033 
01034             for (i = 0; i < language->feature_count; i++)
01035             {
01036                 const GSUB_Feature *feature;
01037                 int j;
01038                 int index = GET_BE_WORD(lang->FeatureIndex[i]);
01039 
01040                 language->features[i].tag = MS_MAKE_TAG(feature_list->FeatureRecord[index].FeatureTag[0], feature_list->FeatureRecord[index].FeatureTag[1], feature_list->FeatureRecord[index].FeatureTag[2], feature_list->FeatureRecord[index].FeatureTag[3]);
01041                 language->features[i].feature = ((const BYTE*)feature_list + GET_BE_WORD(feature_list->FeatureRecord[index].Feature));
01042                 feature = (const GSUB_Feature*)language->features[i].feature;
01043                 language->features[i].lookup_count = GET_BE_WORD(feature->LookupCount);
01044                 language->features[i].lookups = HeapAlloc(GetProcessHeap(),0,sizeof(WORD) * language->features[i].lookup_count);
01045                 for (j = 0; j < language->features[i].lookup_count; j++)
01046                     language->features[i].lookups[j] = GET_BE_WORD(feature->LookupListIndex[j]);
01047             }
01048         }
01049     }
01050 }
01051 
01052 HRESULT OpenType_GSUB_GetFontFeatureTags(ScriptCache *psc, OPENTYPE_TAG script_tag, OPENTYPE_TAG language_tag, BOOL filtered, OPENTYPE_TAG searchingFor, int cMaxTags, OPENTYPE_TAG *pFeatureTags, int *pcTags, LoadedFeature** feature)
01053 {
01054     int i;
01055     HRESULT rc = S_OK;
01056     LoadedScript *script = NULL;
01057     LoadedLanguage *language = NULL;
01058 
01059     GSUB_initialize_script_cache(psc);
01060 
01061     for (i = 0; i < psc->script_count; i++)
01062     {
01063         if (psc->scripts[i].tag == script_tag)
01064         {
01065             script = &psc->scripts[i];
01066             break;
01067         }
01068     }
01069 
01070     if (!script)
01071     {
01072         *pcTags = 0;
01073         if (!filtered)
01074             return S_OK;
01075         else
01076             return E_INVALIDARG;
01077     }
01078 
01079     GSUB_initialize_language_cache(script);
01080 
01081     if (script->default_language.table && script->default_language.tag == language_tag)
01082         language = &script->default_language;
01083     else
01084     {
01085         for (i = 0; i < script->language_count; i++)
01086         {
01087             if (script->languages[i].tag == language_tag)
01088             {
01089                 language = &script->languages[i];
01090                 break;
01091             }
01092         }
01093     }
01094 
01095     if (!language)
01096     {
01097         *pcTags = 0;
01098         return S_OK;
01099     }
01100 
01101     GSUB_initialize_feature_cache(psc->GSUB_Table, language);
01102 
01103     *pcTags = language->feature_count;
01104 
01105     if (!searchingFor && cMaxTags < *pcTags)
01106         rc = E_OUTOFMEMORY;
01107     else if (searchingFor)
01108         rc = E_INVALIDARG;
01109 
01110     for (i = 0; i < language->feature_count; i++)
01111     {
01112         if (i < cMaxTags)
01113             pFeatureTags[i] = language->features[i].tag;
01114 
01115         if (searchingFor)
01116         {
01117             if (searchingFor == language->features[i].tag)
01118             {
01119                 pFeatureTags[0] = language->features[i].tag;
01120                 *pcTags = 1;
01121                 if (feature)
01122                     *feature = &language->features[i];
01123                 rc = S_OK;
01124                 break;
01125             }
01126         }
01127     }
01128     return rc;
01129 }

Generated on Sun May 27 2012 04:26:43 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.