linebreak.c
usp10.c
mirror.c
+ opentype.c
shape.c
shaping.c
${CMAKE_CURRENT_BINARY_DIR}/usp10_stubs.c
--- /dev/null
+/*
+ * Opentype font interfaces for the Uniscribe Script Processor (usp10.dll)
+ *
+ * Copyright 2012 CodeWeavers, Aric Stewart
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ */
+#include <stdarg.h>
+#include <stdlib.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winuser.h"
+#include "winnls.h"
+#include "usp10.h"
+#include "winternl.h"
+
+#include "usp10_internal.h"
+
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(uniscribe);
+
+#ifdef WORDS_BIGENDIAN
+#define GET_BE_WORD(x) (x)
+#define GET_BE_DWORD(x) (x)
+#else
+#define GET_BE_WORD(x) RtlUshortByteSwap(x)
+#define GET_BE_DWORD(x) RtlUlongByteSwap(x)
+#endif
+
+/* These are all structures needed for the cmap format 12 table */
+#define CMAP_TAG MS_MAKE_TAG('c', 'm', 'a', 'p')
+
+typedef struct {
+ WORD platformID;
+ WORD encodingID;
+ DWORD offset;
+} CMAP_EncodingRecord;
+
+typedef struct {
+ WORD version;
+ WORD numTables;
+ CMAP_EncodingRecord tables[1];
+} CMAP_Header;
+
+typedef struct {
+ DWORD startCharCode;
+ DWORD endCharCode;
+ DWORD startGlyphID;
+} CMAP_SegmentedCoverage_group;
+
+typedef struct {
+ WORD format;
+ WORD reserved;
+ DWORD length;
+ DWORD language;
+ DWORD nGroups;
+ CMAP_SegmentedCoverage_group groups[1];
+} CMAP_SegmentedCoverage;
+
+/* These are all structures needed for the GDEF table */
+#define GDEF_TAG MS_MAKE_TAG('G', 'D', 'E', 'F')
+
+enum {BaseGlyph=1, LigatureGlyph, MarkGlyph, ComponentGlyph};
+
+typedef struct {
+ DWORD Version;
+ WORD GlyphClassDef;
+ WORD AttachList;
+ WORD LigCaretList;
+ WORD MarkAttachClassDef;
+} GDEF_Header;
+
+typedef struct {
+ WORD ClassFormat;
+ WORD StartGlyph;
+ WORD GlyphCount;
+ WORD ClassValueArray[1];
+} GDEF_ClassDefFormat1;
+
+typedef struct {
+ WORD Start;
+ WORD End;
+ WORD Class;
+} GDEF_ClassRangeRecord;
+
+typedef struct {
+ WORD ClassFormat;
+ WORD ClassRangeCount;
+ GDEF_ClassRangeRecord ClassRangeRecord[1];
+} GDEF_ClassDefFormat2;
+
+/* These are all structures needed for the GSUB table */
+
+typedef struct {
+ DWORD version;
+ WORD ScriptList;
+ WORD FeatureList;
+ WORD LookupList;
+} GSUB_Header;
+
+typedef struct {
+ CHAR ScriptTag[4];
+ WORD Script;
+} GSUB_ScriptRecord;
+
+typedef struct {
+ WORD ScriptCount;
+ GSUB_ScriptRecord ScriptRecord[1];
+} GSUB_ScriptList;
+
+typedef struct {
+ CHAR LangSysTag[4];
+ WORD LangSys;
+} GSUB_LangSysRecord;
+
+typedef struct {
+ WORD DefaultLangSys;
+ WORD LangSysCount;
+ GSUB_LangSysRecord LangSysRecord[1];
+} GSUB_Script;
+
+typedef struct {
+ WORD LookupOrder; /* Reserved */
+ WORD ReqFeatureIndex;
+ WORD FeatureCount;
+ WORD FeatureIndex[1];
+} GSUB_LangSys;
+
+typedef struct {
+ CHAR FeatureTag[4];
+ WORD Feature;
+} GSUB_FeatureRecord;
+
+typedef struct {
+ WORD FeatureCount;
+ GSUB_FeatureRecord FeatureRecord[1];
+} GSUB_FeatureList;
+
+typedef struct {
+ WORD FeatureParams; /* Reserved */
+ WORD LookupCount;
+ WORD LookupListIndex[1];
+} GSUB_Feature;
+
+typedef struct {
+ WORD LookupCount;
+ WORD Lookup[1];
+} GSUB_LookupList;
+
+typedef struct {
+ WORD LookupType;
+ WORD LookupFlag;
+ WORD SubTableCount;
+ WORD SubTable[1];
+} GSUB_LookupTable;
+
+typedef struct {
+ WORD CoverageFormat;
+ WORD GlyphCount;
+ WORD GlyphArray[1];
+} GSUB_CoverageFormat1;
+
+typedef struct {
+ WORD Start;
+ WORD End;
+ WORD StartCoverageIndex;
+} GSUB_RangeRecord;
+
+typedef struct {
+ WORD CoverageFormat;
+ WORD RangeCount;
+ GSUB_RangeRecord RangeRecord[1];
+} GSUB_CoverageFormat2;
+
+typedef struct {
+ WORD SubstFormat; /* = 1 */
+ WORD Coverage;
+ WORD DeltaGlyphID;
+} GSUB_SingleSubstFormat1;
+
+typedef struct {
+ WORD SubstFormat; /* = 2 */
+ WORD Coverage;
+ WORD GlyphCount;
+ WORD Substitute[1];
+}GSUB_SingleSubstFormat2;
+
+typedef struct {
+ WORD SubstFormat; /* = 1 */
+ WORD Coverage;
+ WORD SequenceCount;
+ WORD Sequence[1];
+}GSUB_MultipleSubstFormat1;
+
+typedef struct {
+ WORD GlyphCount;
+ WORD Substitute[1];
+}GSUB_Sequence;
+
+typedef struct {
+ WORD SubstFormat; /* = 1 */
+ WORD Coverage;
+ WORD LigSetCount;
+ WORD LigatureSet[1];
+}GSUB_LigatureSubstFormat1;
+
+typedef struct {
+ WORD LigatureCount;
+ WORD Ligature[1];
+}GSUB_LigatureSet;
+
+typedef struct{
+ WORD LigGlyph;
+ WORD CompCount;
+ WORD Component[1];
+}GSUB_Ligature;
+
+typedef struct{
+ WORD SequenceIndex;
+ WORD LookupListIndex;
+
+}GSUB_SubstLookupRecord;
+
+typedef struct{
+ WORD SubstFormat; /* = 1 */
+ WORD Coverage;
+ WORD ChainSubRuleSetCount;
+ WORD ChainSubRuleSet[1];
+}GSUB_ChainContextSubstFormat1;
+
+typedef struct {
+ WORD SubstFormat; /* = 3 */
+ WORD BacktrackGlyphCount;
+ WORD Coverage[1];
+}GSUB_ChainContextSubstFormat3_1;
+
+typedef struct{
+ WORD InputGlyphCount;
+ WORD Coverage[1];
+}GSUB_ChainContextSubstFormat3_2;
+
+typedef struct{
+ WORD LookaheadGlyphCount;
+ WORD Coverage[1];
+}GSUB_ChainContextSubstFormat3_3;
+
+typedef struct{
+ WORD SubstCount;
+ GSUB_SubstLookupRecord SubstLookupRecord[1];
+}GSUB_ChainContextSubstFormat3_4;
+
+typedef struct {
+ WORD SubstFormat; /* = 1 */
+ WORD Coverage;
+ WORD AlternateSetCount;
+ WORD AlternateSet[1];
+} GSUB_AlternateSubstFormat1;
+
+typedef struct{
+ WORD GlyphCount;
+ WORD Alternate[1];
+} GSUB_AlternateSet;
+
+/**********
+ * CMAP
+ **********/
+
+static VOID *load_CMAP_format12_table(HDC hdc, ScriptCache *psc)
+{
+ CMAP_Header *CMAP_Table = NULL;
+ int length;
+ int i;
+
+ if (!psc->CMAP_Table)
+ {
+ length = GetFontData(hdc, CMAP_TAG , 0, NULL, 0);
+ if (length != GDI_ERROR)
+ {
+ psc->CMAP_Table = HeapAlloc(GetProcessHeap(),0,length);
+ GetFontData(hdc, CMAP_TAG , 0, psc->CMAP_Table, length);
+ TRACE("Loaded cmap table of %i bytes\n",length);
+ }
+ else
+ return NULL;
+ }
+
+ CMAP_Table = psc->CMAP_Table;
+
+ for (i = 0; i < GET_BE_WORD(CMAP_Table->numTables); i++)
+ {
+ if ( (GET_BE_WORD(CMAP_Table->tables[i].platformID) == 3) &&
+ (GET_BE_WORD(CMAP_Table->tables[i].encodingID) == 10) )
+ {
+ CMAP_SegmentedCoverage *format = (CMAP_SegmentedCoverage*)(((BYTE*)CMAP_Table) + GET_BE_DWORD(CMAP_Table->tables[i].offset));
+ if (GET_BE_WORD(format->format) == 12)
+ return format;
+ }
+ }
+ return NULL;
+}
+
+static int compare_group(const void *a, const void* b)
+{
+ const DWORD *chr = a;
+ const CMAP_SegmentedCoverage_group *group = b;
+
+ if (*chr < GET_BE_DWORD(group->startCharCode))
+ return -1;
+ if (*chr > GET_BE_DWORD(group->endCharCode))
+ return 1;
+ return 0;
+}
+
+DWORD OpenType_CMAP_GetGlyphIndex(HDC hdc, ScriptCache *psc, DWORD utf32c, LPWORD pgi, DWORD flags)
+{
+ /* BMP: use gdi32 for ease */
+ if (utf32c < 0x10000)
+ {
+ WCHAR ch = utf32c;
+ return GetGlyphIndicesW(hdc,&ch, 1, pgi, flags);
+ }
+
+ if (!psc->CMAP_format12_Table)
+ psc->CMAP_format12_Table = load_CMAP_format12_table(hdc, psc);
+
+ if (flags & GGI_MARK_NONEXISTING_GLYPHS)
+ *pgi = 0xffff;
+ else
+ *pgi = 0;
+
+ if (psc->CMAP_format12_Table)
+ {
+ CMAP_SegmentedCoverage *format = NULL;
+ CMAP_SegmentedCoverage_group *group = NULL;
+
+ format = (CMAP_SegmentedCoverage *)psc->CMAP_format12_Table;
+
+ group = bsearch(&utf32c, format->groups, GET_BE_DWORD(format->nGroups),
+ sizeof(CMAP_SegmentedCoverage_group), compare_group);
+
+ if (group)
+ {
+ DWORD offset = utf32c - GET_BE_DWORD(group->startCharCode);
+ *pgi = GET_BE_DWORD(group->startGlyphID) + offset;
+ return 0;
+ }
+ }
+ return 0;
+}
+
+/**********
+ * GDEF
+ **********/
+
+static WORD GDEF_get_glyph_class(const GDEF_Header *header, WORD glyph)
+{
+ int offset;
+ WORD class = 0;
+ const GDEF_ClassDefFormat1 *cf1;
+
+ if (!header)
+ return 0;
+
+ offset = GET_BE_WORD(header->GlyphClassDef);
+ if (!offset)
+ return 0;
+
+ cf1 = (GDEF_ClassDefFormat1*)(((BYTE*)header)+offset);
+ if (GET_BE_WORD(cf1->ClassFormat) == 1)
+ {
+ if (glyph >= GET_BE_WORD(cf1->StartGlyph))
+ {
+ int index = glyph - GET_BE_WORD(cf1->StartGlyph);
+ if (index < GET_BE_WORD(cf1->GlyphCount))
+ class = GET_BE_WORD(cf1->ClassValueArray[index]);
+ }
+ }
+ else if (GET_BE_WORD(cf1->ClassFormat) == 2)
+ {
+ const GDEF_ClassDefFormat2 *cf2 = (GDEF_ClassDefFormat2*)cf1;
+ int i, top;
+ top = GET_BE_WORD(cf2->ClassRangeCount);
+ for (i = 0; i < top; i++)
+ {
+ if (glyph >= GET_BE_WORD(cf2->ClassRangeRecord[i].Start) &&
+ glyph <= GET_BE_WORD(cf2->ClassRangeRecord[i].End))
+ {
+ class = GET_BE_WORD(cf2->ClassRangeRecord[i].Class);
+ break;
+ }
+ }
+ }
+ else
+ ERR("Unknown Class Format %i\n",GET_BE_WORD(cf1->ClassFormat));
+
+ return class;
+}
+
+static VOID *load_gdef_table(HDC hdc)
+{
+ VOID* GDEF_Table = NULL;
+ int length = GetFontData(hdc, GDEF_TAG , 0, NULL, 0);
+ if (length != GDI_ERROR)
+ {
+ GDEF_Table = HeapAlloc(GetProcessHeap(),0,length);
+ GetFontData(hdc, GDEF_TAG , 0, GDEF_Table, length);
+ TRACE("Loaded GDEF table of %i bytes\n",length);
+ }
+ return GDEF_Table;
+}
+
+void OpenType_GDEF_UpdateGlyphProps(HDC hdc, ScriptCache *psc, const WORD *pwGlyphs, const WORD cGlyphs, WORD* pwLogClust, const WORD cChars, SCRIPT_GLYPHPROP *pGlyphProp)
+{
+ int i;
+
+ if (!psc->GDEF_Table)
+ psc->GDEF_Table = load_gdef_table(hdc);
+
+ for (i = 0; i < cGlyphs; i++)
+ {
+ WORD class;
+ int char_count = 0;
+ int k;
+
+ for (k = 0; k < cChars; k++)
+ if (pwLogClust[k] == i)
+ char_count++;
+
+ class = GDEF_get_glyph_class(psc->GDEF_Table, pwGlyphs[i]);
+
+ switch (class)
+ {
+ case 0:
+ case BaseGlyph:
+ pGlyphProp[i].sva.fClusterStart = 1;
+ pGlyphProp[i].sva.fDiacritic = 0;
+ pGlyphProp[i].sva.fZeroWidth = 0;
+ break;
+ case LigatureGlyph:
+ pGlyphProp[i].sva.fClusterStart = 1;
+ pGlyphProp[i].sva.fDiacritic = 0;
+ pGlyphProp[i].sva.fZeroWidth = 0;
+ break;
+ case MarkGlyph:
+ pGlyphProp[i].sva.fClusterStart = 0;
+ pGlyphProp[i].sva.fDiacritic = 1;
+ pGlyphProp[i].sva.fZeroWidth = 1;
+ break;
+ case ComponentGlyph:
+ pGlyphProp[i].sva.fClusterStart = 0;
+ pGlyphProp[i].sva.fDiacritic = 0;
+ pGlyphProp[i].sva.fZeroWidth = 0;
+ break;
+ default:
+ ERR("Unknown glyph class %i\n",class);
+ pGlyphProp[i].sva.fClusterStart = 1;
+ pGlyphProp[i].sva.fDiacritic = 0;
+ pGlyphProp[i].sva.fZeroWidth = 0;
+ }
+
+ if (char_count == 0)
+ pGlyphProp[i].sva.fClusterStart = 0;
+ }
+}
+
+/**********
+ * GSUB
+ **********/
+static INT GSUB_apply_lookup(const GSUB_LookupList* lookup, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count);
+
+static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
+{
+ const GSUB_CoverageFormat1* cf1;
+
+ cf1 = table;
+
+ if (GET_BE_WORD(cf1->CoverageFormat) == 1)
+ {
+ int count = GET_BE_WORD(cf1->GlyphCount);
+ int i;
+ TRACE("Coverage Format 1, %i glyphs\n",count);
+ for (i = 0; i < count; i++)
+ if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
+ return i;
+ return -1;
+ }
+ else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
+ {
+ const GSUB_CoverageFormat2* cf2;
+ int i;
+ int count;
+ cf2 = (const GSUB_CoverageFormat2*)cf1;
+
+ count = GET_BE_WORD(cf2->RangeCount);
+ TRACE("Coverage Format 2, %i ranges\n",count);
+ for (i = 0; i < count; i++)
+ {
+ if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
+ return -1;
+ if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
+ (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
+ {
+ return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
+ glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
+ }
+ }
+ return -1;
+ }
+ else
+ ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
+
+ return -1;
+}
+
+static INT GSUB_apply_SingleSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
+{
+ int j;
+ TRACE("Single Substitution Subtable\n");
+
+ for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
+ {
+ int offset;
+ const GSUB_SingleSubstFormat1 *ssf1;
+ offset = GET_BE_WORD(look->SubTable[j]);
+ ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
+ if (GET_BE_WORD(ssf1->SubstFormat) == 1)
+ {
+ int offset = GET_BE_WORD(ssf1->Coverage);
+ TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
+ if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyphs[glyph_index]) != -1)
+ {
+ TRACE(" Glyph 0x%x ->",glyphs[glyph_index]);
+ glyphs[glyph_index] = glyphs[glyph_index] + GET_BE_WORD(ssf1->DeltaGlyphID);
+ TRACE(" 0x%x\n",glyphs[glyph_index]);
+ return glyph_index + write_dir;
+ }
+ }
+ else
+ {
+ const GSUB_SingleSubstFormat2 *ssf2;
+ INT index;
+ INT offset;
+
+ ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
+ offset = GET_BE_WORD(ssf1->Coverage);
+ TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
+ index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyphs[glyph_index]);
+ TRACE(" Coverage index %i\n",index);
+ if (index != -1)
+ {
+ if (glyphs[glyph_index] == GET_BE_WORD(ssf2->Substitute[index]))
+ return GSUB_E_NOGLYPH;
+
+ TRACE(" Glyph is 0x%x ->",glyphs[glyph_index]);
+ glyphs[glyph_index] = GET_BE_WORD(ssf2->Substitute[index]);
+ TRACE("0x%x\n",glyphs[glyph_index]);
+ return glyph_index + write_dir;
+ }
+ }
+ }
+ return GSUB_E_NOGLYPH;
+}
+
+static INT GSUB_apply_MultipleSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
+{
+ int j;
+ TRACE("Multiple Substitution Subtable\n");
+
+ for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
+ {
+ int offset, index;
+ const GSUB_MultipleSubstFormat1 *msf1;
+ offset = GET_BE_WORD(look->SubTable[j]);
+ msf1 = (const GSUB_MultipleSubstFormat1*)((const BYTE*)look+offset);
+
+ offset = GET_BE_WORD(msf1->Coverage);
+ index = GSUB_is_glyph_covered((const BYTE*)msf1+offset, glyphs[glyph_index]);
+ if (index != -1)
+ {
+ const GSUB_Sequence *seq;
+ int sub_count;
+ int j;
+ offset = GET_BE_WORD(msf1->Sequence[index]);
+ seq = (const GSUB_Sequence*)((const BYTE*)msf1+offset);
+ sub_count = GET_BE_WORD(seq->GlyphCount);
+ TRACE(" Glyph 0x%x (+%i)->",glyphs[glyph_index],(sub_count-1));
+
+ for (j = (*glyph_count)+(sub_count-1); j > glyph_index; j--)
+ glyphs[j] =glyphs[j-(sub_count-1)];
+
+ for (j = 0; j < sub_count; j++)
+ if (write_dir < 0)
+ glyphs[glyph_index + (sub_count-1) - j] = GET_BE_WORD(seq->Substitute[j]);
+ else
+ glyphs[glyph_index + j] = GET_BE_WORD(seq->Substitute[j]);
+
+ *glyph_count = *glyph_count + (sub_count - 1);
+
+ if (TRACE_ON(uniscribe))
+ {
+ for (j = 0; j < sub_count; j++)
+ TRACE(" 0x%x",glyphs[glyph_index+j]);
+ TRACE("\n");
+ }
+
+ return glyph_index + (sub_count * write_dir);
+ }
+ }
+ return GSUB_E_NOGLYPH;
+}
+
+static INT GSUB_apply_AlternateSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
+{
+ int j;
+ TRACE("Alternate Substitution Subtable\n");
+
+ for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
+ {
+ int offset;
+ const GSUB_AlternateSubstFormat1 *asf1;
+ INT index;
+
+ offset = GET_BE_WORD(look->SubTable[j]);
+ asf1 = (const GSUB_AlternateSubstFormat1*)((const BYTE*)look+offset);
+ offset = GET_BE_WORD(asf1->Coverage);
+
+ index = GSUB_is_glyph_covered((const BYTE*)asf1+offset, glyphs[glyph_index]);
+ if (index != -1)
+ {
+ const GSUB_AlternateSet *as;
+ offset = GET_BE_WORD(asf1->AlternateSet[index]);
+ as = (const GSUB_AlternateSet*)((const BYTE*)asf1+offset);
+ FIXME("%i alternates, picking index 0\n",GET_BE_WORD(as->GlyphCount));
+ if (glyphs[glyph_index] == GET_BE_WORD(as->Alternate[0]))
+ return GSUB_E_NOGLYPH;
+
+ TRACE(" Glyph 0x%x ->",glyphs[glyph_index]);
+ glyphs[glyph_index] = GET_BE_WORD(as->Alternate[0]);
+ TRACE(" 0x%x\n",glyphs[glyph_index]);
+ return glyph_index + write_dir;
+ }
+ }
+ return GSUB_E_NOGLYPH;
+}
+
+static INT GSUB_apply_LigatureSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
+{
+ int j;
+
+ TRACE("Ligature Substitution Subtable\n");
+ for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
+ {
+ const GSUB_LigatureSubstFormat1 *lsf1;
+ int offset,index;
+
+ offset = GET_BE_WORD(look->SubTable[j]);
+ lsf1 = (const GSUB_LigatureSubstFormat1*)((const BYTE*)look+offset);
+ offset = GET_BE_WORD(lsf1->Coverage);
+ index = GSUB_is_glyph_covered((const BYTE*)lsf1+offset, glyphs[glyph_index]);
+ TRACE(" Coverage index %i\n",index);
+ if (index != -1)
+ {
+ const GSUB_LigatureSet *ls;
+ int k, count;
+
+ offset = GET_BE_WORD(lsf1->LigatureSet[index]);
+ ls = (const GSUB_LigatureSet*)((const BYTE*)lsf1+offset);
+ count = GET_BE_WORD(ls->LigatureCount);
+ TRACE(" LigatureSet has %i members\n",count);
+ for (k = 0; k < count; k++)
+ {
+ const GSUB_Ligature *lig;
+ int CompCount,l,CompIndex;
+
+ offset = GET_BE_WORD(ls->Ligature[k]);
+ lig = (const GSUB_Ligature*)((const BYTE*)ls+offset);
+ CompCount = GET_BE_WORD(lig->CompCount) - 1;
+ CompIndex = glyph_index+write_dir;
+ for (l = 0; l < CompCount && CompIndex >= 0 && CompIndex < *glyph_count; l++)
+ {
+ int CompGlyph;
+ CompGlyph = GET_BE_WORD(lig->Component[l]);
+ if (CompGlyph != glyphs[CompIndex])
+ break;
+ CompIndex += write_dir;
+ }
+ if (l == CompCount)
+ {
+ int replaceIdx = glyph_index;
+ if (write_dir < 0)
+ replaceIdx = glyph_index - CompCount;
+
+ TRACE(" Glyph is 0x%x (+%i) ->",glyphs[glyph_index],CompCount);
+ glyphs[replaceIdx] = GET_BE_WORD(lig->LigGlyph);
+ TRACE("0x%x\n",glyphs[replaceIdx]);
+ if (CompCount > 0)
+ {
+ int j;
+ for (j = replaceIdx + 1; j < *glyph_count; j++)
+ glyphs[j] =glyphs[j+CompCount];
+ *glyph_count = *glyph_count - CompCount;
+ }
+ return replaceIdx + write_dir;
+ }
+ }
+ }
+ }
+ return GSUB_E_NOGLYPH;
+}
+
+static INT GSUB_apply_ChainContextSubst(const GSUB_LookupList* lookup, const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
+{
+ int j;
+ BOOL done = FALSE;
+
+ TRACE("Chaining Contextual Substitution Subtable\n");
+ for (j = 0; j < GET_BE_WORD(look->SubTableCount) && !done; j++)
+ {
+ const GSUB_ChainContextSubstFormat1 *ccsf1;
+ int offset;
+ int dirLookahead = write_dir;
+ int dirBacktrack = -1 * write_dir;
+
+ offset = GET_BE_WORD(look->SubTable[j]);
+ ccsf1 = (const GSUB_ChainContextSubstFormat1*)((const BYTE*)look+offset);
+ if (GET_BE_WORD(ccsf1->SubstFormat) == 1)
+ {
+ FIXME(" TODO: subtype 1 (Simple context glyph substitution)\n");
+ continue;
+ }
+ else if (GET_BE_WORD(ccsf1->SubstFormat) == 2)
+ {
+ FIXME(" TODO: subtype 2 (Class-based Chaining Context Glyph Substitution)\n");
+ continue;
+ }
+ else if (GET_BE_WORD(ccsf1->SubstFormat) == 3)
+ {
+ int k;
+ int indexGlyphs;
+ const GSUB_ChainContextSubstFormat3_1 *ccsf3_1;
+ const GSUB_ChainContextSubstFormat3_2 *ccsf3_2;
+ const GSUB_ChainContextSubstFormat3_3 *ccsf3_3;
+ const GSUB_ChainContextSubstFormat3_4 *ccsf3_4;
+ int newIndex = glyph_index;
+
+ ccsf3_1 = (const GSUB_ChainContextSubstFormat3_1 *)ccsf1;
+
+ TRACE(" subtype 3 (Coverage-based Chaining Context Glyph Substitution)\n");
+
+ for (k = 0; k < GET_BE_WORD(ccsf3_1->BacktrackGlyphCount); k++)
+ {
+ offset = GET_BE_WORD(ccsf3_1->Coverage[k]);
+ if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (dirBacktrack * (k+1))]) == -1)
+ break;
+ }
+ if (k != GET_BE_WORD(ccsf3_1->BacktrackGlyphCount))
+ continue;
+ TRACE("Matched Backtrack\n");
+
+ ccsf3_2 = (const GSUB_ChainContextSubstFormat3_2 *)(((LPBYTE)ccsf1)+sizeof(GSUB_ChainContextSubstFormat3_1) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_1->BacktrackGlyphCount)-1)));
+
+ indexGlyphs = GET_BE_WORD(ccsf3_2->InputGlyphCount);
+ for (k = 0; k < indexGlyphs; k++)
+ {
+ offset = GET_BE_WORD(ccsf3_2->Coverage[k]);
+ if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (write_dir * k)]) == -1)
+ break;
+ }
+ if (k != indexGlyphs)
+ continue;
+ TRACE("Matched IndexGlyphs\n");
+
+ ccsf3_3 = (const GSUB_ChainContextSubstFormat3_3 *)(((LPBYTE)ccsf3_2)+sizeof(GSUB_ChainContextSubstFormat3_2) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_2->InputGlyphCount)-1)));
+
+ for (k = 0; k < GET_BE_WORD(ccsf3_3->LookaheadGlyphCount); k++)
+ {
+ offset = GET_BE_WORD(ccsf3_3->Coverage[k]);
+ if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (dirLookahead * (indexGlyphs + k))]) == -1)
+ break;
+ }
+ if (k != GET_BE_WORD(ccsf3_3->LookaheadGlyphCount))
+ continue;
+ TRACE("Matched LookAhead\n");
+
+ ccsf3_4 = (const GSUB_ChainContextSubstFormat3_4 *)(((LPBYTE)ccsf3_3)+sizeof(GSUB_ChainContextSubstFormat3_3) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_3->LookaheadGlyphCount)-1)));
+
+ if (GET_BE_WORD(ccsf3_4->SubstCount))
+ {
+ for (k = 0; k < GET_BE_WORD(ccsf3_4->SubstCount); k++)
+ {
+ int lookupIndex = GET_BE_WORD(ccsf3_4->SubstLookupRecord[k].LookupListIndex);
+ int SequenceIndex = GET_BE_WORD(ccsf3_4->SubstLookupRecord[k].SequenceIndex) * write_dir;
+
+ TRACE("SUBST: %i -> %i %i\n",k, SequenceIndex, lookupIndex);
+ newIndex = GSUB_apply_lookup(lookup, lookupIndex, glyphs, glyph_index + SequenceIndex, write_dir, glyph_count);
+ if (newIndex == -1)
+ {
+ ERR("Chain failed to generate a glyph\n");
+ continue;
+ }
+ }
+ return newIndex;
+ }
+ else return GSUB_E_NOGLYPH;
+ }
+ }
+ return -1;
+}
+
+static INT GSUB_apply_lookup(const GSUB_LookupList* lookup, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
+{
+ int offset;
+ const GSUB_LookupTable *look;
+
+ offset = GET_BE_WORD(lookup->Lookup[lookup_index]);
+ look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
+ TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
+ switch(GET_BE_WORD(look->LookupType))
+ {
+ case 1:
+ return GSUB_apply_SingleSubst(look, glyphs, glyph_index, write_dir, glyph_count);
+ case 2:
+ return GSUB_apply_MultipleSubst(look, glyphs, glyph_index, write_dir, glyph_count);
+ case 3:
+ return GSUB_apply_AlternateSubst(look, glyphs, glyph_index, write_dir, glyph_count);
+ case 4:
+ return GSUB_apply_LigatureSubst(look, glyphs, glyph_index, write_dir, glyph_count);
+ case 6:
+ return GSUB_apply_ChainContextSubst(lookup, look, glyphs, glyph_index, write_dir, glyph_count);
+ default:
+ FIXME("We do not handle SubType %i\n",GET_BE_WORD(look->LookupType));
+ }
+ return GSUB_E_NOGLYPH;
+}
+
+INT OpenType_apply_GSUB_lookup(LPCVOID table, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
+{
+ const GSUB_Header *header = (const GSUB_Header *)table;
+ const GSUB_LookupList *lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
+
+ return GSUB_apply_lookup(lookup, lookup_index, glyphs, glyph_index, write_dir, glyph_count);
+}
+
+static void GSUB_initialize_script_cache(ScriptCache *psc)
+{
+ int i;
+
+ if (!psc->script_count)
+ {
+ const GSUB_ScriptList *script;
+ const GSUB_Header* header = (const GSUB_Header*)psc->GSUB_Table;
+ script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
+ psc->script_count = GET_BE_WORD(script->ScriptCount);
+ TRACE("initializing %i scripts in this font\n",psc->script_count);
+ psc->scripts = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(LoadedScript) * psc->script_count);
+ for (i = 0; i < psc->script_count; i++)
+ {
+ int offset = GET_BE_WORD(script->ScriptRecord[i].Script);
+ 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]);
+ psc->scripts[i].table = ((const BYTE*)script + offset);
+ }
+ }
+}
+
+HRESULT OpenType_GSUB_GetFontScriptTags(ScriptCache *psc, OPENTYPE_TAG searchingFor, int cMaxTags, OPENTYPE_TAG *pScriptTags, int *pcTags, LPCVOID* script_table)
+{
+ int i;
+ HRESULT rc = S_OK;
+
+ GSUB_initialize_script_cache(psc);
+ *pcTags = psc->script_count;
+
+ if (!searchingFor && cMaxTags < *pcTags)
+ rc = E_OUTOFMEMORY;
+ else if (searchingFor)
+ rc = USP_E_SCRIPT_NOT_IN_FONT;
+
+ for (i = 0; i < psc->script_count; i++)
+ {
+ if (i < cMaxTags)
+ pScriptTags[i] = psc->scripts[i].tag;
+
+ if (searchingFor)
+ {
+ if (searchingFor == psc->scripts[i].tag)
+ {
+ pScriptTags[0] = psc->scripts[i].tag;
+ *pcTags = 1;
+ if (script_table)
+ *script_table = psc->scripts[i].table;
+ rc = S_OK;
+ break;
+ }
+ }
+ }
+ return rc;
+}
+
+static void GSUB_initialize_language_cache(LoadedScript *script)
+{
+ int i;
+
+ if (!script->language_count)
+ {
+ const GSUB_Script* table = script->table;
+ script->language_count = GET_BE_WORD(table->LangSysCount);
+ script->default_language.tag = MS_MAKE_TAG('d','f','l','t');
+ script->default_language.table = (const BYTE*)table + GET_BE_WORD(table->DefaultLangSys);
+
+ TRACE("Deflang %p, LangCount %i\n",script->default_language.table, script->language_count);
+
+ script->languages = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(LoadedLanguage) * script->language_count);
+
+ for (i = 0; i < script->language_count; i++)
+ {
+ int offset = GET_BE_WORD(table->LangSysRecord[i].LangSys);
+ 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]);
+ script->languages[i].table = ((const BYTE*)table + offset);
+ }
+ }
+}
+
+HRESULT OpenType_GSUB_GetFontLanguageTags(ScriptCache *psc, OPENTYPE_TAG script_tag, OPENTYPE_TAG searchingFor, int cMaxTags, OPENTYPE_TAG *pLanguageTags, int *pcTags, LPCVOID* language_table)
+{
+ int i;
+ HRESULT rc = S_OK;
+ LoadedScript *script = NULL;
+
+ GSUB_initialize_script_cache(psc);
+
+ for (i = 0; i < psc->script_count; i++)
+ {
+ if (psc->scripts[i].tag == script_tag)
+ {
+ script = &psc->scripts[i];
+ break;
+ }
+ }
+
+ if (!script)
+ return E_INVALIDARG;
+
+ GSUB_initialize_language_cache(script);
+
+ if (!searchingFor && cMaxTags < script->language_count)
+ rc = E_OUTOFMEMORY;
+ else if (searchingFor)
+ rc = E_INVALIDARG;
+
+ *pcTags = script->language_count;
+
+ for (i = 0; i < script->language_count; i++)
+ {
+ if (i < cMaxTags)
+ pLanguageTags[i] = script->languages[i].tag;
+
+ if (searchingFor)
+ {
+ if (searchingFor == script->languages[i].tag)
+ {
+ pLanguageTags[0] = script->languages[i].tag;
+ *pcTags = 1;
+ if (language_table)
+ *language_table = script->languages[i].table;
+ rc = S_OK;
+ break;
+ }
+ }
+ }
+
+ if (script->default_language.table)
+ {
+ if (i < cMaxTags)
+ pLanguageTags[i] = script->default_language.tag;
+
+ if (searchingFor && FAILED(rc))
+ {
+ pLanguageTags[0] = script->default_language.tag;
+ if (language_table)
+ *language_table = script->default_language.table;
+ }
+ i++;
+ *pcTags = (*pcTags) + 1;
+ }
+
+ return rc;
+}
+
+
+static void GSUB_initialize_feature_cache(LPCVOID table, LoadedLanguage *language)
+{
+ int i;
+
+ if (!language->feature_count)
+ {
+ const GSUB_LangSys *lang= language->table;
+ const GSUB_Header *header = (const GSUB_Header *)table;
+ const GSUB_FeatureList *feature_list;
+
+ language->feature_count = GET_BE_WORD(lang->FeatureCount);
+ TRACE("%i features\n",language->feature_count);
+
+ language->features = HeapAlloc(GetProcessHeap(),0,sizeof(LoadedFeature)*language->feature_count);
+
+ feature_list = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
+
+ for (i = 0; i < language->feature_count; i++)
+ {
+ const GSUB_Feature *feature;
+ int j;
+ int index = GET_BE_WORD(lang->FeatureIndex[i]);
+
+ 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]);
+ language->features[i].feature = ((const BYTE*)feature_list + GET_BE_WORD(feature_list->FeatureRecord[index].Feature));
+ feature = (const GSUB_Feature*)language->features[i].feature;
+ language->features[i].lookup_count = GET_BE_WORD(feature->LookupCount);
+ language->features[i].lookups = HeapAlloc(GetProcessHeap(),0,sizeof(WORD) * language->features[i].lookup_count);
+ for (j = 0; j < language->features[i].lookup_count; j++)
+ language->features[i].lookups[j] = GET_BE_WORD(feature->LookupListIndex[j]);
+ }
+ }
+}
+
+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)
+{
+ int i;
+ HRESULT rc = S_OK;
+ LoadedScript *script = NULL;
+ LoadedLanguage *language = NULL;
+
+ GSUB_initialize_script_cache(psc);
+
+ for (i = 0; i < psc->script_count; i++)
+ {
+ if (psc->scripts[i].tag == script_tag)
+ {
+ script = &psc->scripts[i];
+ break;
+ }
+ }
+
+ if (!script)
+ {
+ *pcTags = 0;
+ if (!filtered)
+ return S_OK;
+ else
+ return E_INVALIDARG;
+ }
+
+ GSUB_initialize_language_cache(script);
+
+ if (script->default_language.table && script->default_language.tag == language_tag)
+ language = &script->default_language;
+ else
+ {
+ for (i = 0; i < script->language_count; i++)
+ {
+ if (script->languages[i].tag == language_tag)
+ {
+ language = &script->languages[i];
+ break;
+ }
+ }
+ }
+
+ if (!language)
+ {
+ *pcTags = 0;
+ return S_OK;
+ }
+
+ GSUB_initialize_feature_cache(psc->GSUB_Table, language);
+
+ *pcTags = language->feature_count;
+
+ if (!searchingFor && cMaxTags < *pcTags)
+ rc = E_OUTOFMEMORY;
+ else if (searchingFor)
+ rc = E_INVALIDARG;
+
+ for (i = 0; i < language->feature_count; i++)
+ {
+ if (i < cMaxTags)
+ pFeatureTags[i] = language->features[i].tag;
+
+ if (searchingFor)
+ {
+ if (searchingFor == language->features[i].tag)
+ {
+ pFeatureTags[0] = language->features[i].tag;
+ *pcTags = 1;
+ if (feature)
+ *feature = &language->features[i];
+ rc = S_OK;
+ break;
+ }
+ }
+ }
+ return rc;
+}
*
*/
#include <stdarg.h>
+#include <stdlib.h>
#include "windef.h"
#include "winbase.h"
static void ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
+static void ContextualShape_Khmer(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
+static void ContextualShape_Mongolian(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
typedef VOID (*ShapeCharGlyphPropProc)( HDC , ScriptCache*, SCRIPT_ANALYSIS*, const WCHAR*, const INT, const WORD*, const INT, WORD*, SCRIPT_CHARPROP*, SCRIPT_GLYPHPROP*);
static void ShapeCharGlyphProp_Telugu( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
static void ShapeCharGlyphProp_Kannada( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
static void ShapeCharGlyphProp_Malayalam( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
+static void ShapeCharGlyphProp_Khmer( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
extern const unsigned short indic_syllabic_table[];
extern const unsigned short wine_shaping_table[];
Afx
};
-#ifdef WORDS_BIGENDIAN
-#define GET_BE_WORD(x) (x)
-#else
-#define GET_BE_WORD(x) RtlUshortByteSwap(x)
-#endif
-
-/* These are all structures needed for the GSUB table */
-#define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
-#define GSUB_E_NOFEATURE -2
-#define GSUB_E_NOGLYPH -1
-
-typedef struct {
- DWORD version;
- WORD ScriptList;
- WORD FeatureList;
- WORD LookupList;
-} GSUB_Header;
-
-typedef struct {
- CHAR ScriptTag[4];
- WORD Script;
-} GSUB_ScriptRecord;
-
-typedef struct {
- WORD ScriptCount;
- GSUB_ScriptRecord ScriptRecord[1];
-} GSUB_ScriptList;
-
-typedef struct {
- CHAR LangSysTag[4];
- WORD LangSys;
-} GSUB_LangSysRecord;
-
-typedef struct {
- WORD DefaultLangSys;
- WORD LangSysCount;
- GSUB_LangSysRecord LangSysRecord[1];
-} GSUB_Script;
-
-typedef struct {
- WORD LookupOrder; /* Reserved */
- WORD ReqFeatureIndex;
- WORD FeatureCount;
- WORD FeatureIndex[1];
-} GSUB_LangSys;
-
-typedef struct {
- CHAR FeatureTag[4];
- WORD Feature;
-} GSUB_FeatureRecord;
-
-typedef struct {
- WORD FeatureCount;
- GSUB_FeatureRecord FeatureRecord[1];
-} GSUB_FeatureList;
-
-typedef struct {
- WORD FeatureParams; /* Reserved */
- WORD LookupCount;
- WORD LookupListIndex[1];
-} GSUB_Feature;
-
-typedef struct {
- WORD LookupCount;
- WORD Lookup[1];
-} GSUB_LookupList;
-
-typedef struct {
- WORD LookupType;
- WORD LookupFlag;
- WORD SubTableCount;
- WORD SubTable[1];
-} GSUB_LookupTable;
-
-typedef struct {
- WORD CoverageFormat;
- WORD GlyphCount;
- WORD GlyphArray[1];
-} GSUB_CoverageFormat1;
-
-typedef struct {
- WORD Start;
- WORD End;
- WORD StartCoverageIndex;
-} GSUB_RangeRecord;
-
-typedef struct {
- WORD CoverageFormat;
- WORD RangeCount;
- GSUB_RangeRecord RangeRecord[1];
-} GSUB_CoverageFormat2;
-
-typedef struct {
- WORD SubstFormat; /* = 1 */
- WORD Coverage;
- WORD DeltaGlyphID;
-} GSUB_SingleSubstFormat1;
-
-typedef struct {
- WORD SubstFormat; /* = 2 */
- WORD Coverage;
- WORD GlyphCount;
- WORD Substitute[1];
-}GSUB_SingleSubstFormat2;
-
-typedef struct {
- WORD SubstFormat; /* = 1 */
- WORD Coverage;
- WORD SequenceCount;
- WORD Sequence[1];
-}GSUB_MultipleSubstFormat1;
-
-typedef struct {
- WORD GlyphCount;
- WORD Substitute[1];
-}GSUB_Sequence;
-
-typedef struct {
- WORD SubstFormat; /* = 1 */
- WORD Coverage;
- WORD LigSetCount;
- WORD LigatureSet[1];
-}GSUB_LigatureSubstFormat1;
-
-typedef struct {
- WORD LigatureCount;
- WORD Ligature[1];
-}GSUB_LigatureSet;
-
-typedef struct{
- WORD LigGlyph;
- WORD CompCount;
- WORD Component[1];
-}GSUB_Ligature;
-
-typedef struct{
- WORD SequenceIndex;
- WORD LookupListIndex;
-
-}GSUB_SubstLookupRecord;
-
-typedef struct{
- WORD SubstFormat; /* = 1 */
- WORD Coverage;
- WORD ChainSubRuleSetCount;
- WORD ChainSubRuleSet[1];
-}GSUB_ChainContextSubstFormat1;
-
-typedef struct {
- WORD SubstFormat; /* = 3 */
- WORD BacktrackGlyphCount;
- WORD Coverage[1];
-}GSUB_ChainContextSubstFormat3_1;
-
-typedef struct{
- WORD InputGlyphCount;
- WORD Coverage[1];
-}GSUB_ChainContextSubstFormat3_2;
-
-typedef struct{
- WORD LookaheadGlyphCount;
- WORD Coverage[1];
-}GSUB_ChainContextSubstFormat3_3;
-
-typedef struct{
- WORD SubstCount;
- GSUB_SubstLookupRecord SubstLookupRecord[1];
-}GSUB_ChainContextSubstFormat3_4;
-
-typedef struct {
- WORD SubstFormat; /* = 1 */
- WORD Coverage;
- WORD AlternateSetCount;
- WORD AlternateSet[1];
-} GSUB_AlternateSubstFormat1;
-
-typedef struct{
- WORD GlyphCount;
- WORD Alternate[1];
-} GSUB_AlternateSet;
-
-/* These are all structures needed for the GDEF table */
-#define GDEF_TAG MS_MAKE_TAG('G', 'D', 'E', 'F')
-
-enum {BaseGlyph=1, LigatureGlyph, MarkGlyph, ComponentGlyph};
-
-typedef struct {
- DWORD Version;
- WORD GlyphClassDef;
- WORD AttachList;
- WORD LigCaretList;
- WORD MarkAttachClassDef;
-} GDEF_Header;
-
-typedef struct {
- WORD ClassFormat;
- WORD StartGlyph;
- WORD GlyphCount;
- WORD ClassValueArray[1];
-} GDEF_ClassDefFormat1;
-
-typedef struct {
- WORD Start;
- WORD End;
- WORD Class;
-} GDEF_ClassRangeRecord;
-
-typedef struct {
- WORD ClassFormat;
- WORD ClassRangeCount;
- GDEF_ClassRangeRecord ClassRangeRecord[1];
-} GDEF_ClassDefFormat2;
-
-static INT GSUB_apply_lookup(const GSUB_LookupList* lookup, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count);
-
typedef struct tagVowelComponents
{
WCHAR base;
{ MS_MAKE_TAG('c','a','l','t'), 1},
};
+static OPENTYPE_FEATURE_RECORD myanmar_features[] =
+{
+ { MS_MAKE_TAG('l','i','g','a'), 1},
+ { MS_MAKE_TAG('c','l','i','g'), 1},
+};
+
static const char* required_bengali_features[] =
{
"nukt",
NULL
};
-typedef struct ScriptShapeDataTag {
- TEXTRANGE_PROPERTIES defaultTextRange;
- const char** requiredFeatures;
- CHAR otTag[5];
- CHAR newOtTag[5];
- ContextualShapingProc contextProc;
- ShapeCharGlyphPropProc charGlyphPropProc;
-} ScriptShapeData;
-
-/* in order of scripts */
-static const ScriptShapeData ShapingData[] =
+static OPENTYPE_FEATURE_RECORD khmer_features[] =
{
- {{ standard_features, 2}, NULL, "", "", NULL, NULL},
- {{ latin_features, 2}, NULL, "latn", "", NULL, NULL},
- {{ latin_features, 2}, NULL, "latn", "", NULL, NULL},
- {{ latin_features, 2}, NULL, "latn", "", NULL, NULL},
- {{ standard_features, 2}, NULL, "" , "", NULL, NULL},
- {{ latin_features, 2}, NULL, "latn", "", NULL, NULL},
- {{ arabic_features, 6}, required_arabic_features, "arab", "", ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
- {{ arabic_features, 6}, required_arabic_features, "arab", "", ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
- {{ hebrew_features, 1}, NULL, "hebr", "", NULL, NULL},
- {{ syriac_features, 4}, required_syriac_features, "syrc", "", ContextualShape_Syriac, ShapeCharGlyphProp_None},
- {{ arabic_features, 6}, required_arabic_features, "arab", "", ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
- {{ NULL, 0}, NULL, "thaa", "", NULL, ShapeCharGlyphProp_None},
- {{ standard_features, 2}, NULL, "grek", "", NULL, NULL},
- {{ standard_features, 2}, NULL, "cyrl", "", NULL, NULL},
- {{ standard_features, 2}, NULL, "armn", "", NULL, NULL},
- {{ standard_features, 2}, NULL, "geor", "", NULL, NULL},
- {{ sinhala_features, 3}, NULL, "sinh", "", ContextualShape_Sinhala, ShapeCharGlyphProp_Sinhala},
- {{ tibetan_features, 2}, NULL, "tibt", "", NULL, ShapeCharGlyphProp_Tibet},
- {{ tibetan_features, 2}, NULL, "tibt", "", NULL, ShapeCharGlyphProp_Tibet},
- {{ phags_features, 3}, NULL, "phag", "", ContextualShape_Phags_pa, ShapeCharGlyphProp_Thai},
- {{ thai_features, 1}, NULL, "thai", "", NULL, ShapeCharGlyphProp_Thai},
- {{ thai_features, 1}, NULL, "thai", "", NULL, ShapeCharGlyphProp_Thai},
- {{ thai_features, 1}, required_lao_features, "lao", "", NULL, ShapeCharGlyphProp_Thai},
- {{ thai_features, 1}, required_lao_features, "lao", "", NULL, ShapeCharGlyphProp_Thai},
- {{ devanagari_features, 6}, required_devanagari_features, "deva", "dev2", ContextualShape_Devanagari, ShapeCharGlyphProp_Devanagari},
- {{ devanagari_features, 6}, required_devanagari_features, "deva", "dev2", ContextualShape_Devanagari, ShapeCharGlyphProp_Devanagari},
- {{ devanagari_features, 6}, required_bengali_features, "beng", "bng2", ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
- {{ devanagari_features, 6}, required_bengali_features, "beng", "bng2", ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
- {{ devanagari_features, 6}, required_bengali_features, "beng", "bng2", ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
- {{ devanagari_features, 6}, required_gurmukhi_features, "guru", "gur2", ContextualShape_Gurmukhi, ShapeCharGlyphProp_Gurmukhi},
- {{ devanagari_features, 6}, required_gurmukhi_features, "guru", "gur2", ContextualShape_Gurmukhi, ShapeCharGlyphProp_Gurmukhi},
- {{ devanagari_features, 6}, required_devanagari_features, "gujr", "gjr2", ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
- {{ devanagari_features, 6}, required_devanagari_features, "gujr", "gjr2", ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
- {{ devanagari_features, 6}, required_devanagari_features, "gujr", "gjr2", ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
- {{ devanagari_features, 6}, required_oriya_features, "orya", "ory2", ContextualShape_Oriya, ShapeCharGlyphProp_Oriya},
- {{ devanagari_features, 6}, required_oriya_features, "orya", "ory2", ContextualShape_Oriya, ShapeCharGlyphProp_Oriya},
- {{ devanagari_features, 6}, required_tamil_features, "taml", "tam2", ContextualShape_Tamil, ShapeCharGlyphProp_Tamil},
- {{ devanagari_features, 6}, required_tamil_features, "taml", "tam2", ContextualShape_Tamil, ShapeCharGlyphProp_Tamil},
- {{ devanagari_features, 6}, required_telugu_features, "telu", "tel2", ContextualShape_Telugu, ShapeCharGlyphProp_Telugu},
- {{ devanagari_features, 6}, required_telugu_features, "telu", "tel2", ContextualShape_Telugu, ShapeCharGlyphProp_Telugu},
- {{ devanagari_features, 6}, required_telugu_features, "knda", "knd2", ContextualShape_Kannada, ShapeCharGlyphProp_Kannada},
- {{ devanagari_features, 6}, required_telugu_features, "knda", "knd2", ContextualShape_Kannada, ShapeCharGlyphProp_Kannada},
- {{ devanagari_features, 6}, required_telugu_features, "mlym", "mlm2", ContextualShape_Malayalam, ShapeCharGlyphProp_Malayalam},
- {{ devanagari_features, 6}, required_telugu_features, "mlym", "mlm2", ContextualShape_Malayalam, ShapeCharGlyphProp_Malayalam},
- {{ standard_features, 2}, NULL, "" , "", NULL, NULL},
- {{ latin_features, 2}, NULL, "latn" , "", NULL, NULL},
- {{ standard_features, 2}, NULL, "" , "", NULL, NULL},
+ { MS_MAKE_TAG('p','r','e','s'), 1},
+ { MS_MAKE_TAG('b','l','w','s'), 1},
+ { MS_MAKE_TAG('a','b','v','s'), 1},
+ { MS_MAKE_TAG('p','s','t','s'), 1},
+ { MS_MAKE_TAG('c','l','i','g'), 1},
};
-static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
-{
- const GSUB_CoverageFormat1* cf1;
-
- cf1 = table;
-
- if (GET_BE_WORD(cf1->CoverageFormat) == 1)
- {
- int count = GET_BE_WORD(cf1->GlyphCount);
- int i;
- TRACE("Coverage Format 1, %i glyphs\n",count);
- for (i = 0; i < count; i++)
- if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
- return i;
- return -1;
- }
- else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
- {
- const GSUB_CoverageFormat2* cf2;
- int i;
- int count;
- cf2 = (const GSUB_CoverageFormat2*)cf1;
-
- count = GET_BE_WORD(cf2->RangeCount);
- TRACE("Coverage Format 2, %i ranges\n",count);
- for (i = 0; i < count; i++)
- {
- if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
- return -1;
- if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
- (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
- {
- return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
- glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
- }
- }
- return -1;
- }
- else
- ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
-
- return -1;
-}
-
-static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
-{
- const GSUB_ScriptList *script;
- const GSUB_Script *deflt = NULL;
- int i;
- script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
-
- TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
- for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
- {
- const GSUB_Script *scr;
- int offset;
-
- offset = GET_BE_WORD(script->ScriptRecord[i].Script);
- scr = (const GSUB_Script*)((const BYTE*)script + offset);
-
- if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
- return scr;
- if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
- deflt = scr;
- }
- return deflt;
-}
-
-static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
-{
- int i;
- int offset;
- const GSUB_LangSys *Lang;
-
- TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
-
- for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
- {
- offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
- Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
-
- if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
- return Lang;
- }
- offset = GET_BE_WORD(script->DefaultLangSys);
- if (offset)
- {
- Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
- return Lang;
- }
- return NULL;
-}
-
-static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
-{
- int i;
- const GSUB_FeatureList *feature;
- feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
-
- TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
- for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
- {
- int index = GET_BE_WORD(lang->FeatureIndex[i]);
- if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
- {
- const GSUB_Feature *feat;
- feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
- return feat;
- }
- }
- return NULL;
-}
-
-static INT GSUB_apply_SingleSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
-{
- int j;
- TRACE("Single Substitution Subtable\n");
-
- for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
- {
- int offset;
- const GSUB_SingleSubstFormat1 *ssf1;
- offset = GET_BE_WORD(look->SubTable[j]);
- ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
- if (GET_BE_WORD(ssf1->SubstFormat) == 1)
- {
- int offset = GET_BE_WORD(ssf1->Coverage);
- TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
- if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyphs[glyph_index]) != -1)
- {
- TRACE(" Glyph 0x%x ->",glyphs[glyph_index]);
- glyphs[glyph_index] = glyphs[glyph_index] + GET_BE_WORD(ssf1->DeltaGlyphID);
- TRACE(" 0x%x\n",glyphs[glyph_index]);
- return glyph_index + write_dir;
- }
- }
- else
- {
- const GSUB_SingleSubstFormat2 *ssf2;
- INT index;
- INT offset;
-
- ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
- offset = GET_BE_WORD(ssf1->Coverage);
- TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
- index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyphs[glyph_index]);
- TRACE(" Coverage index %i\n",index);
- if (index != -1)
- {
- if (glyphs[glyph_index] == GET_BE_WORD(ssf2->Substitute[index]))
- return GSUB_E_NOGLYPH;
-
- TRACE(" Glyph is 0x%x ->",glyphs[glyph_index]);
- glyphs[glyph_index] = GET_BE_WORD(ssf2->Substitute[index]);
- TRACE("0x%x\n",glyphs[glyph_index]);
- return glyph_index + write_dir;
- }
- }
- }
- return GSUB_E_NOGLYPH;
-}
-
-static INT GSUB_apply_MultipleSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
+static const char* required_khmer_features[] =
{
- int j;
- TRACE("Multiple Substitution Subtable\n");
-
- for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
- {
- int offset, index;
- const GSUB_MultipleSubstFormat1 *msf1;
- offset = GET_BE_WORD(look->SubTable[j]);
- msf1 = (const GSUB_MultipleSubstFormat1*)((const BYTE*)look+offset);
-
- offset = GET_BE_WORD(msf1->Coverage);
- index = GSUB_is_glyph_covered((const BYTE*)msf1+offset, glyphs[glyph_index]);
- if (index != -1)
- {
- const GSUB_Sequence *seq;
- int sub_count;
- int j;
- offset = GET_BE_WORD(msf1->Sequence[index]);
- seq = (const GSUB_Sequence*)((const BYTE*)msf1+offset);
- sub_count = GET_BE_WORD(seq->GlyphCount);
- TRACE(" Glyph 0x%x (+%i)->",glyphs[glyph_index],(sub_count-1));
-
- for (j = (*glyph_count)+(sub_count-1); j > glyph_index; j--)
- glyphs[j] =glyphs[j-(sub_count-1)];
-
- for (j = 0; j < sub_count; j++)
- if (write_dir < 0)
- glyphs[glyph_index + (sub_count-1) - j] = GET_BE_WORD(seq->Substitute[j]);
- else
- glyphs[glyph_index + j] = GET_BE_WORD(seq->Substitute[j]);
-
- *glyph_count = *glyph_count + (sub_count - 1);
-
- if (TRACE_ON(uniscribe))
- {
- for (j = 0; j < sub_count; j++)
- TRACE(" 0x%x",glyphs[glyph_index+j]);
- TRACE("\n");
- }
-
- return glyph_index + (sub_count * write_dir);
- }
- }
- return GSUB_E_NOGLYPH;
-}
-
-static INT GSUB_apply_AlternateSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
-{
- int j;
- TRACE("Alternate Substitution Subtable\n");
-
- for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
- {
- int offset;
- const GSUB_AlternateSubstFormat1 *asf1;
- INT index;
-
- offset = GET_BE_WORD(look->SubTable[j]);
- asf1 = (const GSUB_AlternateSubstFormat1*)((const BYTE*)look+offset);
- offset = GET_BE_WORD(asf1->Coverage);
+ "pref",
+ "blwf",
+ "abvf",
+ "pstf",
+ "pres",
+ "blws",
+ "abvs",
+ "psts",
+ "clig",
+ NULL
+};
- index = GSUB_is_glyph_covered((const BYTE*)asf1+offset, glyphs[glyph_index]);
- if (index != -1)
- {
- const GSUB_AlternateSet *as;
- offset = GET_BE_WORD(asf1->AlternateSet[index]);
- as = (const GSUB_AlternateSet*)((const BYTE*)asf1+offset);
- FIXME("%i alternates, picking index 0\n",GET_BE_WORD(as->GlyphCount));
- if (glyphs[glyph_index] == GET_BE_WORD(as->Alternate[0]))
- return GSUB_E_NOGLYPH;
-
- TRACE(" Glyph 0x%x ->",glyphs[glyph_index]);
- glyphs[glyph_index] = GET_BE_WORD(as->Alternate[0]);
- TRACE(" 0x%x\n",glyphs[glyph_index]);
- return glyph_index + write_dir;
- }
- }
- return GSUB_E_NOGLYPH;
-}
+static OPENTYPE_FEATURE_RECORD no_features[] =
+{ };
-static INT GSUB_apply_LigatureSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
+static OPENTYPE_FEATURE_RECORD ethiopic_features[] =
{
- int j;
-
- TRACE("Ligature Substitution Subtable\n");
- for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
- {
- const GSUB_LigatureSubstFormat1 *lsf1;
- int offset,index;
-
- offset = GET_BE_WORD(look->SubTable[j]);
- lsf1 = (const GSUB_LigatureSubstFormat1*)((const BYTE*)look+offset);
- offset = GET_BE_WORD(lsf1->Coverage);
- index = GSUB_is_glyph_covered((const BYTE*)lsf1+offset, glyphs[glyph_index]);
- TRACE(" Coverage index %i\n",index);
- if (index != -1)
- {
- const GSUB_LigatureSet *ls;
- int k, count;
-
- offset = GET_BE_WORD(lsf1->LigatureSet[index]);
- ls = (const GSUB_LigatureSet*)((const BYTE*)lsf1+offset);
- count = GET_BE_WORD(ls->LigatureCount);
- TRACE(" LigatureSet has %i members\n",count);
- for (k = 0; k < count; k++)
- {
- const GSUB_Ligature *lig;
- int CompCount,l,CompIndex;
-
- offset = GET_BE_WORD(ls->Ligature[k]);
- lig = (const GSUB_Ligature*)((const BYTE*)ls+offset);
- CompCount = GET_BE_WORD(lig->CompCount) - 1;
- CompIndex = glyph_index+write_dir;
- for (l = 0; l < CompCount && CompIndex >= 0 && CompIndex < *glyph_count; l++)
- {
- int CompGlyph;
- CompGlyph = GET_BE_WORD(lig->Component[l]);
- if (CompGlyph != glyphs[CompIndex])
- break;
- CompIndex += write_dir;
- }
- if (l == CompCount)
- {
- int replaceIdx = glyph_index;
- if (write_dir < 0)
- replaceIdx = glyph_index - CompCount;
-
- TRACE(" Glyph is 0x%x (+%i) ->",glyphs[glyph_index],CompCount);
- glyphs[replaceIdx] = GET_BE_WORD(lig->LigGlyph);
- TRACE("0x%x\n",glyphs[replaceIdx]);
- if (CompCount > 0)
- {
- int j;
- for (j = replaceIdx + 1; j < *glyph_count; j++)
- glyphs[j] =glyphs[j+CompCount];
- *glyph_count = *glyph_count - CompCount;
- }
- return replaceIdx + write_dir;
- }
- }
- }
- }
- return GSUB_E_NOGLYPH;
-}
+ { MS_MAKE_TAG('c','c','m','p'), 1},
+ { MS_MAKE_TAG('l','o','c','l'), 1},
+ { MS_MAKE_TAG('c','a','l','t'), 1},
+ { MS_MAKE_TAG('l','i','g','a'), 1},
+};
-static INT GSUB_apply_ChainContextSubst(const GSUB_LookupList* lookup, const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
+static OPENTYPE_FEATURE_RECORD mongolian_features[] =
{
- int j;
- BOOL done = FALSE;
-
- TRACE("Chaining Contextual Substitution Subtable\n");
- for (j = 0; j < GET_BE_WORD(look->SubTableCount) && !done; j++)
- {
- const GSUB_ChainContextSubstFormat1 *ccsf1;
- int offset;
- int dirLookahead = write_dir;
- int dirBacktrack = -1 * write_dir;
-
- offset = GET_BE_WORD(look->SubTable[j]);
- ccsf1 = (const GSUB_ChainContextSubstFormat1*)((const BYTE*)look+offset);
- if (GET_BE_WORD(ccsf1->SubstFormat) == 1)
- {
- FIXME(" TODO: subtype 1 (Simple context glyph substitution)\n");
- continue;
- }
- else if (GET_BE_WORD(ccsf1->SubstFormat) == 2)
- {
- FIXME(" TODO: subtype 2 (Class-based Chaining Context Glyph Substitution)\n");
- continue;
- }
- else if (GET_BE_WORD(ccsf1->SubstFormat) == 3)
- {
- int k;
- int indexGlyphs;
- const GSUB_ChainContextSubstFormat3_1 *ccsf3_1;
- const GSUB_ChainContextSubstFormat3_2 *ccsf3_2;
- const GSUB_ChainContextSubstFormat3_3 *ccsf3_3;
- const GSUB_ChainContextSubstFormat3_4 *ccsf3_4;
- int newIndex = glyph_index;
-
- ccsf3_1 = (const GSUB_ChainContextSubstFormat3_1 *)ccsf1;
-
- TRACE(" subtype 3 (Coverage-based Chaining Context Glyph Substitution)\n");
-
- for (k = 0; k < GET_BE_WORD(ccsf3_1->BacktrackGlyphCount); k++)
- {
- offset = GET_BE_WORD(ccsf3_1->Coverage[k]);
- if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (dirBacktrack * (k+1))]) == -1)
- break;
- }
- if (k != GET_BE_WORD(ccsf3_1->BacktrackGlyphCount))
- continue;
- TRACE("Matched Backtrack\n");
-
- ccsf3_2 = (const GSUB_ChainContextSubstFormat3_2 *)(((LPBYTE)ccsf1)+sizeof(GSUB_ChainContextSubstFormat3_1) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_1->BacktrackGlyphCount)-1)));
-
- indexGlyphs = GET_BE_WORD(ccsf3_2->InputGlyphCount);
- for (k = 0; k < indexGlyphs; k++)
- {
- offset = GET_BE_WORD(ccsf3_2->Coverage[k]);
- if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (write_dir * k)]) == -1)
- break;
- }
- if (k != indexGlyphs)
- continue;
- TRACE("Matched IndexGlyphs\n");
-
- ccsf3_3 = (const GSUB_ChainContextSubstFormat3_3 *)(((LPBYTE)ccsf3_2)+sizeof(GSUB_ChainContextSubstFormat3_2) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_2->InputGlyphCount)-1)));
-
- for (k = 0; k < GET_BE_WORD(ccsf3_3->LookaheadGlyphCount); k++)
- {
- offset = GET_BE_WORD(ccsf3_3->Coverage[k]);
- if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (dirLookahead * (indexGlyphs + k))]) == -1)
- break;
- }
- if (k != GET_BE_WORD(ccsf3_3->LookaheadGlyphCount))
- continue;
- TRACE("Matched LookAhead\n");
-
- ccsf3_4 = (const GSUB_ChainContextSubstFormat3_4 *)(((LPBYTE)ccsf3_3)+sizeof(GSUB_ChainContextSubstFormat3_3) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_3->LookaheadGlyphCount)-1)));
-
- if (GET_BE_WORD(ccsf3_4->SubstCount))
- {
- for (k = 0; k < GET_BE_WORD(ccsf3_4->SubstCount); k++)
- {
- int lookupIndex = GET_BE_WORD(ccsf3_4->SubstLookupRecord[k].LookupListIndex);
- int SequenceIndex = GET_BE_WORD(ccsf3_4->SubstLookupRecord[k].SequenceIndex) * write_dir;
+ { MS_MAKE_TAG('c','c','m','p'), 1},
+ { MS_MAKE_TAG('l','o','c','l'), 1},
+ { MS_MAKE_TAG('c','a','l','t'), 1},
+ { MS_MAKE_TAG('r','l','i','g'), 1},
+};
- TRACE("SUBST: %i -> %i %i\n",k, SequenceIndex, lookupIndex);
- newIndex = GSUB_apply_lookup(lookup, lookupIndex, glyphs, glyph_index + SequenceIndex, write_dir, glyph_count);
- if (newIndex == -1)
- {
- ERR("Chain failed to generate a glyph\n");
- continue;
- }
- }
- return newIndex;
- }
- else return GSUB_E_NOGLYPH;
- }
- }
- return -1;
-}
+typedef struct ScriptShapeDataTag {
+ TEXTRANGE_PROPERTIES defaultTextRange;
+ const char** requiredFeatures;
+ OPENTYPE_TAG newOtTag;
+ ContextualShapingProc contextProc;
+ ShapeCharGlyphPropProc charGlyphPropProc;
+} ScriptShapeData;
-static INT GSUB_apply_lookup(const GSUB_LookupList* lookup, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
+/* in order of scripts */
+static const ScriptShapeData ShapingData[] =
{
- int offset;
- const GSUB_LookupTable *look;
+ {{ standard_features, 2}, NULL, 0, NULL, NULL},
+ {{ latin_features, 2}, NULL, 0, NULL, NULL},
+ {{ latin_features, 2}, NULL, 0, NULL, NULL},
+ {{ latin_features, 2}, NULL, 0, NULL, NULL},
+ {{ standard_features, 2}, NULL, 0, NULL, NULL},
+ {{ latin_features, 2}, NULL, 0, NULL, NULL},
+ {{ arabic_features, 6}, required_arabic_features, 0, ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
+ {{ arabic_features, 6}, required_arabic_features, 0, ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
+ {{ hebrew_features, 1}, NULL, 0, NULL, NULL},
+ {{ syriac_features, 4}, required_syriac_features, 0, ContextualShape_Syriac, ShapeCharGlyphProp_None},
+ {{ arabic_features, 6}, required_arabic_features, 0, ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
+ {{ NULL, 0}, NULL, 0, NULL, ShapeCharGlyphProp_None},
+ {{ standard_features, 2}, NULL, 0, NULL, NULL},
+ {{ standard_features, 2}, NULL, 0, NULL, NULL},
+ {{ standard_features, 2}, NULL, 0, NULL, NULL},
+ {{ standard_features, 2}, NULL, 0, NULL, NULL},
+ {{ sinhala_features, 3}, NULL, 0, ContextualShape_Sinhala, ShapeCharGlyphProp_Sinhala},
+ {{ tibetan_features, 2}, NULL, 0, NULL, ShapeCharGlyphProp_Tibet},
+ {{ tibetan_features, 2}, NULL, 0, NULL, ShapeCharGlyphProp_Tibet},
+ {{ phags_features, 3}, NULL, 0, ContextualShape_Phags_pa, ShapeCharGlyphProp_Thai},
+ {{ thai_features, 1}, NULL, 0, NULL, ShapeCharGlyphProp_Thai},
+ {{ thai_features, 1}, NULL, 0, NULL, ShapeCharGlyphProp_Thai},
+ {{ thai_features, 1}, required_lao_features, 0, NULL, ShapeCharGlyphProp_Thai},
+ {{ thai_features, 1}, required_lao_features, 0, NULL, ShapeCharGlyphProp_Thai},
+ {{ devanagari_features, 6}, required_devanagari_features, MS_MAKE_TAG('d','e','v','2'), ContextualShape_Devanagari, ShapeCharGlyphProp_Devanagari},
+ {{ devanagari_features, 6}, required_devanagari_features, MS_MAKE_TAG('d','e','v','2'), ContextualShape_Devanagari, ShapeCharGlyphProp_Devanagari},
+ {{ devanagari_features, 6}, required_bengali_features, MS_MAKE_TAG('b','n','g','2'), ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
+ {{ devanagari_features, 6}, required_bengali_features, MS_MAKE_TAG('b','n','g','2'), ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
+ {{ devanagari_features, 6}, required_bengali_features, MS_MAKE_TAG('b','n','g','2'), ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
+ {{ devanagari_features, 6}, required_gurmukhi_features, MS_MAKE_TAG('g','u','r','2'), ContextualShape_Gurmukhi, ShapeCharGlyphProp_Gurmukhi},
+ {{ devanagari_features, 6}, required_gurmukhi_features, MS_MAKE_TAG('g','u','r','2'), ContextualShape_Gurmukhi, ShapeCharGlyphProp_Gurmukhi},
+ {{ devanagari_features, 6}, required_devanagari_features, MS_MAKE_TAG('g','j','r','2'), ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
+ {{ devanagari_features, 6}, required_devanagari_features, MS_MAKE_TAG('g','j','r','2'), ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
+ {{ devanagari_features, 6}, required_devanagari_features, MS_MAKE_TAG('g','j','r','2'), ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
+ {{ devanagari_features, 6}, required_oriya_features, MS_MAKE_TAG('o','r','y','2'), ContextualShape_Oriya, ShapeCharGlyphProp_Oriya},
+ {{ devanagari_features, 6}, required_oriya_features, MS_MAKE_TAG('o','r','y','2'), ContextualShape_Oriya, ShapeCharGlyphProp_Oriya},
+ {{ devanagari_features, 6}, required_tamil_features, MS_MAKE_TAG('t','a','m','2'), ContextualShape_Tamil, ShapeCharGlyphProp_Tamil},
+ {{ devanagari_features, 6}, required_tamil_features, MS_MAKE_TAG('t','a','m','2'), ContextualShape_Tamil, ShapeCharGlyphProp_Tamil},
+ {{ devanagari_features, 6}, required_telugu_features, MS_MAKE_TAG('t','e','l','2'), ContextualShape_Telugu, ShapeCharGlyphProp_Telugu},
+ {{ devanagari_features, 6}, required_telugu_features, MS_MAKE_TAG('t','e','l','2'), ContextualShape_Telugu, ShapeCharGlyphProp_Telugu},
+ {{ devanagari_features, 6}, required_telugu_features, MS_MAKE_TAG('k','n','d','2'), ContextualShape_Kannada, ShapeCharGlyphProp_Kannada},
+ {{ devanagari_features, 6}, required_telugu_features, MS_MAKE_TAG('k','n','d','2'), ContextualShape_Kannada, ShapeCharGlyphProp_Kannada},
+ {{ devanagari_features, 6}, required_telugu_features, MS_MAKE_TAG('m','l','m','2'), ContextualShape_Malayalam, ShapeCharGlyphProp_Malayalam},
+ {{ devanagari_features, 6}, required_telugu_features, MS_MAKE_TAG('m','l','m','2'), ContextualShape_Malayalam, ShapeCharGlyphProp_Malayalam},
+ {{ standard_features, 2}, NULL, 0, NULL, NULL},
+ {{ latin_features, 2}, NULL, 0, NULL, NULL},
+ {{ standard_features, 2}, NULL, 0, NULL, NULL},
+ {{ myanmar_features, 2}, NULL, 0, NULL, NULL},
+ {{ myanmar_features, 2}, NULL, 0, NULL, NULL},
+ {{ standard_features, 2}, NULL, 0, NULL, NULL},
+ {{ standard_features, 2}, NULL, 0, NULL, NULL},
+ {{ standard_features, 2}, NULL, 0, NULL, NULL},
+ {{ khmer_features, 5}, required_khmer_features, 0, ContextualShape_Khmer, ShapeCharGlyphProp_Khmer},
+ {{ khmer_features, 5}, required_khmer_features, 0, ContextualShape_Khmer, ShapeCharGlyphProp_Khmer},
+ {{ no_features, 0}, NULL, 0, NULL, NULL},
+ {{ no_features, 0}, NULL, 0, NULL, NULL},
+ {{ no_features, 0}, NULL, 0, NULL, NULL},
+ {{ no_features, 0}, NULL, 0, NULL, NULL},
+ {{ no_features, 0}, NULL, 0, NULL, NULL},
+ {{ no_features, 0}, NULL, 0, NULL, NULL},
+ {{ ethiopic_features, 4}, NULL, 0, NULL, NULL},
+ {{ ethiopic_features, 4}, NULL, 0, NULL, NULL},
+ {{ mongolian_features, 4}, NULL, 0, ContextualShape_Mongolian, NULL},
+ {{ mongolian_features, 4}, NULL, 0, ContextualShape_Mongolian, NULL},
+ {{ no_features, 0}, NULL, 0, NULL, NULL},
+ {{ no_features, 0}, NULL, 0, NULL, NULL},
+ {{ no_features, 0}, NULL, 0, NULL, NULL},
+ {{ no_features, 0}, NULL, 0, NULL, NULL},
+ {{ no_features, 0}, NULL, 0, NULL, NULL},
+ {{ no_features, 0}, NULL, 0, NULL, NULL},
+ {{ no_features, 0}, NULL, 0, NULL, NULL},
+ {{ no_features, 0}, NULL, 0, NULL, NULL},
+ {{ no_features, 0}, NULL, 0, NULL, NULL},
+ {{ no_features, 0}, NULL, 0, NULL, NULL},
+ {{ no_features, 0}, NULL, 0, NULL, NULL},
+ {{ no_features, 0}, NULL, 0, NULL, NULL},
+ {{ no_features, 0}, NULL, 0, NULL, NULL},
+ {{ no_features, 0}, NULL, 0, NULL, NULL},
+ {{ no_features, 0}, NULL, 0, NULL, NULL},
+ {{ hebrew_features, 1}, NULL, 0, NULL, NULL},
+ {{ latin_features, 2}, NULL, 0, NULL, NULL},
+ {{ thai_features, 1}, NULL, 0, NULL, ShapeCharGlyphProp_Thai},
+};
- offset = GET_BE_WORD(lookup->Lookup[lookup_index]);
- look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
- TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
- switch(GET_BE_WORD(look->LookupType))
- {
- case 1:
- return GSUB_apply_SingleSubst(look, glyphs, glyph_index, write_dir, glyph_count);
- case 2:
- return GSUB_apply_MultipleSubst(look, glyphs, glyph_index, write_dir, glyph_count);
- case 3:
- return GSUB_apply_AlternateSubst(look, glyphs, glyph_index, write_dir, glyph_count);
- case 4:
- return GSUB_apply_LigatureSubst(look, glyphs, glyph_index, write_dir, glyph_count);
- case 6:
- return GSUB_apply_ChainContextSubst(lookup, look, glyphs, glyph_index, write_dir, glyph_count);
- default:
- FIXME("We do not handle SubType %i\n",GET_BE_WORD(look->LookupType));
- }
- return GSUB_E_NOGLYPH;
-}
+extern scriptData scriptInformation[];
-static INT GSUB_apply_feature_all_lookups(const GSUB_Header * header, const GSUB_Feature* feature, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
+static INT GSUB_apply_feature_all_lookups(LPCVOID header, LoadedFeature *feature, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
{
int i;
int out_index = GSUB_E_NOGLYPH;
- const GSUB_LookupList *lookup;
-
- lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
- TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
- for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
+ TRACE("%i lookups\n", feature->lookup_count);
+ for (i = 0; i < feature->lookup_count; i++)
{
- out_index = GSUB_apply_lookup(lookup, GET_BE_WORD(feature->LookupListIndex[i]), glyphs, glyph_index, write_dir, glyph_count);
+ out_index = OpenType_apply_GSUB_lookup(header, feature->lookups[i], glyphs, glyph_index, write_dir, glyph_count);
if (out_index != GSUB_E_NOGLYPH)
break;
}
return out_index;
}
-static const char* get_opentype_script(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, BOOL tryNew)
+static OPENTYPE_TAG get_opentype_script(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, BOOL tryNew)
{
UINT charset;
if (psc->userScript != 0)
{
- if (tryNew && ShapingData[psa->eScript].newOtTag[0] != 0 && strncmp((char*)&psc->userScript,ShapingData[psa->eScript].otTag,4)==0)
+ if (tryNew && ShapingData[psa->eScript].newOtTag != 0 && psc->userScript == scriptInformation[psa->eScript].scriptTag)
return ShapingData[psa->eScript].newOtTag;
else
- return (char*)&psc->userScript;
+ return psc->userScript;
}
- if (tryNew && ShapingData[psa->eScript].newOtTag[0] != 0)
+ if (tryNew && ShapingData[psa->eScript].newOtTag != 0)
return ShapingData[psa->eScript].newOtTag;
- if (ShapingData[psa->eScript].otTag[0] != 0)
- return ShapingData[psa->eScript].otTag;
+ if (scriptInformation[psa->eScript].scriptTag)
+ return scriptInformation[psa->eScript].scriptTag;
/*
* fall back to the font charset
charset = GetTextCharsetInfo(hdc, NULL, 0x0);
switch (charset)
{
- case ANSI_CHARSET: return "latn";
- case BALTIC_CHARSET: return "latn"; /* ?? */
- case CHINESEBIG5_CHARSET: return "hani";
- case EASTEUROPE_CHARSET: return "latn"; /* ?? */
- case GB2312_CHARSET: return "hani";
- case GREEK_CHARSET: return "grek";
- case HANGUL_CHARSET: return "hang";
- case RUSSIAN_CHARSET: return "cyrl";
- case SHIFTJIS_CHARSET: return "kana";
- case TURKISH_CHARSET: return "latn"; /* ?? */
- case VIETNAMESE_CHARSET: return "latn";
- case JOHAB_CHARSET: return "latn"; /* ?? */
- case ARABIC_CHARSET: return "arab";
- case HEBREW_CHARSET: return "hebr";
- case THAI_CHARSET: return "thai";
- default: return "latn";
- }
-}
-
-static LPCVOID load_GSUB_feature(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, const char* feat)
-{
- const GSUB_Feature *feature;
- const char* script;
- int i;
-
- script = get_opentype_script(hdc,psa,psc,FALSE);
-
- for (i = 0; i < psc->feature_count; i++)
- {
- if (strncmp(psc->features[i].tag,feat,4)==0 && strncmp(psc->features[i].script,script,4)==0)
- return psc->features[i].feature;
+ case ANSI_CHARSET:
+ case BALTIC_CHARSET: return MS_MAKE_TAG('l','a','t','n');
+ case CHINESEBIG5_CHARSET: return MS_MAKE_TAG('h','a','n','i');
+ case EASTEUROPE_CHARSET: return MS_MAKE_TAG('l','a','t','n'); /* ?? */
+ case GB2312_CHARSET: return MS_MAKE_TAG('h','a','n','i');
+ case GREEK_CHARSET: return MS_MAKE_TAG('g','r','e','k');
+ case HANGUL_CHARSET: return MS_MAKE_TAG('h','a','n','g');
+ case RUSSIAN_CHARSET: return MS_MAKE_TAG('c','y','r','l');
+ case SHIFTJIS_CHARSET: return MS_MAKE_TAG('k','a','n','a');
+ case TURKISH_CHARSET: return MS_MAKE_TAG('l','a','t','n'); /* ?? */
+ case VIETNAMESE_CHARSET: return MS_MAKE_TAG('l','a','t','n');
+ case JOHAB_CHARSET: return MS_MAKE_TAG('l','a','t','n'); /* ?? */
+ case ARABIC_CHARSET: return MS_MAKE_TAG('a','r','a','b');
+ case HEBREW_CHARSET: return MS_MAKE_TAG('h','e','b','r');
+ case THAI_CHARSET: return MS_MAKE_TAG('t','h','a','i');
+ default: return MS_MAKE_TAG('l','a','t','n');
}
+}
- feature = NULL;
+static LoadedFeature* load_GSUB_feature(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, const char* feat)
+{
+ LoadedFeature *feature = NULL;
if (psc->GSUB_Table)
{
- const GSUB_Script *script;
- const GSUB_LangSys *language;
int attempt = 2;
+ OPENTYPE_TAG tags;
+ OPENTYPE_TAG language;
+ OPENTYPE_TAG script;
+ int cTags;
do
{
- script = GSUB_get_script_table(psc->GSUB_Table, get_opentype_script(hdc,psa,psc,(attempt==2)));
+ script = get_opentype_script(hdc,psa,psc,(attempt==2));
+ if (psc->userLang != 0)
+ language = psc->userLang;
+ else
+ language = MS_MAKE_TAG('d','f','l','t');
attempt--;
- if (script)
- {
- if (psc->userLang != 0)
- language = GSUB_get_lang_table(script,(char*)&psc->userLang);
- else
- language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
- if (language)
- feature = GSUB_get_feature(psc->GSUB_Table, language, feat);
- }
+
+ OpenType_GSUB_GetFontFeatureTags(psc, script, language, FALSE, MS_MAKE_TAG(feat[0],feat[1],feat[2],feat[3]), 1, &tags, &cTags, &feature);
+
} while(attempt && !feature);
/* try in the default (latin) table */
if (!feature)
- {
- script = GSUB_get_script_table(psc->GSUB_Table, "latn");
- if (script)
- {
- language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
- if (language)
- feature = GSUB_get_feature(psc->GSUB_Table, language, feat);
- }
- }
+ OpenType_GSUB_GetFontFeatureTags(psc, MS_MAKE_TAG('l','a','t','n'), MS_MAKE_TAG('d','f','l','t'), FALSE, MS_MAKE_TAG(feat[0],feat[1],feat[2],feat[3]), 1, &tags, &cTags, &feature);
}
TRACE("Feature %s located at %p\n",debugstr_an(feat,4),feature);
-
- psc->feature_count++;
-
- if (psc->features)
- psc->features = HeapReAlloc(GetProcessHeap(), 0, psc->features, psc->feature_count * sizeof(LoadedFeature));
- else
- psc->features = HeapAlloc(GetProcessHeap(), 0, psc->feature_count * sizeof(LoadedFeature));
-
- lstrcpynA(psc->features[psc->feature_count - 1].tag, feat, 5);
- lstrcpynA(psc->features[psc->feature_count - 1].script, script, 5);
- psc->features[psc->feature_count - 1].feature = feature;
return feature;
}
static INT apply_GSUB_feature_to_glyph(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache* psc, WORD *glyphs, INT index, INT write_dir, INT* glyph_count, const char* feat)
{
- const GSUB_Feature *feature;
+ LoadedFeature *feature;
feature = load_GSUB_feature(hdc, psa, psc, feat);
if (!feature)
static VOID *load_gsub_table(HDC hdc)
{
VOID* GSUB_Table = NULL;
- int length = GetFontData(hdc, GSUB_TAG , 0, NULL, 0);
+ int length = GetFontData(hdc, MS_MAKE_TAG('G', 'S', 'U', 'B'), 0, NULL, 0);
if (length != GDI_ERROR)
{
GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
- GetFontData(hdc, GSUB_TAG , 0, GSUB_Table, length);
+ GetFontData(hdc, MS_MAKE_TAG('G', 'S', 'U', 'B'), 0, GSUB_Table, length);
TRACE("Loaded GSUB table of %i bytes\n",length);
}
return GSUB_Table;
return rc;
}
-static WORD GDEF_get_glyph_class(const GDEF_Header *header, WORD glyph)
-{
- int offset;
- WORD class = 0;
- const GDEF_ClassDefFormat1 *cf1;
-
- if (!header)
- return 0;
-
- offset = GET_BE_WORD(header->GlyphClassDef);
- if (!offset)
- return 0;
-
- cf1 = (GDEF_ClassDefFormat1*)(((BYTE*)header)+offset);
- if (GET_BE_WORD(cf1->ClassFormat) == 1)
- {
- if (glyph >= GET_BE_WORD(cf1->StartGlyph))
- {
- int index = glyph - GET_BE_WORD(cf1->StartGlyph);
- if (index < GET_BE_WORD(cf1->GlyphCount))
- class = GET_BE_WORD(cf1->ClassValueArray[index]);
- }
- }
- else if (GET_BE_WORD(cf1->ClassFormat) == 2)
- {
- const GDEF_ClassDefFormat2 *cf2 = (GDEF_ClassDefFormat2*)cf1;
- int i, top;
- top = GET_BE_WORD(cf2->ClassRangeCount);
- for (i = 0; i < top; i++)
- {
- if (glyph >= GET_BE_WORD(cf2->ClassRangeRecord[i].Start) &&
- glyph <= GET_BE_WORD(cf2->ClassRangeRecord[i].End))
- {
- class = GET_BE_WORD(cf2->ClassRangeRecord[i].Class);
- break;
- }
- }
- }
- else
- ERR("Unknown Class Format %i\n",GET_BE_WORD(cf1->ClassFormat));
-
- return class;
-}
-
-static VOID *load_gdef_table(HDC hdc)
-{
- VOID* GDEF_Table = NULL;
- int length = GetFontData(hdc, GDEF_TAG , 0, NULL, 0);
- if (length != GDI_ERROR)
- {
- GDEF_Table = HeapAlloc(GetProcessHeap(),0,length);
- GetFontData(hdc, GDEF_TAG , 0, GDEF_Table, length);
- TRACE("Loaded GDEF table of %i bytes\n",length);
- }
- return GDEF_Table;
-}
-
-static void GDEF_UpdateGlyphProps(HDC hdc, ScriptCache *psc, const WORD *pwGlyphs, const WORD cGlyphs, WORD* pwLogClust, const WORD cChars, SCRIPT_GLYPHPROP *pGlyphProp)
-{
- int i;
-
- if (!psc->GDEF_Table)
- psc->GDEF_Table = load_gdef_table(hdc);
-
- for (i = 0; i < cGlyphs; i++)
- {
- WORD class;
- int char_count = 0;
- int k;
-
- for (k = 0; k < cChars; k++)
- if (pwLogClust[k] == i)
- char_count++;
-
- class = GDEF_get_glyph_class(psc->GDEF_Table, pwGlyphs[i]);
-
- switch (class)
- {
- case 0:
- case BaseGlyph:
- pGlyphProp[i].sva.fClusterStart = 1;
- pGlyphProp[i].sva.fDiacritic = 0;
- pGlyphProp[i].sva.fZeroWidth = 0;
- break;
- case LigatureGlyph:
- pGlyphProp[i].sva.fClusterStart = 1;
- pGlyphProp[i].sva.fDiacritic = 0;
- pGlyphProp[i].sva.fZeroWidth = 0;
- break;
- case MarkGlyph:
- pGlyphProp[i].sva.fClusterStart = 0;
- pGlyphProp[i].sva.fDiacritic = 1;
- pGlyphProp[i].sva.fZeroWidth = 1;
- break;
- case ComponentGlyph:
- pGlyphProp[i].sva.fClusterStart = 0;
- pGlyphProp[i].sva.fDiacritic = 0;
- pGlyphProp[i].sva.fZeroWidth = 0;
- break;
- default:
- ERR("Unknown glyph class %i\n",class);
- pGlyphProp[i].sva.fClusterStart = 1;
- pGlyphProp[i].sva.fDiacritic = 0;
- pGlyphProp[i].sva.fZeroWidth = 0;
- }
-
- if (char_count == 0)
- pGlyphProp[i].sva.fClusterStart = 0;
- }
-}
-
static void UpdateClustersFromGlyphProp(const int cGlyphs, const int cChars, WORD* pwLogClust, SCRIPT_GLYPHPROP *pGlyphProp)
{
int i;
{
if (psc->GSUB_Table)
{
- const GSUB_Feature *feature;
- const GSUB_LookupList *lookup;
- const GSUB_Header *header = psc->GSUB_Table;
- int lookup_index, lookup_count;
+ LoadedFeature *feature;
+ int lookup_index;
feature = load_GSUB_feature(hdc, psa, psc, feat);
if (!feature)
return GSUB_E_NOFEATURE;
- TRACE("applying feature %s\n",debugstr_an(feat,4));
- lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
- lookup_count = GET_BE_WORD(feature->LookupCount);
- TRACE("%i lookups\n", lookup_count);
- for (lookup_index = 0; lookup_index < lookup_count; lookup_index++)
+ TRACE("applying feature %s: %i lookups\n",debugstr_an(feat,4),feature->lookup_count);
+ for (lookup_index = 0; lookup_index < feature->lookup_count; lookup_index++)
{
int i;
i = 0;
else
i = *pcGlyphs-1;
- TRACE("applying lookup (%i/%i)\n",lookup_index,lookup_count);
+ TRACE("applying lookup (%i/%i)\n",lookup_index,feature->lookup_count);
while(i < *pcGlyphs && i >= 0)
{
INT nextIndex;
INT prevCount = *pcGlyphs;
- nextIndex = GSUB_apply_lookup(lookup, GET_BE_WORD(feature->LookupListIndex[lookup_index]), pwOutGlyphs, i, write_dir, pcGlyphs);
+ nextIndex = OpenType_apply_GSUB_lookup(psc->GSUB_Table, feature->lookups[lookup_index], pwOutGlyphs, i, write_dir, pcGlyphs);
if (*pcGlyphs != prevCount)
{
UpdateClusters(nextIndex, *pcGlyphs - prevCount, write_dir, cChars, pwLogClust);
static inline BOOL get_GSUB_Indic2(SCRIPT_ANALYSIS *psa, ScriptCache *psc)
{
- return(GSUB_get_script_table(psc->GSUB_Table,ShapingData[psa->eScript].newOtTag)!=NULL);
+ OPENTYPE_TAG tag;
+ HRESULT hr;
+ int count = 0;
+
+ hr = OpenType_GSUB_GetFontScriptTags(psc, ShapingData[psa->eScript].newOtTag, 1, &tag, &count, NULL);
+
+ return(SUCCEEDED(hr));
}
static WCHAR neighbour_char(int i, int delta, const WCHAR* chars, INT cchLen)
glyph_index->pref+= shift;
}
-static void Apply_Indic_BasicForm(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwChars, INT cChars, IndicSyllable *syllable, WORD *pwOutGlyphs, INT* pcGlyphs, WORD *pwLogClust, lexical_function lexical, IndicSyllable *glyph_index, const GSUB_Feature *feature )
+static void Apply_Indic_BasicForm(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwChars, INT cChars, IndicSyllable *syllable, WORD *pwOutGlyphs, INT* pcGlyphs, WORD *pwLogClust, lexical_function lexical, IndicSyllable *glyph_index, LoadedFeature *feature )
{
int index = glyph_index->start;
{
int c;
int overall_shift = 0;
- const GSUB_Feature *locl = (modern)?load_GSUB_feature(hdc, psa, psc, "locl"):NULL;
- const GSUB_Feature *nukt = load_GSUB_feature(hdc, psa, psc, "nukt");
- const GSUB_Feature *akhn = load_GSUB_feature(hdc, psa, psc, "akhn");
- const GSUB_Feature *rkrf = (modern)?load_GSUB_feature(hdc, psa, psc, "rkrf"):NULL;
- const GSUB_Feature *pstf = load_GSUB_feature(hdc, psa, psc, "pstf");
- const GSUB_Feature *vatu = (!rkrf)?load_GSUB_feature(hdc, psa, psc, "vatu"):NULL;
- const GSUB_Feature *cjct = (modern)?load_GSUB_feature(hdc, psa, psc, "cjct"):NULL;
+ LoadedFeature *locl = (modern)?load_GSUB_feature(hdc, psa, psc, "locl"):NULL;
+ LoadedFeature *nukt = load_GSUB_feature(hdc, psa, psc, "nukt");
+ LoadedFeature *akhn = load_GSUB_feature(hdc, psa, psc, "akhn");
+ LoadedFeature *rkrf = (modern)?load_GSUB_feature(hdc, psa, psc, "rkrf"):NULL;
+ LoadedFeature *pstf = load_GSUB_feature(hdc, psa, psc, "pstf");
+ LoadedFeature *vatu = (!rkrf)?load_GSUB_feature(hdc, psa, psc, "vatu"):NULL;
+ LoadedFeature *cjct = (modern)?load_GSUB_feature(hdc, psa, psc, "cjct"):NULL;
BOOL rphf = (load_GSUB_feature(hdc, psa, psc, "rphf") != NULL);
BOOL pref = (load_GSUB_feature(hdc, psa, psc, "pref") != NULL);
BOOL blwf = (load_GSUB_feature(hdc, psa, psc, "blwf") != NULL);
static const ConsonantComponents Gurmukhi_consonants[] = {
{{0x0A32,0x0A3C,0x0000}, 0x0A33},
- {{0x0A38,0x0A3C,0x0000}, 0x0A36},
{{0x0A16,0x0A3C,0x0000}, 0x0A59},
{{0x0A17,0x0A3C,0x0000}, 0x0A5A},
{{0x0A1C,0x0A3C,0x0000}, 0x0A5B},
HeapFree(GetProcessHeap(),0,syllables);
}
+static int khmer_lex(WCHAR c)
+{
+ return unicode_lex(c);
+}
+
+static void ContextualShape_Khmer(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
+{
+ int cCount = cChars;
+ WCHAR *input;
+ IndicSyllable *syllables = NULL;
+ int syllable_count = 0;
+
+ if (*pcGlyphs != cChars)
+ {
+ ERR("Number of Glyphs and Chars need to match at the beginning\n");
+ return;
+ }
+
+ input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
+ memcpy(input, pwcChars, cChars * sizeof(WCHAR));
+
+ /* Step 1: Reorder within Syllables */
+ Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, khmer_lex, Reorder_Like_Devanagari, FALSE);
+ TRACE("reordered string %s\n",debugstr_wn(input,cCount));
+ GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
+ *pcGlyphs = cCount;
+
+ /* Step 2: Base Form application to syllables */
+ ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, khmer_lex, NULL, FALSE);
+
+ HeapFree(GetProcessHeap(),0,input);
+ HeapFree(GetProcessHeap(),0,syllables);
+}
+
+static inline BOOL mongolian_wordbreak(WCHAR chr)
+{
+ return ((chr == 0x0020) || (chr == 0x200C) || (chr == 0x202F) || (chr == 0x180E) || (chr == 0x1800) || (chr == 0x1802) || (chr == 0x1803) || (chr == 0x1805) || (chr == 0x1808) || (chr == 0x1809) || (chr == 0x1807));
+}
+
+static void ContextualShape_Mongolian(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
+{
+ INT *context_shape;
+ INT dirL;
+ int i;
+
+ if (*pcGlyphs != cChars)
+ {
+ ERR("Number of Glyphs and Chars need to match at the beginning\n");
+ return;
+ }
+
+ if (!psa->fLogicalOrder && psa->fRTL)
+ dirL = -1;
+ else
+ dirL = 1;
+
+ if (!psc->GSUB_Table)
+ psc->GSUB_Table = load_gsub_table(hdc);
+
+ if (!psc->GSUB_Table)
+ return;
+
+ context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
+
+ for (i = 0; i < cChars; i++)
+ {
+ if (i == 0 || mongolian_wordbreak(pwcChars[i-1]))
+ {
+ if ((i == cChars-1) || mongolian_wordbreak(pwcChars[i+1]))
+ context_shape[i] = Xn;
+ else
+ context_shape[i] = Xl;
+ }
+ else
+ {
+ if ((i == cChars-1) || mongolian_wordbreak(pwcChars[i+1]))
+ context_shape[i] = Xr;
+ else
+ context_shape[i] = Xm;
+ }
+ }
+
+ /* Contextual Shaping */
+ i = 0;
+ while(i < *pcGlyphs)
+ {
+ INT nextIndex;
+ INT prevCount = *pcGlyphs;
+ nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
+ if (nextIndex > GSUB_E_NOGLYPH)
+ {
+ UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
+ i = nextIndex;
+ }
+ else
+ i++;
+ }
+
+ HeapFree(GetProcessHeap(),0,context_shape);
+}
+
static void ShapeCharGlyphProp_Default( HDC hdc, ScriptCache* psc, SCRIPT_ANALYSIS* psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD* pwLogClust, SCRIPT_CHARPROP* pCharProp, SCRIPT_GLYPHPROP* pGlyphProp)
{
int i,k;
pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
}
- GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
+ OpenType_GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
}
pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
}
- GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
+ OpenType_GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
HeapFree(GetProcessHeap(),0,spaces);
}
}
}
- GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
+ OpenType_GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
for (i = 0; i < cGlyphs; i++)
{
else
pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
}
- GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
+ OpenType_GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
}
else
pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
}
- GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
+ OpenType_GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
/* Tibeten script does not set sva.fDiacritic or sva.fZeroWidth */
}
}
-static void ShapeCharGlyphProp_BaseIndic( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp, lexical_function lexical, BOOL use_syllables)
+static void ShapeCharGlyphProp_BaseIndic( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp, lexical_function lexical, BOOL use_syllables, BOOL override_gsub)
{
int i,k;
- GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
+ OpenType_GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
for (i = 0; i < cGlyphs; i++)
{
int char_index[20];
}
}
- /* Indic scripts do not set fDiacritic or fZeroWidth */
- pGlyphProp[i].sva.fDiacritic = FALSE;
- pGlyphProp[i].sva.fZeroWidth = FALSE;
+ if (override_gsub)
+ {
+ /* Most indic scripts do not set fDiacritic or fZeroWidth */
+ pGlyphProp[i].sva.fDiacritic = FALSE;
+ pGlyphProp[i].sva.fZeroWidth = FALSE;
+ }
if (char_count == 0)
continue;
break;
case lex_ZWJ:
case lex_ZWNJ:
- k = char_count;
+ /* check for dangling joiners */
+ if (pwcChars[char_index[k]-1] == 0x0020 || pwcChars[char_index[k]+1] == 0x0020)
+ pGlyphProp[i].sva.fClusterStart = 1;
+ else
+ k = char_count;
break;
default:
pGlyphProp[i].sva.fClusterStart = 1;
static void ShapeCharGlyphProp_Sinhala( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp )
{
- ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, sinhala_lex, FALSE);
+ ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, sinhala_lex, FALSE, FALSE);
}
static void ShapeCharGlyphProp_Devanagari( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp )
{
- ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, devanagari_lex, TRUE);
+ ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, devanagari_lex, TRUE, TRUE);
}
static void ShapeCharGlyphProp_Bengali( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp )
{
- ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, bengali_lex, TRUE);
+ ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, bengali_lex, TRUE, TRUE);
}
static void ShapeCharGlyphProp_Gurmukhi( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp )
{
- ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gurmukhi_lex, TRUE);
+ ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gurmukhi_lex, TRUE, TRUE);
}
static void ShapeCharGlyphProp_Gujarati( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp )
{
- ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gujarati_lex, TRUE);
+ ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gujarati_lex, TRUE, TRUE);
}
static void ShapeCharGlyphProp_Oriya( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp )
{
- ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, oriya_lex, TRUE);
+ ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, oriya_lex, TRUE, TRUE);
}
static void ShapeCharGlyphProp_Tamil( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp )
{
- ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, tamil_lex, TRUE);
+ ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, tamil_lex, TRUE, TRUE);
}
static void ShapeCharGlyphProp_Telugu( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp )
{
- ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, telugu_lex, TRUE);
+ ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, telugu_lex, TRUE, TRUE);
}
static void ShapeCharGlyphProp_Kannada( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp )
{
- ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, kannada_lex, TRUE);
+ ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, kannada_lex, TRUE, TRUE);
}
static void ShapeCharGlyphProp_Malayalam( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp )
{
- ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, malayalam_lex, TRUE);
+ ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, malayalam_lex, TRUE, TRUE);
+}
+
+static void ShapeCharGlyphProp_Khmer( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp )
+{
+ ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, khmer_lex, TRUE, TRUE);
}
void SHAPE_CharGlyphProp(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp)
HRESULT SHAPE_CheckFontForRequiredFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa)
{
- const GSUB_Feature *feature;
+ LoadedFeature *feature;
int i;
if (!ShapingData[psa->eScript].requiredFeatures)
return USP_E_SCRIPT_NOT_IN_FONT;
}
+
+HRESULT SHAPE_GetFontScriptTags( HDC hdc, ScriptCache *psc,
+ SCRIPT_ANALYSIS *psa, int cMaxTags,
+ OPENTYPE_TAG *pScriptTags, int *pcTags)
+{
+ HRESULT hr;
+ OPENTYPE_TAG searching = 0x00000000;
+
+ if (!psc->GSUB_Table)
+ psc->GSUB_Table = load_gsub_table(hdc);
+
+ if (psa && scriptInformation[psa->eScript].scriptTag)
+ searching = scriptInformation[psa->eScript].scriptTag;
+
+ hr = OpenType_GSUB_GetFontScriptTags(psc, searching, cMaxTags, pScriptTags, pcTags, NULL);
+ if (FAILED(hr))
+ *pcTags = 0;
+ return hr;
+}
+
+HRESULT SHAPE_GetFontLanguageTags( HDC hdc, ScriptCache *psc,
+ SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript,
+ int cMaxTags, OPENTYPE_TAG *pLangSysTags,
+ int *pcTags)
+{
+ HRESULT hr;
+ OPENTYPE_TAG searching = 0x00000000;
+ BOOL fellback = FALSE;
+
+ if (!psc->GSUB_Table)
+ psc->GSUB_Table = load_gsub_table(hdc);
+
+ if (psa && psc->userLang != 0)
+ searching = psc->userLang;
+
+ hr = OpenType_GSUB_GetFontLanguageTags(psc, tagScript, searching, cMaxTags, pLangSysTags, pcTags, NULL);
+ if (FAILED(hr))
+ {
+ fellback = TRUE;
+ hr = OpenType_GSUB_GetFontLanguageTags(psc, MS_MAKE_TAG('l','a','t','n'), searching, cMaxTags, pLangSysTags, pcTags, NULL);
+ }
+
+ if (FAILED(hr) || fellback)
+ *pcTags = 0;
+ if (SUCCEEDED(hr) && fellback && psa)
+ hr = E_INVALIDARG;
+ return hr;
+}
+
+HRESULT SHAPE_GetFontFeatureTags( HDC hdc, ScriptCache *psc,
+ SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript,
+ OPENTYPE_TAG tagLangSys, int cMaxTags,
+ OPENTYPE_TAG *pFeatureTags, int *pcTags)
+{
+ HRESULT hr;
+ BOOL filter = FALSE;
+
+ if (!psc->GSUB_Table)
+ psc->GSUB_Table = load_gsub_table(hdc);
+
+ if (psa && scriptInformation[psa->eScript].scriptTag)
+ {
+ FIXME("Filtering not implemented\n");
+ filter = TRUE;
+ }
+
+ hr = OpenType_GSUB_GetFontFeatureTags(psc, tagScript, tagLangSys, filter, 0x00000000, cMaxTags, pFeatureTags, pcTags, NULL);
+
+ if (FAILED(hr))
+ *pcTags = 0;
+ return hr;
+}
typedef struct _scriptRange
{
WORD script;
- WORD rangeFirst;
- WORD rangeLast;
+ DWORD rangeFirst;
+ DWORD rangeLast;
WORD numericScript;
WORD punctScript;
} scriptRange;
/* Latin Extended-A: U+0100–U+017F */
/* Latin Extended-B: U+0180–U+024F */
/* IPA Extensions: U+0250–U+02AF */
- { Script_Latin, 0x80, 0x2af , Script_Numeric2, Script_Punctuation},
+ /* Spacing Modifier Letters:U+02B0–U+02FF */
+ { Script_Latin, 0x80, 0x2ff , Script_Numeric2, Script_Punctuation},
/* Combining Diacritical Marks : U+0300–U+036F */
{ Script_Diacritical,0x300, 0x36f, 0, 0},
/* Greek: U+0370–U+03FF */
{ Script_Arabic, 0x750, 0x77f, 0, 0},
/* Thaana: U+0780–U+07BF */
{ Script_Thaana, 0x780, 0x7bf, 0, 0},
+ /* N’Ko: U+07C0–U+07FF */
+ { Script_NKo, 0x7c0, 0x7ff, 0, 0},
/* Devanagari: U+0900–U+097F */
{ Script_Devanagari, 0x900, 0x97f, Script_Devanagari_Numeric, 0},
/* Bengali: U+0980–U+09FF */
{ Script_Lao, 0xe80, 0xeff, Script_Lao_Numeric, 0},
/* Tibetan: U+0F00–U+0FFF */
{ Script_Tibetan, 0xf00, 0xfff, 0, 0},
+ /* Myanmar: U+1000–U+109F */
+ { Script_Myanmar, 0x1000, 0x109f, Script_Myanmar_Numeric, 0},
/* Georgian: U+10A0–U+10FF */
{ Script_Georgian, 0x10a0, 0x10ff, 0, 0},
+ /* Hangul Jamo: U+1100–U+11FF */
+ { Script_Hangul, 0x1100, 0x11ff, 0, 0},
+ /* Ethiopic: U+1200–U+137F */
+ /* Ethiopic Extensions: U+1380–U+139F */
+ { Script_Ethiopic, 0x1200, 0x139f, 0, 0},
+ /* Cherokee: U+13A0–U+13FF */
+ { Script_Cherokee, 0x13a0, 0x13ff, 0, 0},
+ /* Canadian Aboriginal Syllabics: U+1400–U+167F */
+ { Script_Canadian, 0x1400, 0x167f, 0, 0},
+ /* Ogham: U+1680–U+169F */
+ { Script_Ogham, 0x1680, 0x169f, 0, 0},
+ /* Runic: U+16A0–U+16F0 */
+ { Script_Runic, 0x16a0, 0x16f0, 0, 0},
+ /* Khmer: U+1780–U+17FF */
+ { Script_Khmer, 0x1780, 0x17ff, Script_Khmer_Numeric, 0},
+ /* Mongolian: U+1800–U+18AF */
+ { Script_Mongolian, 0x1800, 0x18af, Script_Mongolian_Numeric, 0},
+ /* Canadian Aboriginal Syllabics Extended: U+18B0–U+18FF */
+ { Script_Canadian, 0x18b0, 0x18ff, 0, 0},
+ /* Tai Le: U+1950–U+197F */
+ { Script_Tai_Le, 0x1950, 0x197f, 0, 0},
+ /* New Tai Lue: U+1980–U+19DF */
+ { Script_New_Tai_Lue,0x1980, 0x19df, Script_New_Tai_Lue_Numeric, 0},
+ /* Khmer Symbols: U+19E0–U+19FF */
+ { Script_Khmer, 0x19e0, 0x19ff, Script_Khmer_Numeric, 0},
/* Vedic Extensions: U+1CD0-U+1CFF */
{ Script_Devanagari, 0x1cd0, 0x1cff, Script_Devanagari_Numeric, 0},
/* Phonetic Extensions: U+1D00–U+1DBF */
/* Miscellaneous Mathematical Symbols-A : U+27c0 –U+27ef */
/* Supplemental Arrows-A : U+27f0 –U+27ff */
{ Script_Latin, 0x2100, 0x27ff, 0, 0},
+ /* Braille Patterns: U+2800–U+28FF */
+ { Script_Braille, 0x2800, 0x28ff, 0, 0},
/* Supplemental Arrows-B : U+2900 –U+297f */
/* Miscellaneous Mathematical Symbols-B : U+2980 –U+29ff */
/* Supplemental Mathematical Operators : U+2a00 –U+2aff */
{ Script_Latin, 0x2c60, 0x2c7f, 0, 0},
/* Georgian: U+2D00–U+2D2F */
{ Script_Georgian, 0x2d00, 0x2d2f, 0, 0},
+ /* Tifinagh: U+2D30–U+2D7F */
+ { Script_Tifinagh, 0x2d30, 0x2d7f, 0, 0},
+ /* Ethiopic Extensions: U+2D80–U+2DDF */
+ { Script_Ethiopic, 0x2d80, 0x2ddf, 0, 0},
/* Cyrillic Extended-A: U+2DE0–U+2DFF */
{ Script_Cyrillic, 0x2de0, 0x2dff, 0, 0},
+ /* CJK Radicals Supplement: U+2E80–U+2EFF */
+ /* Kangxi Radicals: U+2F00–U+2FDF */
+ { Script_CJK_Han, 0x2e80, 0x2fdf, 0, 0},
+ /* Ideographic Description Characters: U+2FF0–U+2FFF */
+ { Script_Ideograph ,0x2ff0, 0x2fff, 0, 0},
+ /* CJK Symbols and Punctuation: U+3000–U+303F */
+ { Script_Ideograph ,0x3000, 0x3004, 0, 0},
+ { Script_CJK_Han ,0x3005, 0x3005, 0, 0},
+ { Script_Ideograph ,0x3006, 0x3006, 0, 0},
+ { Script_CJK_Han ,0x3007, 0x3007, 0, 0},
+ { Script_Ideograph ,0x3008, 0x3020, 0, 0},
+ { Script_CJK_Han ,0x3021, 0x3029, 0, 0},
+ { Script_Ideograph ,0x302a, 0x3030, 0, 0},
+ /* Kana Marks: */
+ { Script_Kana ,0x3031, 0x3035, 0, 0},
+ { Script_Ideograph ,0x3036, 0x3037, 0, 0},
+ { Script_CJK_Han ,0x3038, 0x303b, 0, 0},
+ { Script_Ideograph ,0x303c, 0x303f, 0, 0},
+ /* Hiragana: U+3040–U+309F */
+ /* Katakana: U+30A0–U+30FF */
+ { Script_Kana ,0x3040, 0x30ff, 0, 0},
+ /* Bopomofo: U+3100–U+312F */
+ { Script_Bopomofo ,0x3100, 0x312f, 0, 0},
+ /* Hangul Compatibility Jamo: U+3130–U+318F */
+ { Script_Hangul ,0x3130, 0x318f, 0, 0},
+ /* Kanbun: U+3190–U+319F */
+ { Script_Ideograph ,0x3190, 0x319f, 0, 0},
+ /* Bopomofo Extended: U+31A0–U+31BF */
+ { Script_Bopomofo ,0x31a0, 0x31bf, 0, 0},
+ /* CJK Strokes: U+31C0–U+31EF */
+ { Script_Ideograph ,0x31c0, 0x31ef, 0, 0},
+ /* Katakana Phonetic Extensions: U+31F0–U+31FF */
+ { Script_Kana ,0x31f0, 0x31ff, 0, 0},
+ /* Enclosed CJK Letters and Months: U+3200–U+32FF */
+ { Script_Hangul ,0x3200, 0x321f, 0, 0},
+ { Script_Ideograph ,0x3220, 0x325f, 0, 0},
+ { Script_Hangul ,0x3260, 0x327f, 0, 0},
+ { Script_Ideograph ,0x3280, 0x32ef, 0, 0},
+ { Script_Kana ,0x32d0, 0x31ff, 0, 0},
+ /* CJK Compatibility: U+3300–U+33FF*/
+ { Script_Kana ,0x3300, 0x3357, 0, 0},
+ { Script_Ideograph ,0x3358, 0x33ff, 0, 0},
+ /* CJK Unified Ideographs Extension A: U+3400–U+4DBF */
+ { Script_CJK_Han ,0x3400, 0x4dbf, 0, 0},
+ /* CJK Unified Ideographs: U+4E00–U+9FFF */
+ { Script_CJK_Han ,0x4e00, 0x9fff, 0, 0},
+ /* Yi: U+A000–U+A4CF */
+ { Script_Yi ,0xa000, 0xa4cf, 0, 0},
+ /* Vai: U+A500–U+A63F */
+ { Script_Vai ,0xa500, 0xa63f, Script_Vai_Numeric, 0},
/* Cyrillic Extended-B: U+A640–U+A69F */
{ Script_Cyrillic, 0xa640, 0xa69f, 0, 0},
/* Modifier Tone Letters: U+A700–U+A71F */
{ Script_Phags_pa, 0xa840, 0xa87f, 0, 0},
/* Devanagari Extended: U+A8E0-U+A8FF */
{ Script_Devanagari, 0xa8e0, 0xa8ff, Script_Devanagari_Numeric, 0},
+ /* Myanmar Extended-A: U+AA60–U+AA7F */
+ { Script_Myanmar, 0xaa60, 0xaa7f, Script_Myanmar_Numeric, 0},
+ /* Hangul Jamo Extended-A: U+A960–U+A97F */
+ { Script_Hangul, 0xa960, 0xa97f, 0, 0},
+ /* Hangul Syllables: U+AC00–U+D7A3 */
+ { Script_Hangul, 0xac00, 0xd7a3, 0, 0},
+ /* Hangul Jamo Extended-B: U+D7B0–U+D7FF */
+ { Script_Hangul, 0xd7b0, 0xd7ff, 0, 0},
+ /* Surrogates Area: U+D800–U+DFFF */
+ { Script_Surrogates, 0xd800, 0xdbfe, 0, 0},
+ { Script_Private, 0xdbff, 0xdc00, 0, 0},
+ { Script_Surrogates, 0xdc01, 0xdfff, 0, 0},
+ /* Private Use Area: U+E000–U+F8FF */
+ { Script_Private, 0xe000, 0xf8ff, 0, 0},
+ /* CJK Compatibility Ideographs: U+F900–U+FAFF */
+ { Script_CJK_Han ,0xf900, 0xfaff, 0, 0},
/* Latin Ligatures: U+FB00–U+FB06 */
{ Script_Latin, 0xfb00, 0xfb06, 0, 0},
/* Armenian ligatures U+FB13..U+FB17 */
{ Script_Hebrew, 0xfb1d, 0xfb4f, 0, 0},
/* Arabic Presentation Forms-A: U+FB50–U+FDFF*/
{ Script_Arabic, 0xfb50, 0xfdff, 0, 0},
+ /* Vertical Forms: U+FE10–U+FE1F */
+ /* Combining Half Marks: U+FE20–U+FE2F */
+ /* CJK Compatibility Forms: U+FE30–U+FE4F */
+ /* Small Form Variants: U+FE50–U+FE6F */
+ { Script_Ideograph ,0xfe10, 0xfe6f, 0, 0},
/* Arabic Presentation Forms-B: U+FE70–U+FEFF*/
{ Script_Arabic, 0xfe70, 0xfeff, 0, 0},
+ /* Halfwidth and Fullwidth Forms: U+FF00–FFEF */
+ { Script_Ideograph ,0xff00, 0xff64, Script_Numeric2, 0},
+ { Script_Kana ,0xff65, 0xff9f, 0, 0},
+ { Script_Hangul ,0xffa0, 0xffdf, 0, 0},
+ { Script_Ideograph ,0xffe0, 0xffef, 0, 0},
+ /* Plane - 1 */
+ /* Deseret: U+10400–U+1044F */
+ { Script_Deseret, 0x10400, 0x1044F, 0, 0},
+ /* Osmanya: U+10480–U+104AF */
+ { Script_Osmanya, 0x10480, 0x104AF, Script_Osmanya_Numeric, 0},
+ /* Mathematical Alphanumeric Symbols: U+1D400–U+1D7FF */
+ { Script_MathAlpha, 0x1D400, 0x1D7FF, 0, 0},
/* END */
{ SCRIPT_UNDEFINED, 0, 0, 0}
};
-typedef struct _scriptData
-{
- SCRIPT_ANALYSIS a;
- SCRIPT_PROPERTIES props;
- OPENTYPE_TAG scriptTag;
- WCHAR fallbackFont[LF_FACESIZE];
-} scriptData;
-
/* the must be in order so that the index matches the Script value */
-static const scriptData scriptInformation[] = {
+const scriptData scriptInformation[] = {
{{SCRIPT_UNDEFINED, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
{LANG_NEUTRAL, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
0x00000000,
{{Script_Latin, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
{LANG_ENGLISH, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
MS_MAKE_TAG('l','a','t','n'),
- {0}},
+ {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
{{Script_CR, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
{LANG_NEUTRAL, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
0x00000000,
{{Script_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
{LANG_ENGLISH, 1, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
0x00000000,
- {0}},
+ {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
{{Script_Control, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
{LANG_ENGLISH, 0, 1, 0, 0, ANSI_CHARSET, 1, 0, 0, 0, 0, 0, 1, 0, 0},
0x00000000,
{{Script_Punctuation, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
{LANG_NEUTRAL, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
0x00000000,
- {0}},
+ {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
{{Script_Arabic, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
{LANG_ARABIC, 0, 1, 0, 0, ARABIC_CHARSET, 0, 0, 0, 0, 0, 0, 1, 1, 0},
MS_MAKE_TAG('a','r','a','b'),
{{Script_Greek, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
{LANG_GREEK, 0, 0, 0, 0, GREEK_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
MS_MAKE_TAG('g','r','e','k'),
- {0}},
+ {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
{{Script_Cyrillic, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
{LANG_RUSSIAN, 0, 0, 0, 0, RUSSIAN_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
MS_MAKE_TAG('c','y','r','l'),
- {0}},
+ {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
{{Script_Armenian, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
{LANG_ARMENIAN, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
MS_MAKE_TAG('a','r','m','n'),
{{Script_Punctuation2, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
{LANG_ENGLISH, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
MS_MAKE_TAG('l','a','t','n'),
- {0}},
+ {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
{{Script_Numeric2, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
{LANG_ENGLISH, 1, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
0x00000000,
{0}},
+ {{Script_Myanmar, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
+ {0x55, 0, 1, 1, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
+ MS_MAKE_TAG('m','y','m','r'),
+ {0}},
+ {{Script_Myanmar_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
+ {0x55, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ MS_MAKE_TAG('m','y','m','r'),
+ {0}},
+ {{Script_Tai_Le, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
+ {0, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ MS_MAKE_TAG('t','a','l','e'),
+ {'M','i','c','r','o','s','o','f','t',' ','T','a','i',' ','L','e'}},
+ {{Script_New_Tai_Lue, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
+ {0, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ MS_MAKE_TAG('t','a','l','u'),
+ {'M','i','c','r','o','s','o','f','t',' ','N','e','w',' ','T','a','i',' ','L','u','e'}},
+ {{Script_New_Tai_Lue_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
+ {0, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ MS_MAKE_TAG('t','a','l','u'),
+ {'M','i','c','r','o','s','o','f','t',' ','N','e','w',' ','T','a','i',' ','L','u','e'}},
+ {{Script_Khmer, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
+ {0x53, 0, 1, 1, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
+ MS_MAKE_TAG('k','h','m','r'),
+ {'D','a','u','n','P','e','n','h'}},
+ {{Script_Khmer, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
+ {0x53, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ MS_MAKE_TAG('k','h','m','r'),
+ {'D','a','u','n','P','e','n','h'}},
+ {{Script_CJK_Han, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
+ {LANG_ENGLISH, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
+ MS_MAKE_TAG('h','a','n','i'),
+ {0}},
+ {{Script_Ideograph, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
+ {LANG_ENGLISH, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
+ MS_MAKE_TAG('h','a','n','i'),
+ {0}},
+ {{Script_Bopomofo, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
+ {LANG_ENGLISH, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
+ MS_MAKE_TAG('b','o','p','o'),
+ {0}},
+ {{Script_Kana, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
+ {LANG_ENGLISH, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
+ MS_MAKE_TAG('k','a','n','a'),
+ {0}},
+ {{Script_Hangul, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
+ {LANG_KOREAN, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
+ MS_MAKE_TAG('h','a','n','g'),
+ {0}},
+ {{Script_Yi, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
+ {LANG_ENGLISH, 0, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
+ MS_MAKE_TAG('y','i',' ',' '),
+ {'M','i','c','r','o','s','o','f','t',' ','Y','i',' ','B','a','i','t','i'}},
+ {{Script_Ethiopic, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
+ {0x5e, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ MS_MAKE_TAG('e','t','h','i'),
+ {'N','y','a','l','a'}},
+ {{Script_Ethiopic_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
+ {0x5e, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ MS_MAKE_TAG('e','t','h','i'),
+ {'N','y','a','l','a'}},
+ {{Script_Mongolian, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
+ {LANG_MONGOLIAN, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ MS_MAKE_TAG('m','o','n','g'),
+ {'M','o','n','g','o','l','i','a','n',' ','B','a','i','t','i'}},
+ {{Script_Mongolian_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
+ {LANG_MONGOLIAN, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ MS_MAKE_TAG('m','o','n','g'),
+ {'M','o','n','g','o','l','i','a','n',' ','B','a','i','t','i'}},
+ {{Script_Tifinagh, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
+ {0, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ MS_MAKE_TAG('t','f','n','g'),
+ {'E','b','r','i','m','a'}},
+ {{Script_NKo, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
+ {0, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ MS_MAKE_TAG('n','k','o',' '),
+ {'E','b','r','i','m','a'}},
+ {{Script_Vai, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
+ {0, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ MS_MAKE_TAG('v','a','i',' '),
+ {'E','b','r','i','m','a'}},
+ {{Script_Vai_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
+ {0, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ MS_MAKE_TAG('v','a','i',' '),
+ {'E','b','r','i','m','a'}},
+ {{Script_Cherokee, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
+ {0x5c, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ MS_MAKE_TAG('c','h','e','r'),
+ {'P','l','a','n','t','a','g','e','n','e','t',' ','C','h','e','r','o','k','e','e'}},
+ {{Script_Canadian, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
+ {0x5d, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ MS_MAKE_TAG('c','a','n','s'),
+ {'E','u','p','h','e','m','i','a'}},
+ {{Script_Ogham, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
+ {0, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ MS_MAKE_TAG('o','g','a','m'),
+ {'S','e','g','o','e',' ','U','I',' ','S','y','m','b','o','l'}},
+ {{Script_Runic, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
+ {0, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ MS_MAKE_TAG('r','u','n','r'),
+ {'S','e','g','o','e',' ','U','I',' ','S','y','m','b','o','l'}},
+ {{Script_Braille, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
+ {LANG_ENGLISH, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ MS_MAKE_TAG('b','r','a','i'),
+ {'S','e','g','o','e',' ','U','I',' ','S','y','m','b','o','l'}},
+ {{Script_Surrogates, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
+ {LANG_ENGLISH, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
+ 0x00000000,
+ {0}},
+ {{Script_Private, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
+ {0, 0, 0, 0, 0, DEFAULT_CHARSET, 0, 1, 0, 0, 0, 0, 1, 0, 0},
+ 0x00000000,
+ {0}},
+ {{Script_Deseret, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
+ {0, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ MS_MAKE_TAG('d','s','r','t'),
+ {'S','e','g','o','e',' ','U','I',' ','S','y','m','b','o','l'}},
+ {{Script_Osmanya, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
+ {0, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ MS_MAKE_TAG('o','s','m','a'),
+ {'E','b','r','i','m','a'}},
+ {{Script_Osmanya_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
+ {0, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ MS_MAKE_TAG('o','s','m','a'),
+ {'E','b','r','i','m','a'}},
+ {{Script_MathAlpha, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
+ {0, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ MS_MAKE_TAG('m','a','t','h'),
+ {'C','a','m','b','r','i','a',' ','M','a','t','h'}},
+ {{Script_Hebrew_Currency, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
+ {LANG_HEBREW, 0, 1, 0, 0, HEBREW_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ MS_MAKE_TAG('h','e','b','r'),
+ {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
+ {{Script_Vietnamese_Currency, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
+ {LANG_VIETNAMESE, 0, 0, 0, 0, VIETNAMESE_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ MS_MAKE_TAG('l','a','t','n'),
+ {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
+ {{Script_Thai_Currency, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
+ {LANG_THAI, 0, 1, 0, 0, THAI_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ MS_MAKE_TAG('t','h','a','i'),
+ {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
};
static const SCRIPT_PROPERTIES *script_props[] =
&scriptInformation[38].props, &scriptInformation[39].props,
&scriptInformation[40].props, &scriptInformation[41].props,
&scriptInformation[42].props, &scriptInformation[43].props,
- &scriptInformation[44].props, &scriptInformation[45].props
+ &scriptInformation[44].props, &scriptInformation[45].props,
+ &scriptInformation[46].props, &scriptInformation[47].props,
+ &scriptInformation[48].props, &scriptInformation[49].props,
+ &scriptInformation[50].props, &scriptInformation[51].props,
+ &scriptInformation[52].props, &scriptInformation[53].props,
+ &scriptInformation[54].props, &scriptInformation[55].props,
+ &scriptInformation[56].props, &scriptInformation[57].props,
+ &scriptInformation[58].props, &scriptInformation[59].props,
+ &scriptInformation[60].props, &scriptInformation[61].props,
+ &scriptInformation[62].props, &scriptInformation[63].props,
+ &scriptInformation[64].props, &scriptInformation[65].props,
+ &scriptInformation[66].props, &scriptInformation[67].props,
+ &scriptInformation[68].props, &scriptInformation[69].props,
+ &scriptInformation[70].props, &scriptInformation[71].props,
+ &scriptInformation[72].props, &scriptInformation[73].props,
+ &scriptInformation[74].props, &scriptInformation[75].props,
+ &scriptInformation[76].props, &scriptInformation[77].props,
+ &scriptInformation[78].props, &scriptInformation[79].props,
+ &scriptInformation[80].props, &scriptInformation[81].props
};
typedef struct {
return ((ScriptCache *)*psc)->tm.tmPitchAndFamily;
}
-static inline WORD get_cache_glyph(SCRIPT_CACHE *psc, WCHAR c)
+static inline WORD get_cache_glyph(SCRIPT_CACHE *psc, DWORD c)
{
WORD *block = ((ScriptCache *)*psc)->glyphs[c >> GLYPH_BLOCK_SHIFT];
return ch + wine_mirror_map[wine_mirror_map[ch >> 8] + (ch & 0xff)];
}
-static WORD get_char_script( WCHAR ch)
+static inline DWORD decode_surrogate_pair(LPCWSTR str, INT index, INT end)
+{
+ if (index < end-1 && IS_SURROGATE_PAIR(str[index],str[index+1]))
+ {
+ DWORD ch = 0x10000 + ((str[index] - 0xd800) << 10) + (str[index+1] - 0xdc00);
+ TRACE("Surrogate Pair %x %x => %x\n",str[index], str[index+1], ch);
+ return ch;
+ }
+ return 0;
+}
+
+static WORD get_char_script( LPCWSTR str, INT index, INT end, INT *consumed)
{
static const WCHAR latin_punc[] = {'#','$','&','\'',',',';','<','>','?','@','\\','^','_','`','{','|','}','~', 0x00a0, 0};
WORD type = 0;
+ DWORD ch;
int i;
- if (ch == 0xc || ch == 0x20 || ch == 0x202f)
+ *consumed = 1;
+
+ if (str[index] == 0xc || str[index] == 0x20 || str[index] == 0x202f)
return Script_CR;
/* These punctuation are separated out as Latin punctuation */
- if (strchrW(latin_punc,ch))
+ if (strchrW(latin_punc,str[index]))
return Script_Punctuation2;
/* These chars are itemized as Punctuation by Windows */
- if (ch == 0x2212 || ch == 0x2044)
+ if (str[index] == 0x2212 || str[index] == 0x2044)
return Script_Punctuation;
- GetStringTypeW(CT_CTYPE1, &ch, 1, &type);
+ /* Currency Symboles by Unicode point */
+ switch (str[index])
+ {
+ case 0x09f2:
+ case 0x09f3: return Script_Bengali_Currency;
+ case 0x0af1: return Script_Gujarati_Currency;
+ case 0x0e3f: return Script_Thai_Currency;
+ case 0x20aa: return Script_Hebrew_Currency;
+ case 0x20ab: return Script_Vietnamese_Currency;
+ case 0xfb29: return Script_Hebrew_Currency;
+ }
+
+ GetStringTypeW(CT_CTYPE1, &str[index], 1, &type);
if (type == 0)
return SCRIPT_UNDEFINED;
if (type & C1_CNTRL)
return Script_Control;
+ ch = decode_surrogate_pair(str, index, end);
+ if (ch)
+ *consumed = 2;
+ else
+ ch = str[index];
+
i = 0;
do
{
}
heap_free(((ScriptCache *)*psc)->GSUB_Table);
heap_free(((ScriptCache *)*psc)->GDEF_Table);
- heap_free(((ScriptCache *)*psc)->features);
+ heap_free(((ScriptCache *)*psc)->CMAP_Table);
+ for (i = 0; i < ((ScriptCache *)*psc)->script_count; i++)
+ {
+ int j;
+ for (j = 0; j < ((ScriptCache *)*psc)->scripts[i].language_count; j++)
+ {
+ int k;
+ for (k = 0; k < ((ScriptCache *)*psc)->scripts[i].languages[j].feature_count; k++)
+ heap_free(((ScriptCache *)*psc)->scripts[i].languages[j].features[k].lookups);
+ heap_free(((ScriptCache *)*psc)->scripts[i].languages[j].features);
+ }
+ heap_free(((ScriptCache *)*psc)->scripts[i].languages);
+ }
+ heap_free(((ScriptCache *)*psc)->scripts);
heap_free(*psc);
*psc = NULL;
}
WORD last_indic = -1;
WORD layoutRTL = 0;
BOOL forceLevels = FALSE;
+ INT consumed = 0;
TRACE("%s,%d,%d,%p,%p,%p,%p\n", debugstr_wn(pwcInChars, cInChars), cInChars, cMaxItems,
psControl, psState, pItems, pcItems);
for (i = 0; i < cInChars; i++)
{
- scripts[i] = get_char_script(pwcInChars[i]);
+ if (consumed <= 0)
+ {
+ scripts[i] = get_char_script(pwcInChars,i,cInChars,&consumed);
+ consumed --;
+ }
+ else
+ {
+ scripts[i] = scripts[i-1];
+ consumed --;
+ }
/* Devanagari danda (U+0964) and double danda (U+0965) are used for
all Indic scripts */
if ((pwcInChars[i] == 0x964 || pwcInChars[i] ==0x965) && last_indic > 0)
LOGFONTW lf;
GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), & lf);
lf.lfCharSet = scriptInformation[analysis->pItem[i].a.eScript].props.bCharSet;
+ lf.lfFaceName[0] = 0;
find_fallback_font(analysis->pItem[i].a.eScript, lf.lfFaceName);
- analysis->glyphs[i].fallbackFont = CreateFontIndirectW(&lf);
- if (analysis->glyphs[i].fallbackFont)
+ if (lf.lfFaceName[0])
{
- ScriptFreeCache(sc);
- originalFont = SelectObject(hdc, analysis->glyphs[i].fallbackFont);
+ analysis->glyphs[i].fallbackFont = CreateFontIndirectW(&lf);
+ if (analysis->glyphs[i].fallbackFont)
+ {
+ ScriptFreeCache(sc);
+ originalFont = SelectObject(hdc, analysis->glyphs[i].fallbackFont);
+ }
}
}
INT runStart, runEnd;
INT iGlyph, cGlyphs;
HFONT oldFont = 0x0;
+ RECT crc;
+ int i;
TRACE("(%p,%d,%d,%d,%d,%d, 0x%1x, %d, %d)\n",
ssa, iX, iY, iItem, cStart, cEnd, uOptions, fSelected, fDisabled);
(cEnd >= 0 && analysis->pItem[iItem].iCharPos >= cEnd))
return S_OK;
+ CopyRect(&crc,prc);
if (fSelected)
{
BkMode = GetBkMode(analysis->hdc);
ScriptStringCPtoX(ssa, cEnd, FALSE, &off_x);
else
ScriptStringCPtoX(ssa, analysis->pItem[iItem+1].iCharPos-1, TRUE, &off_x);
+ crc.left = iX + off_x;
}
else
{
ScriptStringCPtoX(ssa, cStart, FALSE, &off_x);
else
ScriptStringCPtoX(ssa, analysis->pItem[iItem].iCharPos, FALSE, &off_x);
+ crc.left = iX + off_x;
}
if (analysis->pItem[iItem].a.fRTL)
cGlyphs++;
+ /* adjust for cluster glyphs when starting */
+ if (analysis->pItem[iItem].a.fRTL)
+ i = analysis->pItem[iItem+1].iCharPos - 1;
+ else
+ i = analysis->pItem[iItem].iCharPos;
+
+ for (; i >=analysis->pItem[iItem].iCharPos && i < analysis->pItem[iItem+1].iCharPos; (analysis->pItem[iItem].a.fRTL)?i--:i++)
+ {
+ if (analysis->glyphs[iItem].pwLogClust[i - analysis->pItem[iItem].iCharPos] == iGlyph)
+ {
+ if (analysis->pItem[iItem].a.fRTL)
+ ScriptStringCPtoX(ssa, i, TRUE, &off_x);
+ else
+ ScriptStringCPtoX(ssa, i, FALSE, &off_x);
+ break;
+ }
+ }
+
if (cEnd < 0 || scriptInformation[analysis->pItem[iItem].a.eScript].props.fNeedsCaretInfo)
{
INT direction;
hr = ScriptTextOut(analysis->hdc,
(SCRIPT_CACHE *)&analysis->glyphs[iItem].sc, iX + off_x,
- iY, uOptions, prc, &analysis->pItem[iItem].a, NULL, 0,
+ iY, uOptions, &crc, &analysis->pItem[iItem].a, NULL, 0,
&analysis->glyphs[iItem].glyphs[iGlyph], cGlyphs,
&analysis->glyphs[iItem].piAdvance[iGlyph], NULL,
&analysis->glyphs[iItem].pGoffset[iGlyph]);
HRESULT WINAPI ScriptIsComplex(const WCHAR *chars, int len, DWORD flag)
{
int i;
+ INT consumed = 0;
TRACE("(%s,%d,0x%x)\n", debugstr_wn(chars, len), len, flag);
- for (i = 0; i < len; i++)
+ for (i = 0; i < len; i+=consumed)
{
int script;
+ if (i >= len)
+ break;
if ((flag & SIC_ASCIIDIGIT) && chars[i] >= 0x30 && chars[i] <= 0x39)
return S_OK;
- script = get_char_script(chars[i]);
+ script = get_char_script(chars,i,len, &consumed);
if ((scriptInformation[script].props.fComplex && (flag & SIC_COMPLEX))||
(!scriptInformation[script].props.fComplex && (flag & SIC_NEUTRAL)))
return S_OK;
SCRIPT_GLYPHPROP *pOutGlyphProps, int *pcGlyphs)
{
HRESULT hr;
- unsigned int i;
+ unsigned int i,g;
BOOL rtl;
+ int cluster;
TRACE("(%p, %p, %p, %s, %s, %p, %p, %d, %s, %d, %d, %p, %p, %p, %p, %p )\n",
hdc, psc, psa,
((ScriptCache *)*psc)->userLang = tagLangSys;
/* set fNoGlyphIndex non truetype/opentype fonts */
- if (!psa->fNoGlyphIndex && !((ScriptCache *)*psc)->sfnt)
+ if (psa && !psa->fNoGlyphIndex && !((ScriptCache *)*psc)->sfnt)
psa->fNoGlyphIndex = TRUE;
/* Initialize a SCRIPT_VISATTR and LogClust for each char in this run */
rChars = heap_alloc(sizeof(WCHAR) * cChars);
if (!rChars) return E_OUTOFMEMORY;
- for (i = 0; i < cChars; i++)
+ for (i = 0, g = 0, cluster = 0; i < cChars; i++)
{
int idx = i;
- WCHAR chInput;
+ DWORD chInput;
+
if (rtl) idx = cChars - 1 - i;
- if (psa->fRTL)
- chInput = mirror_char(pwcChars[idx]);
- else
- chInput = pwcChars[idx];
- /* special case for tabs */
- if (chInput == 0x0009)
- chInput = 0x0020;
- if (!(pwOutGlyphs[i] = get_cache_glyph(psc, chInput)))
+ if (!cluster)
{
- WORD glyph;
- if (!hdc)
+ chInput = decode_surrogate_pair(pwcChars, idx, cChars);
+ if (!chInput)
+ {
+ if (psa->fRTL)
+ chInput = mirror_char(pwcChars[idx]);
+ else
+ chInput = pwcChars[idx];
+ /* special case for tabs */
+ if (chInput == 0x0009)
+ chInput = 0x0020;
+ rChars[i] = chInput;
+ }
+ else
{
- heap_free(rChars);
- return E_PENDING;
+ rChars[i] = pwcChars[idx];
+ rChars[i+1] = pwcChars[(rtl)?idx-1:idx+1];
+ cluster = 1;
}
- if (GetGlyphIndicesW(hdc, &chInput, 1, &glyph, 0) == GDI_ERROR)
+ if (!(pwOutGlyphs[g] = get_cache_glyph(psc, chInput)))
{
- heap_free(rChars);
- return S_FALSE;
+ WORD glyph;
+ if (!hdc)
+ {
+ heap_free(rChars);
+ return E_PENDING;
+ }
+ if (OpenType_CMAP_GetGlyphIndex(hdc, (ScriptCache *)*psc, chInput, &glyph, 0) == GDI_ERROR)
+ {
+ heap_free(rChars);
+ return S_FALSE;
+ }
+ pwOutGlyphs[g] = set_cache_glyph(psc, chInput, glyph);
}
- pwOutGlyphs[i] = set_cache_glyph(psc, chInput, glyph);
+ g++;
+ }
+ else
+ {
+ int k;
+ cluster--;
+ pwLogClust[idx] = (rtl)?pwLogClust[idx+1]:pwLogClust[idx-1];
+ for (k = (rtl)?idx-1:idx+1; k >= 0 && k < cChars; (rtl)?k--:k++)
+ pwLogClust[k]--;
}
- rChars[i] = chInput;
}
+ *pcGlyphs = g;
SHAPE_ContextualShaping(hdc, (ScriptCache *)*psc, psa, rChars, cChars, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust);
SHAPE_ApplyDefaultOpentypeFeatures(hdc, (ScriptCache *)*psc, psa, pwOutGlyphs, pcGlyphs, cMaxGlyphs, cChars, pwLogClust);
return S_OK;
}
+HRESULT WINAPI ScriptGetFontScriptTags( HDC hdc, SCRIPT_CACHE *psc, SCRIPT_ANALYSIS *psa, int cMaxTags, OPENTYPE_TAG *pScriptTags, int *pcTags)
+{
+ HRESULT hr;
+ if (!pScriptTags || !pcTags || cMaxTags == 0) return E_INVALIDARG;
+ if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
+
+ return SHAPE_GetFontScriptTags(hdc, (ScriptCache *)*psc, psa, cMaxTags, pScriptTags, pcTags);
+}
+
+HRESULT WINAPI ScriptGetFontLanguageTags( HDC hdc, SCRIPT_CACHE *psc, SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript, int cMaxTags, OPENTYPE_TAG *pLangSysTags, int *pcTags)
+{
+ HRESULT hr;
+ if (!pLangSysTags || !pcTags || cMaxTags == 0) return E_INVALIDARG;
+ if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
+
+ return SHAPE_GetFontLanguageTags(hdc, (ScriptCache *)*psc, psa, tagScript, cMaxTags, pLangSysTags, pcTags);
+}
+
+HRESULT WINAPI ScriptGetFontFeatureTags( HDC hdc, SCRIPT_CACHE *psc, SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript, OPENTYPE_TAG tagLangSys, int cMaxTags, OPENTYPE_TAG *pFeatureTags, int *pcTags)
+{
+ HRESULT hr;
+ if (!pFeatureTags || !pcTags || cMaxTags == 0) return E_INVALIDARG;
+ if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
+
+ return SHAPE_GetFontFeatureTags(hdc, (ScriptCache *)*psc, psa, tagScript, tagLangSys, cMaxTags, pFeatureTags, pcTags);
+}
+
BOOL gbLpkPresent = FALSE;
VOID WINAPI LpkPresent()
{
<file>linebreak.c</file>
<file>indicsyllable.c</file>
<file>mirror.c</file>
+ <file>opentype.c</file>
<file>shape.c</file>
<file>shaping.c</file>
<library>wine</library>
@ stdcall ScriptFreeCache(ptr)
@ stdcall ScriptGetCMap(ptr ptr ptr long long ptr)
@ stub ScriptGetFontAlternateGlyphs
-@ stub ScriptGetFontFeatureTags
-@ stub ScriptGetFontLanguageTags
+@ stdcall ScriptGetFontFeatureTags(long ptr ptr long long long ptr ptr)
+@ stdcall ScriptGetFontLanguageTags(long ptr ptr long long ptr ptr)
@ stdcall ScriptGetFontProperties(long ptr ptr)
-@ stub ScriptGetFontScriptTags
+@ stdcall ScriptGetFontScriptTags(long ptr ptr long ptr ptr)
@ stdcall ScriptGetGlyphABCWidth(ptr ptr long ptr)
@ stdcall ScriptGetLogicalWidths(ptr long long ptr ptr ptr ptr)
@ stdcall ScriptGetProperties(ptr long)
#define Script_Diacritical 44
#define Script_Punctuation2 45
#define Script_Numeric2 46
+/* Unicode Chapter 11 continued */
+#define Script_Myanmar 47
+#define Script_Myanmar_Numeric 48
+#define Script_Tai_Le 49
+#define Script_New_Tai_Lue 50
+#define Script_New_Tai_Lue_Numeric 51
+#define Script_Khmer 52
+#define Script_Khmer_Numeric 53
+/* Unicode Chapter 12 */
+#define Script_CJK_Han 54
+#define Script_Ideograph 55
+#define Script_Bopomofo 56
+#define Script_Kana 57
+#define Script_Hangul 58
+#define Script_Yi 59
+/* Unicode Chapter 13 */
+#define Script_Ethiopic 60
+#define Script_Ethiopic_Numeric 61
+#define Script_Mongolian 62
+#define Script_Mongolian_Numeric 63
+#define Script_Tifinagh 64
+#define Script_NKo 65
+#define Script_Vai 66
+#define Script_Vai_Numeric 67
+#define Script_Cherokee 68
+#define Script_Canadian 69
+/* Unicode Chapter 14 */
+#define Script_Ogham 70
+#define Script_Runic 71
+/* Unicode Chapter 15 */
+#define Script_Braille 72
+/* Unicode Chapter 16 */
+#define Script_Surrogates 73
+#define Script_Private 74
+/* Unicode Chapter 13 : Plane 1 */
+#define Script_Deseret 75
+#define Script_Osmanya 76
+#define Script_Osmanya_Numeric 77
+/* Unicode Chapter 15 : Plane 1 */
+#define Script_MathAlpha 78
+/* Additional Currency Scripts */
+#define Script_Hebrew_Currency 79
+#define Script_Vietnamese_Currency 80
+#define Script_Thai_Currency 81
#define GLYPH_BLOCK_SHIFT 8
#define GLYPH_BLOCK_SIZE (1UL << GLYPH_BLOCK_SHIFT)
#define GLYPH_BLOCK_MASK (GLYPH_BLOCK_SIZE - 1)
#define GLYPH_MAX 65536
+#define GSUB_E_NOFEATURE -2
+#define GSUB_E_NOGLYPH -1
+
typedef struct {
- char tag[5];
- char script[5];
+ OPENTYPE_TAG tag;
LPCVOID feature;
+ INT lookup_count;
+ WORD *lookups;
} LoadedFeature;
+typedef struct {
+ OPENTYPE_TAG tag;
+ LPCVOID table;
+ INT feature_count;
+ LoadedFeature *features;
+} LoadedLanguage;
+
+typedef struct {
+ OPENTYPE_TAG tag;
+ LPCVOID table;
+ LoadedLanguage default_language;
+ INT language_count;
+ LoadedLanguage *languages;
+} LoadedScript;
+
typedef struct {
LOGFONTW lf;
TEXTMETRICW tm;
ABC *widths[GLYPH_MAX / GLYPH_BLOCK_SIZE];
LPVOID GSUB_Table;
LPVOID GDEF_Table;
- INT feature_count;
- LoadedFeature *features;
+ LPVOID CMAP_Table;
+ LPVOID CMAP_format12_Table;
+ INT script_count;
+ LoadedScript *scripts;
OPENTYPE_TAG userScript;
OPENTYPE_TAG userLang;
} ScriptCache;
+typedef struct _scriptData
+{
+ SCRIPT_ANALYSIS a;
+ SCRIPT_PROPERTIES props;
+ OPENTYPE_TAG scriptTag;
+ WCHAR fallbackFont[LF_FACESIZE];
+} scriptData;
+
typedef struct {
INT start;
INT base;
HRESULT SHAPE_CheckFontForRequiredFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa) DECLSPEC_HIDDEN;
void SHAPE_CharGlyphProp(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp) DECLSPEC_HIDDEN;
INT SHAPE_does_GSUB_feature_apply_to_chars(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache* psc, const WCHAR *chars, INT write_dir, INT count, const char* feature) DECLSPEC_HIDDEN;
+HRESULT SHAPE_GetFontScriptTags( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, int cMaxTags, OPENTYPE_TAG *pScriptTags, int *pcTags) DECLSPEC_HIDDEN;
+HRESULT SHAPE_GetFontLanguageTags( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript, int cMaxTags, OPENTYPE_TAG *pLangSysTags, int *pcTags) DECLSPEC_HIDDEN;
+HRESULT SHAPE_GetFontFeatureTags( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript, OPENTYPE_TAG tagLangSys, int cMaxTags, OPENTYPE_TAG *pFeatureTags, int *pcTags) DECLSPEC_HIDDEN;
void Indic_ReorderCharacters( HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache* psc, LPWSTR input, int cChars, IndicSyllable **syllables, int *syllable_count, lexical_function lexical_f, reorder_function reorder_f, BOOL modern) DECLSPEC_HIDDEN;
-void Indic_ParseSyllables( HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache* psc, LPCWSTR input, const int cChar, IndicSyllable **syllables, int *syllable_count, lexical_function lex, BOOL modern);
+void Indic_ParseSyllables( HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache* psc, LPCWSTR input, const int cChar, IndicSyllable **syllables, int *syllable_count, lexical_function lex, BOOL modern) DECLSPEC_HIDDEN;
void BREAK_line(const WCHAR *chars, int count, const SCRIPT_ANALYSIS *sa, SCRIPT_LOGATTR *la) DECLSPEC_HIDDEN;
+
+DWORD OpenType_CMAP_GetGlyphIndex(HDC hdc, ScriptCache *psc, DWORD utf32c, LPWORD pgi, DWORD flags) DECLSPEC_HIDDEN;
+void OpenType_GDEF_UpdateGlyphProps(HDC hdc, ScriptCache *psc, const WORD *pwGlyphs, const WORD cGlyphs, WORD* pwLogClust, const WORD cChars, SCRIPT_GLYPHPROP *pGlyphProp) DECLSPEC_HIDDEN;
+INT OpenType_apply_GSUB_lookup(LPCVOID table, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count) DECLSPEC_HIDDEN;
+HRESULT OpenType_GSUB_GetFontScriptTags(ScriptCache *psc, OPENTYPE_TAG searchingFor, int cMaxTags, OPENTYPE_TAG *pScriptTags, int *pcTags, LPCVOID* script_table) DECLSPEC_HIDDEN;
+HRESULT OpenType_GSUB_GetFontLanguageTags(ScriptCache *psc, OPENTYPE_TAG script_tag, OPENTYPE_TAG searchingFor, int cMaxTags, OPENTYPE_TAG *pLanguageTags, int *pcTags, LPCVOID* language_table) DECLSPEC_HIDDEN;
+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) DECLSPEC_HIDDEN;