// borrowed from Wine /************************************************************* * load_VDMX * * load the vdmx entry for the specified height */ typedef struct FONTGDI { ... WORD yMax; WORD yMin; DWORD ttc_item_offset; } FONTGDI, *PFONTGDI; typedef struct { WORD version; WORD numRecs; WORD numRatios; } VDMX_Header; typedef struct { BYTE bCharSet; BYTE xRatio; BYTE yStartRatio; BYTE yEndRatio; } Ros_Ratios; typedef struct { WORD recs; BYTE startsz; BYTE endsz; } VDMX_group; typedef struct { WORD yPelHeight; WORD yMax; WORD yMin; } VDMX_vTable; inline WORD GET_BE_WORD(WORD w) { BYTE b0 = (BYTE)w; BYTE b1 = (BYTE)(w >> 8); return b1 | (b0 << 8); } inline DWORD GET_BE_DWORD(DWORD dw) { BYTE b0 = (BYTE)dw; BYTE b1 = (BYTE)(dw >> 8); BYTE b2 = (BYTE)(dw >> 16); BYTE b3 = (BYTE)(dw >> 24); return b3 | (b2 << 8) | (b1 << 16) | (b0 << 24); } static LONG load_VDMX(PFONTGDI font, LONG height) { VDMX_Header hdr; VDMX_group group; BYTE devXRatio, devYRatio; USHORT numRecs, numRatios; DWORD result, offset = -1; LONG ppem = 0; int i; result = get_font_data(font, TTAG_VDMX, 0, &hdr, sizeof(hdr)); if (result == GDI_ERROR) /* no vdmx table present, use linear scaling */ return ppem; /* FIXME: need the real device aspect ratio */ devXRatio = 1; devYRatio = 1; numRecs = GET_BE_WORD(hdr.numRecs); numRatios = GET_BE_WORD(hdr.numRatios); DPRINT("version = %d numRecs = %d numRatios = %d\n", GET_BE_WORD(hdr.version), numRecs, numRatios); for (i = 0; i < numRatios; i++) { Ros_Ratios ratio; offset = sizeof(hdr) + (i * sizeof(Ros_Ratios)); get_font_data(font, TTAG_VDMX, offset, &ratio, sizeof(Ros_Ratios)); offset = -1; DPRINT("Ros_Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio); if (!ratio.bCharSet) continue; if ((ratio.xRatio == 0 && ratio.yStartRatio == 0 && ratio.yEndRatio == 0) || (devXRatio == ratio.xRatio && devYRatio >= ratio.yStartRatio && devYRatio <= ratio.yEndRatio)) { WORD group_offset; offset = sizeof(hdr) + numRatios * sizeof(ratio) + i * sizeof(group_offset); get_font_data(font, TTAG_VDMX, offset, &group_offset, sizeof(group_offset)); offset = GET_BE_WORD(group_offset); break; } } if (offset == -1) return 0; if (get_font_data(font, TTAG_VDMX, offset, &group, sizeof(group)) != GDI_ERROR) { USHORT recs; BYTE startsz, endsz; WORD *vTable; recs = GET_BE_WORD(group.recs); startsz = group.startsz; endsz = group.endsz; DPRINT("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz); vTable = HeapAlloc(GetProcessHeap(), 0, recs * sizeof(VDMX_vTable)); result = get_font_data(font, TTAG_VDMX, offset + sizeof(group), vTable, recs * sizeof(VDMX_vTable)); if (result == GDI_ERROR) { DPRINT("Failed to retrieve vTable\n"); goto end; } if (height > 0) { for (i = 0; i < recs; i++) { SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]); SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]); ppem = GET_BE_WORD(vTable[i * 3]); if (yMax + -yMin == height) { font->yMax = yMax; font->yMin = yMin; DPRINT("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin); break; } if (yMax + -yMin > height) { if (--i < 0) { ppem = 0; goto end; /* failed */ } font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]); font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]); ppem = GET_BE_WORD(vTable[i * 3]); DPRINT("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin); break; } } if (!font->yMax) { ppem = 0; DPRINT("ppem not found for height %d\n", height); } } else { ppem = -height; if (ppem < startsz || ppem > endsz) { ppem = 0; goto end; } for (i = 0; i < recs; i++) { USHORT yPelHeight; yPelHeight = GET_BE_WORD(vTable[i * 3]); if (yPelHeight > ppem) { ppem = 0; break; /* failed */ } if (yPelHeight == ppem) { font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]); font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]); DPRINT("ppem %d found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin); break; } } } end: HeapFree(GetProcessHeap(), 0, vTable); } return ppem; }