diff --git a/reactos/dll/win32/usp10/indic.c b/reactos/dll/win32/usp10/indic.c index 5871fd5cc5c..4a1bf9538ef 100644 --- a/reactos/dll/win32/usp10/indic.c +++ b/reactos/dll/win32/usp10/indic.c @@ -208,7 +208,7 @@ static INT Indic_process_next_syllable( LPCWSTR input, INT cChar, INT start, INT return parse_consonant_syllable(input, cChar, start, main, next, lex); } -static BOOL Consonent_is_post_base_form(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache* psc, LPCWSTR pwChar, IndicSyllable *s, lexical_function lexical, BOOL modern) +static BOOL Consonant_is_post_base_form(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache* psc, LPCWSTR pwChar, IndicSyllable *s, lexical_function lexical, BOOL modern) { if (is_consonant(lexical(pwChar[s->base])) && s->base > s->start && lexical(pwChar[s->base-1]) == lex_Halant) { @@ -225,7 +225,7 @@ static BOOL Consonent_is_post_base_form(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCac return FALSE; } -static BOOL Consonent_is_below_base_form(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache* psc, LPCWSTR pwChar, IndicSyllable *s, lexical_function lexical, BOOL modern) +static BOOL Consonant_is_below_base_form(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache* psc, LPCWSTR pwChar, IndicSyllable *s, lexical_function lexical, BOOL modern) { if (is_consonant(lexical(pwChar[s->base])) && s->base > s->start && lexical(pwChar[s->base-1]) == lex_Halant) { @@ -242,7 +242,7 @@ static BOOL Consonent_is_below_base_form(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCa return FALSE; } -static BOOL Consonent_is_pre_base_form(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache* psc, LPCWSTR pwChar, IndicSyllable *s, lexical_function lexical, BOOL modern) +static BOOL Consonant_is_pre_base_form(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache* psc, LPCWSTR pwChar, IndicSyllable *s, lexical_function lexical, BOOL modern) { if (is_consonant(lexical(pwChar[s->base])) && s->base > s->start && lexical(pwChar[s->base-1]) == lex_Halant) { @@ -259,7 +259,7 @@ static BOOL Consonent_is_pre_base_form(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCach return FALSE; } -static BOOL Consonent_is_ralf(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache* psc, LPCWSTR pwChar, IndicSyllable *s, lexical_function lexical) +static BOOL Consonant_is_ralf(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache* psc, LPCWSTR pwChar, IndicSyllable *s, lexical_function lexical) { if ((lexical(pwChar[s->start])==lex_Ra) && s->end > s->start && lexical(pwChar[s->start+1]) == lex_Halant) return (SHAPE_does_GSUB_feature_apply_to_chars(hdc, psa, psc, &pwChar[s->start], 1, 2, "rphf") > 0); @@ -273,7 +273,7 @@ static int FindBaseConsonant(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache* psc, LP BOOL pref = FALSE; /* remove ralf from consideration */ - if (Consonent_is_ralf(hdc, psa, psc, input, s, lex)) + if (Consonant_is_ralf(hdc, psa, psc, input, s, lex)) { s->ralf = s->start; s->start+=2; @@ -290,7 +290,7 @@ static int FindBaseConsonant(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache* psc, LP } } - while ((blwf = Consonent_is_below_base_form(hdc, psa, psc, input, s, lex, modern)) || Consonent_is_post_base_form(hdc, psa, psc, input, s, lex, modern) || (pref = Consonent_is_pre_base_form(hdc, psa, psc, input, s, lex, modern))) + while ((blwf = Consonant_is_below_base_form(hdc, psa, psc, input, s, lex, modern)) || Consonant_is_post_base_form(hdc, psa, psc, input, s, lex, modern) || (pref = Consonant_is_pre_base_form(hdc, psa, psc, input, s, lex, modern))) { if (blwf && s->blwf == -1) s->blwf = s->base - 1; diff --git a/reactos/dll/win32/usp10/opentype.c b/reactos/dll/win32/usp10/opentype.c index 2d8d1fcbbfc..b5b2a7dce02 100644 --- a/reactos/dll/win32/usp10/opentype.c +++ b/reactos/dll/win32/usp10/opentype.c @@ -43,6 +43,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(uniscribe); #define GET_BE_DWORD(x) RtlUlongByteSwap(x) #endif +#define round(x) (((x) < 0) ? (int)((x) - 0.5) : (int)((x) + 0.5)) + /* These are all structures needed for the cmap format 12 table */ #define CMAP_TAG MS_MAKE_TAG('c', 'm', 'a', 'p') @@ -117,76 +119,76 @@ typedef struct { typedef struct { CHAR ScriptTag[4]; WORD Script; -} GSUB_ScriptRecord; +} OT_ScriptRecord; typedef struct { WORD ScriptCount; - GSUB_ScriptRecord ScriptRecord[1]; -} GSUB_ScriptList; + OT_ScriptRecord ScriptRecord[1]; +} OT_ScriptList; typedef struct { CHAR LangSysTag[4]; WORD LangSys; -} GSUB_LangSysRecord; +} OT_LangSysRecord; typedef struct { WORD DefaultLangSys; WORD LangSysCount; - GSUB_LangSysRecord LangSysRecord[1]; -} GSUB_Script; + OT_LangSysRecord LangSysRecord[1]; +} OT_Script; typedef struct { WORD LookupOrder; /* Reserved */ WORD ReqFeatureIndex; WORD FeatureCount; WORD FeatureIndex[1]; -} GSUB_LangSys; +} OT_LangSys; typedef struct { CHAR FeatureTag[4]; WORD Feature; -} GSUB_FeatureRecord; +} OT_FeatureRecord; typedef struct { WORD FeatureCount; - GSUB_FeatureRecord FeatureRecord[1]; -} GSUB_FeatureList; + OT_FeatureRecord FeatureRecord[1]; +} OT_FeatureList; typedef struct { WORD FeatureParams; /* Reserved */ WORD LookupCount; WORD LookupListIndex[1]; -} GSUB_Feature; +} OT_Feature; typedef struct { WORD LookupCount; WORD Lookup[1]; -} GSUB_LookupList; +} OT_LookupList; typedef struct { WORD LookupType; WORD LookupFlag; WORD SubTableCount; WORD SubTable[1]; -} GSUB_LookupTable; +} OT_LookupTable; typedef struct { WORD CoverageFormat; WORD GlyphCount; WORD GlyphArray[1]; -} GSUB_CoverageFormat1; +} OT_CoverageFormat1; typedef struct { WORD Start; WORD End; WORD StartCoverageIndex; -} GSUB_RangeRecord; +} OT_RangeRecord; typedef struct { WORD CoverageFormat; WORD RangeCount; - GSUB_RangeRecord RangeRecord[1]; -} GSUB_CoverageFormat2; + OT_RangeRecord RangeRecord[1]; +} OT_CoverageFormat2; typedef struct { WORD SubstFormat; /* = 1 */ @@ -277,6 +279,161 @@ typedef struct{ WORD Alternate[1]; } GSUB_AlternateSet; +/* These are all structures needed for the GPOS table */ + +typedef struct { + DWORD version; + WORD ScriptList; + WORD FeatureList; + WORD LookupList; +} GPOS_Header; + +typedef struct { + WORD StartSize; + WORD EndSize; + WORD DeltaFormat; + WORD DeltaValue[1]; +} OT_DeviceTable; + +typedef struct { + WORD AnchorFormat; + WORD XCoordinate; + WORD YCoordinate; +} GPOS_AnchorFormat1; + +typedef struct { + WORD AnchorFormat; + WORD XCoordinate; + WORD YCoordinate; + WORD AnchorPoint; +} GPOS_AnchorFormat2; + +typedef struct { + WORD AnchorFormat; + WORD XCoordinate; + WORD YCoordinate; + WORD XDeviceTable; + WORD YDeviceTable; +} GPOS_AnchorFormat3; + +typedef struct { + WORD XPlacement; + WORD YPlacement; + WORD XAdvance; + WORD YAdvance; + WORD XPlaDevice; + WORD YPlaDevice; + WORD XAdvDevice; + WORD YAdvDevice; +} GPOS_ValueRecord; + +typedef struct { + WORD PosFormat; + WORD Coverage; + WORD ValueFormat; + WORD Value[1]; +} GPOS_SinglePosFormat1; + +typedef struct { + WORD PosFormat; + WORD Coverage; + WORD ValueFormat; + WORD ValueCount; + WORD Value[1]; +} GPOS_SinglePosFormat2; + +typedef struct { + WORD PosFormat; + WORD Coverage; + WORD ValueFormat1; + WORD ValueFormat2; + WORD PairSetCount; + WORD PairSetOffset[1]; +} GPOS_PairPosFormat1; + +typedef struct { + WORD SecondGlyph; + WORD Value1[1]; + WORD Value2[1]; +} GPOS_PairValueRecord; + +typedef struct { + WORD PairValueCount; + GPOS_PairValueRecord PairValueRecord[1]; +} GPOS_PairSet; + +typedef struct { + WORD PosFormat; + WORD MarkCoverage; + WORD BaseCoverage; + WORD ClassCount; + WORD MarkArray; + WORD BaseArray; +} GPOS_MarkBasePosFormat1; + +typedef struct { + WORD BaseAnchor[1]; +} GPOS_BaseRecord; + +typedef struct { + WORD BaseCount; + GPOS_BaseRecord BaseRecord[1]; +} GPOS_BaseArray; + +typedef struct { + WORD Class; + WORD MarkAnchor; +} GPOS_MarkRecord; + +typedef struct { + WORD MarkCount; + GPOS_MarkRecord MarkRecord[1]; +} GPOS_MarkArray; + +typedef struct { + WORD PosFormat; + WORD Mark1Coverage; + WORD Mark2Coverage; + WORD ClassCount; + WORD Mark1Array; + WORD Mark2Array; +} GPOS_MarkMarkPosFormat1; + +typedef struct { + WORD Mark2Anchor[1]; +} GPOS_Mark2Record; + +typedef struct { + WORD Mark2Count; + GPOS_Mark2Record Mark2Record[1]; +} GPOS_Mark2Array; + +typedef struct { + WORD SequenceIndex; + WORD LookupListIndex; +} GPOS_PosLookupRecord; + +typedef struct { + WORD PosFormat; + WORD BacktrackGlyphCount; + WORD Coverage[1]; +} GPOS_ChainContextPosFormat3_1; + +typedef struct { + WORD InputGlyphCount; + WORD Coverage[1]; +} GPOS_ChainContextPosFormat3_2; + +typedef struct { + WORD LookaheadGlyphCount; + WORD Coverage[1]; +} GPOS_ChainContextPosFormat3_3; + +typedef struct { + WORD PosCount; + GPOS_PosLookupRecord PosLookupRecord[1]; +} GPOS_ChainContextPosFormat3_4; + /********** * CMAP **********/ @@ -485,11 +642,11 @@ void OpenType_GDEF_UpdateGlyphProps(HDC hdc, ScriptCache *psc, const WORD *pwGly /********** * 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_apply_lookup(const OT_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; + const OT_CoverageFormat1* cf1; cf1 = table; @@ -505,10 +662,10 @@ static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph) } else if (GET_BE_WORD(cf1->CoverageFormat) == 2) { - const GSUB_CoverageFormat2* cf2; + const OT_CoverageFormat2* cf2; int i; int count; - cf2 = (const GSUB_CoverageFormat2*)cf1; + cf2 = (const OT_CoverageFormat2*)cf1; count = GET_BE_WORD(cf2->RangeCount); TRACE("Coverage Format 2, %i ranges\n",count); @@ -531,7 +688,7 @@ static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph) return -1; } -static INT GSUB_apply_SingleSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count) +static INT GSUB_apply_SingleSubst(const OT_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count) { int j; TRACE("Single Substitution Subtable\n"); @@ -580,7 +737,7 @@ static INT GSUB_apply_SingleSubst(const GSUB_LookupTable *look, WORD *glyphs, IN return GSUB_E_NOGLYPH; } -static INT GSUB_apply_MultipleSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count) +static INT GSUB_apply_MultipleSubst(const OT_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count) { int j; TRACE("Multiple Substitution Subtable\n"); @@ -628,7 +785,7 @@ static INT GSUB_apply_MultipleSubst(const GSUB_LookupTable *look, WORD *glyphs, return GSUB_E_NOGLYPH; } -static INT GSUB_apply_AlternateSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count) +static INT GSUB_apply_AlternateSubst(const OT_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count) { int j; TRACE("Alternate Substitution Subtable\n"); @@ -662,7 +819,7 @@ static INT GSUB_apply_AlternateSubst(const GSUB_LookupTable *look, WORD *glyphs, return GSUB_E_NOGLYPH; } -static INT GSUB_apply_LigatureSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count) +static INT GSUB_apply_LigatureSubst(const OT_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count) { int j; @@ -727,7 +884,7 @@ static INT GSUB_apply_LigatureSubst(const GSUB_LookupTable *look, WORD *glyphs, 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) +static INT GSUB_apply_ChainContextSubst(const OT_LookupList* lookup, const OT_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count) { int j; BOOL done = FALSE; @@ -776,7 +933,8 @@ static INT GSUB_apply_ChainContextSubst(const GSUB_LookupList* lookup, const GSU 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))); + ccsf3_2 = (const GSUB_ChainContextSubstFormat3_2 *)((BYTE *)ccsf1 + + FIELD_OFFSET(GSUB_ChainContextSubstFormat3_1, Coverage[GET_BE_WORD(ccsf3_1->BacktrackGlyphCount)])); indexGlyphs = GET_BE_WORD(ccsf3_2->InputGlyphCount); for (k = 0; k < indexGlyphs; k++) @@ -789,7 +947,8 @@ static INT GSUB_apply_ChainContextSubst(const GSUB_LookupList* lookup, const GSU 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))); + ccsf3_3 = (const GSUB_ChainContextSubstFormat3_3 *)((BYTE *)ccsf3_2 + + FIELD_OFFSET(GSUB_ChainContextSubstFormat3_2, Coverage[GET_BE_WORD(ccsf3_2->InputGlyphCount)])); for (k = 0; k < GET_BE_WORD(ccsf3_3->LookaheadGlyphCount); k++) { @@ -801,7 +960,8 @@ static INT GSUB_apply_ChainContextSubst(const GSUB_LookupList* lookup, const GSU 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))); + ccsf3_4 = (const GSUB_ChainContextSubstFormat3_4 *)((BYTE *)ccsf3_3 + + FIELD_OFFSET(GSUB_ChainContextSubstFormat3_3, Coverage[GET_BE_WORD(ccsf3_3->LookaheadGlyphCount)])); if (GET_BE_WORD(ccsf3_4->SubstCount)) { @@ -826,13 +986,13 @@ static INT GSUB_apply_ChainContextSubst(const GSUB_LookupList* lookup, const GSU 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) +static INT GSUB_apply_lookup(const OT_LookupList* lookup, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count) { int offset; - const GSUB_LookupTable *look; + const OT_LookupTable *look; offset = GET_BE_WORD(lookup->Lookup[lookup_index]); - look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset); + look = (const OT_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)) { @@ -855,20 +1015,581 @@ static INT GSUB_apply_lookup(const GSUB_LookupList* lookup, INT lookup_index, WO 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)); + const OT_LookupList *lookup = (const OT_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList)); return GSUB_apply_lookup(lookup, lookup_index, glyphs, glyph_index, write_dir, glyph_count); } +/********** + * GPOS + **********/ +static INT GPOS_apply_lookup(LPOUTLINETEXTMETRICW lpotm, LPLOGFONTW lplogfont, INT* piAdvance, const OT_LookupList* lookup, INT lookup_index, const WORD *glyphs, INT glyph_index, INT write_dir, INT glyph_count, GOFFSET *pGoffset); + +static INT GPOS_get_device_table_value(const OT_DeviceTable *DeviceTable, WORD ppem) +{ + static const WORD mask[3] = {3,0xf,0xff}; + if (DeviceTable && ppem >= GET_BE_WORD(DeviceTable->StartSize) && ppem <= GET_BE_WORD(DeviceTable->EndSize)) + { + int format = GET_BE_WORD(DeviceTable->DeltaFormat); + int index = ppem - GET_BE_WORD(DeviceTable->StartSize); + int value; + TRACE("device table, format %i, index %i\n",format, index); + index = index << format; + value = (DeviceTable->DeltaValue[index/sizeof(WORD)] << (index%sizeof(WORD)))&mask[format-1]; + TRACE("offset %i, value %i\n",index, value); + if (value > mask[format-1]/2) + value = -1 * ((mask[format-1]+1) - value); + return value; + } + return 0; +} + +static VOID GPOS_get_anchor_values(LPCVOID table, LPPOINT pt, WORD ppem) +{ + const GPOS_AnchorFormat1* anchor1 = (const GPOS_AnchorFormat1*)table; + + switch (GET_BE_WORD(anchor1->AnchorFormat)) + { + case 1: + { + TRACE("Anchor Format 1\n"); + pt->x = (short)GET_BE_WORD(anchor1->XCoordinate); + pt->y = (short)GET_BE_WORD(anchor1->YCoordinate); + break; + } + case 2: + { + const GPOS_AnchorFormat2* anchor2 = (const GPOS_AnchorFormat2*)table; + TRACE("Anchor Format 2\n"); + pt->x = (short)GET_BE_WORD(anchor2->XCoordinate); + pt->y = (short)GET_BE_WORD(anchor2->YCoordinate); + break; + } + case 3: + { + int offset; + const GPOS_AnchorFormat3* anchor3 = (const GPOS_AnchorFormat3*)table; + TRACE("Anchor Format 3\n"); + pt->x = (short)GET_BE_WORD(anchor3->XCoordinate); + pt->y = (short)GET_BE_WORD(anchor3->YCoordinate); + offset = GET_BE_WORD(anchor3->XDeviceTable); + TRACE("ppem %i\n",ppem); + if (offset) + { + const OT_DeviceTable* DeviceTableX = NULL; + DeviceTableX = (const OT_DeviceTable*)((const BYTE*)anchor3 + offset); + pt->x += GPOS_get_device_table_value(DeviceTableX, ppem); + } + offset = GET_BE_WORD(anchor3->YDeviceTable); + if (offset) + { + const OT_DeviceTable* DeviceTableY = NULL; + DeviceTableY = (const OT_DeviceTable*)((const BYTE*)anchor3 + offset); + pt->y += GPOS_get_device_table_value(DeviceTableY, ppem); + } + break; + } + default: + ERR("Unknown Anchor Format %i\n",GET_BE_WORD(anchor1->AnchorFormat)); + pt->x = 0; + pt->y = 0; + } +} + +static void GPOS_convert_design_units_to_device(LPOUTLINETEXTMETRICW lpotm, LPLOGFONTW lplogfont, int desX, int desY, double *devX, double *devY) +{ + int emHeight = lpotm->otmTextMetrics.tmAscent + lpotm->otmTextMetrics.tmDescent - lpotm->otmTextMetrics.tmInternalLeading; + + TRACE("emHeight %i lfWidth %i\n",emHeight, lplogfont->lfWidth); + *devX = (desX * emHeight) / (double)lpotm->otmEMSquare; + *devY = (desY * emHeight) / (double)lpotm->otmEMSquare; + if (lplogfont->lfWidth) + FIXME("Font with lfWidth set no handled properly\n"); +} + +static INT GPOS_get_value_record(WORD ValueFormat, const WORD data[], GPOS_ValueRecord *record) +{ + INT offset = 0; + if (ValueFormat & 0x0001) record->XPlacement = GET_BE_WORD(data[offset++]); + if (ValueFormat & 0x0002) record->YPlacement = GET_BE_WORD(data[offset++]); + if (ValueFormat & 0x0004) record->XAdvance = GET_BE_WORD(data[offset++]); + if (ValueFormat & 0x0008) record->YAdvance = GET_BE_WORD(data[offset++]); + if (ValueFormat & 0x0010) record->XPlaDevice = GET_BE_WORD(data[offset++]); + if (ValueFormat & 0x0020) record->YPlaDevice = GET_BE_WORD(data[offset++]); + if (ValueFormat & 0x0040) record->XAdvDevice = GET_BE_WORD(data[offset++]); + if (ValueFormat & 0x0080) record->YAdvDevice = GET_BE_WORD(data[offset++]); + return offset; +} + +static VOID GPOS_get_value_record_offsets(const BYTE* head, GPOS_ValueRecord *ValueRecord, WORD ValueFormat, INT ppem, LPPOINT ptPlacement, LPPOINT ptAdvance) +{ + if (ValueFormat & 0x0001) ptPlacement->x += (short)ValueRecord->XPlacement; + if (ValueFormat & 0x0002) ptPlacement->y += (short)ValueRecord->YPlacement; + if (ValueFormat & 0x0004) ptAdvance->x += (short)ValueRecord->XAdvance; + if (ValueFormat & 0x0008) ptAdvance->y += (short)ValueRecord->YAdvance; + if (ValueFormat & 0x0010) ptPlacement->x += GPOS_get_device_table_value((const OT_DeviceTable*)(head + ValueRecord->XPlaDevice), ppem); + if (ValueFormat & 0x0020) ptPlacement->y += GPOS_get_device_table_value((const OT_DeviceTable*)(head + ValueRecord->YPlaDevice), ppem); + if (ValueFormat & 0x0040) ptAdvance->x += GPOS_get_device_table_value((const OT_DeviceTable*)(head + ValueRecord->XAdvDevice), ppem); + if (ValueFormat & 0x0080) ptAdvance->y += GPOS_get_device_table_value((const OT_DeviceTable*)(head + ValueRecord->YAdvDevice), ppem); + if (ValueFormat & 0xFF00) FIXME("Unhandled Value Format %x\n",ValueFormat&0xFF00); +} + +static VOID GPOS_apply_SingleAdjustment(const OT_LookupTable *look, const WORD *glyphs, INT glyph_index, INT write_dir, INT glyph_count, INT ppem, LPPOINT ptAdjust, LPPOINT ptAdvance) +{ + int j; + + TRACE("Single Adjustment Positioning Subtable\n"); + + for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++) + { + const GPOS_SinglePosFormat1 *spf1; + WORD offset = GET_BE_WORD(look->SubTable[j]); + spf1 = (const GPOS_SinglePosFormat1*)((const BYTE*)look+offset); + if (GET_BE_WORD(spf1->PosFormat) == 1) + { + offset = GET_BE_WORD(spf1->Coverage); + if (GSUB_is_glyph_covered((const BYTE*)spf1+offset, glyphs[glyph_index]) != -1) + { + GPOS_ValueRecord ValueRecord = {0,0,0,0,0,0,0,0}; + WORD ValueFormat = GET_BE_WORD(spf1->ValueFormat); + GPOS_get_value_record(ValueFormat, spf1->Value, &ValueRecord); + GPOS_get_value_record_offsets((const BYTE*)spf1, &ValueRecord, ValueFormat, ppem, ptAdjust, ptAdvance); + TRACE("Glyph Adjusted by %i,%i\n",ValueRecord.XPlacement,ValueRecord.YPlacement); + } + } + else if (GET_BE_WORD(spf1->PosFormat) == 2) + { + int index; + const GPOS_SinglePosFormat2 *spf2; + spf2 = (const GPOS_SinglePosFormat2*)spf1; + offset = GET_BE_WORD(spf2->Coverage); + index = GSUB_is_glyph_covered((const BYTE*)spf2+offset, glyphs[glyph_index]); + if (index != -1) + { + int size; + GPOS_ValueRecord ValueRecord = {0,0,0,0,0,0,0,0}; + WORD ValueFormat = GET_BE_WORD(spf2->ValueFormat); + size = GPOS_get_value_record(ValueFormat, spf2->Value, &ValueRecord); + if (index > 0) + { + offset = size * index; + GPOS_get_value_record(ValueFormat, &spf2->Value[offset], &ValueRecord); + } + GPOS_get_value_record_offsets((const BYTE*)spf2, &ValueRecord, ValueFormat, ppem, ptAdjust, ptAdvance); + TRACE("Glyph Adjusted by %i,%i\n",ValueRecord.XPlacement,ValueRecord.YPlacement); + } + } + else + FIXME("Single Adjustment Positioning: Format %i Unhandled\n",GET_BE_WORD(spf1->PosFormat)); + } +} + +static INT GPOS_apply_PairAdjustment(const OT_LookupTable *look, const WORD *glyphs, INT glyph_index, INT write_dir, INT glyph_count, INT ppem, LPPOINT ptAdjust, LPPOINT ptAdvance) +{ + int j; + + TRACE("Pair Adjustment Positioning Subtable\n"); + + for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++) + { + const GPOS_PairPosFormat1 *ppf1; + WORD offset = GET_BE_WORD(look->SubTable[j]); + ppf1 = (const GPOS_PairPosFormat1*)((const BYTE*)look+offset); + if (GET_BE_WORD(ppf1->PosFormat) == 1) + { + int index; + offset = GET_BE_WORD(ppf1->Coverage); + index = GSUB_is_glyph_covered((const BYTE*)ppf1+offset, glyphs[glyph_index]); + if (index != -1 && index < GET_BE_WORD(ppf1->PairSetCount)) + { + int k; + int pair_count; + const GPOS_PairSet *ps; + offset = GET_BE_WORD(ppf1->PairSetOffset[index]); + ps = (const GPOS_PairSet*)((const BYTE*)ppf1+offset); + pair_count = GET_BE_WORD(ps->PairValueCount); + for (k = 0; k < pair_count; k++) + { + WORD second_glyph = GET_BE_WORD(ps->PairValueRecord[k].SecondGlyph); + if (glyphs[glyph_index+write_dir] == second_glyph) + { + int next = 1; + GPOS_ValueRecord ValueRecord1 = {0,0,0,0,0,0,0,0}; + GPOS_ValueRecord ValueRecord2 = {0,0,0,0,0,0,0,0}; + WORD ValueFormat1 = GET_BE_WORD(ppf1->ValueFormat1); + WORD ValueFormat2 = GET_BE_WORD(ppf1->ValueFormat2); + + TRACE("Format 1: Found Pair %x,%x\n",glyphs[glyph_index],glyphs[glyph_index+write_dir]); + + offset = GPOS_get_value_record(ValueFormat1, ps->PairValueRecord[k].Value1, &ValueRecord1); + GPOS_get_value_record(ValueFormat2, (WORD*)((const BYTE*)(ps->PairValueRecord[k].Value2)+offset), &ValueRecord2); + if (ValueFormat1) + { + GPOS_get_value_record_offsets((const BYTE*)ppf1, &ValueRecord1, ValueFormat1, ppem, &ptAdjust[0], &ptAdvance[0]); + TRACE("Glyph 1 resulting cumulative offset is %i,%i design units\n",ptAdjust[0].x,ptAdjust[0].y); + TRACE("Glyph 1 resulting cumulative advance is %i,%i design units\n",ptAdvance[0].x,ptAdvance[0].y); + } + if (ValueFormat2) + { + GPOS_get_value_record_offsets((const BYTE*)ppf1, &ValueRecord2, ValueFormat2, ppem, &ptAdjust[1], &ptAdvance[1]); + TRACE("Glyph 2 resulting cumulative offset is %i,%i design units\n",ptAdjust[1].x,ptAdjust[1].y); + TRACE("Glyph 2 resulting cumulative advance is %i,%i design units\n",ptAdvance[1].x,ptAdvance[1].y); + next++; + } + if (next) + return glyph_index + next; + } + } + } + } + else + FIXME("Pair Adjustment Positioning: Format %i Unhandled\n",GET_BE_WORD(ppf1->PosFormat)); + } + return glyph_index+1; +} + +static VOID GPOS_apply_MarkToBase(const OT_LookupTable *look, const WORD *glyphs, INT glyph_index, INT write_dir, INT glyph_count, INT ppem, LPPOINT pt) +{ + int j; + + TRACE("MarkToBase Attachment Positioning Subtable\n"); + + for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++) + { + int offset; + const GPOS_MarkBasePosFormat1 *mbpf1; + offset = GET_BE_WORD(look->SubTable[j]); + mbpf1 = (const GPOS_MarkBasePosFormat1*)((const BYTE*)look+offset); + if (GET_BE_WORD(mbpf1->PosFormat) == 1) + { + int offset = GET_BE_WORD(mbpf1->MarkCoverage); + int mark_index; + mark_index = GSUB_is_glyph_covered((const BYTE*)mbpf1+offset, glyphs[glyph_index]); + if (mark_index != -1) + { + int base_index; + offset = GET_BE_WORD(mbpf1->BaseCoverage); + base_index = GSUB_is_glyph_covered((const BYTE*)mbpf1+offset, glyphs[glyph_index - write_dir]); + if (base_index != -1) + { + const GPOS_MarkArray *ma; + const GPOS_MarkRecord *mr; + const GPOS_BaseArray *ba; + const GPOS_BaseRecord *br; + int mark_class; + int class_count = GET_BE_WORD(mbpf1->ClassCount); + int baserecord_size; + POINT base_pt; + POINT mark_pt; + TRACE("Mark %x(%i) and base %x(%i)\n",glyphs[glyph_index], mark_index, glyphs[glyph_index - write_dir], base_index); + offset = GET_BE_WORD(mbpf1->MarkArray); + ma = (const GPOS_MarkArray*)((const BYTE*)mbpf1 + offset); + if (mark_index > GET_BE_WORD(ma->MarkCount)) + { + ERR("Mark index exeeded mark count\n"); + return; + } + mr = &ma->MarkRecord[mark_index]; + mark_class = GET_BE_WORD(mr->Class); + TRACE("Mark Class %i total classes %i\n",mark_class,class_count); + offset = GET_BE_WORD(mbpf1->BaseArray); + ba = (const GPOS_BaseArray*)((const BYTE*)mbpf1 + offset); + baserecord_size = class_count * sizeof(WORD); + br = (const GPOS_BaseRecord*)((const BYTE*)ba + sizeof(WORD) + (baserecord_size * base_index)); + offset = GET_BE_WORD(br->BaseAnchor[mark_class]); + GPOS_get_anchor_values((const BYTE*)ba + offset, &base_pt, ppem); + offset = GET_BE_WORD(mr->MarkAnchor); + GPOS_get_anchor_values((const BYTE*)ma + offset, &mark_pt, ppem); + TRACE("Offset on base is %i,%i design units\n",base_pt.x,base_pt.y); + TRACE("Offset on mark is %i,%i design units\n",mark_pt.x, mark_pt.y); + pt->x += base_pt.x - mark_pt.x; + pt->y += base_pt.y - mark_pt.y; + TRACE("Resulting cumulative offset is %i,%i design units\n",pt->x,pt->y); + } + } + } + else + FIXME("Unhandled Mark To Base Format %i\n",GET_BE_WORD(mbpf1->PosFormat)); + } +} + +static VOID GPOS_apply_MarkToMark(const OT_LookupTable *look, const WORD *glyphs, INT glyph_index, INT write_dir, INT glyph_count, INT ppem, LPPOINT pt) +{ + int j; + + TRACE("MarkToMark Attachment Positioning Subtable\n"); + + for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++) + { + int offset; + const GPOS_MarkMarkPosFormat1 *mmpf1; + offset = GET_BE_WORD(look->SubTable[j]); + mmpf1 = (const GPOS_MarkMarkPosFormat1*)((const BYTE*)look+offset); + if (GET_BE_WORD(mmpf1->PosFormat) == 1) + { + int offset = GET_BE_WORD(mmpf1->Mark1Coverage); + int mark_index; + mark_index = GSUB_is_glyph_covered((const BYTE*)mmpf1+offset, glyphs[glyph_index]); + if (mark_index != -1) + { + int mark2_index; + offset = GET_BE_WORD(mmpf1->Mark2Coverage); + mark2_index = GSUB_is_glyph_covered((const BYTE*)mmpf1+offset, glyphs[glyph_index - write_dir]); + if (mark2_index != -1) + { + const GPOS_MarkArray *ma; + const GPOS_MarkRecord *mr; + const GPOS_Mark2Array *m2a; + const GPOS_Mark2Record *m2r; + int mark_class; + int class_count = GET_BE_WORD(mmpf1->ClassCount); + int mark2record_size; + POINT mark2_pt; + POINT mark_pt; + TRACE("Mark %x(%i) and Mark2 %x(%i)\n",glyphs[glyph_index], mark_index, glyphs[glyph_index - write_dir], mark2_index); + offset = GET_BE_WORD(mmpf1->Mark1Array); + ma = (const GPOS_MarkArray*)((const BYTE*)mmpf1 + offset); + if (mark_index > GET_BE_WORD(ma->MarkCount)) + { + ERR("Mark index exeeded mark count\n"); + return; + } + mr = &ma->MarkRecord[mark_index]; + mark_class = GET_BE_WORD(mr->Class); + TRACE("Mark Class %i total classes %i\n",mark_class,class_count); + offset = GET_BE_WORD(mmpf1->Mark2Array); + m2a = (const GPOS_Mark2Array*)((const BYTE*)mmpf1 + offset); + mark2record_size = class_count * sizeof(WORD); + m2r = (const GPOS_Mark2Record*)((const BYTE*)m2a + sizeof(WORD) + (mark2record_size * mark2_index)); + offset = GET_BE_WORD(m2r->Mark2Anchor[mark_class]); + GPOS_get_anchor_values((const BYTE*)m2a + offset, &mark2_pt, ppem); + offset = GET_BE_WORD(mr->MarkAnchor); + GPOS_get_anchor_values((const BYTE*)ma + offset, &mark_pt, ppem); + TRACE("Offset on mark2 is %i,%i design units\n",mark2_pt.x,mark2_pt.y); + TRACE("Offset on mark is %i,%i design units\n",mark_pt.x, mark_pt.y); + pt->x += mark2_pt.x - mark_pt.x; + pt->y += mark2_pt.y - mark_pt.y; + TRACE("Resulting cumulative offset is %i,%i design units\n",pt->x,pt->y); + } + } + } + else + FIXME("Unhandled Mark To Mark Format %i\n",GET_BE_WORD(mmpf1->PosFormat)); + } +} + +static INT GPOS_apply_ChainContextPos(LPOUTLINETEXTMETRICW lpotm, LPLOGFONTW lplogfont, INT* piAdvance, const OT_LookupList *lookup, const OT_LookupTable *look, const WORD *glyphs, INT glyph_index, INT write_dir, INT glyph_count, INT ppem, GOFFSET *pGoffset) +{ + int j; + + TRACE("Chaining Contextual Positioning Subtable\n"); + + for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++) + { + int offset; + const GPOS_ChainContextPosFormat3_1 *ccpf3; + int dirLookahead = write_dir; + int dirBacktrack = -1 * write_dir; + + offset = GET_BE_WORD(look->SubTable[j]); + ccpf3 = (const GPOS_ChainContextPosFormat3_1*)((const BYTE*)look+offset); + + if (GET_BE_WORD(ccpf3->PosFormat) == 1) + { + FIXME(" TODO: subtype 1 (Simple Chaining Context Glyph Positioning)\n"); + continue; + } + else if (GET_BE_WORD(ccpf3->PosFormat) == 2) + { + FIXME(" TODO: subtype 2 (Class-based Chaining Context Glyph Positioning)\n"); + continue; + } + else if (GET_BE_WORD(ccpf3->PosFormat) == 3) + { + int k; + int indexGlyphs; + const GPOS_ChainContextPosFormat3_2 *ccpf3_2; + const GPOS_ChainContextPosFormat3_3 *ccpf3_3; + const GPOS_ChainContextPosFormat3_4 *ccpf3_4; + + TRACE(" subtype 3 (Coverage-based Chaining Context Glyph Positioning)\n"); + + for (k = 0; k < GET_BE_WORD(ccpf3->BacktrackGlyphCount); k++) + { + offset = GET_BE_WORD(ccpf3->Coverage[k]); + if (GSUB_is_glyph_covered((const BYTE*)ccpf3+offset, glyphs[glyph_index + (dirBacktrack * (k+1))]) == -1) + break; + } + if (k != GET_BE_WORD(ccpf3->BacktrackGlyphCount)) + continue; + TRACE("Matched Backtrack\n"); + + ccpf3_2 = (const GPOS_ChainContextPosFormat3_2*)((BYTE *)ccpf3 + + FIELD_OFFSET(GPOS_ChainContextPosFormat3_1, Coverage[GET_BE_WORD(ccpf3->BacktrackGlyphCount)])); + + indexGlyphs = GET_BE_WORD(ccpf3_2->InputGlyphCount); + for (k = 0; k < indexGlyphs; k++) + { + offset = GET_BE_WORD(ccpf3_2->Coverage[k]); + if (GSUB_is_glyph_covered((const BYTE*)ccpf3+offset, glyphs[glyph_index + (write_dir * k)]) == -1) + break; + } + if (k != indexGlyphs) + continue; + TRACE("Matched IndexGlyphs\n"); + + ccpf3_3 = (const GPOS_ChainContextPosFormat3_3*)((BYTE *)ccpf3_2 + + FIELD_OFFSET(GPOS_ChainContextPosFormat3_2, Coverage[GET_BE_WORD(ccpf3_2->InputGlyphCount)])); + + for (k = 0; k < GET_BE_WORD(ccpf3_3->LookaheadGlyphCount); k++) + { + offset = GET_BE_WORD(ccpf3_3->Coverage[k]); + if (GSUB_is_glyph_covered((const BYTE*)ccpf3+offset, glyphs[glyph_index + (dirLookahead * (indexGlyphs + k))]) == -1) + break; + } + if (k != GET_BE_WORD(ccpf3_3->LookaheadGlyphCount)) + continue; + TRACE("Matched LookAhead\n"); + + ccpf3_4 = (const GPOS_ChainContextPosFormat3_4*)((BYTE *)ccpf3_3 + + FIELD_OFFSET(GPOS_ChainContextPosFormat3_3, Coverage[GET_BE_WORD(ccpf3_3->LookaheadGlyphCount)])); + + if (GET_BE_WORD(ccpf3_4->PosCount)) + { + for (k = 0; k < GET_BE_WORD(ccpf3_4->PosCount); k++) + { + int lookupIndex = GET_BE_WORD(ccpf3_4->PosLookupRecord[k].LookupListIndex); + int SequenceIndex = GET_BE_WORD(ccpf3_4->PosLookupRecord[k].SequenceIndex) * write_dir; + + TRACE("Position: %i -> %i %i\n",k, SequenceIndex, lookupIndex); + GPOS_apply_lookup(lpotm, lplogfont, piAdvance, lookup, lookupIndex, glyphs, glyph_index + SequenceIndex, write_dir, glyph_count, pGoffset); + } + return glyph_index + indexGlyphs + GET_BE_WORD(ccpf3_3->LookaheadGlyphCount); + } + else return glyph_index + 1; + } + else + FIXME("Unhandled Chaining Contextual Positioning Format %i\n",GET_BE_WORD(ccpf3->PosFormat)); + } + return glyph_index + 1; +} + +static INT GPOS_apply_lookup(LPOUTLINETEXTMETRICW lpotm, LPLOGFONTW lplogfont, INT* piAdvance, const OT_LookupList* lookup, INT lookup_index, const WORD *glyphs, INT glyph_index, INT write_dir, INT glyph_count, GOFFSET *pGoffset) +{ + int offset; + const OT_LookupTable *look; + int ppem = lpotm->otmTextMetrics.tmAscent + lpotm->otmTextMetrics.tmDescent - lpotm->otmTextMetrics.tmInternalLeading; + + offset = GET_BE_WORD(lookup->Lookup[lookup_index]); + look = (const OT_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: + { + double devX, devY; + POINT adjust = {0,0}; + POINT advance = {0,0}; + GPOS_apply_SingleAdjustment(look, glyphs, glyph_index, write_dir, glyph_count, ppem, &adjust, &advance); + if (adjust.x || adjust.y) + { + GPOS_convert_design_units_to_device(lpotm, lplogfont, adjust.x, adjust.y, &devX, &devY); + pGoffset[glyph_index].du += round(devX); + pGoffset[glyph_index].dv += round(devY); + } + if (advance.x || advance.y) + { + GPOS_convert_design_units_to_device(lpotm, lplogfont, advance.x, advance.y, &devX, &devY); + piAdvance[glyph_index] += round(devX); + if (advance.y) + FIXME("Unhandled adjustment to Y advancement\n"); + } + break; + } + case 2: + { + POINT advance[2]= {{0,0},{0,0}}; + POINT adjust[2]= {{0,0},{0,0}}; + double devX, devY; + int index; + index = GPOS_apply_PairAdjustment(look, glyphs, glyph_index, write_dir, glyph_count, ppem, adjust, advance); + if (adjust[0].x || adjust[0].y) + { + GPOS_convert_design_units_to_device(lpotm, lplogfont, adjust[0].x, adjust[0].y, &devX, &devY); + pGoffset[glyph_index].du += round(devX); + pGoffset[glyph_index].dv += round(devY); + } + if (advance[0].x || advance[0].y) + { + GPOS_convert_design_units_to_device(lpotm, lplogfont, advance[0].x, advance[0].y, &devX, &devY); + piAdvance[glyph_index] += round(devX); + } + if (adjust[1].x || adjust[1].y) + { + GPOS_convert_design_units_to_device(lpotm, lplogfont, adjust[1].x, adjust[1].y, &devX, &devY); + pGoffset[glyph_index + write_dir].du += round(devX); + pGoffset[glyph_index + write_dir].dv += round(devY); + } + if (advance[1].x || advance[1].y) + { + GPOS_convert_design_units_to_device(lpotm, lplogfont, advance[1].x, advance[1].y, &devX, &devY); + piAdvance[glyph_index + write_dir] += round(devX); + } + return index; + } + case 4: + { + double devX, devY; + POINT desU = {0,0}; + GPOS_apply_MarkToBase(look, glyphs, glyph_index, write_dir, glyph_count, ppem, &desU); + if (desU.x || desU.y) + { + GPOS_convert_design_units_to_device(lpotm, lplogfont, desU.x, desU.y, &devX, &devY); + pGoffset[glyph_index].du += (round(devX) - piAdvance[glyph_index-1]); + pGoffset[glyph_index].dv += round(devY); + } + break; + } + case 6: + { + double devX, devY; + POINT desU = {0,0}; + GPOS_apply_MarkToMark(look, glyphs, glyph_index, write_dir, glyph_count, ppem, &desU); + if (desU.x || desU.y) + { + GPOS_convert_design_units_to_device(lpotm, lplogfont, desU.x, desU.y, &devX, &devY); + pGoffset[glyph_index].du += round(devX) + pGoffset[glyph_index-1].du; + pGoffset[glyph_index].dv += round(devY) + pGoffset[glyph_index-1].dv; + } + break; + } + case 8: + { + return GPOS_apply_ChainContextPos(lpotm, lplogfont, piAdvance, lookup, look, glyphs, glyph_index, write_dir, glyph_count, ppem, pGoffset); + } + default: + FIXME("We do not handle SubType %i\n",GET_BE_WORD(look->LookupType)); + } + return glyph_index+1; +} + +INT OpenType_apply_GPOS_lookup(LPOUTLINETEXTMETRICW lpotm, LPLOGFONTW lplogfont, INT* piAdvance, LPCVOID table, INT lookup_index, const WORD *glyphs, INT glyph_index, INT write_dir, INT glyph_count, GOFFSET *pGoffset) +{ + const GPOS_Header *header = (const GPOS_Header *)table; + const OT_LookupList *lookup = (const OT_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList)); + + return GPOS_apply_lookup(lpotm, lplogfont, piAdvance, lookup, lookup_index, glyphs, glyph_index, write_dir, glyph_count, pGoffset); +} + static void GSUB_initialize_script_cache(ScriptCache *psc) { int i; - if (!psc->script_count) + if (psc->GSUB_Table) { - const GSUB_ScriptList *script; + const OT_ScriptList *script; const GSUB_Header* header = (const GSUB_Header*)psc->GSUB_Table; - script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList)); + script = (const OT_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); if (psc->script_count) @@ -878,18 +1599,81 @@ static void GSUB_initialize_script_cache(ScriptCache *psc) { 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); + psc->scripts[i].gsub_table = ((const BYTE*)script + offset); } } } } -HRESULT OpenType_GSUB_GetFontScriptTags(ScriptCache *psc, OPENTYPE_TAG searchingFor, int cMaxTags, OPENTYPE_TAG *pScriptTags, int *pcTags, LPCVOID* script_table) +static void GPOS_expand_script_cache(ScriptCache *psc) +{ + int i, count; + const OT_ScriptList *script; + const GPOS_Header* header = (const GPOS_Header*)psc->GPOS_Table; + + if (!header) + return; + + script = (const OT_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList)); + count = GET_BE_WORD(script->ScriptCount); + + if (!psc->script_count) + { + psc->script_count = count; + TRACE("initializing %i scripts in this font\n",psc->script_count); + if (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].gpos_table = ((const BYTE*)script + offset); + } + } + } + else + { + for (i = 0; i < count; i++) + { + int j; + int offset = GET_BE_WORD(script->ScriptRecord[i].Script); + OPENTYPE_TAG tag = MS_MAKE_TAG(script->ScriptRecord[i].ScriptTag[0], script->ScriptRecord[i].ScriptTag[1], script->ScriptRecord[i].ScriptTag[2], script->ScriptRecord[i].ScriptTag[3]); + for (j = 0; j < psc->script_count; j++) + { + if (psc->scripts[j].tag == tag) + { + psc->scripts[j].gpos_table = ((const BYTE*)script + offset); + break; + } + } + if (j == psc->script_count) + { + psc->script_count++; + psc->scripts = HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,psc->scripts, sizeof(LoadedScript) * psc->script_count); + psc->scripts[j].tag = tag; + psc->scripts[j].gpos_table = ((const BYTE*)script + offset); + } + } + } +} + +static void _initialize_script_cache(ScriptCache *psc) +{ + if (!psc->script_count) + { + GSUB_initialize_script_cache(psc); + GPOS_expand_script_cache(psc); + } +} + +HRESULT OpenType_GetFontScriptTags(ScriptCache *psc, OPENTYPE_TAG searchingFor, int cMaxTags, OPENTYPE_TAG *pScriptTags, int *pcTags) { int i; HRESULT rc = S_OK; - GSUB_initialize_script_cache(psc); + _initialize_script_cache(psc); + *pcTags = psc->script_count; if (!searchingFor && cMaxTags < *pcTags) @@ -908,8 +1692,6 @@ HRESULT OpenType_GSUB_GetFontScriptTags(ScriptCache *psc, OPENTYPE_TAG searching { pScriptTags[0] = psc->scripts[i].tag; *pcTags = 1; - if (script_table) - *script_table = psc->scripts[i].table; rc = S_OK; break; } @@ -922,16 +1704,21 @@ static void GSUB_initialize_language_cache(LoadedScript *script) { int i; - if (!script->language_count) + if (script->gsub_table) { - const GSUB_Script* table = script->table; + DWORD offset; + const OT_Script* table = script->gsub_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); + offset = GET_BE_WORD(table->DefaultLangSys); + if (offset) + { + script->default_language.tag = MS_MAKE_TAG('d','f','l','t'); + script->default_language.gsub_table = (const BYTE*)table + offset; + } if (script->language_count) { - TRACE("Deflang %p, LangCount %i\n",script->default_language.table, script->language_count); + TRACE("Deflang %p, LangCount %i\n",script->default_language.gsub_table, script->language_count); script->languages = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(LoadedLanguage) * script->language_count); @@ -939,19 +1726,85 @@ static void GSUB_initialize_language_cache(LoadedScript *script) { 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); + script->languages[i].gsub_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) +static void GPOS_expand_language_cache(LoadedScript *script) +{ + int count; + const OT_Script* table = script->gpos_table; + DWORD offset; + + if (!table) + return; + + offset = GET_BE_WORD(table->DefaultLangSys); + if (offset) + script->default_language.gpos_table = (const BYTE*)table + offset; + + count = GET_BE_WORD(table->LangSysCount); + + TRACE("Deflang %p, LangCount %i\n",script->default_language.gpos_table, count); + if (!script->language_count) + { + int i; + script->language_count = 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].gpos_table = ((const BYTE*)table + offset); + } + } + else if (count) + { + int i,j; + for (i = 0; i < count; i++) + { + int offset = GET_BE_WORD(table->LangSysRecord[i].LangSys); + OPENTYPE_TAG tag = MS_MAKE_TAG(table->LangSysRecord[i].LangSysTag[0], table->LangSysRecord[i].LangSysTag[1], table->LangSysRecord[i].LangSysTag[2], table->LangSysRecord[i].LangSysTag[3]); + + for (j = 0; j < script->language_count; j++) + { + if (script->languages[j].tag == tag) + { + script->languages[j].gpos_table = ((const BYTE*)table + offset); + break; + } + } + if (j == script->language_count) + { + script->language_count++; + script->languages = HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,script->languages, sizeof(LoadedLanguage) * script->language_count); + script->languages[j].tag = tag; + script->languages[j].gpos_table = ((const BYTE*)table + offset); + } + } + } +} + +static void _initialize_language_cache(LoadedScript *script) +{ + if (!script->language_count) + { + GSUB_initialize_language_cache(script); + GPOS_expand_language_cache(script); + } +} + +HRESULT OpenType_GetFontLanguageTags(ScriptCache *psc, OPENTYPE_TAG script_tag, OPENTYPE_TAG searchingFor, int cMaxTags, OPENTYPE_TAG *pLanguageTags, int *pcTags) { int i; HRESULT rc = S_OK; LoadedScript *script = NULL; - GSUB_initialize_script_cache(psc); + _initialize_script_cache(psc); for (i = 0; i < psc->script_count; i++) { @@ -965,7 +1818,7 @@ HRESULT OpenType_GSUB_GetFontLanguageTags(ScriptCache *psc, OPENTYPE_TAG script_ if (!script) return E_INVALIDARG; - GSUB_initialize_language_cache(script); + _initialize_language_cache(script); if (!searchingFor && cMaxTags < script->language_count) rc = E_OUTOFMEMORY; @@ -985,15 +1838,13 @@ HRESULT OpenType_GSUB_GetFontLanguageTags(ScriptCache *psc, OPENTYPE_TAG script_ { 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 (script->default_language.gsub_table) { if (i < cMaxTags) pLanguageTags[i] = script->default_language.tag; @@ -1001,8 +1852,6 @@ HRESULT OpenType_GSUB_GetFontLanguageTags(ScriptCache *psc, OPENTYPE_TAG script_ if (searchingFor && FAILED(rc)) { pLanguageTags[0] = script->default_language.tag; - if (language_table) - *language_table = script->default_language.table; } i++; *pcTags = (*pcTags) + 1; @@ -1016,11 +1865,11 @@ static void GSUB_initialize_feature_cache(LPCVOID table, LoadedLanguage *languag { int i; - if (!language->feature_count) + if (language->gsub_table) { - const GSUB_LangSys *lang= language->table; + const OT_LangSys *lang = language->gsub_table; const GSUB_Header *header = (const GSUB_Header *)table; - const GSUB_FeatureList *feature_list; + const OT_FeatureList *feature_list; language->feature_count = GET_BE_WORD(lang->FeatureCount); TRACE("%i features\n",language->feature_count); @@ -1029,17 +1878,17 @@ static void GSUB_initialize_feature_cache(LPCVOID table, LoadedLanguage *languag { language->features = HeapAlloc(GetProcessHeap(),0,sizeof(LoadedFeature)*language->feature_count); - feature_list = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList)); + feature_list = (const OT_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList)); for (i = 0; i < language->feature_count; i++) { - const GSUB_Feature *feature; + const OT_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; + feature = (const OT_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++) @@ -1049,14 +1898,84 @@ static void GSUB_initialize_feature_cache(LPCVOID table, LoadedLanguage *languag } } -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) +static void GPOS_expand_feature_cache(LPCVOID table, LoadedLanguage *language) +{ + int i, count; + const OT_LangSys *lang = language->gpos_table; + const GPOS_Header *header = (const GPOS_Header *)table; + const OT_FeatureList *feature_list; + + if (!lang) + return; + + count = GET_BE_WORD(lang->FeatureCount); + feature_list = (const OT_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList)); + + TRACE("%i features\n",count); + if (!language->feature_count) + { + language->feature_count = count; + + if (language->feature_count) + { + language->features = HeapAlloc(GetProcessHeap(),0,sizeof(LoadedFeature)*language->feature_count); + + for (i = 0; i < language->feature_count; i++) + { + const OT_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 OT_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]); + } + } + } + else if (count) + { + language->features = HeapReAlloc(GetProcessHeap(),0,language->features, sizeof(LoadedFeature)*(language->feature_count + count)); + + for (i = 0; i < count; i++) + { + const OT_Feature *feature; + int j; + int index = GET_BE_WORD(lang->FeatureIndex[i]); + int idx = language->feature_count + i; + + language->features[idx].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[idx].feature = ((const BYTE*)feature_list + GET_BE_WORD(feature_list->FeatureRecord[index].Feature)); + feature = (const OT_Feature*)language->features[idx].feature; + language->features[idx].lookup_count = GET_BE_WORD(feature->LookupCount); + language->features[idx].lookups = HeapAlloc(GetProcessHeap(),0,sizeof(WORD) * language->features[idx].lookup_count); + for (j = 0; j < language->features[idx].lookup_count; j++) + language->features[idx].lookups[j] = GET_BE_WORD(feature->LookupListIndex[j]); + } + language->feature_count += count; + } +} + +static void _initialize_feature_cache(ScriptCache *psc, LoadedLanguage *language) +{ + if (!language->feature_count) + { + GSUB_initialize_feature_cache(psc->GSUB_Table, language); + GPOS_expand_feature_cache(psc->GPOS_Table, language); + } +} + +HRESULT OpenType_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); + _initialize_script_cache(psc); for (i = 0; i < psc->script_count; i++) { @@ -1076,9 +1995,9 @@ HRESULT OpenType_GSUB_GetFontFeatureTags(ScriptCache *psc, OPENTYPE_TAG script_t return E_INVALIDARG; } - GSUB_initialize_language_cache(script); + _initialize_language_cache(script); - if (script->default_language.table && script->default_language.tag == language_tag) + if ((script->default_language.gsub_table || script->default_language.gpos_table) && script->default_language.tag == language_tag) language = &script->default_language; else { @@ -1098,7 +2017,7 @@ HRESULT OpenType_GSUB_GetFontFeatureTags(ScriptCache *psc, OPENTYPE_TAG script_t return S_OK; } - GSUB_initialize_feature_cache(psc->GSUB_Table, language); + _initialize_feature_cache(psc, language); *pcTags = language->feature_count; diff --git a/reactos/dll/win32/usp10/shape.c b/reactos/dll/win32/usp10/shape.c index 00c68139747..eadaf724639 100644 --- a/reactos/dll/win32/usp10/shape.c +++ b/reactos/dll/win32/usp10/shape.c @@ -42,8 +42,12 @@ typedef VOID (*ContextualShapingProc)(HDC, ScriptCache*, SCRIPT_ANALYSIS*, WCHAR*, INT, WORD*, INT*, INT, WORD*); static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust); +static void ContextualShape_Hebrew(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust); static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust); +static void ContextualShape_Thaana(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust); static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust); +static void ContextualShape_Thai(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust); +static void ContextualShape_Lao(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust); static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust); static void ContextualShape_Devanagari(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust); static void ContextualShape_Bengali(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust); @@ -61,6 +65,7 @@ typedef VOID (*ShapeCharGlyphPropProc)( HDC , ScriptCache*, SCRIPT_ANALYSIS*, co 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); static void ShapeCharGlyphProp_Arabic( 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_Hebrew( 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_Thai( 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_None( 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_Tibet( 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 ); @@ -114,6 +119,8 @@ typedef struct tagConsonantComponents typedef void (*second_reorder_function)(LPWSTR pwChar, IndicSyllable *syllable,WORD* pwGlyphs, IndicSyllable* glyph_index, lexical_function lex); +typedef int (*combining_lexical_function)(WCHAR c); + /* the orders of joined_forms and contextual_features need to line up */ static const char* contextual_features[] = { @@ -139,6 +146,13 @@ static OPENTYPE_FEATURE_RECORD latin_features[] = { MS_MAKE_TAG('c','l','i','g'), 1}, }; +static OPENTYPE_FEATURE_RECORD latin_gpos_features[] = +{ + { MS_MAKE_TAG('k','e','r','n'), 1}, + { MS_MAKE_TAG('m','a','r','k'), 1}, + { MS_MAKE_TAG('m','k','m','k'), 1}, +}; + static OPENTYPE_FEATURE_RECORD arabic_features[] = { { MS_MAKE_TAG('r','l','i','g'), 1}, @@ -158,11 +172,25 @@ static const char* required_arabic_features[] = NULL }; +static OPENTYPE_FEATURE_RECORD arabic_gpos_features[] = +{ + { MS_MAKE_TAG('c','u','r','s'), 1}, + { MS_MAKE_TAG('k','e','r','n'), 1}, + { MS_MAKE_TAG('m','a','r','k'), 1}, + { MS_MAKE_TAG('m','k','m','k'), 1}, +}; + static OPENTYPE_FEATURE_RECORD hebrew_features[] = { { MS_MAKE_TAG('d','l','i','g'), 0}, }; +static OPENTYPE_FEATURE_RECORD hebrew_gpos_features[] = +{ + { MS_MAKE_TAG('k','e','r','n'), 1}, + { MS_MAKE_TAG('m','a','r','k'), 1}, +}; + static OPENTYPE_FEATURE_RECORD syriac_features[] = { { MS_MAKE_TAG('r','l','i','g'), 1}, @@ -183,6 +211,13 @@ static const char* required_syriac_features[] = NULL }; +static OPENTYPE_FEATURE_RECORD syriac_gpos_features[] = +{ + { MS_MAKE_TAG('k','e','r','n'), 1}, + { MS_MAKE_TAG('m','a','r','k'), 1}, + { MS_MAKE_TAG('m','k','m','k'), 1}, +}; + static OPENTYPE_FEATURE_RECORD sinhala_features[] = { /* Presentation forms */ @@ -197,6 +232,12 @@ static OPENTYPE_FEATURE_RECORD tibetan_features[] = { MS_MAKE_TAG('b','l','w','s'), 1}, }; +static OPENTYPE_FEATURE_RECORD tibetan_gpos_features[] = +{ + { MS_MAKE_TAG('a','b','v','m'), 1}, + { MS_MAKE_TAG('b','l','w','m'), 1}, +}; + static OPENTYPE_FEATURE_RECORD phags_features[] = { { MS_MAKE_TAG('a','b','v','s'), 1}, @@ -209,6 +250,13 @@ static OPENTYPE_FEATURE_RECORD thai_features[] = { MS_MAKE_TAG('c','c','m','p'), 1}, }; +static OPENTYPE_FEATURE_RECORD thai_gpos_features[] = +{ + { MS_MAKE_TAG('k','e','r','n'), 1}, + { MS_MAKE_TAG('m','a','r','k'), 1}, + { MS_MAKE_TAG('m','k','m','k'), 1}, +}; + static const char* required_lao_features[] = { "ccmp", @@ -241,6 +289,14 @@ static OPENTYPE_FEATURE_RECORD devanagari_features[] = { MS_MAKE_TAG('c','a','l','t'), 1}, }; +static OPENTYPE_FEATURE_RECORD devanagari_gpos_features[] = +{ + { MS_MAKE_TAG('k','e','r','n'), 1}, + { MS_MAKE_TAG('d','i','s','t'), 1}, + { MS_MAKE_TAG('a','b','v','m'), 1}, + { MS_MAKE_TAG('b','l','w','m'), 1}, +}; + static OPENTYPE_FEATURE_RECORD myanmar_features[] = { { MS_MAKE_TAG('l','i','g','a'), 1}, @@ -357,6 +413,14 @@ static const char* required_khmer_features[] = NULL }; +static OPENTYPE_FEATURE_RECORD khmer_gpos_features[] = +{ + { MS_MAKE_TAG('d','i','s','t'), 1}, + { MS_MAKE_TAG('b','l','w','m'), 1}, + { MS_MAKE_TAG('a','b','v','m'), 1}, + { MS_MAKE_TAG('m','k','m','k'), 1}, +}; + static OPENTYPE_FEATURE_RECORD ethiopic_features[] = { { MS_MAKE_TAG('c','c','m','p'), 1}, @@ -375,6 +439,7 @@ static OPENTYPE_FEATURE_RECORD mongolian_features[] = typedef struct ScriptShapeDataTag { TEXTRANGE_PROPERTIES defaultTextRange; + TEXTRANGE_PROPERTIES defaultGPOSTextRange; const char** requiredFeatures; OPENTYPE_TAG newOtTag; ContextualShapingProc contextProc; @@ -384,88 +449,88 @@ typedef struct ScriptShapeDataTag { /* in order of scripts */ static const ScriptShapeData ShapingData[] = { - {{ 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}, - {{ NULL, 0}, NULL, 0, NULL, NULL}, - {{ NULL, 0}, NULL, 0, NULL, NULL}, - {{ NULL, 0}, NULL, 0, NULL, NULL}, - {{ NULL, 0}, NULL, 0, NULL, NULL}, - {{ NULL, 0}, NULL, 0, NULL, NULL}, - {{ NULL, 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}, - {{ NULL, 0}, NULL, 0, NULL, NULL}, - {{ NULL, 0}, NULL, 0, NULL, NULL}, - {{ NULL, 0}, NULL, 0, NULL, NULL}, - {{ NULL, 0}, NULL, 0, NULL, NULL}, - {{ NULL, 0}, NULL, 0, NULL, NULL}, - {{ NULL, 0}, NULL, 0, NULL, NULL}, - {{ NULL, 0}, NULL, 0, NULL, NULL}, - {{ NULL, 0}, NULL, 0, NULL, NULL}, - {{ NULL, 0}, NULL, 0, NULL, NULL}, - {{ NULL, 0}, NULL, 0, NULL, NULL}, - {{ NULL, 0}, NULL, 0, NULL, NULL}, - {{ NULL, 0}, NULL, 0, NULL, NULL}, - {{ NULL, 0}, NULL, 0, NULL, NULL}, - {{ NULL, 0}, NULL, 0, NULL, NULL}, - {{ NULL, 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}, + {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL}, + {{ latin_features, 2}, {latin_gpos_features, 3}, NULL, 0, NULL, NULL}, + {{ latin_features, 2}, {latin_gpos_features, 3}, NULL, 0, NULL, NULL}, + {{ latin_features, 2}, {latin_gpos_features, 3}, NULL, 0, NULL, NULL}, + {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL}, + {{ latin_features, 2}, {latin_gpos_features, 3}, NULL, 0, NULL, NULL}, + {{ arabic_features, 6}, {arabic_gpos_features, 4}, required_arabic_features, 0, ContextualShape_Arabic, ShapeCharGlyphProp_Arabic}, + {{ arabic_features, 6}, {arabic_gpos_features, 4}, required_arabic_features, 0, ContextualShape_Arabic, ShapeCharGlyphProp_Arabic}, + {{ hebrew_features, 1}, {hebrew_gpos_features, 2}, NULL, 0, ContextualShape_Hebrew, ShapeCharGlyphProp_Hebrew}, + {{ syriac_features, 4}, {syriac_gpos_features, 3}, required_syriac_features, 0, ContextualShape_Syriac, ShapeCharGlyphProp_None}, + {{ arabic_features, 6}, {arabic_gpos_features, 4}, required_arabic_features, 0, ContextualShape_Arabic, ShapeCharGlyphProp_Arabic}, + {{ NULL, 0}, {NULL, 0}, NULL, 0, ContextualShape_Thaana, ShapeCharGlyphProp_None}, + {{ standard_features, 2}, {latin_gpos_features, 3}, NULL, 0, NULL, NULL}, + {{ standard_features, 2}, {latin_gpos_features, 3}, NULL, 0, NULL, NULL}, + {{ standard_features, 2}, {latin_gpos_features, 3}, NULL, 0, NULL, NULL}, + {{ standard_features, 2}, {latin_gpos_features, 3}, NULL, 0, NULL, NULL}, + {{ sinhala_features, 3}, {NULL, 0}, NULL, 0, ContextualShape_Sinhala, ShapeCharGlyphProp_Sinhala}, + {{ tibetan_features, 2}, {tibetan_gpos_features, 2}, NULL, 0, NULL, ShapeCharGlyphProp_Tibet}, + {{ tibetan_features, 2}, {tibetan_gpos_features, 2}, NULL, 0, NULL, ShapeCharGlyphProp_Tibet}, + {{ phags_features, 3}, {NULL, 0}, NULL, 0, ContextualShape_Phags_pa, ShapeCharGlyphProp_Thai}, + {{ thai_features, 1}, {thai_gpos_features, 3}, NULL, 0, ContextualShape_Thai, ShapeCharGlyphProp_Thai}, + {{ thai_features, 1}, {thai_gpos_features, 3}, NULL, 0, ContextualShape_Thai, NULL}, + {{ thai_features, 1}, {thai_gpos_features, 3}, required_lao_features, 0, ContextualShape_Lao, ShapeCharGlyphProp_Thai}, + {{ thai_features, 1}, {thai_gpos_features, 3}, required_lao_features, 0, ContextualShape_Lao, ShapeCharGlyphProp_Thai}, + {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_devanagari_features, MS_MAKE_TAG('d','e','v','2'), ContextualShape_Devanagari, ShapeCharGlyphProp_Devanagari}, + {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_devanagari_features, MS_MAKE_TAG('d','e','v','2'), ContextualShape_Devanagari, NULL}, + {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_bengali_features, MS_MAKE_TAG('b','n','g','2'), ContextualShape_Bengali, ShapeCharGlyphProp_Bengali}, + {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_bengali_features, MS_MAKE_TAG('b','n','g','2'), ContextualShape_Bengali, NULL}, + {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_bengali_features, MS_MAKE_TAG('b','n','g','2'), ContextualShape_Bengali, ShapeCharGlyphProp_Bengali}, + {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_gurmukhi_features, MS_MAKE_TAG('g','u','r','2'), ContextualShape_Gurmukhi, ShapeCharGlyphProp_Gurmukhi}, + {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_gurmukhi_features, MS_MAKE_TAG('g','u','r','2'), ContextualShape_Gurmukhi, NULL}, + {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_devanagari_features, MS_MAKE_TAG('g','j','r','2'), ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati}, + {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_devanagari_features, MS_MAKE_TAG('g','j','r','2'), ContextualShape_Gujarati, NULL}, + {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_devanagari_features, MS_MAKE_TAG('g','j','r','2'), ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati}, + {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_oriya_features, MS_MAKE_TAG('o','r','y','2'), ContextualShape_Oriya, ShapeCharGlyphProp_Oriya}, + {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_oriya_features, MS_MAKE_TAG('o','r','y','2'), ContextualShape_Oriya, NULL}, + {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_tamil_features, MS_MAKE_TAG('t','a','m','2'), ContextualShape_Tamil, ShapeCharGlyphProp_Tamil}, + {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_tamil_features, MS_MAKE_TAG('t','a','m','2'), ContextualShape_Tamil, NULL}, + {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_telugu_features, MS_MAKE_TAG('t','e','l','2'), ContextualShape_Telugu, ShapeCharGlyphProp_Telugu}, + {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_telugu_features, MS_MAKE_TAG('t','e','l','2'), ContextualShape_Telugu, NULL}, + {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_telugu_features, MS_MAKE_TAG('k','n','d','2'), ContextualShape_Kannada, ShapeCharGlyphProp_Kannada}, + {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_telugu_features, MS_MAKE_TAG('k','n','d','2'), ContextualShape_Kannada, NULL}, + {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_telugu_features, MS_MAKE_TAG('m','l','m','2'), ContextualShape_Malayalam, ShapeCharGlyphProp_Malayalam}, + {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_telugu_features, MS_MAKE_TAG('m','l','m','2'), ContextualShape_Malayalam, NULL}, + {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL}, + {{ latin_features, 2}, {latin_gpos_features, 3}, NULL, 0, NULL, NULL}, + {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL}, + {{ myanmar_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL}, + {{ myanmar_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL}, + {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL}, + {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL}, + {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL}, + {{ khmer_features, 5}, {khmer_gpos_features, 4}, required_khmer_features, 0, ContextualShape_Khmer, ShapeCharGlyphProp_Khmer}, + {{ khmer_features, 5}, {khmer_gpos_features, 4}, required_khmer_features, 0, ContextualShape_Khmer, ShapeCharGlyphProp_Khmer}, + {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL}, + {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL}, + {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL}, + {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL}, + {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL}, + {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL}, + {{ ethiopic_features, 4}, {NULL, 0}, NULL, 0, NULL, NULL}, + {{ ethiopic_features, 4}, {NULL, 0}, NULL, 0, NULL, NULL}, + {{ mongolian_features, 4}, {NULL, 0}, NULL, 0, ContextualShape_Mongolian, NULL}, + {{ mongolian_features, 4}, {NULL, 0}, NULL, 0, ContextualShape_Mongolian, NULL}, + {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL}, + {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL}, + {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL}, + {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL}, + {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL}, + {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL}, + {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL}, + {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL}, + {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL}, + {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL}, + {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL}, + {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL}, + {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL}, + {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL}, + {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL}, + {{ hebrew_features, 1}, {hebrew_gpos_features, 2}, NULL, 0, ContextualShape_Hebrew, NULL}, + {{ latin_features, 2}, {latin_gpos_features, 3}, NULL, 0, NULL, NULL}, + {{ thai_features, 1}, {thai_gpos_features, 3}, NULL, 0, ContextualShape_Thai, ShapeCharGlyphProp_Thai}, }; extern scriptData scriptInformation[]; @@ -537,11 +602,11 @@ static OPENTYPE_TAG get_opentype_script(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCac } } -static LoadedFeature* load_GSUB_feature(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, const char* feat) +static LoadedFeature* load_OT_feature(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, const char* feat) { LoadedFeature *feature = NULL; - if (psc->GSUB_Table) + if (psc->GSUB_Table || psc->GPOS_Table) { int attempt = 2; OPENTYPE_TAG tags; @@ -558,13 +623,13 @@ static LoadedFeature* load_GSUB_feature(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCac language = MS_MAKE_TAG('d','f','l','t'); attempt--; - OpenType_GSUB_GetFontFeatureTags(psc, script, language, FALSE, MS_MAKE_TAG(feat[0],feat[1],feat[2],feat[3]), 1, &tags, &cTags, &feature); + OpenType_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) - 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); + OpenType_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); @@ -575,7 +640,7 @@ static INT apply_GSUB_feature_to_glyph(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCach { LoadedFeature *feature; - feature = load_GSUB_feature(hdc, psa, psc, feat); + feature = load_OT_feature(hdc, psa, psc, feat); if (!feature) return GSUB_E_NOFEATURE; @@ -596,6 +661,27 @@ static VOID *load_gsub_table(HDC hdc) return GSUB_Table; } +static VOID *load_gpos_table(HDC hdc) +{ + VOID* GPOS_Table = NULL; + int length = GetFontData(hdc, MS_MAKE_TAG('G', 'P', 'O', 'S'), 0, NULL, 0); + if (length != GDI_ERROR) + { + GPOS_Table = HeapAlloc(GetProcessHeap(),0,length); + GetFontData(hdc, MS_MAKE_TAG('G', 'P', 'O', 'S'), 0, GPOS_Table, length); + TRACE("Loaded GPOS table of %i bytes\n",length); + } + return GPOS_Table; +} + +static VOID load_ot_tables(HDC hdc, ScriptCache *psc) +{ + if (!psc->GSUB_Table) + psc->GSUB_Table = load_gsub_table(hdc); + if (!psc->GPOS_Table) + psc->GPOS_Table = load_gpos_table(hdc); +} + 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) { WORD *glyphs; @@ -628,9 +714,9 @@ static void UpdateClustersFromGlyphProp(const int cGlyphs, const int cChars, WOR if (pwLogClust[j] == i) { int k = j; - while (!pGlyphProp[pwLogClust[k]].sva.fClusterStart && k >= 0 && k = 0 && k = 0 && k lookup_count); + for (i = 0; i < feature->lookup_count; i++) + { + int j; + for (j = 0; j < glyph_count; ) + j = OpenType_apply_GPOS_lookup(lpotm, lplogfont, piAdvance, header, feature->lookups[i], glyphs, j, write_dir, glyph_count, pGoffset); + } +} + static inline BOOL get_GSUB_Indic2(SCRIPT_ANALYSIS *psa, ScriptCache *psc) { OPENTYPE_TAG tag; HRESULT hr; int count = 0; - hr = OpenType_GSUB_GetFontScriptTags(psc, ShapingData[psa->eScript].newOtTag, 1, &tag, &count, NULL); + hr = OpenType_GetFontScriptTags(psc, ShapingData[psa->eScript].newOtTag, 1, &tag, &count); return(SUCCEEDED(hr)); } +static void insert_glyph(WORD *pwGlyphs, INT *pcGlyphs, INT cChars, INT write_dir, WORD glyph, INT index, WORD *pwLogClust) +{ + int i; + for (i = *pcGlyphs; i>=index; i--) + pwGlyphs[i+1] = pwGlyphs[i]; + pwGlyphs[index] = glyph; + *pcGlyphs = *pcGlyphs+1; + if (write_dir < 0) + UpdateClusters(index-3, 1, write_dir, cChars, pwLogClust); + else + UpdateClusters(index, 1, write_dir, cChars, pwLogClust); +} + +static void mark_invalid_combinations(HDC hdc, const WCHAR* pwcChars, INT cChars, WORD *pwGlyphs, INT *pcGlyphs, INT write_dir, WORD *pwLogClust, combining_lexical_function lex) +{ + CHAR *context_type; + int i,g; + WCHAR invalid = 0x25cc; + WORD invalid_glyph; + + context_type = HeapAlloc(GetProcessHeap(),0,cChars); + + /* Mark invalid combinations */ + for (i = 0; i < cChars; i++) + context_type[i] = lex(pwcChars[i]); + + GetGlyphIndicesW(hdc, &invalid, 1, &invalid_glyph, 0); + for (i = 1, g=1; i < cChars; i++, g++) + { + if (context_type[i] != 0 && context_type[i+write_dir]==context_type[i]) + { + insert_glyph(pwGlyphs, pcGlyphs, cChars, write_dir, invalid_glyph, g, pwLogClust); + g++; + } + } + + HeapFree(GetProcessHeap(),0,context_type); +} + static WCHAR neighbour_char(int i, int delta, const WCHAR* chars, INT cchLen) { if (i + delta < 0) @@ -839,6 +977,51 @@ static inline BOOL word_break_causing(WCHAR chr) return (chr == 0 || chr == 0x20 ); } +static int combining_lexical_Arabic(WCHAR c) +{ + enum {Arab_Norm = 0, Arab_DIAC1, Arab_DIAC2, Arab_DIAC3, Arab_DIAC4, Arab_DIAC5, Arab_DIAC6, Arab_DIAC7, Arab_DIAC8}; + + switch(c) + { + case 0x064B: + case 0x064C: + case 0x064E: + case 0x064F: + case 0x0652: + case 0x0657: + case 0x0658: + case 0x06E1: return Arab_DIAC1; + case 0x064D: + case 0x0650: + case 0x0656: return Arab_DIAC2; + case 0x0651: return Arab_DIAC3; + case 0x0610: + case 0x0611: + case 0x0612: + case 0x0613: + case 0x0614: + case 0x0659: + case 0x06D6: + case 0x06DC: + case 0x06DF: + case 0x06E0: + case 0x06E2: + case 0x06E4: + case 0x06E7: + case 0x06E8: + case 0x06EB: + case 0x06EC: return Arab_DIAC4; + case 0x06E3: + case 0x06EA: + case 0x06ED: return Arab_DIAC5; + case 0x0670: return Arab_DIAC6; + case 0x0653: return Arab_DIAC7; + case 0x0655: + case 0x0654: return Arab_DIAC8; + default: return Arab_Norm; + } +} + /* * ContextualShape_Arabic */ @@ -866,8 +1049,7 @@ static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *p dirL = 1; } - if (!psc->GSUB_Table) - psc->GSUB_Table = load_gsub_table(hdc); + load_ot_tables(hdc, psc); context_type = HeapAlloc(GetProcessHeap(),0,cChars); context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars); @@ -929,12 +1111,137 @@ static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *p HeapFree(GetProcessHeap(),0,context_shape); HeapFree(GetProcessHeap(),0,context_type); + + mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Arabic); +} + +static int combining_lexical_Hebrew(WCHAR c) +{ + enum {Hebr_Norm=0, Hebr_DIAC, Hebr_CANT1, Hebr_CANT2, Hebr_CANT3, Hebr_CANT4, Hebr_CANT5, Hebr_CANT6, Hebr_CANT7, Hebr_CANT8, Hebr_CANT9, Hebr_CANT10, Hebr_DAGESH, Hebr_DOTABV, Hebr_HOLAM, Hebr_METEG, Hebr_PATAH, Hebr_QAMATS, Hebr_RAFE, Hebr_SHINSIN}; + + switch(c) + { + case 0x05B0: + case 0x05B1: + case 0x05B2: + case 0x05B3: + case 0x05B4: + case 0x05B5: + case 0x05B6: + case 0x05BB: return Hebr_DIAC; + case 0x0599: + case 0x05A1: + case 0x05A9: + case 0x05AE: return Hebr_CANT1; + case 0x0597: + case 0x05A8: + case 0x05AC: return Hebr_CANT2; + case 0x0592: + case 0x0593: + case 0x0594: + case 0x0595: + case 0x05A7: + case 0x05AB: return Hebr_CANT3; + case 0x0598: + case 0x059C: + case 0x059E: + case 0x059F: return Hebr_CANT4; + case 0x059D: + case 0x05A0: return Hebr_CANT5; + case 0x059B: + case 0x05A5: return Hebr_CANT6; + case 0x0591: + case 0x05A3: + case 0x05A6: return Hebr_CANT7; + case 0x0596: + case 0x05A4: + case 0x05AA: return Hebr_CANT8; + case 0x059A: + case 0x05AD: return Hebr_CANT9; + case 0x05AF: return Hebr_CANT10; + case 0x05BC: return Hebr_DAGESH; + case 0x05C4: return Hebr_DOTABV; + case 0x05B9: return Hebr_HOLAM; + case 0x05BD: return Hebr_METEG; + case 0x05B7: return Hebr_PATAH; + case 0x05B8: return Hebr_QAMATS; + case 0x05BF: return Hebr_RAFE; + case 0x05C1: + case 0x05C2: return Hebr_SHINSIN; + default: return Hebr_Norm; + } +} + +static void ContextualShape_Hebrew(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust) +{ + INT dirL; + + 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; + + mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Hebrew); } /* * ContextualShape_Syriac */ +static int combining_lexical_Syriac(WCHAR c) +{ + enum {Syriac_Norm=0, Syriac_DIAC1, Syriac_DIAC2, Syriac_DIAC3, Syriac_DIAC4, Syriac_DIAC5, Syriac_DIAC6, Syriac_DIAC7, Syriac_DIAC8, Syriac_DIAC9, Syriac_DIAC10, Syriac_DIAC11, Syriac_DIAC12, Syriac_DIAC13, Syriac_DIAC14, Syriac_DIAC15, Syriac_DIAC16, Syriac_DIAC17}; + + switch(c) + { + case 0x730: + case 0x733: + case 0x736: + case 0x73A: + case 0x73D: return Syriac_DIAC1; + case 0x731: + case 0x734: + case 0x737: + case 0x73B: + case 0x73E: return Syriac_DIAC2; + case 0x740: + case 0x749: + case 0x74A: return Syriac_DIAC3; + case 0x732: + case 0x735: + case 0x73F: return Syriac_DIAC4; + case 0x738: + case 0x739: + case 0x73C: return Syriac_DIAC5; + case 0x741: + case 0x30A: return Syriac_DIAC6; + case 0x742: + case 0x325: return Syriac_DIAC7; + case 0x747: + case 0x303: return Syriac_DIAC8; + case 0x748: + case 0x32D: + case 0x32E: + case 0x330: + case 0x331: return Syriac_DIAC9; + case 0x308: return Syriac_DIAC10; + case 0x304: return Syriac_DIAC11; + case 0x307: return Syriac_DIAC12; + case 0x323: return Syriac_DIAC13; + case 0x743: return Syriac_DIAC14; + case 0x744: return Syriac_DIAC15; + case 0x745: return Syriac_DIAC16; + case 0x746: return Syriac_DIAC17; + default: return Syriac_Norm; + } +} + #define ALAPH 0x710 #define DALATH 0x715 #define RISH 0x72A @@ -963,8 +1270,7 @@ static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *p dirL = 1; } - if (!psc->GSUB_Table) - psc->GSUB_Table = load_gsub_table(hdc); + load_ot_tables(hdc, psc); if (!psc->GSUB_Table) return; @@ -1025,6 +1331,46 @@ right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa))) HeapFree(GetProcessHeap(),0,context_shape); HeapFree(GetProcessHeap(),0,context_type); + + mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Syriac); +} + +static int combining_lexical_Thaana(WCHAR c) +{ + enum {Thaana_Norm=0, Thaana_FILI}; + + switch(c) + { + case 0x7A6: + case 0x7A7: + case 0x7A8: + case 0x7A9: + case 0x7AA: + case 0x7AB: + case 0x7AC: + case 0x7AD: + case 0x7AE: + case 0x7AF: return Thaana_FILI; + default: return Thaana_Norm; + } +} + +static void ContextualShape_Thaana(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust) +{ + INT dirL; + + 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; + + mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Thaana); } /* @@ -1058,8 +1404,7 @@ static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS dirL = 1; } - if (!psc->GSUB_Table) - psc->GSUB_Table = load_gsub_table(hdc); + load_ot_tables(hdc, psc); if (!psc->GSUB_Table) return; @@ -1112,6 +1457,95 @@ static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS HeapFree(GetProcessHeap(),0,context_shape); } +static int combining_lexical_Thai(WCHAR c) +{ + enum {Thai_Norm=0, Thai_ABOVE1, Thai_ABOVE2, Thai_ABOVE3, Thai_ABOVE4, Thai_BELOW1, Thai_BELOW2, Thai_AM}; + + switch(c) + { + case 0xE31: + case 0xE34: + case 0xE35: + case 0xE36: + case 0xE37: return Thai_ABOVE1; + case 0xE47: + case 0xE4D: return Thai_ABOVE2; + case 0xE48: + case 0xE49: + case 0xE4A: + case 0xE4B: return Thai_ABOVE3; + case 0xE4C: + case 0xE4E: return Thai_ABOVE4; + case 0xE38: + case 0xE39: return Thai_BELOW1; + case 0xE3A: return Thai_BELOW2; + case 0xE33: return Thai_AM; + default: return Thai_Norm; + } +} + +static void ContextualShape_Thai(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust) +{ + INT dirL; + + 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; + + mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Thai); +} + +static int combining_lexical_Lao(WCHAR c) +{ + enum {Lao_Norm=0, Lao_ABOVE1, Lao_ABOVE2, Lao_BELOW1, Lao_BELOW2, Lao_AM}; + + switch(c) + { + case 0xEB1: + case 0xEB4: + case 0xEB5: + case 0xEB6: + case 0xEB7: + case 0xEBB: + case 0xECD: return Lao_ABOVE1; + case 0xEC8: + case 0xEC9: + case 0xECA: + case 0xECB: + case 0xECC: return Lao_ABOVE2; + case 0xEBC: return Lao_BELOW1; + case 0xEB8: + case 0xEB9: return Lao_BELOW2; + case 0xEB3: return Lao_AM; + default: return Lao_Norm; + } +} + +static void ContextualShape_Lao(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust) +{ + INT dirL; + + 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; + + mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Lao); +} + static void ReplaceInsertChars(HDC hdc, INT cWalk, INT* pcChars, WCHAR *pwOutChars, const WCHAR *replacements) { int i; @@ -1586,17 +2020,17 @@ static void ShapeIndicSyllables(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, { int c; int overall_shift = 0; - 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); - BOOL half = (load_GSUB_feature(hdc, psa, psc, "half") != NULL); + LoadedFeature *locl = (modern)?load_OT_feature(hdc, psa, psc, "locl"):NULL; + LoadedFeature *nukt = load_OT_feature(hdc, psa, psc, "nukt"); + LoadedFeature *akhn = load_OT_feature(hdc, psa, psc, "akhn"); + LoadedFeature *rkrf = (modern)?load_OT_feature(hdc, psa, psc, "rkrf"):NULL; + LoadedFeature *pstf = load_OT_feature(hdc, psa, psc, "pstf"); + LoadedFeature *vatu = (!rkrf)?load_OT_feature(hdc, psa, psc, "vatu"):NULL; + LoadedFeature *cjct = (modern)?load_OT_feature(hdc, psa, psc, "cjct"):NULL; + BOOL rphf = (load_OT_feature(hdc, psa, psc, "rphf") != NULL); + BOOL pref = (load_OT_feature(hdc, psa, psc, "pref") != NULL); + BOOL blwf = (load_OT_feature(hdc, psa, psc, "blwf") != NULL); + BOOL half = (load_OT_feature(hdc, psa, psc, "half") != NULL); IndicSyllable glyph_indexs; for (c = 0; c < syllable_count; c++) @@ -1876,7 +2310,7 @@ static void ContextualShape_Bengali(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS * input = HeapAlloc(GetProcessHeap(), 0, (cChars * 2) * sizeof(WCHAR)); memcpy(input, pwcChars, cChars * sizeof(WCHAR)); - /* Step 1: Decompose Vowels and Compose Consonents */ + /* Step 1: Decompose Vowels and Compose Consonants */ DecomposeVowels(hdc, input, &cCount, Bengali_vowels, pwLogClust, cChars); ComposeConsonants(hdc, input, &cCount, Bengali_consonants, pwLogClust); TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount); @@ -1940,7 +2374,7 @@ static void ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR)); memcpy(input, pwcChars, cChars * sizeof(WCHAR)); - /* Step 1: Compose Consonents */ + /* Step 1: Compose Consonants */ ComposeConsonants(hdc, input, &cCount, Gurmukhi_consonants, pwLogClust); TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount); @@ -2035,7 +2469,7 @@ static void ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *ps input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR)); memcpy(input, pwcChars, cChars * sizeof(WCHAR)); - /* Step 1: Decompose Vowels and Compose Consonents */ + /* Step 1: Decompose Vowels and Compose Consonants */ DecomposeVowels(hdc, input, &cCount, Oriya_vowels, pwLogClust, cChars); ComposeConsonants(hdc, input, &cCount, Oriya_consonants, pwLogClust); TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount); @@ -2085,7 +2519,7 @@ static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *ps input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR)); memcpy(input, pwcChars, cChars * sizeof(WCHAR)); - /* Step 1: Decompose Vowels and Compose Consonents */ + /* Step 1: Decompose Vowels and Compose Consonants */ DecomposeVowels(hdc, input, &cCount, Tamil_vowels, pwLogClust, cChars); ComposeConsonants(hdc, input, &cCount, Tamil_consonants, pwLogClust); TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount); @@ -2305,8 +2739,7 @@ static void ContextualShape_Mongolian(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS else dirL = 1; - if (!psc->GSUB_Table) - psc->GSUB_Table = load_gsub_table(hdc); + load_ot_tables(hdc, psc); if (!psc->GSUB_Table) return; @@ -2492,38 +2925,9 @@ static void ShapeCharGlyphProp_Arabic( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSI HeapFree(GetProcessHeap(),0,spaces); } -static void ShapeCharGlyphProp_Thai( 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_Hebrew( 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; - int finaGlyph; - INT dirL; - BYTE *spaces; - - spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs); - memset(spaces,0,cGlyphs); - - if (!psa->fLogicalOrder && psa->fRTL) - { - finaGlyph = 0; - dirL = -1; - } - else - { - finaGlyph = cGlyphs-1; - dirL = 1; - } - - for (i = 0; i < cGlyphs; i++) - { - for (k = 0; k < cChars; k++) - if (pwLogClust[k] == i) - { - if (pwcChars[k] == 0x0020) - spaces[i] = 1; - } - } - - OpenType_GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp); for (i = 0; i < cGlyphs; i++) { @@ -2538,24 +2942,67 @@ static void ShapeCharGlyphProp_Thai( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS } if (char_count == 0) - continue; - - if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */ + pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE; + else { pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER; - pCharProp[char_index[0]].fCanGlyphAlone = 1; + if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */ + pCharProp[char_index[0]].fCanGlyphAlone = 1; } - else if (i == finaGlyph) + } + + OpenType_GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp); + UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp); +} + +static void ShapeCharGlyphProp_Thai( 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; + int finaGlyph; + INT dirL; + + if (!psa->fLogicalOrder && psa->fRTL) + { + finaGlyph = 0; + dirL = -1; + } + else + { + finaGlyph = cGlyphs-1; + dirL = 1; + } + + OpenType_GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp); + + for (i = 0; i < cGlyphs; i++) + { + int k; + int char_index[20]; + int char_count = 0; + + k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i); + if (k>=0) + { + for (; k < cChars && pwLogClust[k] == i; k++) + char_index[char_count++] = k; + } + + if (i == finaGlyph) pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE; else pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER; + if (char_count == 0) + continue; + + if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */ + pCharProp[char_index[0]].fCanGlyphAlone = 1; + /* handle Thai SARA AM (U+0E33) differently than GDEF */ if (char_count == 1 && pwcChars[char_index[0]] == 0x0e33) pGlyphProp[i].sva.fClusterStart = 0; } - HeapFree(GetProcessHeap(),0,spaces); UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp); /* Do not allow justification between marks and their base */ @@ -2663,7 +3110,10 @@ static void ShapeCharGlyphProp_BaseIndic( HDC hdc, ScriptCache *psc, SCRIPT_ANAL } if (char_count == 0) + { + pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE; continue; + } if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */ { @@ -2791,8 +3241,7 @@ void SHAPE_CharGlyphProp(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const void SHAPE_ContextualShaping(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust) { - if (!psc->GSUB_Table) - psc->GSUB_Table = load_gsub_table(hdc); + load_ot_tables(hdc, psc); if (ShapingData[psa->eScript].contextProc) ShapingData[psa->eScript].contextProc(hdc, psc, psa, pwcChars, cChars, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust); @@ -2806,8 +3255,7 @@ static void SHAPE_ApplyOpenTypeFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYS if (!rpRangeProperties) return; - if (!psc->GSUB_Table) - psc->GSUB_Table = load_gsub_table(hdc); + load_ot_tables(hdc, psc); if (!psc->GSUB_Table) return; @@ -2832,6 +3280,42 @@ rpRangeProperties = &ShapingData[psa->eScript].defaultTextRange; SHAPE_ApplyOpenTypeFeatures(hdc, psc, psa, pwOutGlyphs, pcGlyphs, cMaxGlyphs, cChars, rpRangeProperties, pwLogClust); } +void SHAPE_ApplyOpenTypePositions(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WORD* pwGlyphs, INT cGlyphs, int *piAdvance, GOFFSET *pGoffset ) +{ + const TEXTRANGE_PROPERTIES *rpRangeProperties; + int i; + INT dirL; + + rpRangeProperties = &ShapingData[psa->eScript].defaultGPOSTextRange; + + if (!rpRangeProperties) + return; + + load_ot_tables(hdc, psc); + + if (!psc->GPOS_Table || !psc->otm) + return; + + if (!psa->fLogicalOrder && psa->fRTL) + dirL = -1; + else + dirL = 1; + + for (i = 0; i < rpRangeProperties->cotfRecords; i++) + { + if (rpRangeProperties->potfRecords[i].lParameter > 0) + { + LoadedFeature *feature; + + feature = load_OT_feature(hdc, psa, psc, (const char*)&rpRangeProperties->potfRecords[i].tagFeature); + if (!feature) + continue; + + GPOS_apply_feature(psc->otm, &psc->lf, piAdvance, psc->GPOS_Table, feature, pwGlyphs, dirL, cGlyphs, pGoffset); + } + } +} + HRESULT SHAPE_CheckFontForRequiredFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa) { LoadedFeature *feature; @@ -2840,14 +3324,13 @@ HRESULT SHAPE_CheckFontForRequiredFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANA if (!ShapingData[psa->eScript].requiredFeatures) return S_OK; - if (!psc->GSUB_Table) - psc->GSUB_Table = load_gsub_table(hdc); + load_ot_tables(hdc, psc); /* we need to have at least one of the required features */ i = 0; while (ShapingData[psa->eScript].requiredFeatures[i]) { - feature = load_GSUB_feature(hdc, psa, psc, ShapingData[psa->eScript].requiredFeatures[i]); + feature = load_OT_feature(hdc, psa, psc, ShapingData[psa->eScript].requiredFeatures[i]); if (feature) return S_OK; i++; @@ -2863,13 +3346,12 @@ HRESULT SHAPE_GetFontScriptTags( HDC hdc, ScriptCache *psc, HRESULT hr; OPENTYPE_TAG searching = 0x00000000; - if (!psc->GSUB_Table) - psc->GSUB_Table = load_gsub_table(hdc); + load_ot_tables(hdc, psc); if (psa && scriptInformation[psa->eScript].scriptTag) searching = scriptInformation[psa->eScript].scriptTag; - hr = OpenType_GSUB_GetFontScriptTags(psc, searching, cMaxTags, pScriptTags, pcTags, NULL); + hr = OpenType_GetFontScriptTags(psc, searching, cMaxTags, pScriptTags, pcTags); if (FAILED(hr)) *pcTags = 0; return hr; @@ -2884,17 +3366,16 @@ HRESULT SHAPE_GetFontLanguageTags( HDC hdc, ScriptCache *psc, OPENTYPE_TAG searching = 0x00000000; BOOL fellback = FALSE; - if (!psc->GSUB_Table) - psc->GSUB_Table = load_gsub_table(hdc); + load_ot_tables(hdc, psc); if (psa && psc->userLang != 0) searching = psc->userLang; - hr = OpenType_GSUB_GetFontLanguageTags(psc, tagScript, searching, cMaxTags, pLangSysTags, pcTags, NULL); + hr = OpenType_GetFontLanguageTags(psc, tagScript, searching, cMaxTags, pLangSysTags, pcTags); if (FAILED(hr)) { fellback = TRUE; - hr = OpenType_GSUB_GetFontLanguageTags(psc, MS_MAKE_TAG('l','a','t','n'), searching, cMaxTags, pLangSysTags, pcTags, NULL); + hr = OpenType_GetFontLanguageTags(psc, MS_MAKE_TAG('l','a','t','n'), searching, cMaxTags, pLangSysTags, pcTags); } if (FAILED(hr) || fellback) @@ -2912,8 +3393,7 @@ HRESULT SHAPE_GetFontFeatureTags( HDC hdc, ScriptCache *psc, HRESULT hr; BOOL filter = FALSE; - if (!psc->GSUB_Table) - psc->GSUB_Table = load_gsub_table(hdc); + load_ot_tables(hdc, psc); if (psa && scriptInformation[psa->eScript].scriptTag) { @@ -2921,7 +3401,7 @@ HRESULT SHAPE_GetFontFeatureTags( HDC hdc, ScriptCache *psc, filter = TRUE; } - hr = OpenType_GSUB_GetFontFeatureTags(psc, tagScript, tagLangSys, filter, 0x00000000, cMaxTags, pFeatureTags, pcTags, NULL); + hr = OpenType_GetFontFeatureTags(psc, tagScript, tagLangSys, filter, 0x00000000, cMaxTags, pFeatureTags, pcTags, NULL); if (FAILED(hr)) *pcTags = 0; diff --git a/reactos/dll/win32/usp10/usp10.c b/reactos/dll/win32/usp10/usp10.c index c2a76669fbd..d384d681916 100644 --- a/reactos/dll/win32/usp10/usp10.c +++ b/reactos/dll/win32/usp10/usp10.c @@ -729,9 +729,61 @@ static inline BOOL heap_free(LPVOID mem) return HeapFree(GetProcessHeap(), 0, mem); } -static inline WCHAR get_cache_default_char(SCRIPT_CACHE *psc) +/* TODO Fix font properties on Arabic locale */ +static inline BOOL set_cache_font_properties(const HDC hdc, ScriptCache *sc) { - return ((ScriptCache *)*psc)->tm.tmDefaultChar; + if (!sc->sfnt) + { + sc->sfp.wgBlank = sc->tm.tmBreakChar; + sc->sfp.wgDefault = sc->tm.tmDefaultChar; + sc->sfp.wgInvalid = sc->sfp.wgBlank; + sc->sfp.wgKashida = 0xFFFF; + sc->sfp.iKashidaWidth = 0; + } + else + { + static const WCHAR chars[4] = {0x0020, 0x200B, 0xF71B, 0x0640}; + /* U+0020: numeric space + U+200B: zero width space + U+F71B: unknow char found by black box testing + U+0640: kashida */ + WORD gi[4]; + + if (GetGlyphIndicesW(hdc, chars, 4, gi, GGI_MARK_NONEXISTING_GLYPHS) != GDI_ERROR) + { + if(gi[0] != 0xFFFF) /* 0xFFFF: index of default non exist char */ + sc->sfp.wgBlank = gi[0]; + else + sc->sfp.wgBlank = 0; + + sc->sfp.wgDefault = 0; + + if (gi[2] != 0xFFFF) + sc->sfp.wgInvalid = gi[2]; + else if (gi[1] != 0xFFFF) + sc->sfp.wgInvalid = gi[1]; + else if (gi[0] != 0xFFFF) + sc->sfp.wgInvalid = gi[0]; + else + sc->sfp.wgInvalid = 0; + + sc->sfp.wgKashida = gi[3]; + + sc->sfp.iKashidaWidth = 0; /* TODO */ + } + else + return FALSE; + } + return TRUE; +} + +static inline void get_cache_font_properties(SCRIPT_FONTPROPERTIES *sfp, ScriptCache *sc) +{ + sfp->wgBlank = sc->sfp.wgBlank; + sfp->wgDefault = sc->sfp.wgDefault; + sfp->wgInvalid = sc->sfp.wgInvalid; + sfp->wgKashida = sc->sfp.wgKashida; + sfp->iKashidaWidth = sc->sfp.iKashidaWidth; } static inline LONG get_cache_height(SCRIPT_CACHE *psc) @@ -746,18 +798,24 @@ static inline BYTE get_cache_pitch_family(SCRIPT_CACHE *psc) static inline WORD get_cache_glyph(SCRIPT_CACHE *psc, DWORD c) { - WORD *block = ((ScriptCache *)*psc)->glyphs[c >> GLYPH_BLOCK_SHIFT]; + CacheGlyphPage *page = ((ScriptCache *)*psc)->page[c / 0x10000]; + WORD *block; + if (!page) return 0; + block = page->glyphs[(c % 0x10000) >> GLYPH_BLOCK_SHIFT]; if (!block) return 0; - return block[c & GLYPH_BLOCK_MASK]; + return block[(c % 0x10000) & GLYPH_BLOCK_MASK]; } static inline WORD set_cache_glyph(SCRIPT_CACHE *psc, WCHAR c, WORD glyph) { - WORD **block = &((ScriptCache *)*psc)->glyphs[c >> GLYPH_BLOCK_SHIFT]; + CacheGlyphPage **page = &((ScriptCache *)*psc)->page[c / 0x10000]; + WORD **block; + if (!*page && !(*page = heap_alloc_zero(sizeof(CacheGlyphPage)))) return 0; + block = &(*page)->glyphs[(c % 0x10000) >> GLYPH_BLOCK_SHIFT]; if (!*block && !(*block = heap_alloc_zero(sizeof(WORD) * GLYPH_BLOCK_SIZE))) return 0; - return ((*block)[c & GLYPH_BLOCK_MASK] = glyph); + return ((*block)[(c % 0x10000) & GLYPH_BLOCK_MASK] = glyph); } static inline BOOL get_cache_glyph_widths(SCRIPT_CACHE *psc, WORD glyph, ABC *abc) @@ -782,6 +840,7 @@ static inline BOOL set_cache_glyph_widths(SCRIPT_CACHE *psc, WORD glyph, ABC *ab static HRESULT init_script_cache(const HDC hdc, SCRIPT_CACHE *psc) { ScriptCache *sc; + int size; if (!psc) return E_INVALIDARG; if (*psc) return S_OK; @@ -793,12 +852,24 @@ static HRESULT init_script_cache(const HDC hdc, SCRIPT_CACHE *psc) heap_free(sc); return E_INVALIDARG; } + size = GetOutlineTextMetricsW(hdc, 0, NULL); + if (size) + { + sc->otm = heap_alloc(size); + sc->otm->otmSize = size; + GetOutlineTextMetricsW(hdc, size, sc->otm); + } if (!GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(LOGFONTW), &sc->lf)) { heap_free(sc); return E_INVALIDARG; } sc->sfnt = (GetFontData(hdc, MS_MAKE_TAG('h','e','a','d'), 0, NULL, 0)!=GDI_ERROR); + if (!set_cache_font_properties(hdc, sc)) + { + heap_free(sc); + return E_INVALIDARG; + } *psc = sc; TRACE("<- %p\n", sc); return S_OK; @@ -965,12 +1036,20 @@ HRESULT WINAPI ScriptFreeCache(SCRIPT_CACHE *psc) unsigned int i; for (i = 0; i < GLYPH_MAX / GLYPH_BLOCK_SIZE; i++) { - heap_free(((ScriptCache *)*psc)->glyphs[i]); heap_free(((ScriptCache *)*psc)->widths[i]); } + for (i = 0; i < 0x10; i++) + { + int j; + if (((ScriptCache *)*psc)->page[i]) + for (j = 0; j < GLYPH_MAX / GLYPH_BLOCK_SIZE; j++) + heap_free(((ScriptCache *)*psc)->page[i]->glyphs[j]); + heap_free(((ScriptCache *)*psc)->page[i]); + } heap_free(((ScriptCache *)*psc)->GSUB_Table); heap_free(((ScriptCache *)*psc)->GDEF_Table); heap_free(((ScriptCache *)*psc)->CMAP_Table); + heap_free(((ScriptCache *)*psc)->GPOS_Table); for (i = 0; i < ((ScriptCache *)*psc)->script_count; i++) { int j; @@ -984,6 +1063,7 @@ HRESULT WINAPI ScriptFreeCache(SCRIPT_CACHE *psc) heap_free(((ScriptCache *)*psc)->scripts[i].languages); } heap_free(((ScriptCache *)*psc)->scripts); + heap_free(((ScriptCache *)*psc)->otm); heap_free(*psc); *psc = NULL; } @@ -1040,12 +1120,7 @@ HRESULT WINAPI ScriptGetFontProperties(HDC hdc, SCRIPT_CACHE *psc, SCRIPT_FONTPR if (sfp->cBytes != sizeof(SCRIPT_FONTPROPERTIES)) return E_INVALIDARG; - /* return something sensible? */ - sfp->wgBlank = 0; - sfp->wgDefault = get_cache_default_char(psc); - sfp->wgInvalid = 0; - sfp->wgKashida = 0xffff; - sfp->iKashidaWidth = 0; + get_cache_font_properties(sfp, *psc); return S_OK; } @@ -2084,7 +2159,7 @@ static HRESULT SS_ItemOut( SCRIPT_STRING_ANALYSIS ssa, * ssa [I] buffer to hold the analysed string components * iX [I] X axis displacement for output * iY [I] Y axis displacement for output - * uOptions [I] flags controling output processing + * uOptions [I] flags controlling output processing * prc [I] rectangle coordinates * iMinSel [I] starting pos for substringing output string * iMaxSel [I] ending pos for substringing output string @@ -3030,6 +3105,8 @@ HRESULT WINAPI ScriptPlaceOpenType( HDC hdc, SCRIPT_CACHE *psc, SCRIPT_ANALYSIS if (piAdvance) piAdvance[i] = abc.abcA + abc.abcB + abc.abcC; } + SHAPE_ApplyOpenTypePositions(hdc, (ScriptCache *)*psc, psa, pwGlyphs, cGlyphs, piAdvance, pGoffset); + if (pABC) TRACE("Total for run: abcA=%d, abcB=%d, abcC=%d\n", pABC->abcA, pABC->abcB, pABC->abcC); return S_OK; } @@ -3160,6 +3237,8 @@ HRESULT WINAPI ScriptTextOut(const HDC hdc, SCRIPT_CACHE *psc, int x, int y, UIN const int *piJustify, const GOFFSET *pGoffset) { HRESULT hr = S_OK; + INT i; + INT *lpDx; TRACE("(%p, %p, %d, %d, %04x, %p, %p, %p, %d, %p, %d, %p, %p, %p)\n", hdc, psc, x, y, fuOptions, lprc, psa, pwcReserved, iReserved, pwGlyphs, cGlyphs, @@ -3173,6 +3252,45 @@ HRESULT WINAPI ScriptTextOut(const HDC hdc, SCRIPT_CACHE *psc, int x, int y, UIN if (!psa->fNoGlyphIndex) /* Have Glyphs? */ fuOptions |= ETO_GLYPH_INDEX; /* Say don't do translation to glyph */ + lpDx = heap_alloc(cGlyphs * sizeof(INT) * 2); + + if (pGoffset) + { + for (i = 0; i < cGlyphs; i++) + if (!(fuOptions&ETO_PDY) && pGoffset[i].dv) + fuOptions |= ETO_PDY; + } + for (i = 0; i < cGlyphs; i++) + { + int idx = i; + if (fuOptions&ETO_PDY) + { + idx *=2; + lpDx[idx+1] = 0; + } + lpDx[idx] = piAdvance[i]; + } + if (pGoffset) + { + for (i = 1; i < cGlyphs; i++) + { + int idx = i; + int prev_idx = i-1; + if (fuOptions&ETO_PDY) + { + idx*=2; + prev_idx = idx-2; + } + lpDx[prev_idx] += pGoffset[i].du; + lpDx[idx] -= pGoffset[i].du; + if (fuOptions&ETO_PDY) + { + lpDx[prev_idx+1] += pGoffset[i].dv; + lpDx[idx+1] -= pGoffset[i].dv; + } + } + } + if (psa->fRTL && psa->fLogicalOrder) { int i; @@ -3180,19 +3298,24 @@ HRESULT WINAPI ScriptTextOut(const HDC hdc, SCRIPT_CACHE *psc, int x, int y, UIN rtlGlyphs = heap_alloc(cGlyphs * sizeof(WORD)); if (!rtlGlyphs) + { + heap_free(lpDx); return E_OUTOFMEMORY; + } for (i = 0; i < cGlyphs; i++) rtlGlyphs[i] = pwGlyphs[cGlyphs-1-i]; - if (!ExtTextOutW(hdc, x, y, fuOptions, lprc, rtlGlyphs, cGlyphs, NULL)) + if (!ExtTextOutW(hdc, x, y, fuOptions, lprc, rtlGlyphs, cGlyphs, lpDx)) hr = S_FALSE; heap_free(rtlGlyphs); } else - if (!ExtTextOutW(hdc, x, y, fuOptions, lprc, pwGlyphs, cGlyphs, NULL)) + if (!ExtTextOutW(hdc, x, y, fuOptions, lprc, pwGlyphs, cGlyphs, lpDx)) hr = S_FALSE; + heap_free(lpDx); + return hr; } diff --git a/reactos/dll/win32/usp10/usp10_internal.h b/reactos/dll/win32/usp10/usp10_internal.h index 558eb554200..e92648c3b52 100644 --- a/reactos/dll/win32/usp10/usp10_internal.h +++ b/reactos/dll/win32/usp10/usp10_internal.h @@ -137,29 +137,38 @@ typedef struct { typedef struct { OPENTYPE_TAG tag; - LPCVOID table; + LPCVOID gsub_table; + LPCVOID gpos_table; INT feature_count; LoadedFeature *features; } LoadedLanguage; typedef struct { OPENTYPE_TAG tag; - LPCVOID table; + LPCVOID gsub_table; + LPCVOID gpos_table; LoadedLanguage default_language; INT language_count; LoadedLanguage *languages; } LoadedScript; +typedef struct { + WORD *glyphs[GLYPH_MAX / GLYPH_BLOCK_SIZE]; +} CacheGlyphPage; + typedef struct { LOGFONTW lf; TEXTMETRICW tm; + OUTLINETEXTMETRICW *otm; + SCRIPT_FONTPROPERTIES sfp; BOOL sfnt; - WORD *glyphs[GLYPH_MAX / GLYPH_BLOCK_SIZE]; + CacheGlyphPage *page[0x10]; ABC *widths[GLYPH_MAX / GLYPH_BLOCK_SIZE]; LPVOID GSUB_Table; LPVOID GDEF_Table; LPVOID CMAP_Table; LPVOID CMAP_format12_Table; + LPVOID GPOS_Table; INT script_count; LoadedScript *scripts; @@ -214,6 +223,7 @@ INT BIDI_ReorderV2lLevel(int level, int *pIndexs, const BYTE* plevel, int cch, B INT BIDI_ReorderL2vLevel(int level, int *pIndexs, const BYTE* plevel, int cch, BOOL fReverse) DECLSPEC_HIDDEN; void SHAPE_ContextualShaping(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust) DECLSPEC_HIDDEN; void SHAPE_ApplyDefaultOpentypeFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, INT cChars, WORD *pwLogClust) DECLSPEC_HIDDEN; +void SHAPE_ApplyOpenTypePositions(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WORD* pwGlyphs, INT cGlyphs, int *piAdvance, GOFFSET *pGoffset ); 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; @@ -229,6 +239,7 @@ void BREAK_line(const WCHAR *chars, int count, const SCRIPT_ANALYSIS *sa, SCRIPT 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; +INT OpenType_apply_GPOS_lookup(LPOUTLINETEXTMETRICW lpotm, LPLOGFONTW lplogfont, INT* piAdvance, LPCVOID table, INT lookup_index, const WORD *glyphs, INT glyph_index, INT write_dir, INT glyph_count, GOFFSET *pGoffset) DECLSPEC_HIDDEN; +HRESULT OpenType_GetFontScriptTags(ScriptCache *psc, OPENTYPE_TAG searchingFor, int cMaxTags, OPENTYPE_TAG *pScriptTags, int *pcTags) DECLSPEC_HIDDEN; +HRESULT OpenType_GetFontLanguageTags(ScriptCache *psc, OPENTYPE_TAG script_tag, OPENTYPE_TAG searchingFor, int cMaxTags, OPENTYPE_TAG *pLanguageTags, int *pcTags) DECLSPEC_HIDDEN; +HRESULT OpenType_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; diff --git a/reactos/media/doc/README.WINE b/reactos/media/doc/README.WINE index 0a97a2a88ee..b4d9c592e83 100644 --- a/reactos/media/doc/README.WINE +++ b/reactos/media/doc/README.WINE @@ -179,7 +179,7 @@ reactos/dll/win32/unicows # Synced to Wine-1.3.32 (Win9x only, why do we reactos/dll/win32/updspapi # Synced to Wine-1.5.4 reactos/dll/win32/url # Synced to Wine-1.5.19 reactos/dll/win32/urlmon # Autosync -reactos/dll/win32/usp10 # Synced to Wine-1.5.4 +reactos/dll/win32/usp10 # Synced to Wine-1.5.19 reactos/dll/win32/uxtheme # Forked reactos/dll/win32/version # Autosync reactos/dll/win32/wer # Autosync