Bug 468568. Part 0.5: _cairo_dwrite_scaled_font_create_win32_scaled_font should check font names to ensure that GDI gave us back the correct font. r=jfkthame
authorRobert O'Callahan <robert@ocallahan.org>
Mon, 17 Sep 2012 16:25:24 +1200
changeset 107564 37a981b0771b0220aab6a58fe88a6ff6eb47c981
parent 107563 ff1c9905f645412f3fdb152198106ed3c5390447
child 107565 9dec661d4ce568b228df50a01a590ef55697f399
push id15113
push userrocallahan@mozilla.com
push dateThu, 20 Sep 2012 04:14:13 +0000
treeherdermozilla-inbound@84317c2f199c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjfkthame
bugs468568
milestone18.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 468568. Part 0.5: _cairo_dwrite_scaled_font_create_win32_scaled_font should check font names to ensure that GDI gave us back the correct font. r=jfkthame
gfx/cairo/README
gfx/cairo/cairo/src/cairo-dwrite-font.cpp
gfx/cairo/cairo/src/cairo-truetype-subset-private.h
gfx/cairo/dwrite-font-printing.patch
--- a/gfx/cairo/README
+++ b/gfx/cairo/README
@@ -183,16 +183,18 @@ avoid-extend-none.patch: Avoid incorrect
 win32-ExtCreatePen-zero-size.patch: Don't pass zero width or dash lengths to ExtCreatePen (bug 768348)
 
 d2d-repeating-gradients.patch: Minimize number of gradient stops added to handle repeating with path fills (bug 768775)
 
 xlib-glyph-clip-region.patch: bug 709477, addressed upstream by be1ff2f45fdbc69537e513834fcffa0435e63073
 
 gdi-RGB24-ARGB32.patch: bug 788794
 
+dwrite-font-printing.patch: bug 468568; don't substitute a GDI font for a DWrite font if the name tables aren't equal
+
 ==== pixman patches ====
 
 pixman-android-cpu-detect.patch: Add CPU detection support for Android, where we can't reliably access /proc/self/auxv.
 
 pixman-rename-and-endian.patch: include cairo-platform.h for renaming of external symbols and endian macros
 
 NOTE: we previously supported ARM assembler on MSVC, this has been removed because of the maintenance burden
 
--- a/gfx/cairo/cairo/src/cairo-dwrite-font.cpp
+++ b/gfx/cairo/cairo/src/cairo-dwrite-font.cpp
@@ -37,16 +37,17 @@
 #include "cairoint.h"
 
 #include "cairo-win32-private.h"
 #include "cairo-surface-private.h"
 #include "cairo-clip-private.h"
 
 #include "cairo-d2d-private.h"
 #include "cairo-dwrite-private.h"
+#include "cairo-truetype-subset-private.h"
 #include <float.h>
 
 typedef HRESULT (WINAPI*D2D1CreateFactoryFunc)(
     D2D1_FACTORY_TYPE factoryType,
     REFIID iid,
     CONST D2D1_FACTORY_OPTIONS *pFactoryOptions,
     void **factory
 );
