dwrite: Read legacy kerning table directly.
Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
f8e3cba746
commit
968a9e6b0c
|
@ -182,12 +182,13 @@ struct fontfacecached
|
|||
|
||||
enum font_flags
|
||||
{
|
||||
FONT_IS_SYMBOL = 0x00000001,
|
||||
FONT_IS_MONOSPACED = 0x00000002,
|
||||
FONT_IS_COLORED = 0x00000004, /* CPAL/COLR support */
|
||||
FONTFACE_HAS_KERNING_PAIRS = 0x00000008,
|
||||
FONTFACE_VERTICAL_VARIANTS = 0x00000010,
|
||||
FONTFACE_NO_VERTICAL_VARIANTS = 0x00000020,
|
||||
FONT_IS_SYMBOL = 0x00000001,
|
||||
FONT_IS_MONOSPACED = 0x00000002,
|
||||
FONT_IS_COLORED = 0x00000004, /* CPAL/COLR support */
|
||||
FONTFACE_KERNING_PAIRS = 0x00000008,
|
||||
FONTFACE_NO_KERNING_PAIRS = 0x00000010,
|
||||
FONTFACE_VERTICAL_VARIANTS = 0x00000020,
|
||||
FONTFACE_NO_VERTICAL_VARIANTS = 0x00000040,
|
||||
};
|
||||
|
||||
struct dwrite_cmap;
|
||||
|
@ -266,6 +267,7 @@ struct dwrite_fontface
|
|||
struct dwrite_fonttable gasp;
|
||||
struct dwrite_fonttable cpal;
|
||||
struct dwrite_fonttable colr;
|
||||
struct dwrite_fonttable kern;
|
||||
DWRITE_GLYPH_METRICS *glyphs[GLYPH_MAX/GLYPH_BLOCK_SIZE];
|
||||
|
||||
DWRITE_FONT_STYLE style;
|
||||
|
@ -407,6 +409,9 @@ extern HRESULT opentype_get_cpal_entries(const struct dwrite_fonttable *table, u
|
|||
unsigned int first_entry_index, unsigned int entry_count, DWRITE_COLOR_F *entries) DECLSPEC_HIDDEN;
|
||||
extern UINT32 opentype_get_glyph_image_formats(IDWriteFontFace5 *fontface) DECLSPEC_HIDDEN;
|
||||
extern DWRITE_CONTAINER_TYPE opentype_analyze_container_type(void const *, UINT32) DECLSPEC_HIDDEN;
|
||||
extern HRESULT opentype_get_kerning_pairs(struct dwrite_fontface *fontface, unsigned int count,
|
||||
const UINT16 *glyphs, INT32 *values) DECLSPEC_HIDDEN;
|
||||
extern BOOL opentype_has_kerning_pairs(struct dwrite_fontface *fontface) DECLSPEC_HIDDEN;
|
||||
|
||||
struct dwrite_colorglyph {
|
||||
USHORT layer; /* [0, num_layers) index indicating current layer */
|
||||
|
@ -460,8 +465,6 @@ extern HRESULT freetype_get_glyphrun_outline(IDWriteFontFace5 *fontface, float e
|
|||
float const *advances, DWRITE_GLYPH_OFFSET const *offsets, unsigned int count, BOOL is_rtl,
|
||||
IDWriteGeometrySink *sink) DECLSPEC_HIDDEN;
|
||||
extern UINT16 freetype_get_glyphcount(IDWriteFontFace5 *fontface) DECLSPEC_HIDDEN;
|
||||
extern BOOL freetype_has_kerning_pairs(IDWriteFontFace5 *fontface) DECLSPEC_HIDDEN;
|
||||
extern INT32 freetype_get_kerning_pair_adjustment(IDWriteFontFace5 *fontface, UINT16 left, UINT16 right) DECLSPEC_HIDDEN;
|
||||
extern void freetype_get_glyph_bbox(struct dwrite_glyphbitmap *bitmap_desc) DECLSPEC_HIDDEN;
|
||||
extern BOOL freetype_get_glyph_bitmap(struct dwrite_glyphbitmap*) DECLSPEC_HIDDEN;
|
||||
extern INT32 freetype_get_glyph_advance(IDWriteFontFace5 *fontface, FLOAT emsize, UINT16 index,
|
||||
|
|
|
@ -639,6 +639,8 @@ static ULONG WINAPI dwritefontface_Release(IDWriteFontFace5 *iface)
|
|||
IDWriteFontFace5_ReleaseFontTable(iface, fontface->cpal.context);
|
||||
if (fontface->colr.context)
|
||||
IDWriteFontFace5_ReleaseFontTable(iface, fontface->colr.context);
|
||||
if (fontface->kern.context)
|
||||
IDWriteFontFace5_ReleaseFontTable(iface, fontface->kern.context);
|
||||
if (fontface->file)
|
||||
IDWriteFontFile_Release(fontface->file);
|
||||
if (fontface->stream)
|
||||
|
@ -1155,32 +1157,22 @@ static HRESULT WINAPI dwritefontface1_GetGdiCompatibleGlyphAdvances(IDWriteFontF
|
|||
}
|
||||
|
||||
static HRESULT WINAPI dwritefontface1_GetKerningPairAdjustments(IDWriteFontFace5 *iface, UINT32 count,
|
||||
const UINT16 *indices, INT32 *adjustments)
|
||||
const UINT16 *glyphs, INT32 *values)
|
||||
{
|
||||
struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
|
||||
UINT32 i;
|
||||
|
||||
TRACE("%p, %u, %p, %p.\n", iface, count, indices, adjustments);
|
||||
TRACE("%p, %u, %p, %p.\n", iface, count, glyphs, values);
|
||||
|
||||
if (!(indices || adjustments) || !count)
|
||||
if (!(glyphs || values) || !count)
|
||||
return E_INVALIDARG;
|
||||
|
||||
if (!indices || count == 1) {
|
||||
memset(adjustments, 0, count*sizeof(INT32));
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
if (!(fontface->flags & FONTFACE_HAS_KERNING_PAIRS))
|
||||
if (!glyphs || count == 1)
|
||||
{
|
||||
memset(adjustments, 0, count*sizeof(INT32));
|
||||
return S_OK;
|
||||
memset(values, 0, count * sizeof(*values));
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
for (i = 0; i < count-1; i++)
|
||||
adjustments[i] = freetype_get_kerning_pair_adjustment(iface, indices[i], indices[i+1]);
|
||||
adjustments[count-1] = 0;
|
||||
|
||||
return S_OK;
|
||||
return opentype_get_kerning_pairs(fontface, count, glyphs, values);
|
||||
}
|
||||
|
||||
static BOOL WINAPI dwritefontface1_HasKerningPairs(IDWriteFontFace5 *iface)
|
||||
|
@ -1189,7 +1181,7 @@ static BOOL WINAPI dwritefontface1_HasKerningPairs(IDWriteFontFace5 *iface)
|
|||
|
||||
TRACE("%p.\n", iface);
|
||||
|
||||
return !!(fontface->flags & FONTFACE_HAS_KERNING_PAIRS);
|
||||
return opentype_has_kerning_pairs(fontface);
|
||||
}
|
||||
|
||||
static HRESULT WINAPI dwritefontface1_GetRecommendedRenderingMode(IDWriteFontFace5 *iface,
|
||||
|
@ -4980,6 +4972,7 @@ HRESULT create_fontface(const struct fontface_desc *desc, struct list *cached_li
|
|||
fontface->gasp.exists = TRUE;
|
||||
fontface->cpal.exists = TRUE;
|
||||
fontface->colr.exists = TRUE;
|
||||
fontface->kern.exists = TRUE;
|
||||
fontface->index = desc->index;
|
||||
fontface->simulations = desc->simulations;
|
||||
fontface->factory = desc->factory;
|
||||
|
@ -5001,9 +4994,6 @@ HRESULT create_fontface(const struct fontface_desc *desc, struct list *cached_li
|
|||
fontface->caret.slopeRun = fontface->caret.slopeRise / 3;
|
||||
}
|
||||
}
|
||||
|
||||
if (freetype_has_kerning_pairs(&fontface->IDWriteFontFace5_iface))
|
||||
fontface->flags |= FONTFACE_HAS_KERNING_PAIRS;
|
||||
fontface->glyph_image_formats = opentype_get_glyph_image_formats(&fontface->IDWriteFontFace5_iface);
|
||||
|
||||
/* Font properties are reused from font object when 'normal' face creation path is used:
|
||||
|
|
|
@ -562,37 +562,6 @@ UINT16 freetype_get_glyphcount(IDWriteFontFace5 *fontface)
|
|||
return count;
|
||||
}
|
||||
|
||||
BOOL freetype_has_kerning_pairs(IDWriteFontFace5 *fontface)
|
||||
{
|
||||
BOOL has_kerning_pairs = FALSE;
|
||||
FT_Face face;
|
||||
|
||||
EnterCriticalSection(&freetype_cs);
|
||||
if (pFTC_Manager_LookupFace(cache_manager, fontface, &face) == 0)
|
||||
has_kerning_pairs = !!FT_HAS_KERNING(face);
|
||||
LeaveCriticalSection(&freetype_cs);
|
||||
|
||||
return has_kerning_pairs;
|
||||
}
|
||||
|
||||
INT32 freetype_get_kerning_pair_adjustment(IDWriteFontFace5 *fontface, UINT16 left, UINT16 right)
|
||||
{
|
||||
INT32 adjustment = 0;
|
||||
FT_Face face;
|
||||
|
||||
EnterCriticalSection(&freetype_cs);
|
||||
if (pFTC_Manager_LookupFace(cache_manager, fontface, &face) == 0) {
|
||||
FT_Vector kern;
|
||||
if (FT_HAS_KERNING(face)) {
|
||||
pFT_Get_Kerning(face, left, right, FT_KERNING_UNSCALED, &kern);
|
||||
adjustment = kern.x;
|
||||
}
|
||||
}
|
||||
LeaveCriticalSection(&freetype_cs);
|
||||
|
||||
return adjustment;
|
||||
}
|
||||
|
||||
static inline void ft_matrix_from_dwrite_matrix(const DWRITE_MATRIX *m, FT_Matrix *ft_matrix)
|
||||
{
|
||||
ft_matrix->xx = m->m11 * 0x10000;
|
||||
|
@ -880,16 +849,6 @@ UINT16 freetype_get_glyphcount(IDWriteFontFace5 *fontface)
|
|||
return 0;
|
||||
}
|
||||
|
||||
BOOL freetype_has_kerning_pairs(IDWriteFontFace5 *fontface)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
INT32 freetype_get_kerning_pair_adjustment(IDWriteFontFace5 *fontface, UINT16 left, UINT16 right)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void freetype_get_glyph_bbox(struct dwrite_glyphbitmap *bitmap)
|
||||
{
|
||||
SetRectEmpty(&bitmap->bbox);
|
||||
|
|
|
@ -46,6 +46,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(dwrite);
|
|||
#define MS_CBLC_TAG DWRITE_MAKE_OPENTYPE_TAG('C','B','L','C')
|
||||
#define MS_CMAP_TAG DWRITE_MAKE_OPENTYPE_TAG('c','m','a','p')
|
||||
#define MS_META_TAG DWRITE_MAKE_OPENTYPE_TAG('m','e','t','a')
|
||||
#define MS_KERN_TAG DWRITE_MAKE_OPENTYPE_TAG('k','e','r','n')
|
||||
|
||||
/* 'sbix' formats */
|
||||
#define MS_PNG__TAG DWRITE_MAKE_OPENTYPE_TAG('p','n','g',' ')
|
||||
|
@ -820,6 +821,19 @@ typedef struct {
|
|||
DWORD ExtensionOffset;
|
||||
} GSUB_ExtensionPosFormat1;
|
||||
|
||||
struct kern_header
|
||||
{
|
||||
WORD version;
|
||||
WORD table_count;
|
||||
};
|
||||
|
||||
struct kern_subtable_header
|
||||
{
|
||||
WORD version;
|
||||
WORD length;
|
||||
WORD coverage;
|
||||
};
|
||||
|
||||
#include "poppack.h"
|
||||
|
||||
enum TT_NAME_WINDOWS_ENCODING_ID
|
||||
|
@ -6451,3 +6465,132 @@ HRESULT opentype_get_vertical_glyph_variants(struct dwrite_fontface *fontface, u
|
|||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
BOOL opentype_has_kerning_pairs(struct dwrite_fontface *fontface)
|
||||
{
|
||||
const struct kern_subtable_header *subtable;
|
||||
struct file_stream_desc stream_desc;
|
||||
const struct kern_header *header;
|
||||
unsigned int offset, count, i;
|
||||
|
||||
if (fontface->flags & (FONTFACE_KERNING_PAIRS | FONTFACE_NO_KERNING_PAIRS))
|
||||
return !!(fontface->flags & FONTFACE_KERNING_PAIRS);
|
||||
|
||||
fontface->flags |= FONTFACE_NO_KERNING_PAIRS;
|
||||
|
||||
stream_desc.stream = fontface->stream;
|
||||
stream_desc.face_type = fontface->type;
|
||||
stream_desc.face_index = fontface->index;
|
||||
|
||||
opentype_get_font_table(&stream_desc, MS_KERN_TAG, &fontface->kern);
|
||||
if (fontface->kern.exists)
|
||||
{
|
||||
if ((header = table_read_ensure(&fontface->kern, 0, sizeof(*header))))
|
||||
{
|
||||
count = GET_BE_WORD(header->table_count);
|
||||
offset = sizeof(*header);
|
||||
|
||||
/* Freetype limits table count this way. */
|
||||
count = min(count, 32);
|
||||
|
||||
/* Check for presence of format 0 subtable with horizontal coverage. */
|
||||
for (i = 0; i < count; ++i)
|
||||
{
|
||||
if (!(subtable = table_read_ensure(&fontface->kern, offset, sizeof(*subtable))))
|
||||
break;
|
||||
|
||||
if (subtable->version == 0 && GET_BE_WORD(subtable->coverage) & 1)
|
||||
{
|
||||
fontface->flags &= ~FONTFACE_NO_KERNING_PAIRS;
|
||||
fontface->flags |= FONTFACE_KERNING_PAIRS;
|
||||
break;
|
||||
}
|
||||
|
||||
offset += GET_BE_WORD(subtable->length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (fontface->flags & FONTFACE_NO_KERNING_PAIRS && fontface->kern.data)
|
||||
IDWriteFontFileStream_ReleaseFileFragment(stream_desc.stream, fontface->kern.context);
|
||||
|
||||
return !!(fontface->flags & FONTFACE_KERNING_PAIRS);
|
||||
}
|
||||
|
||||
struct kern_format0_compare_key
|
||||
{
|
||||
UINT16 left;
|
||||
UINT16 right;
|
||||
};
|
||||
|
||||
static int kern_format0_compare(const void *a, const void *b)
|
||||
{
|
||||
const struct kern_format0_compare_key *key = a;
|
||||
const WORD *data = b;
|
||||
UINT16 left = GET_BE_WORD(data[0]), right = GET_BE_WORD(data[1]);
|
||||
int ret;
|
||||
|
||||
if ((ret = (int)key->left - (int)left)) return ret;
|
||||
if ((ret = (int)key->right - (int)right)) return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
HRESULT opentype_get_kerning_pairs(struct dwrite_fontface *fontface, unsigned int count,
|
||||
const UINT16 *glyphs, INT32 *values)
|
||||
{
|
||||
const struct kern_subtable_header *subtable;
|
||||
unsigned int i, s, offset, pair_count, subtable_count;
|
||||
struct kern_format0_compare_key key;
|
||||
const struct kern_header *header;
|
||||
const WORD *data;
|
||||
|
||||
if (!opentype_has_kerning_pairs(fontface))
|
||||
{
|
||||
memset(values, 0, count * sizeof(*values));
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
subtable_count = table_read_be_word(&fontface->kern, 2);
|
||||
subtable_count = min(subtable_count, 32);
|
||||
|
||||
for (i = 0; i < count - 1; ++i)
|
||||
{
|
||||
offset = sizeof(*header);
|
||||
|
||||
key.left = glyphs[i];
|
||||
key.right = glyphs[i + 1];
|
||||
values[i] = 0;
|
||||
|
||||
for (s = 0; s < subtable_count; ++s)
|
||||
{
|
||||
if (!(subtable = table_read_ensure(&fontface->kern, offset, sizeof(*subtable))))
|
||||
break;
|
||||
|
||||
if (subtable->version == 0 && GET_BE_WORD(subtable->coverage) & 1)
|
||||
{
|
||||
if ((data = table_read_ensure(&fontface->kern, offset, GET_BE_WORD(subtable->length))))
|
||||
{
|
||||
/* Skip subtable header */
|
||||
data += 3;
|
||||
pair_count = GET_BE_WORD(*data);
|
||||
data += 4;
|
||||
/* Move to pair data */
|
||||
if ((data = table_read_ensure(&fontface->kern, offset + 7 * sizeof(*data),
|
||||
pair_count * 3 * sizeof(*data))))
|
||||
{
|
||||
if ((data = bsearch(&key, data, pair_count, 3 * sizeof(*data), kern_format0_compare)))
|
||||
{
|
||||
values[i] = (short)GET_BE_WORD(data[2]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
offset += GET_BE_WORD(subtable->length);
|
||||
}
|
||||
}
|
||||
values[count - 1] = 0;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue