diff --git a/dlls/gdi/freetype.c b/dlls/gdi/freetype.c index fc95a86afa7..b0c4fd99de5 100644 --- a/dlls/gdi/freetype.c +++ b/dlls/gdi/freetype.c @@ -247,6 +247,8 @@ struct tagGdiFont { SHORT yMin; OUTLINETEXTMETRICW *potm; FONTSIGNATURE fs; + GdiFont base_font; + struct list child_fonts; LONG ppem; }; @@ -261,6 +263,7 @@ typedef struct { static struct list gdi_font_list = LIST_INIT(gdi_font_list); static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list); #define UNUSED_CACHE_SIZE 10 +static struct list child_font_list = LIST_INIT(child_font_list); static struct list system_links = LIST_INIT(system_links); static struct list font_list = LIST_INIT(font_list); @@ -1588,11 +1591,29 @@ static GdiFont alloc_font(void) ret->potm = NULL; ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0; list_init(&ret->hfontlist); + list_init(&ret->child_fonts); return ret; } static void free_font(GdiFont font) { + struct list *cursor, *cursor2; + + LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts) + { + CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry); + struct list *first_hfont; + HFONTLIST *hfontlist; + list_remove(cursor); + first_hfont = list_head(&child->font->hfontlist); + hfontlist = LIST_ENTRY(first_hfont, HFONTLIST, entry); + DeleteObject(hfontlist->hfont); + HeapFree(GetProcessHeap(), 0, hfontlist); + free_font(child->font); + HeapFree(GetProcessHeap(), 0, child->file_name); + HeapFree(GetProcessHeap(), 0, child); + } + if (font->ft_face) pFT_Done_Face(font->ft_face); HeapFree(GetProcessHeap(), 0, font->potm); HeapFree(GetProcessHeap(), 0, font->name); @@ -1829,6 +1850,38 @@ static GdiFont find_in_cache(HFONT hfont, LOGFONTW *plf, XFORM *pxf, BOOL can_us return NULL; } + +/************************************************************* + * create_child_font_list + */ +static BOOL create_child_font_list(GdiFont font) +{ + BOOL ret = FALSE; + SYSTEM_LINKS *font_link; + CHILD_FONT *font_link_entry, *new_child; + + LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry) + { + if(!strcmpW(font_link->font_name, font->name)) + { + TRACE("found entry in system list\n"); + LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry) + { + new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child)); + new_child->file_name = strdupA(font_link_entry->file_name); + new_child->index = font_link_entry->index; + new_child->font = NULL; + list_add_tail(&font->child_fonts, &new_child->entry); + TRACE("font %s %d\n", debugstr_a(new_child->file_name), new_child->index); + } + ret = TRUE; + break; + } + } + + return ret; +} + /************************************************************* * WineEngCreateFontInstance * @@ -1846,6 +1899,14 @@ GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont) CHARSETINFO csi; HFONTLIST *hflist; + LIST_FOR_EACH_ENTRY(ret, &child_font_list, struct tagGdiFont, entry) + { + struct list *first_hfont = list_head(&ret->hfontlist); + hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry); + if(hflist->hfont == hfont) + return ret; + } + if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL; can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE; @@ -1922,7 +1983,7 @@ GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont) if(!strcmpiW(family->FamilyName, lf.lfFaceName)) { LIST_FOR_EACH(face_elem_ptr, &family->faces) { face = LIST_ENTRY(face_elem_ptr, Face, entry); - if((csi.fs.fsCsb[0] & face->fs.fsCsb[0]) || !csi.fs.fsCsb[0]) + if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0]) if(face->scalable || can_use_bitmap) goto found; } @@ -1958,7 +2019,7 @@ GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont) if(!strcmpiW(family->FamilyName, lf.lfFaceName)) { LIST_FOR_EACH(face_elem_ptr, &family->faces) { face = LIST_ENTRY(face_elem_ptr, Face, entry); - if(csi.fs.fsCsb[0] & face->fs.fsCsb[0]) + if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) if(face->scalable || can_use_bitmap) goto found; } @@ -1969,7 +2030,7 @@ GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont) family = LIST_ENTRY(family_elem_ptr, Family, entry); LIST_FOR_EACH(face_elem_ptr, &family->faces) { face = LIST_ENTRY(face_elem_ptr, Face, entry); - if(csi.fs.fsCsb[0] & face->fs.fsCsb[0]) + if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) if(face->scalable || can_use_bitmap) goto found; } @@ -2002,7 +2063,7 @@ found: LIST_FOR_EACH(face_elem_ptr, &family->faces) { face = LIST_ENTRY(face_elem_ptr, Face, entry); if(!(face->Italic ^ it) && !(face->Bold ^ bd) && - ((csi.fs.fsCsb[0] & face->fs.fsCsb[0]) || !csi.fs.fsCsb[0])) { + ((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])) { if(face->scalable) break; if(height > 0) @@ -2026,7 +2087,7 @@ found: best = NULL; LIST_FOR_EACH(face_elem_ptr, &family->faces) { face = LIST_ENTRY(face_elem_ptr, Face, entry); - if((csi.fs.fsCsb[0] & face->fs.fsCsb[0]) || !csi.fs.fsCsb[0]) { + if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0]) { if(face->scalable) break; if(height > 0) @@ -2089,6 +2150,7 @@ found: ret->name = strdupW(family->FamilyName); ret->underline = lf.lfUnderline ? 0xff : 0; ret->strikeout = lf.lfStrikeOut ? 0xff : 0; + create_child_font_list(ret); TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont); @@ -3218,6 +3280,55 @@ end: return ret; } +static BOOL load_child_font(GdiFont font, CHILD_FONT *child) +{ + HFONTLIST *hfontlist; + child->font = alloc_font(); + child->font->ft_face = OpenFontFile(child->font, child->file_name, child->index, 0, -font->ppem); + if(!child->font->ft_face) + return FALSE; + + child->font->orientation = font->orientation; + hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist)); + hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf); + list_add_head(&child->font->hfontlist, &hfontlist->entry); + child->font->base_font = font; + list_add_head(&child_font_list, &child->font->entry); + TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font); + return TRUE; +} + +static BOOL get_glyph_index_linked(GdiFont font, UINT c, GdiFont *linked_font, FT_UInt *glyph) +{ + FT_UInt g; + CHILD_FONT *child_font; + + if(font->base_font) + font = font->base_font; + + *linked_font = font; + + if((*glyph = get_glyph_index(font, c))) + return TRUE; + + LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry) + { + if(!child_font->font) + if(!load_child_font(font, child_font)) + continue; + + if(!child_font->font->ft_face) + continue; + g = get_glyph_index(child_font->font, c); + if(g) + { + *glyph = g; + *linked_font = child_font->font; + return TRUE; + } + } + return FALSE; +} /************************************************************* * WineEngGetCharWidth @@ -3396,6 +3507,25 @@ UINT WineEngGetTextCharsetInfo(GdiFont font, LPFONTSIGNATURE fs, DWORD flags) return font->charset; } +BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph) +{ + GdiFont font = dc->gdiFont, linked_font; + struct list *first_hfont; + BOOL ret; + + ret = get_glyph_index_linked(font, c, &linked_font, glyph); + TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font); + if(font == linked_font) + *new_hfont = dc->hFont; + else + { + first_hfont = list_head(&linked_font->hfontlist); + *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont; + } + + return ret; +} + #else /* HAVE_FREETYPE */ BOOL WineEngInit(void) @@ -3502,4 +3632,8 @@ UINT WineEngGetTextCharsetInfo(GdiFont font, LPFONTSIGNATURE fs, DWORD flags) return DEFAULT_CHARSET; } +BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph) +{ + return FALSE; +} #endif /* HAVE_FREETYPE */ diff --git a/dlls/gdi/gdi_private.h b/dlls/gdi/gdi_private.h index 12d33e88b33..c15325fe92d 100644 --- a/dlls/gdi/gdi_private.h +++ b/dlls/gdi/gdi_private.h @@ -366,6 +366,7 @@ extern DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count, extern DWORD WineEngGetGlyphOutline(GdiFont, UINT glyph, UINT format, LPGLYPHMETRICS, DWORD buflen, LPVOID buf, const MAT2*); +extern BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph); extern UINT WineEngGetOutlineTextMetrics(GdiFont, UINT, LPOUTLINETEXTMETRICW); extern UINT WineEngGetTextCharsetInfo(GdiFont font, LPFONTSIGNATURE fs, DWORD flags); extern BOOL WineEngGetTextExtentPoint(GdiFont, LPCWSTR, INT, LPSIZE);