@@ -1036,17 +1037,17 @@ cairo_int_status_t
 {
     cairo_dwrite_scaled_font_t *dwritesf = static_cast<cairo_dwrite_scaled_font_t*>(scaled_font);
     cairo_dwrite_font_face_t *face = reinterpret_cast<cairo_dwrite_font_face_t*>(dwritesf->base.font_face);
 
     const void *data;
     UINT32 size;
     void *tableContext;
     BOOL exists;
-    face->dwriteface->TryGetFontTable(tag,
+    face->dwriteface->TryGetFontTable(be32_to_cpu (tag),
 				      &data,
 				      &size,
 				      &tableContext,
 				      &exists);
 
     if (!exists) {
 	return CAIRO_INT_STATUS_UNSUPPORTED;
     }
@@ -1476,16 +1477,59 @@ DWriteFactory::CreateRenderingParams()
     Instance()->CreateCustomRenderingParams(gamma, contrast, clearTypeLevel,
 	pixelGeometry, renderingMode,
 	&mCustomClearTypeRenderingParams);
     Instance()->CreateCustomRenderingParams(gamma, contrast, clearTypeLevel,
         pixelGeometry, DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC,
         &mForceGDIClassicRenderingParams);
 }
 
+static cairo_bool_t
+_name_tables_match (cairo_scaled_font_t *font1,
+                    cairo_scaled_font_t *font2)
+{
+    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;
+
+    if (!font1->backend->load_truetype_table ||
+        !font2->backend->load_truetype_table)
+        return false;
+
+    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;
+        }
+    }
+
+    free (buffer1);
+    free (buffer2);
+    return result;
+}
+
 // 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)
 {
     if (cairo_scaled_font_get_type (scaled_font) != CAIRO_FONT_TYPE_DWRITE) {
@@ -1528,19 +1572,18 @@ cairo_int_status_t
 			                                  &ctm,
 			                                  &options);
     cairo_font_face_destroy (win32_face);
 
     if (!font) {
         return CAIRO_INT_STATUS_UNSUPPORTED;
     }
 
-    if (_cairo_win32_scaled_font_is_type1 (font) || _cairo_win32_scaled_font_is_bitmap (font)) {
-        // If we somehow got a Type1 or bitmap font, it can't be the same physical font
-        // as directwrite was using, so glyph IDs will not match; best we can do is to
-        // throw it away and fall back on rendering paths or blitting bitmaps instead.
+    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);
         return CAIRO_INT_STATUS_UNSUPPORTED;
     }
 
     *new_font = font;
     return CAIRO_INT_STATUS_SUCCESS;
 }
--- a/gfx/cairo/cairo/src/cairo-truetype-subset-private.h
+++ b/gfx/cairo/cairo/src/cairo-truetype-subset-private.h
@@ -34,16 +34,18 @@
  *	Adrian Johnson <ajohnson@redneon.com>
  */
 
 #ifndef CAIRO_TRUETYPE_SUBSET_PRIVATE_H
 #define CAIRO_TRUETYPE_SUBSET_PRIVATE_H
 
 #include "cairoint.h"
 
+CAIRO_BEGIN_DECLS
+
 #if CAIRO_HAS_FONT_SUBSET
 
 /* The structs defined here should strictly follow the TrueType
  * specification and not be padded.  We use only 16-bit integer
  * in their definition to guarantee that.  The fields of type
  * "FIXED" in the TT spec are broken into two *_1 and *_2 16-bit
  * parts, and 64-bit members are broken into four.
  *
@@ -191,9 +193,11 @@ typedef struct _tt_composite_glyph {
 typedef struct _tt_glyph_data {
     int16_t           num_contours;
     int8_t            data[8];
     tt_composite_glyph_t glyph;
 } tt_glyph_data_t;
 
 #endif /* CAIRO_HAS_FONT_SUBSET */
 
+CAIRO_END_DECLS
+
 #endif /* CAIRO_TRUETYPE_SUBSET_PRIVATE_H */
new file mode 100644
--- /dev/null
+++ b/gfx/cairo/dwrite-font-printing.patch
@@ -0,0 +1,157 @@
+diff --git a/gfx/cairo/cairo/src/cairo-dwrite-font.cpp b/gfx/cairo/cairo/src/cairo-dwrite-font.cpp
+--- a/gfx/cairo/cairo/src/cairo-dwrite-font.cpp
++++ b/gfx/cairo/cairo/src/cairo-dwrite-font.cpp
+@@ -37,16 +37,17 @@
+ #include "cairoint.h"
+ 
+ #include "cairo-win32-private.h"
+ #include "cairo-surface-private.h"
+ #include "cairo-clip-private.h"
+ 
+ #include "cairo-d2d-private.h"
+ #include "cairo-dwrite-private.h"
++#include "cairo-truetype-subset-private.h"
+ #include <float.h>
+ 
+ typedef HRESULT (WINAPI*D2D1CreateFactoryFunc)(
+     D2D1_FACTORY_TYPE factoryType,
+     REFIID iid,
+     CONST D2D1_FACTORY_OPTIONS *pFactoryOptions,
+     void **factory
+ );
+@@ -1036,17 +1037,17 @@ cairo_int_status_t
+ {
+     cairo_dwrite_scaled_font_t *dwritesf = static_cast<cairo_dwrite_scaled_font_t*>(scaled_font);
+     cairo_dwrite_font_face_t *face = reinterpret_cast<cairo_dwrite_font_face_t*>(dwritesf->base.font_face);
+ 
+     const void *data;
+     UINT32 size;
+     void *tableContext;
+     BOOL exists;
+-    face->dwriteface->TryGetFontTable(tag,
++    face->dwriteface->TryGetFontTable(be32_to_cpu (tag),
+ 				      &data,
+ 				      &size,
+ 				      &tableContext,
+ 				      &exists);
+ 
+     if (!exists) {
+ 	return CAIRO_INT_STATUS_UNSUPPORTED;
+     }
+@@ -1476,16 +1477,59 @@ DWriteFactory::CreateRenderingParams()
+     Instance()->CreateCustomRenderingParams(gamma, contrast, clearTypeLevel,
+ 	pixelGeometry, renderingMode,
+ 	&mCustomClearTypeRenderingParams);
+     Instance()->CreateCustomRenderingParams(gamma, contrast, clearTypeLevel,
+         pixelGeometry, DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC,
+         &mForceGDIClassicRenderingParams);
+ }
+ 
++static cairo_bool_t
++_name_tables_match (cairo_scaled_font_t *font1,
++                    cairo_scaled_font_t *font2)
++{
++    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;
++
++    if (!font1->backend->load_truetype_table ||
++        !font2->backend->load_truetype_table)
++        return false;
++
++    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;
++        }
++    }
++
++    free (buffer1);
++    free (buffer2);
++    return result;
++}
++
+ // 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)
+ {
+     if (cairo_scaled_font_get_type (scaled_font) != CAIRO_FONT_TYPE_DWRITE) {
+@@ -1528,19 +1572,18 @@ cairo_int_status_t
+ 			                                  &ctm,
+ 			                                  &options);
+     cairo_font_face_destroy (win32_face);
+ 
+     if (!font) {
+         return CAIRO_INT_STATUS_UNSUPPORTED;
+     }
+ 
+-    if (_cairo_win32_scaled_font_is_type1 (font) || _cairo_win32_scaled_font_is_bitmap (font)) {
+-        // If we somehow got a Type1 or bitmap font, it can't be the same physical font
+-        // as directwrite was using, so glyph IDs will not match; best we can do is to
+-        // throw it away and fall back on rendering paths or blitting bitmaps instead.
++    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);
+         return CAIRO_INT_STATUS_UNSUPPORTED;
+     }
+ 
+     *new_font = font;
+     return CAIRO_INT_STATUS_SUCCESS;
+ }
+diff --git a/gfx/cairo/cairo/src/cairo-truetype-subset-private.h b/gfx/cairo/cairo/src/cairo-truetype-subset-private.h
+--- a/gfx/cairo/cairo/src/cairo-truetype-subset-private.h
++++ b/gfx/cairo/cairo/src/cairo-truetype-subset-private.h
+@@ -34,16 +34,18 @@
+  *	Adrian Johnson <ajohnson@redneon.com>
+  */
+ 
+ #ifndef CAIRO_TRUETYPE_SUBSET_PRIVATE_H
+ #define CAIRO_TRUETYPE_SUBSET_PRIVATE_H
+ 
+ #include "cairoint.h"
+ 
++CAIRO_BEGIN_DECLS
++
+ #if CAIRO_HAS_FONT_SUBSET
+ 
+ /* The structs defined here should strictly follow the TrueType
+  * specification and not be padded.  We use only 16-bit integer
+  * in their definition to guarantee that.  The fields of type
+  * "FIXED" in the TT spec are broken into two *_1 and *_2 16-bit
+  * parts, and 64-bit members are broken into four.
+  *
+@@ -191,9 +193,11 @@ typedef struct _tt_composite_glyph {
+ typedef struct _tt_glyph_data {
+     int16_t           num_contours;
+     int8_t            data[8];
+     tt_composite_glyph_t glyph;
+ } tt_glyph_data_t;
+ 
+ #endif /* CAIRO_HAS_FONT_SUBSET */
+ 
++CAIRO_END_DECLS
++
+ #endif /* CAIRO_TRUETYPE_SUBSET_PRIVATE_H */