From c8c27cf35b59119ee46ef299833b79b21898889b Mon Sep 17 00:00:00 2001 From: James Tabor Date: Thu, 26 Jan 2012 15:07:46 +0000 Subject: [PATCH] [Usp10] - Sync to Wine 1.3.37. svn path=/trunk/; revision=55201 --- reactos/dll/win32/usp10/CMakeLists.txt | 1 + reactos/dll/win32/usp10/opentype.c | 1117 ++++++++++++++++++ reactos/dll/win32/usp10/shape.c | 1337 +++++++--------------- reactos/dll/win32/usp10/usp10.c | 516 ++++++++- reactos/dll/win32/usp10/usp10.rbuild | 1 + reactos/dll/win32/usp10/usp10.spec | 6 +- reactos/dll/win32/usp10/usp10_internal.h | 93 +- 7 files changed, 2079 insertions(+), 992 deletions(-) create mode 100644 reactos/dll/win32/usp10/opentype.c diff --git a/reactos/dll/win32/usp10/CMakeLists.txt b/reactos/dll/win32/usp10/CMakeLists.txt index 6d2ac1d1b41..e0732956029 100644 --- a/reactos/dll/win32/usp10/CMakeLists.txt +++ b/reactos/dll/win32/usp10/CMakeLists.txt @@ -12,6 +12,7 @@ list(APPEND SOURCE linebreak.c usp10.c mirror.c + opentype.c shape.c shaping.c ${CMAKE_CURRENT_BINARY_DIR}/usp10_stubs.c diff --git a/reactos/dll/win32/usp10/opentype.c b/reactos/dll/win32/usp10/opentype.c new file mode 100644 index 00000000000..c30d5131ede --- /dev/null +++ b/reactos/dll/win32/usp10/opentype.c @@ -0,0 +1,1117 @@ +/* + * 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 +#include + +#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; +} diff --git a/reactos/dll/win32/usp10/shape.c b/reactos/dll/win32/usp10/shape.c index 8d3a355fffa..5f71d6cff19 100644 --- a/reactos/dll/win32/usp10/shape.c +++ b/reactos/dll/win32/usp10/shape.c @@ -19,6 +19,7 @@ * */ #include +#include #include "windef.h" #include "winbase.h" @@ -53,6 +54,8 @@ static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *ps 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*); @@ -71,6 +74,7 @@ static void ShapeCharGlyphProp_Tamil( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS 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[]; @@ -96,221 +100,6 @@ enum joined_forms { 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; @@ -452,6 +241,12 @@ static OPENTYPE_FEATURE_RECORD devanagari_features[] = { 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", @@ -539,11 +334,52 @@ static const char* required_telugu_features[] = NULL }; +static OPENTYPE_FEATURE_RECORD khmer_features[] = +{ + { 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 const char* required_khmer_features[] = +{ + "pref", + "blwf", + "abvf", + "pstf", + "pres", + "blws", + "abvs", + "psts", + "clig", + NULL +}; + +static OPENTYPE_FEATURE_RECORD no_features[] = +{ }; + +static OPENTYPE_FEATURE_RECORD ethiopic_features[] = +{ + { 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 OPENTYPE_FEATURE_RECORD mongolian_features[] = +{ + { 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}, +}; + typedef struct ScriptShapeDataTag { TEXTRANGE_PROPERTIES defaultTextRange; const char** requiredFeatures; - CHAR otTag[5]; - CHAR newOtTag[5]; + OPENTYPE_TAG newOtTag; ContextualShapingProc contextProc; ShapeCharGlyphPropProc charGlyphPropProc; } ScriptShapeData; @@ -551,501 +387,101 @@ typedef struct ScriptShapeDataTag { /* in order of scripts */ static const ScriptShapeData ShapingData[] = { - {{ 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}, + {{ 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}, }; -static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph) -{ - const GSUB_CoverageFormat1* cf1; +extern scriptData scriptInformation[]; - 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) -{ - 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; -} - -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; } @@ -1061,23 +497,23 @@ static INT GSUB_apply_feature_all_lookups(const GSUB_Header * header, const GSUB 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 @@ -1085,93 +521,62 @@ static const char* get_opentype_script(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCach 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"; + 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'); } } -static LPCVOID load_GSUB_feature(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, const char* feat) +static LoadedFeature* 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; - } - - feature = NULL; + 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) @@ -1184,11 +589,11 @@ static INT apply_GSUB_feature_to_glyph(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCach 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; @@ -1212,117 +617,6 @@ INT SHAPE_does_GSUB_feature_apply_to_chars(HDC hdc, SCRIPT_ANALYSIS *psa, Script 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; @@ -1445,20 +739,15 @@ static int apply_GSUB_feature(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache* psc, W { 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; @@ -1466,13 +755,13 @@ static int apply_GSUB_feature(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache* psc, W 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); @@ -1489,7 +778,13 @@ static int apply_GSUB_feature(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache* psc, W 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) @@ -2157,7 +1452,7 @@ static inline void shift_syllable_glyph_indexs(IndicSyllable *glyph_index, INT i 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; @@ -2294,13 +1589,13 @@ static void ShapeIndicSyllables(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, { 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); @@ -2625,7 +1920,6 @@ static int gurmukhi_lex(WCHAR c) 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}, @@ -2958,6 +2252,107 @@ static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS 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; @@ -2988,7 +2383,7 @@ static void ShapeCharGlyphProp_Default( HDC hdc, ScriptCache* psc, SCRIPT_ANALYS 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); } @@ -3099,7 +2494,7 @@ static void ShapeCharGlyphProp_Arabic( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSI 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); } @@ -3135,7 +2530,7 @@ static void ShapeCharGlyphProp_Thai( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS } } - 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++) { @@ -3209,7 +2604,7 @@ static void ShapeCharGlyphProp_None( HDC hdc, ScriptCache* psc, SCRIPT_ANALYSIS* 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); } @@ -3242,7 +2637,7 @@ static void ShapeCharGlyphProp_Tibet( HDC hdc, ScriptCache* psc, SCRIPT_ANALYSIS 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 */ @@ -3256,11 +2651,11 @@ static void ShapeCharGlyphProp_Tibet( HDC hdc, ScriptCache* psc, SCRIPT_ANALYSIS } } -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]; @@ -3275,9 +2670,12 @@ static void ShapeCharGlyphProp_BaseIndic( HDC hdc, ScriptCache *psc, SCRIPT_ANAL } } - /* 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; @@ -3303,7 +2701,11 @@ static void ShapeCharGlyphProp_BaseIndic( HDC hdc, ScriptCache *psc, SCRIPT_ANAL 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; @@ -3341,52 +2743,57 @@ static void ShapeCharGlyphProp_BaseIndic( HDC hdc, ScriptCache *psc, SCRIPT_ANAL 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) @@ -3442,7 +2849,7 @@ rpRangeProperties = &ShapingData[psa->eScript].defaultTextRange; HRESULT SHAPE_CheckFontForRequiredFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa) { - const GSUB_Feature *feature; + LoadedFeature *feature; int i; if (!ShapingData[psa->eScript].requiredFeatures) @@ -3463,3 +2870,75 @@ HRESULT SHAPE_CheckFontForRequiredFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANA 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; +} diff --git a/reactos/dll/win32/usp10/usp10.c b/reactos/dll/win32/usp10/usp10.c index 422c229fa75..a017baf392c 100644 --- a/reactos/dll/win32/usp10/usp10.c +++ b/reactos/dll/win32/usp10/usp10.c @@ -44,8 +44,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(uniscribe); typedef struct _scriptRange { WORD script; - WORD rangeFirst; - WORD rangeLast; + DWORD rangeFirst; + DWORD rangeLast; WORD numericScript; WORD punctScript; } scriptRange; @@ -57,7 +57,8 @@ static const scriptRange scriptRanges[] = { /* 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 */ @@ -81,6 +82,8 @@ static const scriptRange scriptRanges[] = { { 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 */ @@ -107,8 +110,35 @@ static const scriptRange scriptRanges[] = { { 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 */ @@ -145,6 +175,8 @@ static const scriptRange scriptRanges[] = { /* 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 */ @@ -154,8 +186,62 @@ static const scriptRange scriptRanges[] = { { 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 */ @@ -165,6 +251,22 @@ static const scriptRange scriptRanges[] = { { 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 */ @@ -173,22 +275,31 @@ static const scriptRange scriptRanges[] = { { 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, @@ -196,7 +307,7 @@ static const scriptData scriptInformation[] = { {{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, @@ -204,7 +315,7 @@ static const scriptData scriptInformation[] = { {{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, @@ -212,7 +323,7 @@ static const scriptData scriptInformation[] = { {{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'), @@ -240,11 +351,11 @@ static const scriptData scriptInformation[] = { {{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'), @@ -372,11 +483,151 @@ static const scriptData scriptInformation[] = { {{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[] = @@ -403,7 +654,25 @@ 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 { @@ -469,7 +738,7 @@ static inline BYTE get_cache_pitch_family(SCRIPT_CACHE *psc) 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]; @@ -535,24 +804,50 @@ static WCHAR mirror_char( WCHAR ch ) 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; @@ -560,6 +855,12 @@ static WORD get_char_script( WCHAR ch) 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 { @@ -623,7 +924,20 @@ HRESULT WINAPI ScriptFreeCache(SCRIPT_CACHE *psc) } 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; } @@ -874,6 +1188,7 @@ HRESULT WINAPI ScriptItemizeOpenType(const WCHAR *pwcInChars, int cInChars, int 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); @@ -887,7 +1202,16 @@ HRESULT WINAPI ScriptItemizeOpenType(const WCHAR *pwcInChars, int cInChars, int 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) @@ -1480,12 +1804,16 @@ HRESULT WINAPI ScriptStringAnalyse(HDC hdc, const void *pString, int cString, 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); + } } } @@ -1578,6 +1906,8 @@ static HRESULT SS_ItemOut( SCRIPT_STRING_ANALYSIS ssa, 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); @@ -1588,6 +1918,7 @@ static HRESULT SS_ItemOut( SCRIPT_STRING_ANALYSIS ssa, (cEnd >= 0 && analysis->pItem[iItem].iCharPos >= cEnd)) return S_OK; + CopyRect(&crc,prc); if (fSelected) { BkMode = GetBkMode(analysis->hdc); @@ -1618,6 +1949,7 @@ static HRESULT SS_ItemOut( SCRIPT_STRING_ANALYSIS ssa, ScriptStringCPtoX(ssa, cEnd, FALSE, &off_x); else ScriptStringCPtoX(ssa, analysis->pItem[iItem+1].iCharPos-1, TRUE, &off_x); + crc.left = iX + off_x; } else { @@ -1625,6 +1957,7 @@ static HRESULT SS_ItemOut( SCRIPT_STRING_ANALYSIS ssa, 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) @@ -1639,6 +1972,24 @@ static HRESULT SS_ItemOut( SCRIPT_STRING_ANALYSIS ssa, 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; @@ -1660,7 +2011,7 @@ static HRESULT SS_ItemOut( SCRIPT_STRING_ANALYSIS ssa, 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]); @@ -2299,17 +2650,20 @@ HRESULT WINAPI ScriptBreak(const WCHAR *chars, int count, const SCRIPT_ANALYSIS 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; @@ -2354,8 +2708,9 @@ HRESULT WINAPI ScriptShapeOpenType( HDC hdc, SCRIPT_CACHE *psc, 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, @@ -2382,7 +2737,7 @@ HRESULT WINAPI ScriptShapeOpenType( HDC hdc, SCRIPT_CACHE *psc, ((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 */ @@ -2411,35 +2766,59 @@ HRESULT WINAPI ScriptShapeOpenType( HDC hdc, SCRIPT_CACHE *psc, 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) { - heap_free(rChars); - return E_PENDING; + if (psa->fRTL) + chInput = mirror_char(pwcChars[idx]); + else + chInput = pwcChars[idx]; + /* special case for tabs */ + if (chInput == 0x0009) + chInput = 0x0020; + rChars[i] = chInput; } - if (GetGlyphIndicesW(hdc, &chInput, 1, &glyph, 0) == GDI_ERROR) + else { - heap_free(rChars); - return S_FALSE; + rChars[i] = pwcChars[idx]; + rChars[i+1] = pwcChars[(rtl)?idx-1:idx+1]; + cluster = 1; } - pwOutGlyphs[i] = set_cache_glyph(psc, chInput, glyph); + if (!(pwOutGlyphs[g] = get_cache_glyph(psc, chInput))) + { + 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); + } + 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); @@ -3176,6 +3555,33 @@ HRESULT WINAPI ScriptJustify(const SCRIPT_VISATTR *sva, const int *advance, 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() { diff --git a/reactos/dll/win32/usp10/usp10.rbuild b/reactos/dll/win32/usp10/usp10.rbuild index 9c477d1ecd8..714ed009d96 100644 --- a/reactos/dll/win32/usp10/usp10.rbuild +++ b/reactos/dll/win32/usp10/usp10.rbuild @@ -13,6 +13,7 @@ linebreak.c indicsyllable.c mirror.c + opentype.c shape.c shaping.c wine diff --git a/reactos/dll/win32/usp10/usp10.spec b/reactos/dll/win32/usp10/usp10.spec index 99b3e2bda9f..36a712c683b 100644 --- a/reactos/dll/win32/usp10/usp10.spec +++ b/reactos/dll/win32/usp10/usp10.spec @@ -7,10 +7,10 @@ @ 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) diff --git a/reactos/dll/win32/usp10/usp10_internal.h b/reactos/dll/win32/usp10/usp10_internal.h index 6f5d3d14d86..02beaf628dc 100644 --- a/reactos/dll/win32/usp10/usp10_internal.h +++ b/reactos/dll/win32/usp10/usp10_internal.h @@ -75,18 +75,81 @@ #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; @@ -95,13 +158,23 @@ typedef struct { 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; @@ -142,8 +215,18 @@ void SHAPE_ApplyDefaultOpentypeFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYS 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;