mirror of
https://gitlab.freedesktop.org/cairo/cairo.git
synced 2026-05-05 18:08:03 +02:00
DWrite: check 'head' table as well as 'name' when comparing fonts
There may be different versions of fonts with the same name. As an additional check, compare the 'head' table wich contains the checksum for the font. Also, load the DWrite tables directly to avoid the memcpy in load_truetype_table.
This commit is contained in:
parent
2b355954a8
commit
3998a79cc2
3 changed files with 139 additions and 50 deletions
|
|
@ -41,6 +41,8 @@
|
|||
|
||||
#if CAIRO_HAS_FONT_SUBSET
|
||||
|
||||
CAIRO_BEGIN_DECLS
|
||||
|
||||
typedef struct _cairo_scaled_font_subsets_glyph {
|
||||
unsigned int font_id;
|
||||
unsigned int subset_id;
|
||||
|
|
@ -735,6 +737,9 @@ cairo_private void
|
|||
dump_scaled_font_subsets (cairo_scaled_font_subsets_t *font_subsets);
|
||||
#endif
|
||||
|
||||
CAIRO_END_DECLS
|
||||
|
||||
|
||||
#endif /* CAIRO_HAS_FONT_SUBSET */
|
||||
|
||||
#endif /* CAIRO_SCALED_FONT_SUBSETS_PRIVATE_H */
|
||||
|
|
|
|||
|
|
@ -44,10 +44,10 @@
|
|||
/**
|
||||
* SECTION:cairo-dwrite-fonts
|
||||
* @Title: DWrite Fonts
|
||||
* @Short_Description: Font support for Microsoft DWrite
|
||||
* @Short_Description: Font support for Microsoft DirectWrite
|
||||
* @See_Also: #cairo_font_face_t
|
||||
*
|
||||
* The Microsoft DWrite font backend is primarily used to render text on
|
||||
* The Microsoft DirectWrite font backend is primarily used to render text on
|
||||
* Microsoft Windows systems.
|
||||
**/
|
||||
|
||||
|
|
@ -106,6 +106,17 @@
|
|||
* cairo_show_text(cr, "😃");
|
||||
* ]]></programlisting></informalexample>
|
||||
*
|
||||
* Note: When printing a DWrite font to a
|
||||
* #CAIRO_SURFACE_TYPE_WIN32_PRINTING surface, the printing surface
|
||||
* will substitute each DWrite font with a Win32 font created from the same
|
||||
* underlying font file. If the matching font file can not be found,
|
||||
* the #CAIRO_SURFACE_TYPE_WIN32_PRINTING surface will convert each
|
||||
* glyph to a filled path. If a DWrite font was not created from a system
|
||||
* font, it is recommended that the font used to create the DWrite
|
||||
* font be made available to GDI to avoid the undesirable fallback
|
||||
* to emitting paths. This can be achieved using the GDI font loading functions
|
||||
* such as AddFontMemResourceEx().
|
||||
*
|
||||
* Return value: a newly created #cairo_font_face_t. Free with
|
||||
* cairo_font_face_destroy() when you are done using it.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@
|
|||
#include "cairo-win32-refptr.hpp"
|
||||
#include "cairo-dwrite-private.hpp"
|
||||
#include "cairo-truetype-subset-private.h"
|
||||
#include "cairo-scaled-font-subsets-private.h"
|
||||
#include <float.h>
|
||||
|
||||
#include <wincodec.h>
|
||||
|
|
@ -1752,53 +1753,100 @@ DWriteFactory::CreateRenderingParams()
|
|||
&mForceGDIClassicRenderingParams);
|
||||
}
|
||||
|
||||
static cairo_bool_t
|
||||
_name_tables_match (cairo_scaled_font_t *font1,
|
||||
cairo_scaled_font_t *font2)
|
||||
/* Check if a specific font table in a DWrite font and a scaled font is identical */
|
||||
static cairo_int_status_t
|
||||
compare_font_tables (cairo_dwrite_font_face_t *dwface,
|
||||
cairo_scaled_font_t *scaled_font,
|
||||
unsigned long tag,
|
||||
cairo_bool_t *match)
|
||||
{
|
||||
unsigned long size1;
|
||||
unsigned long size2;
|
||||
cairo_int_status_t status1;
|
||||
cairo_int_status_t status2;
|
||||
unsigned char *buffer1;
|
||||
unsigned char *buffer2;
|
||||
cairo_bool_t result = false;
|
||||
unsigned long size;
|
||||
cairo_int_status_t status;
|
||||
unsigned char *buffer = NULL;
|
||||
const void *dw_data;
|
||||
UINT32 dw_size;
|
||||
void *dw_tableContext = NULL;
|
||||
BOOL dw_exists = FALSE;
|
||||
HRESULT hr;
|
||||
|
||||
if (!font1->backend || !font2->backend ||
|
||||
!font1->backend->load_truetype_table ||
|
||||
!font2->backend->load_truetype_table)
|
||||
return false;
|
||||
hr = dwface->dwriteface->TryGetFontTable(be32_to_cpu (tag),
|
||||
&dw_data,
|
||||
&dw_size,
|
||||
&dw_tableContext,
|
||||
&dw_exists);
|
||||
if (FAILED(hr))
|
||||
return _cairo_dwrite_error (hr, "TryGetFontTable failed");
|
||||
|
||||
status1 = font1->backend->load_truetype_table (font1,
|
||||
TT_TAG_name, 0, NULL, &size1);
|
||||
status2 = font2->backend->load_truetype_table (font2,
|
||||
TT_TAG_name, 0, NULL, &size2);
|
||||
if (status1 || status2)
|
||||
return false;
|
||||
if (size1 != size2)
|
||||
return false;
|
||||
|
||||
buffer1 = (unsigned char*)malloc (size1);
|
||||
buffer2 = (unsigned char*)malloc (size2);
|
||||
|
||||
if (buffer1 && buffer2) {
|
||||
status1 = font1->backend->load_truetype_table (font1,
|
||||
TT_TAG_name, 0, buffer1, &size1);
|
||||
status2 = font2->backend->load_truetype_table (font2,
|
||||
TT_TAG_name, 0, buffer2, &size2);
|
||||
if (!status1 && !status2) {
|
||||
result = memcmp (buffer1, buffer2, size1) == 0;
|
||||
}
|
||||
if (!dw_exists) {
|
||||
*match = FALSE;
|
||||
status = CAIRO_INT_STATUS_SUCCESS;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
free (buffer1);
|
||||
free (buffer2);
|
||||
return result;
|
||||
status = scaled_font->backend->load_truetype_table (scaled_font, tag, 0, NULL, &size);
|
||||
if (unlikely(status))
|
||||
goto cleanup;
|
||||
|
||||
if (size != dw_size) {
|
||||
*match = FALSE;
|
||||
status = CAIRO_INT_STATUS_SUCCESS;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
buffer = (unsigned char *) _cairo_malloc (size);
|
||||
if (unlikely (buffer == NULL)) {
|
||||
status = (cairo_int_status_t) _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
status = scaled_font->backend->load_truetype_table (scaled_font, tag, 0, buffer, &size);
|
||||
if (unlikely(status))
|
||||
goto cleanup;
|
||||
|
||||
*match = memcmp (dw_data, buffer, size) == 0;
|
||||
status = CAIRO_INT_STATUS_SUCCESS;
|
||||
|
||||
cleanup:
|
||||
free (buffer);
|
||||
if (dw_tableContext)
|
||||
dwface->dwriteface->ReleaseFontTable(dw_tableContext);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
// Helper for _cairo_win32_printing_surface_show_glyphs to create a win32 equivalent
|
||||
// of a dwrite scaled_font so that we can print using ExtTextOut instead of drawing
|
||||
// paths or blitting glyph bitmaps.
|
||||
/* Check if a DWrite font and a scaled font areis identical
|
||||
*
|
||||
* DWrite does not allow accessing the entire font data using tag=0 so we compare
|
||||
* two of the font tables:
|
||||
* - 'name' table
|
||||
* - 'head' table since this contains the checksum for the entire font
|
||||
*/
|
||||
static cairo_int_status_t
|
||||
font_tables_match (cairo_dwrite_font_face_t *dwface,
|
||||
cairo_scaled_font_t *scaled_font,
|
||||
cairo_bool_t *match)
|
||||
{
|
||||
cairo_int_status_t status;
|
||||
|
||||
status = compare_font_tables (dwface, scaled_font, TT_TAG_name, match);
|
||||
if (unlikely(status))
|
||||
return status;
|
||||
|
||||
if (!*match)
|
||||
return CAIRO_INT_STATUS_SUCCESS;
|
||||
|
||||
status = compare_font_tables (dwface, scaled_font, TT_TAG_head, match);
|
||||
if (unlikely(status))
|
||||
return status;
|
||||
|
||||
return CAIRO_INT_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper for _cairo_win32_printing_surface_show_glyphs to create a win32 equivalent
|
||||
* of a dwrite scaled_font so that we can print using ExtTextOut instead of drawing
|
||||
* paths or blitting glyph bitmaps.
|
||||
*/
|
||||
cairo_int_status_t
|
||||
_cairo_dwrite_scaled_font_create_win32_scaled_font (cairo_scaled_font_t *scaled_font,
|
||||
cairo_scaled_font_t **new_font)
|
||||
|
|
@ -1820,12 +1868,15 @@ _cairo_dwrite_scaled_font_create_win32_scaled_font (cairo_scaled_font_t *scaled_
|
|||
if (FAILED(gdiInterop->ConvertFontFaceToLOGFONT (dwface->dwriteface, &logfont))) {
|
||||
return CAIRO_INT_STATUS_UNSUPPORTED;
|
||||
}
|
||||
// DW must have been using an outline font, so we want GDI to use the same,
|
||||
// even if there's also a bitmap face available
|
||||
|
||||
/* DWrite must have been using an outline font, so we want GDI to use the same,
|
||||
* even if there's also a bitmap face available
|
||||
*/
|
||||
logfont.lfOutPrecision = OUT_OUTLINE_PRECIS;
|
||||
|
||||
cairo_font_face_t *win32_face = cairo_win32_font_face_create_for_logfontw (&logfont);
|
||||
if (!win32_face) {
|
||||
if (cairo_font_face_status (win32_face)) {
|
||||
cairo_font_face_destroy (win32_face);
|
||||
return CAIRO_INT_STATUS_UNSUPPORTED;
|
||||
}
|
||||
|
||||
|
|
@ -1844,14 +1895,36 @@ _cairo_dwrite_scaled_font_create_win32_scaled_font (cairo_scaled_font_t *scaled_
|
|||
&options);
|
||||
cairo_font_face_destroy (win32_face);
|
||||
|
||||
if (!font) {
|
||||
if (cairo_scaled_font_status(font)) {
|
||||
cairo_scaled_font_destroy (font);
|
||||
return CAIRO_INT_STATUS_UNSUPPORTED;
|
||||
}
|
||||
|
||||
if (!_name_tables_match (font, scaled_font)) {
|
||||
// If the font name tables aren't equal, then GDI may have failed to
|
||||
// find the right font and substituted a different font.
|
||||
cairo_scaled_font_destroy (font);
|
||||
cairo_bool_t match;
|
||||
cairo_int_status_t status;
|
||||
status = font_tables_match (dwface, font, &match);
|
||||
if (status) {
|
||||
cairo_scaled_font_destroy (font);
|
||||
return status;
|
||||
}
|
||||
|
||||
/* If the font tables aren't equal, then GDI may have failed to
|
||||
* find the right font and substituted a different font.
|
||||
*/
|
||||
if (!match) {
|
||||
#if 0
|
||||
char *ps_name;
|
||||
char *font_name;
|
||||
status = _cairo_truetype_read_font_name (scaled_font, &ps_name, &font_name);
|
||||
printf("dwrite fontname: %s PS name: %s\n", font_name, ps_name);
|
||||
free (font_name);
|
||||
free (ps_name);
|
||||
status = _cairo_truetype_read_font_name (font, &ps_name, &font_name);
|
||||
printf("win32 fontname: %s PS name: %s\n", font_name, ps_name);
|
||||
free (font_name);
|
||||
free (ps_name);
|
||||
#endif
|
||||
cairo_scaled_font_destroy (font);
|
||||
return CAIRO_INT_STATUS_UNSUPPORTED;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue