29 commits - boilerplate/cairo-boilerplate-win32-printing.c meson.build meson.options meson_options.txt README.md src/win32

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Fri Feb 21 17:32:39 UTC 2025


 README.md                                      |    2 
 boilerplate/cairo-boilerplate-win32-printing.c |   47 -
 meson.build                                    |    3 
 src/win32/cairo-dwrite-font.cpp                |  773 ++++++++++++++++++++-----
 src/win32/cairo-dwrite-private.hpp             |    6 
 src/win32/cairo-win32-device.c                 |   46 -
 src/win32/cairo-win32-display-surface.c        |   34 -
 src/win32/cairo-win32-font.c                   |  117 ++-
 src/win32/cairo-win32-gdi-compositor.c         |   36 -
 src/win32/cairo-win32-printing-surface.c       |   59 +
 src/win32/cairo-win32-private.h                |   32 -
 src/win32/cairo-win32-surface.c                |   40 -
 src/win32/cairo-win32-system.c                 |  126 +++-
 13 files changed, 884 insertions(+), 437 deletions(-)

New commits:
commit bdd12408a72f1825818fba141b45987389ddfc0c
Merge: 3bfe1eed0 4d141f08f
Author: Emmanuele Bassi <ebassi at gmail.com>
Date:   Fri Feb 21 17:32:28 2025 +0000

    Merge branch 'dwrite-coverage-map' into 'master'
    
    DWrite: Get glyph coverage using IDWriteGlyphRunAnalysis
    
    See merge request cairo/cairo!602

commit 4d141f08fb55a71efd6fb194a08169122edb7b47
Author: Luca Bacci <luca.bacci982 at gmail.com>
Date:   Wed Jan 8 10:32:37 2025 +0100

    DWrite: Add fallback for OS versions up to Windows 8
    
    IDWriteGlyphRunAnalysis supports gray-scale antialiasing only when
    created via IDWriteFactory2 (and newer), introduced in Windows 8.1
    
    Fallback to using DIrect2D on A8 targets when IDWriteFactory2 is
    not available.

diff --git a/src/win32/cairo-dwrite-font.cpp b/src/win32/cairo-dwrite-font.cpp
index 3e83a59ee..bf5191967 100644
--- a/src/win32/cairo-dwrite-font.cpp
+++ b/src/win32/cairo-dwrite-font.cpp
@@ -1319,6 +1319,81 @@ _cairo_dwrite_scaled_font_init_glyph_color_surface(cairo_dwrite_scaled_font_t *s
     return CAIRO_INT_STATUS_SUCCESS;
 }
 
+// Helper for OS versions up to Windows 8
+static cairo_int_status_t
+init_glyph_surface_fallback_a8 (cairo_dwrite_scaled_font_t  *scaled_font,
+                                cairo_scaled_glyph_t        *scaled_glyph,
+                                int                          width,
+                                int                          height,
+                                double                       x1,
+                                double                       y1,
+                                DWRITE_MATRIX               *matrix,
+                                DWRITE_GLYPH_RUN            *run)
+{
+    RefPtr<IWICBitmap> bitmap;
+    HRESULT hr;
+
+    hr = WICImagingFactory::Instance()->CreateBitmap ((UINT)width,
+                                                      (UINT)height,
+                                                      GUID_WICPixelFormat8bppAlpha,
+                                                      WICBitmapCacheOnLoad,
+                                                      &bitmap);
+    if (FAILED(hr))
+        return _cairo_dwrite_error (hr, "CreateBitmap failed");
+
+    D2D1_RENDER_TARGET_PROPERTIES properties = D2D1::RenderTargetProperties(
+        D2D1_RENDER_TARGET_TYPE_DEFAULT,
+        D2D1::PixelFormat(
+            DXGI_FORMAT_A8_UNORM,
+            D2D1_ALPHA_MODE_PREMULTIPLIED),
+        0,
+        0,
+        D2D1_RENDER_TARGET_USAGE_NONE,
+        D2D1_FEATURE_LEVEL_DEFAULT);
+
+    RefPtr<ID2D1RenderTarget> rt;
+    hr = D2DFactory::Instance()->CreateWicBitmapRenderTarget (bitmap, properties, &rt);
+    if (FAILED(hr))
+        return _cairo_dwrite_error (hr, "CreateWicBitmapRenderTarget failed");
+
+    RefPtr<ID2D1SolidColorBrush> brush;
+    hr = rt->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::Black, 1.0), &brush);
+
+    rt->BeginDraw();
+
+    rt->SetTransform(*(D2D1_MATRIX_3X2_F*)matrix);
+
+    rt->DrawGlyphRun({0, 0}, run, brush, scaled_font->measuring_mode);
+
+    hr = rt->EndDraw();
+    if (FAILED(hr))
+        return _cairo_dwrite_error (hr, "EndDraw failed");
+
+    // TODO: rt->Flush()?
+
+    cairo_surface_t *surface = cairo_image_surface_create (CAIRO_FORMAT_A8, width, height);
+    if (cairo_surface_status (surface))
+        return CAIRO_INT_STATUS_UNSUPPORTED;
+
+    // Tell pixman that it should use component alpha blending when the surface is
+    // used as a source
+    pixman_image_set_component_alpha (((cairo_image_surface_t*)surface)->pixman_image, TRUE);
+
+    int stride = cairo_image_surface_get_stride (surface);
+    WICRect rect = { 0, 0, width, height };
+    bitmap->CopyPixels(&rect,
+                       stride,
+                       height * stride,
+                       cairo_image_surface_get_data (surface));
+    cairo_surface_mark_dirty (surface);
+    cairo_surface_set_device_offset (surface, -x1, -y1);
+    _cairo_scaled_glyph_set_surface (scaled_glyph,
+                                     &scaled_font->base,
+                                     (cairo_image_surface_t*)surface);
+
+    return CAIRO_INT_STATUS_SUCCESS;
+}
+
 static cairo_int_status_t
 _cairo_dwrite_scaled_font_init_glyph_surface (cairo_dwrite_scaled_font_t *scaled_font,
                                               cairo_scaled_glyph_t       *scaled_glyph)
@@ -1481,6 +1556,14 @@ _cairo_dwrite_scaled_font_init_glyph_surface (cairo_dwrite_scaled_font_t *scaled
                                                                 &dwrite_glyph_run_analysis);
     }
     else {
+        if (antialias == ANTIALIAS_GRAY) {
+            // IDWriteGlyphRunAnalysis supports gray-scale antialiasing only when
+            // created from IDWriteFactory2 or later. If we have IDWriteFactory
+            // only, fallback to rendering with Direct2D on A8 targets.
+            return init_glyph_surface_fallback_a8 (scaled_font, scaled_glyph,
+                                                   width, height, x1, y1, &matrix, &run);
+        }
+
         hr = DWriteFactory::Instance()->CreateGlyphRunAnalysis(&run, 1,
                                                                &matrix,
                                                                rendering_mode,
commit 78fca779ba3af806d48dd8ebbf6633f566734328
Author: Luca Bacci <luca.bacci982 at gmail.com>
Date:   Wed Nov 13 13:51:53 2024 +0100

    DWrite: Get glyph coverage using IDWriteGlyphRunAnalysis

diff --git a/src/win32/cairo-dwrite-font.cpp b/src/win32/cairo-dwrite-font.cpp
index 4e8970fdc..3e83a59ee 100644
--- a/src/win32/cairo-dwrite-font.cpp
+++ b/src/win32/cairo-dwrite-font.cpp
@@ -47,6 +47,7 @@
 #include "cairo-scaled-font-subsets-private.h"
 #include "cairo-dwrite.h"
 
+#include <utility>
 #include <float.h>
 
 #include <wincodec.h>
@@ -226,21 +227,6 @@ RefPtr<IDWriteRenderingParams> DWriteFactory::mDefaultRenderingParams;
 RefPtr<ID2D1Factory> D2DFactory::mFactoryInstance;
 RefPtr<ID2D1DCRenderTarget> D2DFactory::mRenderTarget;
 
-static int
-_quality_from_antialias_mode(cairo_antialias_t antialias)
-{
-    switch (antialias) {
-    case CAIRO_ANTIALIAS_NONE:
-	return NONANTIALIASED_QUALITY;
-    case CAIRO_ANTIALIAS_FAST:
-    case CAIRO_ANTIALIAS_GRAY:
-	return ANTIALIASED_QUALITY;
-    default:
-	break;
-    }
-    return CLEARTYPE_QUALITY;    
-}
-
 static RefPtr<IDWriteRenderingParams>
 _create_rendering_params(IDWriteRenderingParams     *params,
 			 const cairo_font_options_t *options,
@@ -1334,60 +1320,41 @@ _cairo_dwrite_scaled_font_init_glyph_color_surface(cairo_dwrite_scaled_font_t *s
 }
 
 static cairo_int_status_t
-_cairo_dwrite_scaled_font_init_glyph_surface(cairo_dwrite_scaled_font_t *scaled_font,
-					     cairo_scaled_glyph_t	*scaled_glyph)
+_cairo_dwrite_scaled_font_init_glyph_surface (cairo_dwrite_scaled_font_t *scaled_font,
+                                              cairo_scaled_glyph_t       *scaled_glyph)
 {
-    cairo_int_status_t status;
-    cairo_win32_surface_t *surface;
-    cairo_t *cr;
-    cairo_surface_t *image;
-    int width, height;
-    double x1, y1, x2, y2;
+    HRESULT hr;
 
-    x1 = _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.x);
-    y1 = _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.y);
-    x2 = _cairo_fixed_integer_ceil (scaled_glyph->bbox.p2.x);
-    y2 = _cairo_fixed_integer_ceil (scaled_glyph->bbox.p2.y);
-    width = (int)(x2 - x1);
-    height = (int)(y2 - y1);
+    double x1 = _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.x);
+    double y1 = _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.y);
+    double x2 = _cairo_fixed_integer_ceil (scaled_glyph->bbox.p2.x);
+    double y2 = _cairo_fixed_integer_ceil (scaled_glyph->bbox.p2.y);
+    int width = (int)(x2 - x1);
+    int height = (int)(y2 - y1);
+
+    if (width <= 0)
+        width = 1;
+    if (height <= 0)
+        height = 1;
 
-    DWRITE_GLYPH_RUN run;
     FLOAT advance = 0;
     UINT16 index = (UINT16)_cairo_scaled_glyph_index (scaled_glyph);
     DWRITE_GLYPH_OFFSET offset;
     double x = -x1 + .25 * _cairo_scaled_glyph_xphase (scaled_glyph);
     double y = -y1 + .25 * _cairo_scaled_glyph_yphase (scaled_glyph);
-    RECT area;
-    DWRITE_MATRIX matrix;
-
-    surface = (cairo_win32_surface_t *)
-	cairo_win32_surface_create_with_dib (CAIRO_FORMAT_RGB24, width, height);
 
-    cr = cairo_create (&surface->base);
-    cairo_set_source_rgb (cr, 1, 1, 1);
-    cairo_paint (cr);
-    status = (cairo_int_status_t)cairo_status (cr);
-    cairo_destroy(cr);
-    if (status)
-	goto FAIL;
-
-    /*
-     * We transform by the inverse transformation here. This will put our glyph
+    /* We transform by the inverse transformation here. This will put our glyph
      * locations in the space in which we draw. Which is later transformed by
      * the transformation matrix that we use. This will transform the
      * glyph positions back to where they were before when drawing, but the
-     * glyph shapes will be transformed by the transformation matrix.
-     */
+     * glyph shapes will be transformed by the transformation matrix. */
     cairo_matrix_transform_point(&scaled_font->mat_inverse, &x, &y);
     offset.advanceOffset = (FLOAT)x;
-    /* Y-axis is inverted */
-    offset.ascenderOffset = -(FLOAT)y;
+    offset.ascenderOffset = -(FLOAT)y; /* Y axis is inverted */
 
-    area.top = 0;
-    area.bottom = height;
-    area.left = 0;
-    area.right = width;
+    DWRITE_MATRIX matrix = _cairo_dwrite_matrix_from_matrix(&scaled_font->mat);
 
+    DWRITE_GLYPH_RUN run;
     run.glyphCount = 1;
     run.glyphAdvances = &advance;
     run.fontFace = scaled_font->dwriteface;
@@ -1397,29 +1364,370 @@ _cairo_dwrite_scaled_font_init_glyph_surface(cairo_dwrite_scaled_font_t *scaled_
     run.isSideways = FALSE;
     run.glyphOffsets = &offset;
 
-    matrix = _cairo_dwrite_matrix_from_matrix(&scaled_font->mat);
+    // Reduce the many Cairo antialias values to the
+    // three we actually care about: NONE, GRAY, RGB
+    enum {
+        ANTIALIAS_NONE,
+        ANTIALIAS_GRAY,
+        ANTIALIAS_CLEARTYPE,
+    } antialias = ANTIALIAS_CLEARTYPE;
+
+    switch (scaled_font->antialias_mode) {
+        case CAIRO_ANTIALIAS_NONE:
+            antialias = ANTIALIAS_NONE;
+            break;
+        case CAIRO_ANTIALIAS_FAST:
+        case CAIRO_ANTIALIAS_GRAY:
+            antialias = ANTIALIAS_GRAY;
+            break;
+        case CAIRO_ANTIALIAS_DEFAULT:
+        case CAIRO_ANTIALIAS_GOOD:
+        case CAIRO_ANTIALIAS_BEST:
+        case CAIRO_ANTIALIAS_SUBPIXEL:
+            antialias = ANTIALIAS_CLEARTYPE;
+            break;
+    }
+
+    // Set DWrite rendering options
+
+    DWRITE_RENDERING_MODE rendering_mode;
+    DWRITE_RENDERING_MODE1 rendering_mode1;
+    DWRITE_TEXT_ANTIALIAS_MODE text_antialias_mode;
+    DWRITE_TEXTURE_TYPE texture_type;
 
-    status = _dwrite_draw_glyphs_to_gdi_surface_gdi (surface, &matrix, &run,
-            RGB(0,0,0), scaled_font, area);
-    if (status)
-	goto FAIL;
+    switch (antialias) {
+        case ANTIALIAS_NONE:
+            rendering_mode1 = DWRITE_RENDERING_MODE1_ALIASED;
+            rendering_mode = DWRITE_RENDERING_MODE_ALIASED;
+            text_antialias_mode = DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE;
+            texture_type = DWRITE_TEXTURE_ALIASED_1x1;
+            break;
+        case ANTIALIAS_GRAY:
+            rendering_mode1 = DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC;
+            rendering_mode = DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC;
+            text_antialias_mode = DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE;
+            texture_type = DWRITE_TEXTURE_ALIASED_1x1;
+            break;
+        case ANTIALIAS_CLEARTYPE:
+            rendering_mode1 = DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC;
+            rendering_mode = DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC;
+            text_antialias_mode = DWRITE_TEXT_ANTIALIAS_MODE_CLEARTYPE;
+            texture_type = DWRITE_TEXTURE_CLEARTYPE_3x1;
+            break;
+    }
+
+    DWRITE_GRID_FIT_MODE grid_fit_mode = DWRITE_GRID_FIT_MODE_DEFAULT;
+
+    switch (cairo_font_options_get_hint_style (&scaled_font->base.options)) {
+        case CAIRO_HINT_STYLE_DEFAULT:
+            grid_fit_mode = DWRITE_GRID_FIT_MODE_DEFAULT;
+        case CAIRO_HINT_STYLE_NONE:
+            grid_fit_mode = DWRITE_GRID_FIT_MODE_DISABLED;
+        case CAIRO_HINT_STYLE_SLIGHT:
+        case CAIRO_HINT_STYLE_MEDIUM:
+        case CAIRO_HINT_STYLE_FULL:
+            grid_fit_mode = DWRITE_GRID_FIT_MODE_ENABLED;
+    }
+
+    cairo_subpixel_order_t subpixel_order;
+    subpixel_order = cairo_font_options_get_subpixel_order (&scaled_font->base.options);
+
+    bool subpixel_order_is_vertical = false;
+    if (antialias == ANTIALIAS_CLEARTYPE) {
+        switch (subpixel_order) {
+            case CAIRO_SUBPIXEL_ORDER_DEFAULT:
+            case CAIRO_SUBPIXEL_ORDER_RGB:
+            case CAIRO_SUBPIXEL_ORDER_BGR:
+                break;
+            case CAIRO_SUBPIXEL_ORDER_VRGB:
+            case CAIRO_SUBPIXEL_ORDER_VBGR:
+                subpixel_order_is_vertical = true;
+                break;
+        }
+    }
 
-    GdiFlush();
+    if (subpixel_order_is_vertical) {
+        // DirectWrite does not support vertical pixel geometries.
+        // As a workaround, apply a simmetry which swaps x and y
+        // coordinates, then re-swap while copying the back into
+        // the image surface
+
+        // swap the two rows
+        std::swap (matrix.m11, matrix.m21);
+        std::swap (matrix.m12, matrix.m22);
+    }
+
+    RefPtr<IDWriteGlyphRunAnalysis> dwrite_glyph_run_analysis;
+    if (DWriteFactory::Instance3()) {
+        hr = DWriteFactory::Instance3()->CreateGlyphRunAnalysis(&run,
+                                                                &matrix,
+                                                                rendering_mode1,
+                                                                scaled_font->measuring_mode,
+                                                                grid_fit_mode,
+                                                                text_antialias_mode,
+                                                                0, // baselineOriginX,
+                                                                0, // baselineOriginY,
+                                                                &dwrite_glyph_run_analysis);
+    }
+    else if (DWriteFactory::Instance2()) {
+        hr = DWriteFactory::Instance2()->CreateGlyphRunAnalysis(&run,
+                                                                &matrix,
+                                                                rendering_mode,
+                                                                scaled_font->measuring_mode,
+                                                                grid_fit_mode,
+                                                                text_antialias_mode,
+                                                                0, // baselineOriginX,
+                                                                0, // baselineOriginY,
+                                                                &dwrite_glyph_run_analysis);
+    }
+    else {
+        hr = DWriteFactory::Instance()->CreateGlyphRunAnalysis(&run, 1,
+                                                               &matrix,
+                                                               rendering_mode,
+                                                               scaled_font->measuring_mode,
+                                                               0, // baselineOriginX,
+                                                               0, // baselineOriginY,
+                                                               &dwrite_glyph_run_analysis);
+    }
+    if (FAILED(hr))
+       return CAIRO_INT_STATUS_UNSUPPORTED;
 
-    image = _cairo_compute_glyph_mask (&surface->base, _quality_from_antialias_mode(scaled_font->antialias_mode));
-    status = (cairo_int_status_t)image->status;
-    if (status)
-	goto FAIL;
+    cairo_format_t surface_format = antialias == ANTIALIAS_NONE ? CAIRO_FORMAT_A1 :
+                                    antialias == ANTIALIAS_GRAY ? CAIRO_FORMAT_A8 :
+                                    CAIRO_FORMAT_ARGB32;
 
-    cairo_surface_set_device_offset (image, -x1, -y1);
-    _cairo_scaled_glyph_set_surface (scaled_glyph,
-				     &scaled_font->base,
-				     (cairo_image_surface_t *) image);
+    cairo_surface_t *surface = cairo_image_surface_create (surface_format, width, height);
+    if (cairo_surface_status (surface))
+        return CAIRO_INT_STATUS_UNSUPPORTED;
 
-  FAIL:
-    cairo_surface_destroy (&surface->base);
+    // Tell pixman that it should use component alpha blending when the surface is
+    // used as a source
+    pixman_image_set_component_alpha (((cairo_image_surface_t*)surface)->pixman_image, TRUE);
 
-    return status;
+    // That's probably not needed right after creation
+    cairo_surface_flush (surface);
+    unsigned char *surface_data = cairo_image_surface_get_data (surface);
+    int surface_stride = cairo_image_surface_get_stride (surface);
+
+    UINT32 dwrite_data_size;
+    BYTE *dwrite_data;
+    RECT dwrite_rect = {
+        0,       // left
+        0,       // top
+        width,   // right
+        height   // bottom
+    };
+
+    if (subpixel_order_is_vertical) {
+        std::swap (dwrite_rect.right,
+                   dwrite_rect.bottom);
+    }
+
+    // Whether IDWriteGlyphRunAnalysis::CreateAlphaTexture() can render directly
+    // on the cairo image surface (because the pixel formats match) or a separate
+    // buffer is needed
+    bool render_is_direct;
+
+    switch (antialias) {
+        case ANTIALIAS_NONE:
+        {
+            dwrite_data_size = width * height; //TODO: check overflow
+
+            dwrite_data = (BYTE*) _cairo_malloc (dwrite_data_size);
+            if (!dwrite_data)
+                return CAIRO_INT_STATUS_UNSUPPORTED;
+
+            render_is_direct = false;
+            break;
+        }
+        case ANTIALIAS_GRAY:
+        {
+            // The image surface may have a stride that's bigger than width-
+            // account for that by passing stride as width to DWrite. Note:
+            // stride is a byte-size, but here pixel-size is exactly 1 byte.
+            dwrite_rect.right = cairo_image_surface_get_stride (surface);
+
+            dwrite_data_size = dwrite_rect.right * height; //TODO: check overflow
+            dwrite_data = static_cast<BYTE*>(surface_data);
+
+            render_is_direct = true;
+            break;
+        }
+        case ANTIALIAS_CLEARTYPE:
+        {
+            dwrite_data_size = 3 * width * height; //TODO: check overflow
+
+            dwrite_data = (BYTE*) _cairo_malloc (dwrite_data_size);
+            if (!dwrite_data)
+                return CAIRO_INT_STATUS_UNSUPPORTED;
+
+            render_is_direct = false;
+            break;
+        }
+    }
+
+    hr = dwrite_glyph_run_analysis->CreateAlphaTexture(texture_type, &dwrite_rect, dwrite_data, dwrite_data_size);
+    if (FAILED (hr))
+        return CAIRO_INT_STATUS_UNSUPPORTED;
+
+    // Most of the code here was copied and adapted from cairoft-font.c
+    switch (antialias) {
+        case ANTIALIAS_NONE:
+        {
+            unsigned char *src = static_cast<unsigned char*>(dwrite_data);
+            unsigned char *dst = surface_data;
+
+            for (int i = 0; i < height; i++) {
+                unsigned char *d = dst;
+
+                for (int j = 0; j < width / 8; j++) {
+                    *d = (src[0] ? (1 << 0) : 0) +
+                           (src[1] ? (1 << 1) : 0) +
+                           (src[2] ? (1 << 2) : 0) +
+                           (src[3] ? (1 << 3) : 0) +
+                           (src[4] ? (1 << 4) : 0) +
+                           (src[5] ? (1 << 5) : 0) +
+                           (src[6] ? (1 << 6) : 0) +
+                           (src[7] ? (1 << 7) : 0);
+
+                    d++;
+                    src += 8;
+                }
+
+                if (width % 8 != 0) {
+                    *d = 0;
+
+                    for (int k = 0; k < width % 8; k++) {
+                        *d += (src[k] ? (1 << k) : 0);
+                    }
+
+                    d++;
+                    src += (width % 8);
+                }
+
+                dst += surface_stride;
+            }
+            break;
+        }
+        case ANTIALIAS_GRAY:
+        {
+           // Nothing to do
+           break;
+        }
+        case ANTIALIAS_CLEARTYPE:
+        {
+            unsigned char *src = static_cast<unsigned char*>(dwrite_data);
+            unsigned char *dst = surface_data;
+
+            // The alpha channel is unused for component-alpha blending.
+            // Here we set the alpha channel anyway so that things work
+            // even in case of normal blending (but one likely gets some
+            // color fringing)
+
+            switch (subpixel_order) {
+                case CAIRO_SUBPIXEL_ORDER_DEFAULT:
+                case CAIRO_SUBPIXEL_ORDER_RGB:
+                {
+                    for (int i = 0; i < height; i++) {
+                        UINT32 *d = reinterpret_cast<UINT32*>(dst);
+
+                        for (int j = 0; j < width; j++) {
+                            // CAIRO_FORMAT_ARGB32 is BGRA on little-endian
+                            *d = (src[2] << 0) +
+                                 (src[1] << 8) +
+                                 (src[0] << 16) +
+                                 (src[1] << 24); // unused
+
+                            d++;
+                            src += 3;
+                        }
+
+                        dst += surface_stride;
+                    }
+                }
+                break;
+                case CAIRO_SUBPIXEL_ORDER_BGR:
+                {
+                    for (int i = 0; i < height; i++) {
+                        UINT32 *d = reinterpret_cast<UINT32*>(dst);
+
+                        for (int j = 0; j < width; j++) {
+                            *d = (src[0] << 0) +
+                                 (src[1] << 8) +
+                                 (src[2] << 16) +
+                                 (src[1] << 24); // unused
+
+                            d++;
+                            src += 3;
+                        }
+
+                        dst += surface_stride;
+                    }
+                }
+                break;
+                case CAIRO_SUBPIXEL_ORDER_VRGB:
+                {
+                    size_t p;
+
+                    for (int i = 0; i < height; i++) {
+                        UINT32 *d = reinterpret_cast<UINT32*>(dst);
+
+                        p = i * 3;
+                        for (int j = 0; j < width; j++) {
+                            *d = (src[p + 2] << 0) +
+                                 (src[p + 1] << 8) +
+                                 (src[p + 0] << 16) +
+                                 (src[p + 1] << 24); // unused
+
+                            d++;
+                            p += 3 * height;
+                        }
+
+                        dst += surface_stride;
+                    }
+                }
+                break;
+                case CAIRO_SUBPIXEL_ORDER_VBGR:
+                {
+                    size_t p;
+
+                    for (int i = 0; i < height; i++) {
+                        UINT32 *d = reinterpret_cast<UINT32*>(dst);
+
+                        p = i * 3;
+                        for (int j = 0; j < width; j++) {
+                            *d = (src[p + 0] << 0) +
+                                 (src[p + 1] << 8) +
+                                 (src[p + 2] << 16) +
+                                 (src[p + 1] << 24); // unused
+
+                            d++;
+                            p += 3 * height;
+                        }
+
+                        dst += surface_stride;
+                    }
+                }
+                break;
+            }
+
+            break;
+        }
+    }
+
+    // That's probably not needed. cairoft-font.c doesn't do that
+    cairo_surface_mark_dirty (surface);
+
+    if (!render_is_direct) {
+        free (dwrite_data);
+    }
+
+    cairo_surface_set_device_offset (surface, -x1, -y1);
+    _cairo_scaled_glyph_set_surface (scaled_glyph,
+                                     &scaled_font->base,
+                                     (cairo_image_surface_t*)surface);
+
+    return CAIRO_INT_STATUS_SUCCESS;
 }
 
 static cairo_int_status_t
@@ -1828,6 +2136,7 @@ _cairo_dwrite_show_glyphs_on_surface(void			*surface,
     cairo_dwrite_scaled_font_t *dwritesf = reinterpret_cast<cairo_dwrite_scaled_font_t*>(scaled_font);
     cairo_win32_surface_t *dst = reinterpret_cast<cairo_win32_surface_t*>(surface);
     cairo_int_status_t status;
+
     /* We can only handle dwrite fonts */
     if (cairo_scaled_font_get_type (scaled_font) != CAIRO_FONT_TYPE_DWRITE)
 	return CAIRO_INT_STATUS_UNSUPPORTED;
diff --git a/src/win32/cairo-win32-private.h b/src/win32/cairo-win32-private.h
index ae8dc52c3..a9eda8fdb 100644
--- a/src/win32/cairo-win32-private.h
+++ b/src/win32/cairo-win32-private.h
@@ -191,10 +191,6 @@ cairo_bool_t
 _cairo_win32_surface_get_extents (void			  *abstract_surface,
 				  cairo_rectangle_int_t   *rectangle);
 
-cairo_surface_t *
-_cairo_compute_glyph_mask (cairo_surface_t *surface,
-			   int quality);
-
 uint32_t
 _cairo_win32_flags_for_dc (HDC dc, cairo_format_t format);
 
commit 3bfe1eed026bc7ed60c77c58257fead23654ad55
Merge: fe87f1c3f af4f14905
Author: Emmanuele Bassi <ebassi at gmail.com>
Date:   Thu Jan 30 09:31:59 2025 +0000

    Merge branch 'meson' into 'master'
    
    Minor Meson cleanups
    
    See merge request cairo/cairo!584

commit fe87f1c3fb5b8fb031285c38250ff187f3bab0fc
Merge: e2a52c087 864ede8e1
Author: Emmanuele Bassi <ebassi at gmail.com>
Date:   Thu Jan 30 09:29:01 2025 +0000

    Merge branch 'win32-cleanup' into 'master'
    
    Win32 cleanup
    
    See merge request cairo/cairo!605

commit e2a52c0870ad8752002e5de4173c677c60bbb508
Merge: ed7b0a54b b84b3542d
Author: Emmanuele Bassi <ebassi at gmail.com>
Date:   Thu Jan 30 09:26:49 2025 +0000

    Merge branch 'dwrite-font-variations' into 'master'
    
    DWrite: Add support for font variations
    
    Closes #877
    
    See merge request cairo/cairo!601

commit ed7b0a54b9e86f3aea04a42ca99ab4526027f2ed
Merge: 727966dfc e0287e09f
Author: Emmanuele Bassi <ebassi at gmail.com>
Date:   Thu Jan 30 09:25:57 2025 +0000

    Merge branch 'dwrite-fix-warnings' into 'master'
    
    DWrite: Fix warnings
    
    See merge request cairo/cairo!603

commit e0287e09f41fc7d063d2e3d707a5e5a5521b6f85
Author: Luca Bacci <luca.bacci982 at gmail.com>
Date:   Thu Jan 16 12:13:39 2025 +0100

    DWrite/GeometryRecorder: Add final specifier

diff --git a/src/win32/cairo-dwrite-font.cpp b/src/win32/cairo-dwrite-font.cpp
index a69adec0b..92d2980cd 100644
--- a/src/win32/cairo-dwrite-font.cpp
+++ b/src/win32/cairo-dwrite-font.cpp
@@ -838,7 +838,8 @@ _cairo_dwrite_scaled_font_init_glyph_metrics(cairo_dwrite_scaled_font_t *scaled_
  * Used to determine the path of the glyphs.
  */
 
-class GeometryRecorder : public IDWriteGeometrySink
+class GeometryRecorder final
+    : public IDWriteGeometrySink
 {
 public:
     GeometryRecorder(cairo_path_fixed_t *aCairoPath, const cairo_matrix_t &matrix)
commit 46153a04087d1bef8f2ef3da3cb14e1b97bf4a6c
Author: Luca Bacci <luca.bacci982 at gmail.com>
Date:   Thu Jan 16 12:02:27 2025 +0100

    DWrite/GeometryRecorder: Complete implementation of QueryInterface
    
    ...by checking for IUnknown.
    
    This makes GeometryRecorder::QueryInterface compliant with the
    rules of COM.
    
    QueryInterface for IUnknown has a special meaning in COM: it's
    used to check whether two interface pointers refer to the same
    object.

diff --git a/src/win32/cairo-dwrite-font.cpp b/src/win32/cairo-dwrite-font.cpp
index 36d6b5c7b..a69adec0b 100644
--- a/src/win32/cairo-dwrite-font.cpp
+++ b/src/win32/cairo-dwrite-font.cpp
@@ -845,15 +845,18 @@ public:
 	: mCairoPath(aCairoPath)
 	, mMatrix(matrix) {}
 
-    // IUnknown interface
     IFACEMETHOD (QueryInterface)(IID const& iid, OUT void** ppObject) noexcept override
     {
-	if (iid != __uuidof(IDWriteGeometrySink))
-	    return E_NOINTERFACE;
-
-	*ppObject = static_cast<IDWriteGeometrySink*>(this);
-
-	return S_OK;
+        if (iid == __uuidof (IUnknown) ||
+            iid == __uuidof (IDWriteGeometrySink))
+        {
+            AddRef();
+            *ppObject = this;
+            return S_OK;
+        }
+
+        *ppObject = nullptr;
+        return E_NOINTERFACE;
     }
 
     IFACEMETHOD_(ULONG, AddRef)() noexcept override
commit 59197e779106985fb14625159318b0d48afb9882
Author: Luca Bacci <luca.bacci982 at gmail.com>
Date:   Thu Jan 16 11:52:52 2025 +0100

    DWrite/GeometryRecorder: Add noexcept specifier
    
    STDMETHOD / IFACEMETHOD macros already add __declspec(nothrow), but
    noexcept is better. From MSDN [1]:
    
      We recommend that all new code use the noexcept operator rather than
      __declspec(nothrow).
      This attribute tells the compiler that the declared function and the
      functions it calls never throw an exception. However, it does not
      enforce the directive. In other words, it never causes std::terminate
      to be invoked, unlike noexcept, or in std:c++17 mode (Visual Studio
      2017 version 15.5 and later), throw().
    
    See also [2]:
    
      Non-throwing functions are permitted to call potentially-throwing
      functions. Whenever an exception is thrown and the search for a handler
      encounters the outermost block of a non-throwing function, the function
      std::terminate is called:
    
      extern void f(); // potentially-throwing
    
      void g() noexcept {
        f();      // valid, even if f throws
        throw 42; // valid, effectively a call to std::terminate
      }
    
    References:
    
     [1] https://learn.microsoft.com/en-us/cpp/cpp/nothrow-cpp?view=msvc-170
     [2] https://en.cppreference.com/w/cpp/language/noexcept_spec

diff --git a/src/win32/cairo-dwrite-font.cpp b/src/win32/cairo-dwrite-font.cpp
index f20df6de9..36d6b5c7b 100644
--- a/src/win32/cairo-dwrite-font.cpp
+++ b/src/win32/cairo-dwrite-font.cpp
@@ -846,7 +846,7 @@ public:
 	, mMatrix(matrix) {}
 
     // IUnknown interface
-    IFACEMETHOD (QueryInterface)(IID const& iid, OUT void** ppObject) override
+    IFACEMETHOD (QueryInterface)(IID const& iid, OUT void** ppObject) noexcept override
     {
 	if (iid != __uuidof(IDWriteGeometrySink))
 	    return E_NOINTERFACE;
@@ -856,34 +856,34 @@ public:
 	return S_OK;
     }
 
-    IFACEMETHOD_(ULONG, AddRef)() override
+    IFACEMETHOD_(ULONG, AddRef)() noexcept override
     {
 	return 1;
     }
 
-    IFACEMETHOD_(ULONG, Release)() override
+    IFACEMETHOD_(ULONG, Release)() noexcept override
     {
 	return 1;
     }
 
-    IFACEMETHOD_(void, SetFillMode)(D2D1_FILL_MODE fillMode) override
+    IFACEMETHOD_(void, SetFillMode)(D2D1_FILL_MODE fillMode) noexcept override
     {
 	return;
     }
 
-    IFACEMETHOD (Close)() override
+    IFACEMETHOD (Close)() noexcept override
     {
 	return S_OK;
     }
 
-    IFACEMETHOD_(void, SetSegmentFlags)(D2D1_PATH_SEGMENT vertexFlags) override
+    IFACEMETHOD_(void, SetSegmentFlags)(D2D1_PATH_SEGMENT vertexFlags) noexcept override
     {
 	return;
     }
 
     IFACEMETHOD_(void, BeginFigure)(
 	D2D1_POINT_2F startPoint,
-	D2D1_FIGURE_BEGIN figureBegin) override
+	D2D1_FIGURE_BEGIN figureBegin) noexcept override
     {
 	double x = startPoint.x;
 	double y = startPoint.y;
@@ -897,7 +897,7 @@ public:
     }
 
     IFACEMETHOD_(void, EndFigure)(
-	D2D1_FIGURE_END figureEnd) override
+	D2D1_FIGURE_END figureEnd) noexcept override
     {
 	if (figureEnd == D2D1_FIGURE_END_CLOSED) {
 	    cairo_status_t status = _cairo_path_fixed_line_to(mCairoPath,
@@ -909,7 +909,7 @@ public:
 
     IFACEMETHOD_(void, AddBeziers)(
 	const D2D1_BEZIER_SEGMENT *beziers,
-	UINT beziersCount) override
+	UINT beziersCount) noexcept override
     {
 	for (unsigned int i = 0; i < beziersCount; i++) {
 	    double x1 = beziers[i].point1.x;
@@ -934,7 +934,7 @@ public:
 
     IFACEMETHOD_(void, AddLines)(
 	const D2D1_POINT_2F *points,
-	UINT pointsCount) override
+	UINT pointsCount) noexcept override
     {
 	for (unsigned int i = 0; i < pointsCount; i++) {
 	    double x = points[i].x;
commit 8107086c6a8d52a2b86352e86b32799885a3b746
Author: Luca Bacci <luca.bacci982 at gmail.com>
Date:   Thu Jan 16 11:37:39 2025 +0100

    DWrite/GeometryRecorder: Add override specifier
    
    IFACEMETHOD already adds the __override / __allowed(on_function) SAL
    annotation (only on Windows SDK, not mingw-w64), which is understood
    by some code analysis tools [1]. Since we're compiling in C++11 mode,
    we can add the override specifier, so that the compiler is informed
    as well.
    
    [1] https://devblogs.microsoft.com/oldnewthing/20200911-00/?p=104205

diff --git a/src/win32/cairo-dwrite-font.cpp b/src/win32/cairo-dwrite-font.cpp
index bcff2d42a..f20df6de9 100644
--- a/src/win32/cairo-dwrite-font.cpp
+++ b/src/win32/cairo-dwrite-font.cpp
@@ -846,7 +846,7 @@ public:
 	, mMatrix(matrix) {}
 
     // IUnknown interface
-    IFACEMETHOD (QueryInterface)(IID const& iid, OUT void** ppObject)
+    IFACEMETHOD (QueryInterface)(IID const& iid, OUT void** ppObject) override
     {
 	if (iid != __uuidof(IDWriteGeometrySink))
 	    return E_NOINTERFACE;
@@ -856,34 +856,34 @@ public:
 	return S_OK;
     }
 
-    IFACEMETHOD_(ULONG, AddRef)()
+    IFACEMETHOD_(ULONG, AddRef)() override
     {
 	return 1;
     }
 
-    IFACEMETHOD_(ULONG, Release)()
+    IFACEMETHOD_(ULONG, Release)() override
     {
 	return 1;
     }
 
-    IFACEMETHOD_(void, SetFillMode)(D2D1_FILL_MODE fillMode)
+    IFACEMETHOD_(void, SetFillMode)(D2D1_FILL_MODE fillMode) override
     {
 	return;
     }
 
-    IFACEMETHOD (Close)()
+    IFACEMETHOD (Close)() override
     {
 	return S_OK;
     }
 
-    IFACEMETHOD_(void, SetSegmentFlags)(D2D1_PATH_SEGMENT vertexFlags)
+    IFACEMETHOD_(void, SetSegmentFlags)(D2D1_PATH_SEGMENT vertexFlags) override
     {
 	return;
     }
 
     IFACEMETHOD_(void, BeginFigure)(
 	D2D1_POINT_2F startPoint,
-	D2D1_FIGURE_BEGIN figureBegin)
+	D2D1_FIGURE_BEGIN figureBegin) override
     {
 	double x = startPoint.x;
 	double y = startPoint.y;
@@ -897,7 +897,7 @@ public:
     }
 
     IFACEMETHOD_(void, EndFigure)(
-	D2D1_FIGURE_END figureEnd)
+	D2D1_FIGURE_END figureEnd) override
     {
 	if (figureEnd == D2D1_FIGURE_END_CLOSED) {
 	    cairo_status_t status = _cairo_path_fixed_line_to(mCairoPath,
@@ -909,7 +909,7 @@ public:
 
     IFACEMETHOD_(void, AddBeziers)(
 	const D2D1_BEZIER_SEGMENT *beziers,
-	UINT beziersCount)
+	UINT beziersCount) override
     {
 	for (unsigned int i = 0; i < beziersCount; i++) {
 	    double x1 = beziers[i].point1.x;
@@ -934,7 +934,7 @@ public:
 
     IFACEMETHOD_(void, AddLines)(
 	const D2D1_POINT_2F *points,
-	UINT pointsCount)
+	UINT pointsCount) override
     {
 	for (unsigned int i = 0; i < pointsCount; i++) {
 	    double x = points[i].x;
commit bdac72997480b9e71e1f341d8e09388703f1bde3
Author: Luca Bacci <luca.bacci982 at gmail.com>
Date:   Wed Jan 8 11:20:08 2025 +0100

    DWrite/GeometryRecorder: Use IFACEMETHOD consistently
    
    Fixes the following warnings on CLang:
    
      ../cairo/src/win32/cairo-dwrite-font.cpp:869:27: warning: exception specification
      of overriding function is more lax than base version [-Wmicrosoft-exception-spec]
        869 |     IFACEMETHODIMP_(void) SetFillMode(D2D1_FILL_MODE fillMode)
            |                           ^
      D:/msys64/clang64/include/d2d1.h:1491:22: note: overridden virtual function is here
       1491 |     STDMETHOD_(void, SetFillMode)(D2D1_FILL_MODE fillMode) PURE;
            |
    
    COM objects are usually implemented like that:
    
    1. The class is defined with only method declarations. For that,
       one should use IFACEMETHOD macros.
    2. Then methods are implemented (defined), outside of the class
       definition. For that, one should use the IFACEMETHODIMP macros
    
    If one really wants to provide inline method definitions (that is,
    inside the class definition), then IFACEMETHOD macros should be used
    (and not IFACEMETHODIMP, though it's a definition / implementation).

diff --git a/src/win32/cairo-dwrite-font.cpp b/src/win32/cairo-dwrite-font.cpp
index ba1695259..bcff2d42a 100644
--- a/src/win32/cairo-dwrite-font.cpp
+++ b/src/win32/cairo-dwrite-font.cpp
@@ -846,7 +846,7 @@ public:
 	, mMatrix(matrix) {}
 
     // IUnknown interface
-    IFACEMETHOD(QueryInterface)(IID const& iid, OUT void** ppObject)
+    IFACEMETHOD (QueryInterface)(IID const& iid, OUT void** ppObject)
     {
 	if (iid != __uuidof(IDWriteGeometrySink))
 	    return E_NOINTERFACE;
@@ -866,22 +866,22 @@ public:
 	return 1;
     }
 
-    IFACEMETHODIMP_(void) SetFillMode(D2D1_FILL_MODE fillMode)
+    IFACEMETHOD_(void, SetFillMode)(D2D1_FILL_MODE fillMode)
     {
 	return;
     }
 
-    STDMETHODIMP Close()
+    IFACEMETHOD (Close)()
     {
 	return S_OK;
     }
 
-    IFACEMETHODIMP_(void) SetSegmentFlags(D2D1_PATH_SEGMENT vertexFlags)
+    IFACEMETHOD_(void, SetSegmentFlags)(D2D1_PATH_SEGMENT vertexFlags)
     {
 	return;
     }
 
-    IFACEMETHODIMP_(void) BeginFigure(
+    IFACEMETHOD_(void, BeginFigure)(
 	D2D1_POINT_2F startPoint,
 	D2D1_FIGURE_BEGIN figureBegin)
     {
@@ -896,7 +896,7 @@ public:
 	(void)status; /* squelch warning */
     }
 
-    IFACEMETHODIMP_(void) EndFigure(
+    IFACEMETHOD_(void, EndFigure)(
 	D2D1_FIGURE_END figureEnd)
     {
 	if (figureEnd == D2D1_FIGURE_END_CLOSED) {
@@ -907,7 +907,7 @@ public:
 	}
     }
 
-    IFACEMETHODIMP_(void) AddBeziers(
+    IFACEMETHOD_(void, AddBeziers)(
 	const D2D1_BEZIER_SEGMENT *beziers,
 	UINT beziersCount)
     {
@@ -932,7 +932,7 @@ public:
 	}
     }
 
-    IFACEMETHODIMP_(void) AddLines(
+    IFACEMETHOD_(void, AddLines)(
 	const D2D1_POINT_2F *points,
 	UINT pointsCount)
     {
commit 864ede8e1a8e9205d7c75d3a6ea3360282121ba5
Author: Luca Bacci <luca.bacci982 at gmail.com>
Date:   Thu Jan 16 18:08:55 2025 +0100

    Win32: Load system DLLs from System32

diff --git a/src/win32/cairo-dwrite-font.cpp b/src/win32/cairo-dwrite-font.cpp
index 74d12c6a0..bc8177fd9 100644
--- a/src/win32/cairo-dwrite-font.cpp
+++ b/src/win32/cairo-dwrite-font.cpp
@@ -137,8 +137,9 @@ public:
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wcast-function-type"
 #endif
+            HMODULE d2d1 = _cairo_win32_load_library_from_system32 (L"d2d1.dll");
 	    D2D1CreateFactoryFunc createD2DFactory = (D2D1CreateFactoryFunc)
-		GetProcAddress(LoadLibraryW(L"d2d1.dll"), "D2D1CreateFactory");
+                GetProcAddress(d2d1, "D2D1CreateFactory");
 #ifdef __GNUC__
 #pragma GCC diagnostic pop
 #endif
diff --git a/src/win32/cairo-dwrite-private.hpp b/src/win32/cairo-dwrite-private.hpp
index c7a24822a..3e0d9a14e 100644
--- a/src/win32/cairo-dwrite-private.hpp
+++ b/src/win32/cairo-dwrite-private.hpp
@@ -83,8 +83,9 @@ public:
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wcast-function-type"
 #endif
+            HMODULE dwrite = _cairo_win32_load_library_from_system32 (L"dwrite.dll");
 	    DWriteCreateFactoryFunc createDWriteFactory = (DWriteCreateFactoryFunc)
-		GetProcAddress(LoadLibraryW(L"dwrite.dll"), "DWriteCreateFactory");
+                GetProcAddress(dwrite, "DWriteCreateFactory");
 #ifdef __GNUC__
 #pragma GCC diagnostic pop
 #endif
diff --git a/src/win32/cairo-win32-private.h b/src/win32/cairo-win32-private.h
index 6dd60f1f0..ae8dc52c3 100644
--- a/src/win32/cairo-win32-private.h
+++ b/src/win32/cairo-win32-private.h
@@ -237,6 +237,9 @@ _cairo_win32_scaled_font_is_bitmap (cairo_scaled_font_t *scaled_font);
 cairo_public BYTE
 cairo_win32_get_system_text_quality (void);
 
+HMODULE
+_cairo_win32_load_library_from_system32 (const wchar_t *name);
+
 #if CAIRO_HAS_DWRITE_FONT
 
 cairo_int_status_t
diff --git a/src/win32/cairo-win32-system.c b/src/win32/cairo-win32-system.c
index 6ea14ebed..c5ef24e8d 100644
--- a/src/win32/cairo-win32-system.c
+++ b/src/win32/cairo-win32-system.c
@@ -79,6 +79,34 @@ _cairo_win32_print_api_error (const char *context, const char *api)
     return _cairo_error (CAIRO_STATUS_WIN32_GDI_ERROR);
 }
 
+/**
+ * _cairo_win32_load_library_from_system32:
+ * @name: name of the module to load from System32
+ *
+ * Helper function to load system modules in the System32
+ * folder.
+ *
+ * Return value: An module HANDLE, NULL on error.
+ **/
+HMODULE
+_cairo_win32_load_library_from_system32 (const wchar_t *name)
+{
+    HMODULE module_handle;
+
+    module_handle = LoadLibraryExW (name, NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
+    if (module_handle == NULL) {
+        DWORD code = GetLastError();
+        if (code == ERROR_INVALID_PARAMETER) {
+            /* Support for flag LOAD_LIBRARY_SEARCH_SYSTEM32 was backported
+             * to Windows Vista / 7 with Update KB2533623. If the flag is
+             * not supported, simply use LoadLibrary */
+            return LoadLibraryW (name);
+        }
+    }
+
+    return module_handle;
+}
+
 #if CAIRO_MUTEX_IMPL_WIN32
 
 static void NTAPI
commit 995c09ba67f47e17b883ac0dc4f5a849f100f600
Author: Luca Bacci <luca.bacci982 at gmail.com>
Date:   Tue Jan 21 11:29:05 2025 +0100

    Win32: Avoid library finalization on process termination
    
    Library finalization should be done only for explicit library
    unloads (dlclose / FreeLibrary), not for process termination.

diff --git a/src/win32/cairo-win32-system.c b/src/win32/cairo-win32-system.c
index ae1489ac6..6ea14ebed 100644
--- a/src/win32/cairo-win32-system.c
+++ b/src/win32/cairo-win32-system.c
@@ -90,7 +90,9 @@ cairo_win32_tls_callback (PVOID hinstance, DWORD dwReason, PVOID lpvReserved)
             break;
 
         case DLL_PROCESS_DETACH:
-            CAIRO_MUTEX_FINALIZE ();
+            if (lpvReserved == NULL) {
+                CAIRO_MUTEX_FINALIZE ();
+            }
             break;
     }
 }
commit 1e5740c75631310adb83992ed61438a08df914bd
Author: Luca Bacci <luca.bacci982 at gmail.com>
Date:   Tue Jan 21 11:25:06 2025 +0100

    Revert "win32: Initialize mutexes for static builds for win32"
    
    This reverts commit 5f90f0a706206ea3b940392bf1492fead832d99b.
    
    This is not needed anymore now that we have TLS callbacks.

diff --git a/src/win32/cairo-win32-device.c b/src/win32/cairo-win32-device.c
index c55b0789e..91ef74588 100644
--- a/src/win32/cairo-win32-device.c
+++ b/src/win32/cairo-win32-device.c
@@ -81,8 +81,6 @@ _cairo_win32_device_get (void)
 {
     cairo_win32_device_t *device;
 
-    CAIRO_MUTEX_INITIALIZE ();
-
     if (__cairo_win32_device)
 	return cairo_device_reference (__cairo_win32_device);
 
commit 3921eb96be5071405f898ee7cd36f50a96d15a5c
Author: Luca Bacci <luca.bacci982 at gmail.com>
Date:   Thu Jan 16 18:01:07 2025 +0100

    Win32: Use TLS callback for module initialization and finalization
    
    TLS callbacks are pretty much like DllMain but work also in
    static builds.

diff --git a/src/win32/cairo-win32-system.c b/src/win32/cairo-win32-system.c
index 7163d4470..ae1489ac6 100644
--- a/src/win32/cairo-win32-system.c
+++ b/src/win32/cairo-win32-system.c
@@ -80,20 +80,11 @@ _cairo_win32_print_api_error (const char *context, const char *api)
 }
 
 #if CAIRO_MUTEX_IMPL_WIN32
-#if !CAIRO_WIN32_STATIC_BUILD
-
-/* declare to avoid "no previous prototype for 'DllMain'" warning */
-BOOL WINAPI
-DllMain (HINSTANCE hinstDLL,
-         DWORD     fdwReason,
-         LPVOID    lpvReserved);
-
-BOOL WINAPI
-DllMain (HINSTANCE hinstDLL,
-         DWORD     fdwReason,
-         LPVOID    lpvReserved)
+
+static void NTAPI
+cairo_win32_tls_callback (PVOID hinstance, DWORD dwReason, PVOID lpvReserved)
 {
-    switch (fdwReason) {
+    switch (dwReason) {
         case DLL_PROCESS_ATTACH:
             CAIRO_MUTEX_INITIALIZE ();
             break;
@@ -102,9 +93,50 @@ DllMain (HINSTANCE hinstDLL,
             CAIRO_MUTEX_FINALIZE ();
             break;
     }
-
-    return TRUE;
 }
 
+#ifdef _MSC_VER
+
+#ifdef _M_IX86
+# define SYMBOL_PREFIX "_"
+#else
+# define SYMBOL_PREFIX ""
 #endif
+
+#ifdef __cplusplus
+# define EXTERN_C_BEGIN extern "C" {
+# define EXTERN_C_END }
+# define EXTERN_CONST extern const
+#else
+# define EXTERN_C_BEGIN
+# define EXTERN_C_END
+# define EXTERN_CONST const
 #endif
+
+#define DEFINE_TLS_CALLBACK(func) \
+__pragma (section (".CRT$XLD", long, read))                          \
+                                                                     \
+static void NTAPI func (PVOID, DWORD, PVOID);                        \
+                                                                     \
+EXTERN_C_BEGIN                                                       \
+__declspec (allocate (".CRT$XLD"))                                   \
+EXTERN_CONST PIMAGE_TLS_CALLBACK _ptr_##func = func;                 \
+EXTERN_C_END                                                         \
+                                                                     \
+__pragma (comment (linker, "/INCLUDE:" SYMBOL_PREFIX "_tls_used"))   \
+__pragma (comment (linker, "/INCLUDE:" SYMBOL_PREFIX "_ptr_" #func))
+
+#else /* _MSC_VER */
+
+#define DEFINE_TLS_CALLBACK(func) \
+static void NTAPI func (PVOID, DWORD, PVOID);        \
+                                                     \
+__attribute__ ((used, section (".CRT$XLD")))         \
+static const PIMAGE_TLS_CALLBACK _ptr_##func = func;
+
+
+#endif /* !_MSC_VER */
+
+DEFINE_TLS_CALLBACK (cairo_win32_tls_callback);
+
+#endif /* CAIRO_MUTEX_IMPL_WIN32 */
commit 3bc6b616a46655ded95a6f5e016f43ca30be96d7
Author: Luca Bacci <luca.bacci982 at gmail.com>
Date:   Thu Jan 16 17:33:52 2025 +0100

    Win32: Rename _cairo_win32_print_gdi_error function
    
    ...to _cairo_win32_print_api_error, since it should not be used
    with most GDI functions. Also move the function definition to
    cairo-win32-system.c and change argument signature.

diff --git a/src/win32/cairo-win32-display-surface.c b/src/win32/cairo-win32-display-surface.c
index 8be03c03c..7f0770b4f 100644
--- a/src/win32/cairo-win32-display-surface.c
+++ b/src/win32/cairo-win32-display-surface.c
@@ -210,7 +210,7 @@ _create_dc_and_bitmap (cairo_win32_display_surface_t *surface,
 					&bits,
 					NULL, 0);
     if (!surface->bitmap) {
-        _cairo_win32_print_gdi_error ("_create_dc_and_bitmap:CreateDIBSection");
+        _cairo_win32_print_api_error (__FUNCTION__, "CreateDIBSection");
 	goto FAIL;
     }
 
@@ -549,7 +549,7 @@ _cairo_win32_display_surface_flush (void *abstract_surface, unsigned flags)
 			 fallback->win32.dc,
 			 surface->win32.extents.x, surface->win32.extents.y,
 			 SRCCOPY))
-                status = _cairo_win32_print_gdi_error ("_cairo_win32_display_surface_flush:BitBlt");
+                status = _cairo_win32_print_api_error (__FUNCTION__, "BitBlt");
 	} else if (damage->region) {
 	    int n = cairo_region_num_rectangles (damage->region), i;
 	    for (i = 0; i < n; i++) {
@@ -566,7 +566,7 @@ _cairo_win32_display_surface_flush (void *abstract_surface, unsigned flags)
 			     fallback->win32.dc,
 			     rect.x, rect.y,
 			     SRCCOPY)) {
-                    status = _cairo_win32_print_gdi_error ("_cairo_win32_display_surface_flush:BitBlt");
+                    status = _cairo_win32_print_api_error (__FUNCTION__, "BitBlt");
 		    break;
 		}
 	    }
diff --git a/src/win32/cairo-win32-font.c b/src/win32/cairo-win32-font.c
index d1ad087f9..1412c8bbc 100644
--- a/src/win32/cairo-win32-font.c
+++ b/src/win32/cairo-win32-font.c
@@ -258,7 +258,7 @@ _have_cleartype_quality (void)
     version_info.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
 
     if (!GetVersionEx (&version_info)) {
-	_cairo_win32_print_gdi_error ("_have_cleartype_quality");
+        _cairo_win32_print_api_error (__FUNCTION__, "GetVersionEx");
 	return FALSE;
     }
 
@@ -274,7 +274,7 @@ cairo_win32_get_system_text_quality (void)
     UINT smoothing_type;
 
     if (!SystemParametersInfo (SPI_GETFONTSMOOTHING, 0, &font_smoothing, 0)) {
-	_cairo_win32_print_gdi_error ("_get_system_quality");
+        _cairo_win32_print_api_error (__FUNCTION__, "SystemParametersInfo");
 	return DEFAULT_QUALITY;
     }
 
@@ -282,7 +282,7 @@ cairo_win32_get_system_text_quality (void)
 	if (_have_cleartype_quality ()) {
 	    if (!SystemParametersInfo (SPI_GETFONTSMOOTHINGTYPE,
 				       0, &smoothing_type, 0)) {
-		_cairo_win32_print_gdi_error ("_get_system_quality");
+                _cairo_win32_print_api_error (__FUNCTION__, "SystemParametersInfo");
 		return DEFAULT_QUALITY;
 	    }
 
diff --git a/src/win32/cairo-win32-private.h b/src/win32/cairo-win32-private.h
index 4e180a81e..6dd60f1f0 100644
--- a/src/win32/cairo-win32-private.h
+++ b/src/win32/cairo-win32-private.h
@@ -176,7 +176,7 @@ const cairo_compositor_t *
 _cairo_win32_gdi_compositor_get (void);
 
 cairo_status_t
-_cairo_win32_print_gdi_error (const char *context);
+_cairo_win32_print_api_error (const char *context, const char *api);
 
 cairo_bool_t
 _cairo_surface_is_win32 (const cairo_surface_t *surface);
diff --git a/src/win32/cairo-win32-surface.c b/src/win32/cairo-win32-surface.c
index 8e22996da..e1ac51558 100644
--- a/src/win32/cairo-win32-surface.c
+++ b/src/win32/cairo-win32-surface.c
@@ -79,41 +79,6 @@
  * Since: 1.0
  **/
 
-/**
- * _cairo_win32_print_gdi_error:
- * @context: context string to display along with the error
- *
- * Helper function to dump out a human readable form of the
- * current error code.
- *
- * Return value: A cairo status code for the error code
- **/
-cairo_status_t
-_cairo_win32_print_gdi_error (const char *context)
-{
-    void *lpMsgBuf;
-    DWORD last_error = GetLastError ();
-
-    if (!FormatMessageW (FORMAT_MESSAGE_ALLOCATE_BUFFER |
-                         FORMAT_MESSAGE_IGNORE_INSERTS |
-			 FORMAT_MESSAGE_FROM_SYSTEM,
-			 NULL,
-			 last_error,
-			 MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
-			 (LPWSTR) &lpMsgBuf,
-			 0, NULL)) {
-	fprintf (stderr, "%s: Unknown GDI error", context);
-    } else {
-	fprintf (stderr, "%s: %S", context, (wchar_t *)lpMsgBuf);
-
-	LocalFree (lpMsgBuf);
-    }
-
-    fflush (stderr);
-
-    return _cairo_error (CAIRO_STATUS_WIN32_GDI_ERROR);
-}
-
 cairo_bool_t
 _cairo_win32_surface_get_extents (void		          *abstract_surface,
 				  cairo_rectangle_int_t   *rectangle)
diff --git a/src/win32/cairo-win32-system.c b/src/win32/cairo-win32-system.c
index 01bbe89df..7163d4470 100644
--- a/src/win32/cairo-win32-system.c
+++ b/src/win32/cairo-win32-system.c
@@ -44,14 +44,44 @@
  * And no other function should live here.
  */
 
-
 #include "cairoint.h"
 
+#include <windows.h>
+
+/**
+ * _cairo_win32_print_api_error:
+ * @context: context string to display along with the error
+ * @api: name of the failing api
+ *
+ * Helper function to dump out a human readable form of the
+ * current error code.
+ *
+ * Return value: A cairo status code for the error code
+ **/
+cairo_status_t
+_cairo_win32_print_api_error (const char *context, const char *api)
+{
+    const DWORD lang_id = MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT);
+    const DWORD flags = FORMAT_MESSAGE_ALLOCATE_BUFFER |
+                        FORMAT_MESSAGE_IGNORE_INSERTS |
+                        FORMAT_MESSAGE_FROM_SYSTEM;
+    const DWORD last_error = GetLastError ();
+    void *lpMsgBuf = NULL;
+
+    if (!FormatMessageW (flags, NULL, last_error, lang_id, (LPWSTR) &lpMsgBuf, 0, NULL)) {
+       fprintf (stderr, "%s: %s failed with error code %lu\n", context, api, last_error);
+    }
+    else {
+       fprintf (stderr, "%s: %s failed - %S\n", context, api, (wchar_t *)lpMsgBuf);
+       LocalFree (lpMsgBuf);
+    }
+
+    return _cairo_error (CAIRO_STATUS_WIN32_GDI_ERROR);
+}
+
 #if CAIRO_MUTEX_IMPL_WIN32
 #if !CAIRO_WIN32_STATIC_BUILD
 
-#include <windows.h>
-
 /* declare to avoid "no previous prototype for 'DllMain'" warning */
 BOOL WINAPI
 DllMain (HINSTANCE hinstDLL,
commit 85f308f690f522e2f69e489c3f54587cf20d2c01
Author: Luca Bacci <luca.bacci982 at gmail.com>
Date:   Thu Jan 16 14:44:01 2025 +0100

    Win32: Avoid checking the last error for GDI functions that don't set it
    
    Most GDI functions do not set the last error, so GetLastError() returns
    unrelated error codes. There are some exceptions, however, like BitBlt
    and CreateDIBSection.
    
    Whether a GDI function sets the last error is stated in the reference
    documentation on MSDN.

diff --git a/boilerplate/cairo-boilerplate-win32-printing.c b/boilerplate/cairo-boilerplate-win32-printing.c
index a156deb24..9177480fc 100644
--- a/boilerplate/cairo-boilerplate-win32-printing.c
+++ b/boilerplate/cairo-boilerplate-win32-printing.c
@@ -36,36 +36,6 @@
 
 #include <windows.h>
 
-static cairo_status_t
-_cairo_win32_print_gdi_error (const char *context)
-{
-    void *lpMsgBuf;
-    DWORD last_error = GetLastError ();
-
-    if (!FormatMessageW (FORMAT_MESSAGE_ALLOCATE_BUFFER |
-                         FORMAT_MESSAGE_IGNORE_INSERTS |
-			 FORMAT_MESSAGE_FROM_SYSTEM,
-			 NULL,
-			 last_error,
-			 MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
-			 (LPWSTR) &lpMsgBuf,
-			 0, NULL)) {
-	fprintf (stderr, "%s: Unknown GDI error", context);
-    } else {
-	fprintf (stderr, "%s: %S", context, (wchar_t *)lpMsgBuf);
-
-	LocalFree (lpMsgBuf);
-    }
-
-    fflush (stderr);
-
-    /* We should switch off of last_status, but we'd either return
-     * CAIRO_STATUS_NO_MEMORY or CAIRO_STATUS_UNKNOWN_ERROR and there
-     * is no CAIRO_STATUS_UNKNOWN_ERROR.
-     */
-    return CAIRO_STATUS_NO_MEMORY;
-}
-
 static cairo_user_data_key_t win32_closure_key;
 
 typedef struct _win32_target_closure {
@@ -159,7 +129,7 @@ create_printer_dc (win32_target_closure_t *ptc)
     xform.eDx = 0;
     xform.eDy = printable_height - ptc->height*y_dpi/72.0;
     if (!SetWorldTransform (ptc->dc, &xform)) {
-	_cairo_win32_print_gdi_error ("cairo-boilerplate-win32-printing:SetWorldTransform");
+        fprintf (stderr, "%s:%s\n", "cairo-boilerplate-win32-printing", "SetWorldTransform");
 	return;
     }
 
diff --git a/src/win32/cairo-win32-display-surface.c b/src/win32/cairo-win32-display-surface.c
index 4f4e8f847..8be03c03c 100644
--- a/src/win32/cairo-win32-display-surface.c
+++ b/src/win32/cairo-win32-display-surface.c
@@ -95,8 +95,6 @@ _create_dc_and_bitmap (cairo_win32_display_surface_t *surface,
 		       unsigned char        **bits_out,
 		       int                   *rowstride_out)
 {
-    cairo_status_t status;
-
     BITMAPINFO *bitmap_info = NULL;
     struct {
 	BITMAPINFOHEADER bmiHeader;
@@ -201,16 +199,20 @@ _create_dc_and_bitmap (cairo_win32_display_surface_t *surface,
     }
 
     surface->win32.dc = CreateCompatibleDC (original_dc);
-    if (!surface->win32.dc)
+    if (!surface->win32.dc) {
+        fprintf (stderr, "%s:%s\n", __FUNCTION__, "CreateCompatibleDC");
 	goto FAIL;
+    }
 
     surface->bitmap = CreateDIBSection (surface->win32.dc,
 					bitmap_info,
 					DIB_RGB_COLORS,
 					&bits,
 					NULL, 0);
-    if (!surface->bitmap)
+    if (!surface->bitmap) {
+        _cairo_win32_print_gdi_error ("_create_dc_and_bitmap:CreateDIBSection");
 	goto FAIL;
+    }
 
     surface->is_dib = TRUE;
 
@@ -218,8 +220,10 @@ _create_dc_and_bitmap (cairo_win32_display_surface_t *surface,
 
     surface->saved_dc_bitmap = SelectObject (surface->win32.dc,
 					     surface->bitmap);
-    if (!surface->saved_dc_bitmap)
+    if (!surface->saved_dc_bitmap) {
+        fprintf (stderr, "%s:%s\n", __FUNCTION__, "SelectObject");
 	goto FAIL;
+    }
 
     if (bitmap_info && num_palette > 2)
 	free (bitmap_info);
@@ -256,8 +260,6 @@ _create_dc_and_bitmap (cairo_win32_display_surface_t *surface,
     return CAIRO_STATUS_SUCCESS;
 
  FAIL:
-    status = _cairo_win32_print_gdi_error (__FUNCTION__);
-
     if (bitmap_info && num_palette > 2)
 	free (bitmap_info);
 
@@ -276,7 +278,7 @@ _create_dc_and_bitmap (cairo_win32_display_surface_t *surface,
 	surface->win32.dc = NULL;
     }
 
-    return status;
+    return _cairo_error (CAIRO_STATUS_WIN32_GDI_ERROR);
 }
 
 static cairo_surface_t *
@@ -547,7 +549,7 @@ _cairo_win32_display_surface_flush (void *abstract_surface, unsigned flags)
 			 fallback->win32.dc,
 			 surface->win32.extents.x, surface->win32.extents.y,
 			 SRCCOPY))
-		status = _cairo_win32_print_gdi_error (__FUNCTION__);
+                status = _cairo_win32_print_gdi_error ("_cairo_win32_display_surface_flush:BitBlt");
 	} else if (damage->region) {
 	    int n = cairo_region_num_rectangles (damage->region), i;
 	    for (i = 0; i < n; i++) {
@@ -564,7 +566,7 @@ _cairo_win32_display_surface_flush (void *abstract_surface, unsigned flags)
 			     fallback->win32.dc,
 			     rect.x, rect.y,
 			     SRCCOPY)) {
-		    status = _cairo_win32_print_gdi_error (__FUNCTION__);
+                    status = _cairo_win32_print_gdi_error ("_cairo_win32_display_surface_flush:BitBlt");
 		    break;
 		}
 	    }
@@ -615,7 +617,7 @@ _cairo_win32_save_initial_clip (HDC hdc, cairo_win32_display_surface_t *surface)
 
     clipBoxType = GetClipBox (hdc, &rect);
     if (clipBoxType == ERROR) {
-	_cairo_win32_print_gdi_error (__FUNCTION__);
+        fprintf (stderr, "%s:%s\n", __FUNCTION__, "GetClipBox");
 	SetGraphicsMode (hdc, gm);
 	/* XXX: Can we make a more reasonable guess at the error cause here? */
 	return _cairo_error (CAIRO_STATUS_DEVICE_ERROR);
@@ -748,8 +750,10 @@ _cairo_win32_display_surface_set_clip (cairo_win32_display_surface_t *surface,
 
     /* AND the new region into our DC */
     status = CAIRO_STATUS_SUCCESS;
-    if (ExtSelectClipRgn (surface->win32.dc, gdi_region, RGN_AND) == ERROR)
-	status = _cairo_win32_print_gdi_error (__FUNCTION__);
+    if (ExtSelectClipRgn (surface->win32.dc, gdi_region, RGN_AND) == ERROR) {
+        fprintf (stderr, "%s:%s\n", __FUNCTION__, "ExtSelectClipRgn");
+        status = _cairo_error (CAIRO_STATUS_WIN32_GDI_ERROR);
+    }
 
     DeleteObject (gdi_region);
 
diff --git a/src/win32/cairo-win32-font.c b/src/win32/cairo-win32-font.c
index 265f93294..d1ad087f9 100644
--- a/src/win32/cairo-win32-font.c
+++ b/src/win32/cairo-win32-font.c
@@ -159,12 +159,12 @@ _get_global_font_dc (void)
     if (!hdc) {
 	hdc = CreateCompatibleDC (NULL);
 	if (!hdc) {
-	    _cairo_win32_print_gdi_error ("_get_global_font_dc");
+            fprintf (stderr, "%s:%s\n", __FUNCTION__, "CreateCompatibleDC");
 	    return NULL;
 	}
 
 	if (!SetGraphicsMode (hdc, GM_ADVANCED)) {
-	    _cairo_win32_print_gdi_error ("_get_global_font_dc");
+            fprintf (stderr, "%s:%s\n", __FUNCTION__, "SetGraphicsMode");
 	    DeleteDC (hdc);
 	    return NULL;
 	}
@@ -409,8 +409,10 @@ _win32_scaled_font_set_world_transform (cairo_win32_scaled_font_t *scaled_font,
 
     _cairo_matrix_to_win32_xform (&scaled_font->logical_to_device, &xform);
 
-    if (!SetWorldTransform (hdc, &xform))
-	return _cairo_win32_print_gdi_error ("_win32_scaled_font_set_world_transform");
+    if (!SetWorldTransform (hdc, &xform)) {
+        fprintf (stderr, "%s:%s\n", __FUNCTION__, "SetWorldTransform");
+        return _cairo_error (CAIRO_STATUS_WIN32_GDI_ERROR);
+    }
 
     return CAIRO_STATUS_SUCCESS;
 }
@@ -418,8 +420,10 @@ _win32_scaled_font_set_world_transform (cairo_win32_scaled_font_t *scaled_font,
 static cairo_status_t
 _win32_scaled_font_set_identity_transform (HDC hdc)
 {
-    if (!ModifyWorldTransform (hdc, NULL, MWT_IDENTITY))
-	return _cairo_win32_print_gdi_error ("_win32_scaled_font_set_identity_transform");
+    if (!ModifyWorldTransform (hdc, NULL, MWT_IDENTITY)) {
+        fprintf (stderr, "%s:%s\n", __FUNCTION__, "ModifyWorldTransform");
+        return _cairo_error (CAIRO_STATUS_WIN32_GDI_ERROR);
+    }
 
     return CAIRO_STATUS_SUCCESS;
 }
@@ -437,8 +441,10 @@ _win32_scaled_font_get_scaled_hfont (cairo_win32_scaled_font_t *scaled_font,
 	logfont.lfQuality = scaled_font->quality;
 
 	scaled_font->scaled_hfont = CreateFontIndirectW (&logfont);
-	if (!scaled_font->scaled_hfont)
-	    return _cairo_win32_print_gdi_error ("_win32_scaled_font_get_scaled_hfont");
+	if (!scaled_font->scaled_hfont) {
+            fprintf (stderr, "%s:%s\n", __FUNCTION__, "CreateFontIndirect");
+            return _cairo_error (CAIRO_STATUS_WIN32_GDI_ERROR);
+        }
     }
 
     *hfont_out = scaled_font->scaled_hfont;
@@ -462,25 +468,30 @@ _win32_scaled_font_get_unscaled_hfont (cairo_win32_scaled_font_t *scaled_font,
 	if (status)
 	    return status;
 
-	if (! SelectObject (hdc, scaled_hfont))
-	    return _cairo_win32_print_gdi_error ("_win32_scaled_font_get_unscaled_hfont:SelectObject");
+	if (! SelectObject (hdc, scaled_hfont)) {
+            fprintf (stderr, "%s:%s\n", __FUNCTION__, "SelectObject");
+            return _cairo_error (CAIRO_STATUS_WIN32_GDI_ERROR);
+        }
 
 	otm_size = GetOutlineTextMetrics (hdc, 0, NULL);
-	if (! otm_size)
-	    return _cairo_win32_print_gdi_error ("_win32_scaled_font_get_unscaled_hfont:GetOutlineTextMetrics");
+	if (! otm_size) {
+            fprintf (stderr, "%s:%s\n", __FUNCTION__, "GetOutlineTextMetrics");
+            return _cairo_error (CAIRO_STATUS_WIN32_GDI_ERROR);
+        }
 
 	otm = _cairo_malloc (otm_size);
 	if (otm == NULL)
 	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
 	if (! GetOutlineTextMetrics (hdc, otm_size, otm)) {
-	    status = _cairo_win32_print_gdi_error ("_win32_scaled_font_get_unscaled_hfont:GetOutlineTextMetrics");
-	    free (otm);
-	    return status;
+            fprintf (stderr, "%s:%s\n", __FUNCTION__, "GetOutlineTextMetrics");
+            free (otm);
+            return _cairo_error (CAIRO_STATUS_WIN32_GDI_ERROR);
 	}
 
 	scaled_font->em_square = otm->otmEMSquare;
 	free (otm);
+        otm = NULL;
 
 	logfont = scaled_font->logfont;
 	logfont.lfHeight = -scaled_font->em_square;
@@ -490,8 +501,10 @@ _win32_scaled_font_get_unscaled_hfont (cairo_win32_scaled_font_t *scaled_font,
 	logfont.lfQuality = scaled_font->quality;
 
 	scaled_font->unscaled_hfont = CreateFontIndirectW (&logfont);
-	if (! scaled_font->unscaled_hfont)
-	    return _cairo_win32_print_gdi_error ("_win32_scaled_font_get_unscaled_hfont:CreateIndirect");
+	if (! scaled_font->unscaled_hfont) {
+            fprintf (stderr, "%s:%s\n", __FUNCTION__, "CreateFontIndirect");
+            return _cairo_error (CAIRO_STATUS_WIN32_GDI_ERROR);
+        }
     }
 
     *hfont_out = scaled_font->unscaled_hfont;
@@ -511,8 +524,10 @@ _cairo_win32_scaled_font_select_unscaled_font (cairo_scaled_font_t *scaled_font,
 	return status;
 
     old_hfont = SelectObject (hdc, hfont);
-    if (!old_hfont)
-	return _cairo_win32_print_gdi_error ("_cairo_win32_scaled_font_select_unscaled_font");
+    if (!old_hfont) {
+        fprintf (stderr, "%s:%s\n", __FUNCTION__, "CreateSolidBrush");
+        return _cairo_error (CAIRO_STATUS_WIN32_GDI_ERROR);
+    }
 
     status = _win32_scaled_font_set_identity_transform (hdc);
     if (status) {
@@ -651,7 +666,7 @@ _cairo_win32_scaled_font_ucs4_to_index (void		*abstract_font,
     unicode[0] = ucs4;
     unicode[1] = 0;
     if (GetGlyphIndicesW (hdc, unicode, 1, &glyph_index, 0) == GDI_ERROR) {
-	_cairo_win32_print_gdi_error ("_cairo_win32_scaled_font_ucs4_to_index:GetGlyphIndicesW");
+        fprintf (stderr, "%s:%s\n", __FUNCTION__, "GetGlyphIndices");
 	glyph_index = 0;
     }
 
@@ -681,7 +696,8 @@ _cairo_win32_scaled_font_set_metrics (cairo_win32_scaled_font_t *scaled_font)
 	    return status;
 
 	if (!GetTextMetrics (hdc, &metrics)) {
-	    status = _cairo_win32_print_gdi_error ("_cairo_win32_scaled_font_set_metrics:GetTextMetrics");
+            fprintf (stderr, "%s:%s\n", __FUNCTION__, "GetTextMetrics");
+            status = _cairo_error (CAIRO_STATUS_WIN32_GDI_ERROR);
 	}
 
 	cairo_win32_scaled_font_done_font (&scaled_font->base);
@@ -766,7 +782,8 @@ _cairo_win32_scaled_font_init_glyph_metrics (cairo_win32_scaled_font_t *scaled_f
 	    return status;
 
 	if (!GetCharWidth32(hdc, charIndex, charIndex, &width)) {
-	    status = _cairo_win32_print_gdi_error ("_cairo_win32_scaled_font_init_glyph_metrics:GetCharWidth32");
+            fprintf (stderr, "%s:%s\n", __FUNCTION__, "GetCharWidth32");
+            status = _cairo_error (CAIRO_STATUS_WIN32_GDI_ERROR);
 	    width = 0;
 	}
 	cairo_win32_scaled_font_done_font (&scaled_font->base);
@@ -965,7 +982,8 @@ _flush_glyphs (cairo_glyph_state_t *state)
 		      elements,
 		      state->glyphs.num_elements,
 		      dx_elements)) {
-	return _cairo_win32_print_gdi_error ("_flush_glyphs");
+        fprintf (stderr, "%s:%s\n", __FUNCTION__, "CreateSolidBrush");
+        return _cairo_error (CAIRO_STATUS_WIN32_GDI_ERROR);
     }
 
     _cairo_array_truncate (&state->glyphs, 0);
@@ -1045,8 +1063,10 @@ _draw_glyphs_on_surface (cairo_win32_surface_t     *surface,
     cairo_status_t status, status2;
     int i;
 
-    if (!SaveDC (surface->dc))
-	return _cairo_win32_print_gdi_error ("_draw_glyphs_on_surface:SaveDC");
+    if (!SaveDC (surface->dc)) {
+        fprintf (stderr, "%s:%s\n", __FUNCTION__, "SaveDC");
+        return _cairo_error (CAIRO_STATUS_WIN32_GDI_ERROR);
+    }
 
     status = cairo_win32_scaled_font_select_font (&scaled_font->base, surface->dc);
     if (status)
@@ -1167,8 +1187,8 @@ _cairo_win32_scaled_font_index_to_ucs4 (void		*abstract_font,
 
     res = GetFontUnicodeRanges(hdc, NULL);
     if (res == 0) {
-	status = _cairo_win32_print_gdi_error (
-	    "_cairo_win32_scaled_font_index_to_ucs4:GetFontUnicodeRanges");
+        fprintf (stderr, "%s:%s\n", __FUNCTION__, "GetFontUnicodeRanges");
+        status = _cairo_error (CAIRO_STATUS_WIN32_GDI_ERROR);
 	goto exit1;
     }
 
@@ -1180,8 +1200,8 @@ _cairo_win32_scaled_font_index_to_ucs4 (void		*abstract_font,
 
     res = GetFontUnicodeRanges(hdc, glyph_set);
     if (res == 0) {
-	status = _cairo_win32_print_gdi_error (
-	    "_cairo_win32_scaled_font_index_to_ucs4:GetFontUnicodeRanges");
+        fprintf (stderr, "%s:%s\n", __FUNCTION__, "GetFontUnicodeRanges");
+        status = _cairo_error (CAIRO_STATUS_WIN32_GDI_ERROR);
 	goto exit1;
     }
 
@@ -1206,8 +1226,8 @@ _cairo_win32_scaled_font_index_to_ucs4 (void		*abstract_font,
 	utf16[j] = 0;
 
 	if (GetGlyphIndicesW (hdc, utf16, num_glyphs, glyph_indices, 0) == GDI_ERROR) {
-	    status = _cairo_win32_print_gdi_error (
-		"_cairo_win32_scaled_font_index_to_ucs4:GetGlyphIndicesW");
+            fprintf (stderr, "%s:%s\n", __FUNCTION__, "GetGlyphIndices");
+            status = _cairo_error (CAIRO_STATUS_WIN32_GDI_ERROR);
 	    goto exit2;
 	}
 
@@ -1476,7 +1496,8 @@ _cairo_win32_scaled_font_init_glyph_path (cairo_win32_scaled_font_t *scaled_font
 				   &metrics, 0, NULL, &matrix);
 
     if (bytesGlyph == GDI_ERROR) {
-	status = _cairo_win32_print_gdi_error ("_cairo_win32_scaled_font_glyph_path");
+        fprintf (stderr, "%s:%s\n", __FUNCTION__, "GetGlyphOutline");
+        status = _cairo_error (CAIRO_STATUS_WIN32_GDI_ERROR);
 	goto CLEANUP_FONT;
     }
 
@@ -1489,7 +1510,8 @@ _cairo_win32_scaled_font_init_glyph_path (cairo_win32_scaled_font_t *scaled_font
     if (GetGlyphOutlineW (hdc, _cairo_scaled_glyph_index (scaled_glyph),
 			  GGO_NATIVE | GGO_GLYPH_INDEX,
 			  &metrics, bytesGlyph, buffer, &matrix) == GDI_ERROR) {
-	status = _cairo_win32_print_gdi_error ("_cairo_win32_scaled_font_glyph_path");
+        fprintf (stderr, "%s:%s\n", __FUNCTION__, "GetGlyphOutline");
+        status = _cairo_error (CAIRO_STATUS_WIN32_GDI_ERROR);
 	goto CLEANUP_BUFFER;
     }
 
@@ -1987,14 +2009,16 @@ cairo_win32_scaled_font_select_font (cairo_scaled_font_t *scaled_font,
 	return status;
 
     old_hfont = SelectObject (hdc, hfont);
-    if (!old_hfont)
-	return _cairo_win32_print_gdi_error ("cairo_win32_scaled_font_select_font:SelectObject");
+    if (!old_hfont) {
+        fprintf (stderr, "%s:%s\n", __FUNCTION__, "SelectObject");
+        return _cairo_error (CAIRO_STATUS_WIN32_GDI_ERROR);
+    }
 
     old_mode = SetGraphicsMode (hdc, GM_ADVANCED);
     if (!old_mode) {
-	status = _cairo_win32_print_gdi_error ("cairo_win32_scaled_font_select_font:SetGraphicsMode");
+        fprintf (stderr, "%s:%s\n", __FUNCTION__, "SetGraphicsMode");
 	SelectObject (hdc, old_hfont);
-	return status;
+        return _cairo_error (CAIRO_STATUS_WIN32_GDI_ERROR);
     }
 
     status = _win32_scaled_font_set_world_transform ((cairo_win32_scaled_font_t *)scaled_font, hdc);
diff --git a/src/win32/cairo-win32-gdi-compositor.c b/src/win32/cairo-win32-gdi-compositor.c
index 268ca0100..347cd7ed5 100644
--- a/src/win32/cairo-win32-gdi-compositor.c
+++ b/src/win32/cairo-win32-gdi-compositor.c
@@ -166,8 +166,10 @@ fill_boxes (cairo_win32_display_surface_t	*dst,
 
     fb.dc = dst->win32.dc;
     fb.brush = CreateSolidBrush (color_to_rgb(color));
-    if (!fb.brush)
-	return _cairo_win32_print_gdi_error (__FUNCTION__);
+    if (!fb.brush) {
+        fprintf (stderr, "%s:%s\n", __FUNCTION__, "CreateSolidBrush");
+        return _cairo_error (CAIRO_STATUS_WIN32_GDI_ERROR);
+    }
 
     if (! _cairo_boxes_for_each_box (boxes, fill_box, &fb))
 	status = CAIRO_INT_STATUS_UNSUPPORTED;
diff --git a/src/win32/cairo-win32-printing-surface.c b/src/win32/cairo-win32-printing-surface.c
index 8305ede9c..c5b5f5cab 100644
--- a/src/win32/cairo-win32-printing-surface.c
+++ b/src/win32/cairo-win32-printing-surface.c
@@ -477,8 +477,10 @@ _cairo_win32_printing_surface_select_solid_brush (cairo_win32_printing_surface_t
     color = _cairo_win32_printing_surface_flatten_transparency (surface,
 								&pattern->color);
     surface->brush = CreateSolidBrush (color);
-    if (!surface->brush)
-	return _cairo_win32_print_gdi_error ("_cairo_win32_surface_select_solid_brush(CreateSolidBrush)");
+    if (!surface->brush) {
+        fprintf (stderr, "%s:%s\n", __FUNCTION__, "CreateSolidBrush");
+        return _cairo_error (CAIRO_STATUS_WIN32_GDI_ERROR);
+    }
     surface->old_brush = SelectObject (surface->win32.dc, surface->brush);
 
     return CAIRO_STATUS_SUCCESS;
@@ -501,13 +503,17 @@ _cairo_win32_printing_surface_get_ctm_clip_box (cairo_win32_printing_surface_t *
     XFORM xform;
 
     _cairo_matrix_to_win32_xform (&surface->ctm, &xform);
-    if (!ModifyWorldTransform (surface->win32.dc, &xform, MWT_LEFTMULTIPLY))
-	return _cairo_win32_print_gdi_error ("_cairo_win32_printing_surface_get_clip_box:ModifyWorldTransform");
+    if (!ModifyWorldTransform (surface->win32.dc, &xform, MWT_LEFTMULTIPLY)) {
+        fprintf (stderr, "%s:%s\n", __FUNCTION__, "ModifyWorldTransform");
+        return _cairo_error (CAIRO_STATUS_WIN32_GDI_ERROR);
+    }
     GetClipBox (surface->win32.dc, clip);
 
     _cairo_matrix_to_win32_xform (&surface->gdi_ctm, &xform);
-    if (!SetWorldTransform (surface->win32.dc, &xform))
-	return _cairo_win32_print_gdi_error ("_cairo_win32_printing_surface_get_clip_box:SetWorldTransform");
+    if (!SetWorldTransform (surface->win32.dc, &xform)) {
+        fprintf (stderr, "%s:%s\n", __FUNCTION__, "SetWorldTransform");
+        return _cairo_error (CAIRO_STATUS_WIN32_GDI_ERROR);
+    }
 
     return CAIRO_STATUS_SUCCESS;
 }
@@ -887,7 +893,8 @@ _cairo_win32_printing_surface_paint_image_pattern (cairo_win32_printing_surface_
     _cairo_matrix_to_win32_xform (&m, &xform);
 
     if (! SetWorldTransform (surface->win32.dc, &xform)) {
-	status = _cairo_win32_print_gdi_error ("_cairo_win32_printing_surface_paint_image_pattern");
+        fprintf (stderr, "%s:%s\n", __FUNCTION__, "SetWorldTransform");
+        status = _cairo_error (CAIRO_STATUS_WIN32_GDI_ERROR);
 	goto CLEANUP_OPAQUE_IMAGE;
     }
 
@@ -922,7 +929,8 @@ _cairo_win32_printing_surface_paint_image_pattern (cairo_win32_printing_surface_
 				DIB_RGB_COLORS,
 				SRCCOPY))
 	    {
-		status = _cairo_win32_print_gdi_error ("_cairo_win32_printing_surface_paint(StretchDIBits)");
+                fprintf (stderr, "%s:%s\n", __FUNCTION__, "StretchDIBits");
+                status = _cairo_error (CAIRO_STATUS_WIN32_GDI_ERROR);
 		goto CLEANUP_OPAQUE_IMAGE;
 	    }
 	}
@@ -996,8 +1004,10 @@ _cairo_win32_printing_surface_paint_linear_pattern (cairo_win32_printing_surface
 
     _cairo_matrix_to_win32_xform (&mat, &xform);
 
-    if (!SetWorldTransform (surface->win32.dc, &xform))
-	return _cairo_win32_print_gdi_error ("_win32_printing_surface_paint_linear_pattern:SetWorldTransform2");
+    if (!SetWorldTransform (surface->win32.dc, &xform)) {
+        fprintf (stderr, "%s:%s\n", __FUNCTION__, "SetWorldTransform");
+        return _cairo_error (CAIRO_STATUS_WIN32_GDI_ERROR);
+    }
 
     GetClipBox (surface->win32.dc, &clip);
 
@@ -1086,7 +1096,10 @@ _cairo_win32_printing_surface_paint_linear_pattern (cairo_win32_printing_surface
 		       vert, total_verts,
 		       rect, total_rects,
 		       GRADIENT_FILL_RECT_H))
-	return _cairo_win32_print_gdi_error ("_win32_printing_surface_paint_linear_pattern:GradientFill");
+    {
+        fprintf (stderr, "%s:%s\n", __FUNCTION__, "GradientFill");
+        return _cairo_error (CAIRO_STATUS_WIN32_GDI_ERROR);
+    }
 
     free (rect);
     free (vert);
@@ -1556,13 +1569,15 @@ _cairo_win32_printing_surface_stroke (void			*abstract_surface,
 		       style->num_dashes,
 		       dash_array);
     if (pen == NULL) {
-	status = _cairo_win32_print_gdi_error ("_win32_surface_stroke:ExtCreatePen");
+        fprintf (stderr, "%s:%s\n", __FUNCTION__, "ExtCreatePen");
+        status = _cairo_error (CAIRO_STATUS_WIN32_GDI_ERROR);
 	goto cleanup_composite;
     }
 
     obj = SelectObject (surface->win32.dc, pen);
     if (obj == NULL) {
-	status = _cairo_win32_print_gdi_error ("_win32_surface_stroke:SelectObject");
+        fprintf (stderr, "%s:%s\n", __FUNCTION__, "SelectObject");
+        status = _cairo_error (CAIRO_STATUS_WIN32_GDI_ERROR);
 	goto cleanup_composite;
     }
 
@@ -1582,7 +1597,8 @@ _cairo_win32_printing_surface_stroke (void			*abstract_surface,
     xform.eDy = 0.0f;
 
     if (!ModifyWorldTransform (surface->win32.dc, &xform, MWT_LEFTMULTIPLY)) {
-	status = _cairo_win32_print_gdi_error ("_win32_surface_stroke:SetWorldTransform");
+        fprintf (stderr, "%s:%s\n", __FUNCTION__, "ModifyWorldTransform");
+        status = _cairo_error (CAIRO_STATUS_WIN32_GDI_ERROR);
 	goto cleanup_composite;
     }
 
@@ -1590,18 +1606,21 @@ _cairo_win32_printing_surface_stroke (void			*abstract_surface,
 	StrokePath (surface->win32.dc);
     } else {
 	if (!WidenPath (surface->win32.dc)) {
-	    status = _cairo_win32_print_gdi_error ("_win32_surface_stroke:WidenPath");
+            fprintf (stderr, "%s:%s\n", __FUNCTION__, "WidenPath");
+            status = _cairo_error (CAIRO_STATUS_WIN32_GDI_ERROR);
 	    goto cleanup_composite;
 	}
 	if (!SelectClipPath (surface->win32.dc, RGN_AND)) {
-	    status = _cairo_win32_print_gdi_error ("_win32_surface_stroke:SelectClipPath");
+            fprintf (stderr, "%s:%s\n", __FUNCTION__, "SelectClipPath");
+            status = _cairo_error (CAIRO_STATUS_WIN32_GDI_ERROR);
 	    goto cleanup_composite;
 	}
 
 	/* Return to device space to paint the pattern */
 	_cairo_matrix_to_win32_xform (&surface->gdi_ctm, &xform);
 	if (!SetWorldTransform (surface->win32.dc, &xform)) {
-	    status = _cairo_win32_print_gdi_error ("_win32_surface_stroke:ModifyWorldTransform");
+            fprintf (stderr, "%s:%s\n", __FUNCTION__, "SetWorldTransform");
+            status = _cairo_error (CAIRO_STATUS_WIN32_GDI_ERROR);
 	    goto cleanup_composite;
 	}
 	status = _cairo_win32_printing_surface_paint_pattern (surface, source, &extents.bounded);
@@ -2102,8 +2121,10 @@ _cairo_win32_printing_surface_start_page (void *abstract_surface)
 	surface->ctm.x0 = xform.eDx;
 	surface->ctm.y0 = xform.eDy;
 	cairo_matrix_init_identity (&surface->gdi_ctm);
-	if (!ModifyWorldTransform (surface->win32.dc, NULL, MWT_IDENTITY))
-	    return _cairo_win32_print_gdi_error ("_cairo_win32_printing_surface_start_page:ModifyWorldTransform");
+	if (!ModifyWorldTransform (surface->win32.dc, NULL, MWT_IDENTITY)) {
+            fprintf (stderr, "%s:%s\n", __FUNCTION__, "ModifyWorldTransform");
+            return _cairo_error (CAIRO_STATUS_WIN32_GDI_ERROR);
+        }
     }
 
     surface->has_ctm = !_cairo_matrix_is_identity (&surface->ctm);
diff --git a/src/win32/cairo-win32-surface.c b/src/win32/cairo-win32-surface.c
index 6862e2090..8e22996da 100644
--- a/src/win32/cairo-win32-surface.c
+++ b/src/win32/cairo-win32-surface.c
@@ -319,7 +319,7 @@ _cairo_win32_surface_emit_glyphs (cairo_win32_surface_t *dst,
                              num_glyphs,
                              dxy_buf);
     if (!win_result) {
-        _cairo_win32_print_gdi_error("_cairo_win32_surface_show_glyphs(ExtTextOutW failed)");
+        fprintf (stderr, "%s:%s\n", __FUNCTION__, "ExtTextOut");
     }
 
     RestoreDC(dst->dc, -1);
commit f289bea1d28718c94e8451a80db607b88d7a3692
Author: Luca Bacci <luca.bacci982 at gmail.com>
Date:   Thu Jan 16 15:31:23 2025 +0100

    Readme: Update Windows OS requirements to Windows Vista

diff --git a/README.md b/README.md
index ebe3f99e1..2bd26068b 100644
--- a/README.md
+++ b/README.md
@@ -126,7 +126,7 @@ system pixman.
 
 #### Windows backend
 
-- Microsoft Windows 2000 or newer.
+- Microsoft Windows Vista or newer.
 
 #### XCB backend
 
commit e10adb1c2b81c8b3f1e280b7d32ff63bbfe56c71
Author: Luca Bacci <luca.bacci982 at gmail.com>
Date:   Thu Jan 16 14:33:58 2025 +0100

    Win32: Pass FORMAT_MESSAGE_IGNORE_INSERTS
    
    This should always be passed when retreving messages from third
    parties (unless the third party documents format strings)
    
    See https://devblogs.microsoft.com/oldnewthing/20071128-00/?p=24353

diff --git a/boilerplate/cairo-boilerplate-win32-printing.c b/boilerplate/cairo-boilerplate-win32-printing.c
index a3802d2e9..a156deb24 100644
--- a/boilerplate/cairo-boilerplate-win32-printing.c
+++ b/boilerplate/cairo-boilerplate-win32-printing.c
@@ -43,6 +43,7 @@ _cairo_win32_print_gdi_error (const char *context)
     DWORD last_error = GetLastError ();
 
     if (!FormatMessageW (FORMAT_MESSAGE_ALLOCATE_BUFFER |
+                         FORMAT_MESSAGE_IGNORE_INSERTS |
 			 FORMAT_MESSAGE_FROM_SYSTEM,
 			 NULL,
 			 last_error,
diff --git a/src/win32/cairo-dwrite-font.cpp b/src/win32/cairo-dwrite-font.cpp
index f7d1c4767..74d12c6a0 100644
--- a/src/win32/cairo-dwrite-font.cpp
+++ b/src/win32/cairo-dwrite-font.cpp
@@ -110,6 +110,7 @@ _cairo_dwrite_error (HRESULT hr, const char *context)
     void *lpMsgBuf;
 
     if (!FormatMessageW (FORMAT_MESSAGE_ALLOCATE_BUFFER |
+                         FORMAT_MESSAGE_IGNORE_INSERTS |
 			 FORMAT_MESSAGE_FROM_SYSTEM,
 			 NULL,
 			 hr,
diff --git a/src/win32/cairo-win32-surface.c b/src/win32/cairo-win32-surface.c
index 6e82638ff..6862e2090 100644
--- a/src/win32/cairo-win32-surface.c
+++ b/src/win32/cairo-win32-surface.c
@@ -95,6 +95,7 @@ _cairo_win32_print_gdi_error (const char *context)
     DWORD last_error = GetLastError ();
 
     if (!FormatMessageW (FORMAT_MESSAGE_ALLOCATE_BUFFER |
+                         FORMAT_MESSAGE_IGNORE_INSERTS |
 			 FORMAT_MESSAGE_FROM_SYSTEM,
 			 NULL,
 			 last_error,
commit d0ee67a14285788f3b423df5b87ab81c08f50c8f
Author: Luca Bacci <luca.bacci982 at gmail.com>
Date:   Thu Jan 16 14:26:04 2025 +0100

    Win32: Remove unused code and defines for old toolchains

diff --git a/boilerplate/cairo-boilerplate-win32-printing.c b/boilerplate/cairo-boilerplate-win32-printing.c
index e8fcdcef5..a3802d2e9 100644
--- a/boilerplate/cairo-boilerplate-win32-printing.c
+++ b/boilerplate/cairo-boilerplate-win32-printing.c
@@ -36,22 +36,6 @@
 
 #include <windows.h>
 
-#if !defined(POSTSCRIPT_IDENTIFY)
-# define POSTSCRIPT_IDENTIFY 0x1015
-#endif
-
-#if !defined(PSIDENT_GDICENTRIC)
-# define PSIDENT_GDICENTRIC 0x0000
-#endif
-
-#if !defined(GET_PS_FEATURESETTING)
-# define GET_PS_FEATURESETTING 0x1019
-#endif
-
-#if !defined(FEATURESETTING_PSLEVEL)
-# define FEATURESETTING_PSLEVEL 0x0002
-#endif
-
 static cairo_status_t
 _cairo_win32_print_gdi_error (const char *context)
 {
diff --git a/src/win32/cairo-win32-device.c b/src/win32/cairo-win32-device.c
index 575239352..c55b0789e 100644
--- a/src/win32/cairo-win32-device.c
+++ b/src/win32/cairo-win32-device.c
@@ -76,20 +76,6 @@ static const cairo_device_backend_t _cairo_win32_device_backend = {
     _cairo_win32_device_destroy,
 };
 
-#if 0
-D2D1_RENDER_TARGET_PROPERTIES props = D2D1::RenderTargetProperties(D2D1_RENDER_TARGET_TYPE_DEFAULT,
-								   D2D1::PixelFormat(
-										     DXGI_FORMAT_B8G8R8A8_UNORM,
-										     D2D1_ALPHA_MODE_IGNORE),
-								   0,
-								   0,
-								   D2D1_RENDER_TARGET_USAGE_NONE,
-								   D2D1_FEATURE_LEVEL_DEFAULT
-								  );
-
-hr = m_pD2DFactory->CreateDCRenderTarget(&props, &device->d2d);
-#endif
-
 cairo_device_t *
 _cairo_win32_device_get (void)
 {
diff --git a/src/win32/cairo-win32-display-surface.c b/src/win32/cairo-win32-display-surface.c
index 2800052bc..4f4e8f847 100644
--- a/src/win32/cairo-win32-display-surface.c
+++ b/src/win32/cairo-win32-display-surface.c
@@ -56,10 +56,6 @@
 #include <wchar.h>
 #include <windows.h>
 
-#if defined(__MINGW32__) && !defined(ETO_PDY)
-# define ETO_PDY 0x2000
-#endif
-
 #define PELS_72DPI  ((LONG)(72. / 0.0254))
 
 /**
diff --git a/src/win32/cairo-win32-font.c b/src/win32/cairo-win32-font.c
index 3ad4f7ff4..265f93294 100644
--- a/src/win32/cairo-win32-font.c
+++ b/src/win32/cairo-win32-font.c
@@ -45,19 +45,6 @@
 
 #include <wchar.h>
 
-#ifndef SPI_GETFONTSMOOTHINGTYPE
-#define SPI_GETFONTSMOOTHINGTYPE 0x200a
-#endif
-#ifndef FE_FONTSMOOTHINGCLEARTYPE
-#define FE_FONTSMOOTHINGCLEARTYPE 2
-#endif
-#ifndef CLEARTYPE_QUALITY
-#define CLEARTYPE_QUALITY 5
-#endif
-#ifndef TT_PRIM_CSPLINE
-#define TT_PRIM_CSPLINE 3
-#endif
-
 #define CMAP_TAG 0x70616d63
 
 /**
diff --git a/src/win32/cairo-win32-gdi-compositor.c b/src/win32/cairo-win32-gdi-compositor.c
index 08e5abfb3..268ca0100 100644
--- a/src/win32/cairo-win32-gdi-compositor.c
+++ b/src/win32/cairo-win32-gdi-compositor.c
@@ -55,23 +55,6 @@
 #include "cairo-surface-inline.h"
 #include "cairo-surface-offset-private.h"
 
-#if !defined(AC_SRC_OVER)
-#define AC_SRC_OVER                 0x00
-#pragma pack(1)
-typedef struct {
-    BYTE   BlendOp;
-    BYTE   BlendFlags;
-    BYTE   SourceConstantAlpha;
-    BYTE   AlphaFormat;
-}BLENDFUNCTION;
-#pragma pack()
-#endif
-
-/* for compatibility with VC++ 6 */
-#ifndef AC_SRC_ALPHA
-#define AC_SRC_ALPHA                0x01
-#endif
-
 #define PELS_72DPI  ((LONG)(72. / 0.0254))
 
 /* the low-level interface */
diff --git a/src/win32/cairo-win32-private.h b/src/win32/cairo-win32-private.h
index 594e2b085..4e180a81e 100644
--- a/src/win32/cairo-win32-private.h
+++ b/src/win32/cairo-win32-private.h
@@ -44,13 +44,6 @@
 #include "cairo-surface-clipper-private.h"
 #include "cairo-surface-private.h"
 
-#ifndef SHADEBLENDCAPS
-#define SHADEBLENDCAPS 120
-#endif
-#ifndef SB_NONE
-#define SB_NONE 0
-#endif
-
 #define WIN32_FONT_LOGICAL_SCALE 32
 
 CAIRO_BEGIN_DECLS
diff --git a/src/win32/cairo-win32-surface.c b/src/win32/cairo-win32-surface.c
index ca5c9d823..6e82638ff 100644
--- a/src/win32/cairo-win32-surface.c
+++ b/src/win32/cairo-win32-surface.c
@@ -53,10 +53,6 @@
 #include <wchar.h>
 #include <windows.h>
 
-#if defined(__MINGW32__) && !defined(ETO_PDY)
-# define ETO_PDY 0x2000
-#endif
-
 /**
  * SECTION:cairo-win32
  * @Title: Win32 Surfaces
commit 361240657c2d668a719cdf4e999867025c8caeb1
Author: Luca Bacci <luca.bacci982 at gmail.com>
Date:   Thu Jan 16 14:19:55 2025 +0100

    Win32: Do not load msimg32.dll at runtime
    
    This commit drops support for Windows 98

diff --git a/src/win32/cairo-win32-device.c b/src/win32/cairo-win32-device.c
index 42f013392..575239352 100644
--- a/src/win32/cairo-win32-device.c
+++ b/src/win32/cairo-win32-device.c
@@ -90,18 +90,6 @@ D2D1_RENDER_TARGET_PROPERTIES props = D2D1::RenderTargetProperties(D2D1_RENDER_T
 hr = m_pD2DFactory->CreateDCRenderTarget(&props, &device->d2d);
 #endif
 
-static void *
-_cairo_win32_device_get_alpha_blend (cairo_win32_device_t *device)
-{
-    void *func = NULL;
-
-    device->msimg32_dll = LoadLibraryW (L"msimg32");
-    if (device->msimg32_dll)
-	func = GetProcAddress (device->msimg32_dll, "AlphaBlend");
-
-    return func;
-}
-
 cairo_device_t *
 _cairo_win32_device_get (void)
 {
@@ -118,9 +106,6 @@ _cairo_win32_device_get (void)
 
     device->compositor = _cairo_win32_gdi_compositor_get ();
 
-    device->msimg32_dll = NULL;
-    device->alpha_blend = _cairo_win32_device_get_alpha_blend (device);
-
     if (_cairo_atomic_ptr_cmpxchg ((cairo_atomic_intptr_t *)&__cairo_win32_device, NULL, device))
 	return cairo_device_reference(&device->base);
 
diff --git a/src/win32/cairo-win32-gdi-compositor.c b/src/win32/cairo-win32-gdi-compositor.c
index bc1f69e70..08e5abfb3 100644
--- a/src/win32/cairo-win32-gdi-compositor.c
+++ b/src/win32/cairo-win32-gdi-compositor.c
@@ -105,7 +105,6 @@ struct copy_box {
     int tx, ty;
     HDC dst, src;
     BLENDFUNCTION bf;
-    cairo_win32_alpha_blend_func_t alpha_blend;
 };
 
 static cairo_bool_t copy_box (cairo_box_t *box, void *closure)
@@ -131,9 +130,9 @@ static cairo_bool_t alpha_box (cairo_box_t *box, void *closure)
     int height = _cairo_fixed_integer_part (box->p2.y - box->p1.y);
 
     TRACE ((stderr, "%s\n", __FUNCTION__));
-    return cb->alpha_blend (cb->dst, x, y, width, height,
-			    cb->src, x + cb->tx, y + cb->ty, width, height,
-			    cb->bf);
+    return AlphaBlend (cb->dst, x, y, width, height,
+                       cb->src, x + cb->tx, y + cb->ty, width, height,
+                       cb->bf);
 }
 
 struct upload_box {
@@ -382,7 +381,6 @@ alpha_blend_boxes (cairo_win32_display_surface_t *dst,
     cb.bf.BlendFlags = 0;
     cb.bf.SourceConstantAlpha = alpha;
     cb.bf.AlphaFormat = (src->win32.format == CAIRO_FORMAT_ARGB32) ? AC_SRC_ALPHA : 0;
-    cb.alpha_blend = to_win32_device(dst->win32.base.device)->alpha_blend;
 
     cb.tx += cb.limit.x;
     cb.ty += cb.limit.y;
@@ -397,10 +395,7 @@ alpha_blend_boxes (cairo_win32_display_surface_t *dst,
 static cairo_bool_t
 can_alpha_blend (cairo_win32_display_surface_t *dst)
 {
-    if ((dst->win32.flags & CAIRO_WIN32_SURFACE_CAN_ALPHABLEND) == 0)
-	return FALSE;
-
-    return to_win32_device(dst->win32.base.device)->alpha_blend != NULL;
+    return (dst->win32.flags & CAIRO_WIN32_SURFACE_CAN_ALPHABLEND) != 0;
 }
 
 static cairo_status_t
diff --git a/src/win32/cairo-win32-private.h b/src/win32/cairo-win32-private.h
index 6af09c0e1..594e2b085 100644
--- a/src/win32/cairo-win32-private.h
+++ b/src/win32/cairo-win32-private.h
@@ -168,26 +168,10 @@ typedef struct _cairo_win32_printing_surface {
 } cairo_win32_printing_surface_t;
 #define to_win32_printing_surface(S) ((cairo_win32_printing_surface_t *)(S))
 
-typedef BOOL (WINAPI *cairo_win32_alpha_blend_func_t) (HDC hdcDest,
-						       int nXOriginDest,
-						       int nYOriginDest,
-						       int nWidthDest,
-						       int hHeightDest,
-						       HDC hdcSrc,
-						       int nXOriginSrc,
-						       int nYOriginSrc,
-						       int nWidthSrc,
-						       int nHeightSrc,
-						       BLENDFUNCTION blendFunction);
-
 typedef struct _cairo_win32_device {
     cairo_device_t base;
 
-    HMODULE msimg32_dll;
-
     const cairo_compositor_t *compositor;
-
-    cairo_win32_alpha_blend_func_t alpha_blend;
 } cairo_win32_device_t;
 #define to_win32_device(D) ((cairo_win32_device_t *)(D))
 #define to_win32_device_from_surface(S) to_win32_device(((cairo_surface_t *)(S))->device)
commit 613df92660903f5a5fa31199ba568b6d99fee9bd
Author: Luca Bacci <luca.bacci982 at gmail.com>
Date:   Thu Jan 16 14:12:34 2025 +0100

    Win32: Remove check for Windows 98

diff --git a/src/win32/cairo-win32-device.c b/src/win32/cairo-win32-device.c
index e000b11f6..42f013392 100644
--- a/src/win32/cairo-win32-device.c
+++ b/src/win32/cairo-win32-device.c
@@ -90,26 +90,11 @@ D2D1_RENDER_TARGET_PROPERTIES props = D2D1::RenderTargetProperties(D2D1_RENDER_T
 hr = m_pD2DFactory->CreateDCRenderTarget(&props, &device->d2d);
 #endif
 
-static cairo_bool_t is_win98 (void)
-{
-    OSVERSIONINFO os;
-
-    os.dwOSVersionInfoSize = sizeof (os);
-    GetVersionEx (&os);
-
-    return (VER_PLATFORM_WIN32_WINDOWS == os.dwPlatformId &&
-	    os.dwMajorVersion == 4 &&
-	    os.dwMinorVersion == 10);
-}
-
 static void *
 _cairo_win32_device_get_alpha_blend (cairo_win32_device_t *device)
 {
     void *func = NULL;
 
-    if (is_win98 ())
-	return NULL;
-
     device->msimg32_dll = LoadLibraryW (L"msimg32");
     if (device->msimg32_dll)
 	func = GetProcAddress (device->msimg32_dll, "AlphaBlend");
commit dfd06ab3884d79de3b5bac782d1e8b2a0bd791ab
Author: Luca Bacci <luca.bacci982 at gmail.com>
Date:   Thu Jan 16 16:48:12 2025 +0100

    Meson: Require C++11

diff --git a/meson.build b/meson.build
index 162b2927c..de89fb235 100644
--- a/meson.build
+++ b/meson.build
@@ -2,6 +2,7 @@ project('cairo', 'c',
   meson_version: '>= 1.3.0',
   version: run_command(find_program('version.py'), check: true).stdout().strip(),
   default_options: ['c_std=gnu11,c11',
+                    'cpp_std=gnu++11,c++11',
                     'warning_level=2'],
 )
 
commit 56b8933ede912a7a679157811009f87d1fac6ce7
Author: Luca Bacci <luca.bacci982 at gmail.com>
Date:   Wed Jan 8 11:05:01 2025 +0100

    DWrite: Remove unused variables

diff --git a/src/win32/cairo-dwrite-font.cpp b/src/win32/cairo-dwrite-font.cpp
index f7d1c4767..ba1695259 100644
--- a/src/win32/cairo-dwrite-font.cpp
+++ b/src/win32/cairo-dwrite-font.cpp
@@ -1689,7 +1689,6 @@ _dwrite_draw_glyphs_to_gdi_surface_d2d(cairo_win32_surface_t *surface,
     if (FAILED(hr))
 	return CAIRO_INT_STATUS_UNSUPPORTED;
 
-    float x = 0, y = 0;
     if (transform) {
 	rt->SetTransform(D2D1::Matrix3x2F(transform->m11,
 					  transform->m12,
@@ -1722,7 +1721,6 @@ _cairo_dwrite_show_glyphs_on_surface(void			*surface,
 {
     // TODO: Check font & surface for types.
     cairo_dwrite_scaled_font_t *dwritesf = reinterpret_cast<cairo_dwrite_scaled_font_t*>(scaled_font);
-    cairo_dwrite_font_face_t *dwriteff = reinterpret_cast<cairo_dwrite_font_face_t*>(scaled_font->font_face);
     cairo_win32_surface_t *dst = reinterpret_cast<cairo_win32_surface_t*>(surface);
     cairo_int_status_t status;
     /* We can only handle dwrite fonts */
@@ -1747,10 +1745,6 @@ _cairo_dwrite_show_glyphs_on_surface(void			*surface,
     AutoDWriteGlyphRun run;
     run.allocate(num_glyphs);
 
-    UINT16 *indices = const_cast<UINT16*>(run.glyphIndices);
-    FLOAT *advances = const_cast<FLOAT*>(run.glyphAdvances);
-    DWRITE_GLYPH_OFFSET *offsets = const_cast<DWRITE_GLYPH_OFFSET*>(run.glyphOffsets);
-
     BOOL transform = FALSE;
     _cairo_dwrite_glyph_run_from_glyphs(glyphs, num_glyphs, dwritesf, &run, &transform);
 
commit b84b3542d153e7255e911d6bfe43a184a19df2db
Author: Luca Bacci <luca.bacci982 at gmail.com>
Date:   Fri Nov 8 11:52:10 2024 +0100

    DWrite: Add support for font variations
    
    Fixes https://gitlab.freedesktop.org/cairo/cairo/-/issues/877

diff --git a/src/win32/cairo-dwrite-font.cpp b/src/win32/cairo-dwrite-font.cpp
index 489131c11..62ad7a1a1 100644
--- a/src/win32/cairo-dwrite-font.cpp
+++ b/src/win32/cairo-dwrite-font.cpp
@@ -626,6 +626,54 @@ do_grayscale(IDWriteFontFace *dwface, unsigned int ppem)
     return true;
 }
 
+static void
+set_dwrite_axes_from_string (const char             *string,
+                             DWRITE_FONT_AXIS_VALUE *dwrite_axes,
+                             UINT32                  count)
+{
+    const char *p = string;
+
+    while (p && *p) {
+        const char *start;
+        const char *end, *end2;
+        DWRITE_FONT_AXIS_TAG tag;
+        double value;
+
+        while (_cairo_isspace (*p)) p++;
+
+        start = p;
+        end = strchr (p, ',');
+        if (end && (end - p < 6))
+            goto skip;
+
+        tag = DWRITE_MAKE_FONT_AXIS_TAG (p[0], p[1], p[2], p[3]);
+
+        p += 4;
+        while (_cairo_isspace (*p)) p++;
+        if (*p == '=') p++;
+
+        if (p - start < 5)
+            goto skip;
+
+        value = _cairo_strtod (p, (char **) &end2);
+
+        while (end2 && _cairo_isspace (*end2)) end2++;
+
+        if (end2 && (*end2 != ',' && *end2 != '\0'))
+            goto skip;
+
+        for (UINT32 i = 0; i < count; i++) {
+            if (dwrite_axes[i].axisTag == tag) {
+                dwrite_axes[i].value = value;
+                break;
+            }
+        }
+
+skip:
+        p = end ? end + 1 : NULL;
+    }
+}
+
 static cairo_status_t
 _cairo_dwrite_font_face_scaled_font_create (void			*abstract_face,
 					    const cairo_matrix_t	*font_matrix,
@@ -654,8 +702,59 @@ _cairo_dwrite_font_face_scaled_font_create (void			*abstract_face,
 	return status;
     }
 
-    dwrite_font->dwriteface->AddRef ();
-    dwrite_font->dwriteface = dwrite_font->dwriteface;
+    if (options->variations) {
+        RefPtr<IDWriteFontFace5> dwriteface5;
+
+        /* Since Windows 10 20348 */
+        if (SUCCEEDED (font_face->dwriteface->QueryInterface(&dwriteface5))) {
+            RefPtr<IDWriteFontResource> dwritefontresource;
+
+            if (dwriteface5->HasVariations () &&
+                SUCCEEDED (dwriteface5->GetFontResource (&dwritefontresource)))
+            {
+                UINT32 count = MIN (dwriteface5->GetFontAxisValueCount (), 500);
+                DWRITE_FONT_AXIS_VALUE *dwrite_axes = new DWRITE_FONT_AXIS_VALUE[count];
+                UINT32 variables_count = 0;
+
+                /* Sort variable axes first */
+                for (UINT32 i = 0; i < count; i++) {
+                    if (dwritefontresource->GetFontAxisAttributes (i) & DWRITE_FONT_AXIS_ATTRIBUTES_VARIABLE) {
+                       if (variables_count != i) {
+                           DWRITE_FONT_AXIS_VALUE swap_aux = dwrite_axes[variables_count];
+                           dwrite_axes[variables_count] = dwrite_axes[i];
+                           dwrite_axes[i] = swap_aux;
+                       }
+
+                       variables_count++;
+                    }
+                }
+
+                if (SUCCEEDED (dwriteface5->GetFontAxisValues(dwrite_axes, count))) {
+                    RefPtr<IDWriteFontFace5> dwriteface_new5;
+
+                    set_dwrite_axes_from_string (options->variations, dwrite_axes, variables_count);
+
+                    /* Can't use constexpr with mingw-w64 headers */
+                    const DWRITE_FONT_SIMULATIONS all_simulations = DWRITE_FONT_SIMULATIONS_BOLD |
+                                                                    DWRITE_FONT_SIMULATIONS_OBLIQUE;
+                    if (SUCCEEDED (dwritefontresource->CreateFontFace(all_simulations,
+                                                                      dwrite_axes,
+                                                                      count,
+                                                                      &dwriteface_new5)))
+                    {
+                        dwrite_font->dwriteface = dwriteface_new5.forget().drop();
+                    }
+                }
+
+                delete[] dwrite_axes;
+            }
+        }
+    }
+
+    if (!dwrite_font->dwriteface) {
+        font_face->dwriteface->AddRef ();
+        dwrite_font->dwriteface = font_face->dwriteface;
+    }
 
     dwrite_font->mat = dwrite_font->base.ctm;
     cairo_matrix_multiply(&dwrite_font->mat, &dwrite_font->mat, font_matrix);
commit 6cd0a7d3952953040f9b891806fc69b7aa7be12e
Author: Luca Bacci <luca.bacci982 at gmail.com>
Date:   Wed Nov 6 23:42:04 2024 +0100

    DWrite: Add IDWriteFontFace field in the scaled font subclass
    
    ...and make the code use that instead of the original IDWriteFontFace
    in the font face subclass. We do that because to apply a few settings
    (font variations) a new IDWriteFontFace must be created out of the
    original one.
    
    For now the IDWriteFontFace in the scaled font is a copy of the one in
    the font face. In the next commit we'll add code to create a different
    object.

diff --git a/src/win32/cairo-dwrite-font.cpp b/src/win32/cairo-dwrite-font.cpp
index b6931b367..489131c11 100644
--- a/src/win32/cairo-dwrite-font.cpp
+++ b/src/win32/cairo-dwrite-font.cpp
@@ -507,7 +507,7 @@ _cairo_dwrite_font_face_destroy (void *font_face)
 {
     cairo_dwrite_font_face_t *dwrite_font_face = static_cast<cairo_dwrite_font_face_t*>(font_face);
     if (dwrite_font_face->dwriteface)
-	dwrite_font_face->dwriteface->Release();
+        dwrite_font_face->dwriteface->Release();
     if (dwrite_font_face->rendering_params)
 	dwrite_font_face->rendering_params->Release();
     return TRUE;
@@ -532,10 +532,8 @@ _cairo_dwrite_glyph_run_from_glyphs(cairo_glyph_t *glyphs,
     FLOAT *advances = const_cast<FLOAT*>(run->glyphAdvances);
     DWRITE_GLYPH_OFFSET *offsets = const_cast<DWRITE_GLYPH_OFFSET*>(run->glyphOffsets);
 
-    cairo_dwrite_font_face_t *dwriteff = reinterpret_cast<cairo_dwrite_font_face_t*>(scaled_font->base.font_face);
-
     run->bidiLevel = 0;
-    run->fontFace = dwriteff->dwriteface;
+    run->fontFace = scaled_font->dwriteface;
     run->glyphCount = num_glyphs;
     run->isSideways = FALSE;
 
@@ -656,6 +654,9 @@ _cairo_dwrite_font_face_scaled_font_create (void			*abstract_face,
 	return status;
     }
 
+    dwrite_font->dwriteface->AddRef ();
+    dwrite_font->dwriteface = dwrite_font->dwriteface;
+
     dwrite_font->mat = dwrite_font->base.ctm;
     cairo_matrix_multiply(&dwrite_font->mat, &dwrite_font->mat, font_matrix);
     dwrite_font->mat_inverse = dwrite_font->mat;
@@ -667,9 +668,9 @@ _cairo_dwrite_font_face_scaled_font_create (void			*abstract_face,
     if (dwrite_font->measuring_mode == DWRITE_MEASURING_MODE_GDI_CLASSIC ||
 	dwrite_font->measuring_mode == DWRITE_MEASURING_MODE_GDI_NATURAL) {
 	DWRITE_MATRIX transform = _cairo_dwrite_matrix_from_matrix (&dwrite_font->mat);
-	font_face->dwriteface->GetGdiCompatibleMetrics(1, 1, &transform, &metrics);
+        dwrite_font->dwriteface->GetGdiCompatibleMetrics(1, 1, &transform, &metrics);
     } else {
-	font_face->dwriteface->GetMetrics(&metrics);
+        dwrite_font->dwriteface->GetMetrics(&metrics);
     }
 
     extents.ascent = (FLOAT)metrics.ascent / metrics.designUnitsPerEm;
@@ -698,7 +699,7 @@ _cairo_dwrite_font_face_scaled_font_create (void			*abstract_face,
     }
 
     if (default_quality == CAIRO_ANTIALIAS_GRAY) {
-	if (!do_grayscale(font_face->dwriteface, (unsigned int)_cairo_round(font_matrix->yy))) {
+        if (!do_grayscale(dwrite_font->dwriteface, (unsigned int)_cairo_round(font_matrix->yy))) {
 	    default_quality = CAIRO_ANTIALIAS_NONE;
 	}
     }
@@ -720,6 +721,9 @@ static void
 _cairo_dwrite_scaled_font_fini(void *scaled_font)
 {
     cairo_dwrite_scaled_font_t *dwrite_font = static_cast<cairo_dwrite_scaled_font_t*>(scaled_font);
+
+    dwrite_font->dwriteface->Release ();
+
     if (dwrite_font->rendering_params)
 	dwrite_font->rendering_params->Release();
 }
@@ -765,10 +769,9 @@ _cairo_dwrite_ucs4_to_index(void			     *scaled_font,
 			    uint32_t		      ucs4)
 {
     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);
+    UINT16 index = 0;
 
-    UINT16 index;
-    face->dwriteface->GetGlyphIndicesA(&ucs4, 1, &index);
+    dwritesf->dwriteface->GetGlyphIndicesA(&ucs4, 1, &index);
     return index;
 }
 
@@ -787,12 +790,12 @@ _cairo_dwrite_scaled_font_init_glyph_metrics(cairo_dwrite_scaled_font_t *scaled_
     if (font_face->measuring_mode == DWRITE_MEASURING_MODE_GDI_CLASSIC ||
 	font_face->measuring_mode == DWRITE_MEASURING_MODE_GDI_NATURAL) {
 	DWRITE_MATRIX transform = _cairo_dwrite_matrix_from_matrix (&scaled_font->mat);
-	font_face->dwriteface->GetGdiCompatibleMetrics(1, 1, &transform, &fontMetrics);
+        scaled_font->dwriteface->GetGdiCompatibleMetrics(1, 1, &transform, &fontMetrics);
 	BOOL natural = font_face->measuring_mode == DWRITE_MEASURING_MODE_GDI_NATURAL;
-	hr = font_face->dwriteface->GetGdiCompatibleGlyphMetrics (1, 1, &transform, natural, &charIndex, 1, &metrics, FALSE);
+        hr = scaled_font->dwriteface->GetGdiCompatibleGlyphMetrics (1, 1, &transform, natural, &charIndex, 1, &metrics, FALSE);
     } else {
-	font_face->dwriteface->GetMetrics(&fontMetrics);
-	hr = font_face->dwriteface->GetDesignGlyphMetrics(&charIndex, 1, &metrics);
+	scaled_font->dwriteface->GetMetrics(&fontMetrics);
+        hr = scaled_font->dwriteface->GetDesignGlyphMetrics(&charIndex, 1, &metrics);
     }
     if (FAILED(hr)) {
 	return CAIRO_INT_STATUS_UNSUPPORTED;
@@ -968,16 +971,15 @@ _cairo_dwrite_scaled_font_init_glyph_path(cairo_dwrite_scaled_font_t *scaled_fon
     offset.ascenderOffset = 0;
     UINT16 glyphId = (UINT16)_cairo_scaled_glyph_index(scaled_glyph);
     FLOAT advance = 0.0;
-    cairo_dwrite_font_face_t *dwriteff = (cairo_dwrite_font_face_t*)scaled_font->base.font_face;
-
-    HRESULT hr = dwriteff->dwriteface->GetGlyphRunOutline(1,
-							  &glyphId,
-							  &advance,
-							  &offset,
-							  1,
-							  FALSE,
-							  FALSE,
-							  &recorder);
+
+    HRESULT hr = scaled_font->dwriteface->GetGlyphRunOutline(1,
+                                                             &glyphId,
+                                                             &advance,
+                                                             &offset,
+                                                             1,
+                                                             FALSE,
+                                                             FALSE,
+                                                             &recorder);
     if (!SUCCEEDED(hr))
 	return _cairo_dwrite_error (hr, "GetGlyphRunOutline failed");
 
@@ -1035,7 +1037,7 @@ _cairo_dwrite_scaled_font_init_glyph_color_surface(cairo_dwrite_scaled_font_t *s
     /* Y-axis is inverted */
     offset.ascenderOffset = -(FLOAT)y;
 
-    run.fontFace = dwrite_font_face->dwriteface;
+    run.fontFace = scaled_font->dwriteface;
     run.fontEmSize = 1;
     run.glyphCount = 1;
     run.glyphIndices = &index;
@@ -1057,7 +1059,7 @@ _cairo_dwrite_scaled_font_init_glyph_color_surface(cairo_dwrite_scaled_font_t *s
 
     RefPtr<IDWriteFontFace2> fontFace2;
     UINT32 palette_count = 0;
-    if (SUCCEEDED(dwrite_font_face->dwriteface->QueryInterface(&fontFace2)))
+    if (SUCCEEDED(scaled_font->dwriteface->QueryInterface(&fontFace2)))
 	palette_count = fontFace2->GetColorPaletteCount();
 
     UINT32 palette_index = CAIRO_COLOR_PALETTE_DEFAULT;
@@ -1283,7 +1285,7 @@ _cairo_dwrite_scaled_font_init_glyph_surface(cairo_dwrite_scaled_font_t *scaled_
 
     run.glyphCount = 1;
     run.glyphAdvances = &advance;
-    run.fontFace = ((cairo_dwrite_font_face_t*)scaled_font->base.font_face)->dwriteface;
+    run.fontFace = scaled_font->dwriteface;
     run.fontEmSize = 1.0f;
     run.bidiLevel = 0;
     run.glyphIndices = &index;
@@ -1323,18 +1325,17 @@ _cairo_dwrite_load_truetype_table(void                 *scaled_font,
 				  unsigned long        *length)
 {
     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;
     HRESULT hr;
-    hr = face->dwriteface->TryGetFontTable (be32_to_cpu (tag),
-					    &data,
-					    &size,
-					    &tableContext,
-					    &exists);
+    hr = dwritesf->dwriteface->TryGetFontTable (be32_to_cpu (tag),
+                                                &data,
+                                                &size,
+                                                &tableContext,
+                                                &exists);
     if (FAILED(hr))
 	return _cairo_dwrite_error (hr, "TryGetFontTable failed");
 
@@ -1349,7 +1350,7 @@ _cairo_dwrite_load_truetype_table(void                 *scaled_font,
     *length = size;
 
     if (tableContext) {
-	face->dwriteface->ReleaseFontTable(tableContext);
+        dwritesf->dwriteface->ReleaseFontTable(tableContext);
     }
     return (cairo_int_status_t)CAIRO_STATUS_SUCCESS;
 }
@@ -1359,17 +1360,16 @@ _cairo_dwrite_is_synthetic(void                      *scaled_font,
 			   cairo_bool_t              *is_synthetic)
 {
     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);
     HRESULT hr;
     cairo_int_status_t status;
 
-    if (face->dwriteface->GetSimulations() != DWRITE_FONT_SIMULATIONS_NONE) {
+    if (dwritesf->dwriteface->GetSimulations() != DWRITE_FONT_SIMULATIONS_NONE) {
 	*is_synthetic = FALSE;
 	return CAIRO_INT_STATUS_SUCCESS;
     }
 
     RefPtr<IDWriteFontFace5> fontFace5;
-    if (FAILED(face->dwriteface->QueryInterface(&fontFace5))) {
+    if (FAILED(dwritesf->dwriteface->QueryInterface(&fontFace5))) {
 	/* If IDWriteFontFace5 is not available, assume this version of
 	 * DirectWrite does not support variations.
 	 */
@@ -1722,7 +1722,6 @@ _cairo_dwrite_show_glyphs_on_surface(void			*surface,
 {
     // TODO: Check font & surface for types.
     cairo_dwrite_scaled_font_t *dwritesf = reinterpret_cast<cairo_dwrite_scaled_font_t*>(scaled_font);
-    cairo_dwrite_font_face_t *dwriteff = reinterpret_cast<cairo_dwrite_font_face_t*>(scaled_font->font_face);
     cairo_win32_surface_t *dst = reinterpret_cast<cairo_win32_surface_t*>(surface);
     cairo_int_status_t status;
     /* We can only handle dwrite fonts */
@@ -1827,10 +1826,10 @@ compare_font_tables (cairo_dwrite_font_face_t *dwface,
     HRESULT hr;
 
     hr = dwface->dwriteface->TryGetFontTable(be32_to_cpu (tag),
-					     &dw_data,
-					     &dw_size,
-					     &dw_tableContext,
-					     &dw_exists);
+                                             &dw_data,
+                                             &dw_size,
+                                             &dw_tableContext,
+                                             &dw_exists);
     if (FAILED(hr))
 	return _cairo_dwrite_error (hr, "TryGetFontTable failed");
 
@@ -1866,7 +1865,7 @@ compare_font_tables (cairo_dwrite_font_face_t *dwface,
 cleanup:
     free (buffer);
     if (dw_tableContext)
-	dwface->dwriteface->ReleaseFontTable(dw_tableContext);
+        dwface->dwriteface->ReleaseFontTable(dw_tableContext);
 
     return status;
 }
@@ -1931,6 +1930,8 @@ _cairo_dwrite_scaled_font_create_win32_scaled_font (cairo_scaled_font_t *scaled_
         return CAIRO_INT_STATUS_UNSUPPORTED;
     }
 
+    /* TODO: use scaled font? */
+
     LOGFONTW logfont;
     if (FAILED(gdiInterop->ConvertFontFaceToLOGFONT (dwface->dwriteface, &logfont))) {
 	return CAIRO_INT_STATUS_UNSUPPORTED;
diff --git a/src/win32/cairo-dwrite-private.hpp b/src/win32/cairo-dwrite-private.hpp
index c7a24822a..19c666da5 100644
--- a/src/win32/cairo-dwrite-private.hpp
+++ b/src/win32/cairo-dwrite-private.hpp
@@ -68,7 +68,8 @@ struct _cairo_dwrite_scaled_font {
     cairo_matrix_t mat;
     cairo_matrix_t mat_inverse;
     cairo_antialias_t antialias_mode;
-    IDWriteRenderingParams *rendering_params;
+    IDWriteFontFace *dwriteface; /* Can't use RefPtr because this struct is malloc'd.  */
+    IDWriteRenderingParams *rendering_params; /* Can't use RefPtr because this struct is malloc'd.  */
     DWRITE_MEASURING_MODE measuring_mode;
 };
 typedef struct _cairo_dwrite_scaled_font cairo_dwrite_scaled_font_t;
commit af4f149057f3484ea64ffbfddea0c77bdb3fc9bc
Author: Benjamin Gilbert <bgilbert at backtick.net>
Date:   Wed Sep 4 21:46:04 2024 -0700

    meson: Don't require C++ compiler for build machine on Windows
    
    We only build C++ code for the host.  Fixes Meson warning:
    
        meson.build:486: WARNING: add_languages is missing native:, assuming languages are wanted for both host and build.

diff --git a/meson.build b/meson.build
index 4051a7c11..553314d2b 100644
--- a/meson.build
+++ b/meson.build
@@ -483,7 +483,7 @@ if host_machine.system() == 'darwin' and not get_option('quartz').disabled()
 endif
 
 if host_machine.system() == 'windows'
-  add_languages('cpp')
+  add_languages('cpp', native: false)
 
   add_project_arguments('-DWIN32_LEAN_AND_MEAN', '-DNOMINMAX', language: ['c', 'cpp'])
 
commit 3e97e1f16b4ebe5516c0afc092122a224b5c13eb
Author: Benjamin Gilbert <bgilbert at backtick.net>
Date:   Wed Sep 4 20:58:30 2024 -0700

    meson: Rename meson_options.txt to meson.options
    
    The new name is a bit cleaner and is supported by all versions of Meson
    that we support.

diff --git a/meson_options.txt b/meson.options
similarity index 100%
rename from meson_options.txt
rename to meson.options


More information about the cairo-commit mailing list