Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  cairo-dwrite-font.cpp

  Sprache: C
 

/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
/* Cairo - a vector graphics library with display and print output
 *
 * Copyright © 2010 Mozilla Foundation
 *
 * This library is free software; you can redistribute it and/or
 * modify it either under the terms of the GNU Lesser General Public
 * License version 2.1 as published by the Free Software Foundation
 * (the "LGPL") or, at your option, under the terms of the Mozilla
 * Public License Version 1.1 (the "MPL"). If you do not alter this
 * notice, a recipient may use your version of this file under either
 * the MPL or the LGPL.
 *
 * You should have received a copy of the LGPL along with this library
 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 * You should have received a copy of the MPL along with this library
 * in the file COPYING-MPL-1.1
 *
 * The contents of this file are subject to the Mozilla Public License
 * Version 1.1 (the "License"); you may not use this file except in
 * compliance with the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
 * the specific language governing rights and limitations.
 *
 * The Original Code is the cairo graphics library.
 *
 * The Initial Developer of the Original Code is the Mozilla Foundation
 *
 * Contributor(s):
 * Bas Schouten <bschouten@mozilla.com>
 */


#include "cairoint.h"

#include "cairo-win32-private.h"
#include "cairo-pattern-private.h"
#include "cairo-surface-private.h"
#include "cairo-image-surface-private.h"
#include "cairo-clip-private.h"
#include "cairo-win32-refptr.hpp"
#include "cairo-dwrite-private.hpp"
#include "cairo-truetype-subset-private.h"
#include "cairo-scaled-font-subsets-private.h"
#include "cairo-dwrite.h"

#include <utility>
#include <float.h>

#include <wincodec.h>

/**
 * SECTION:cairo-dwrite-fonts
 * @Title: DWrite Fonts
 * @Short_Description: Font support for Microsoft DirectWrite
 * @See_Also: #cairo_font_face_t
 *
 * The Microsoft DirectWrite font backend is primarily used to render text on
 * Microsoft Windows systems.
 **/


/**
 * CAIRO_HAS_DWRITE_FONT:
 *
 * Defined if the Microsoft DWrite font backend is available.
 * This macro can be used to conditionally compile backend-specific code.
 *
 * Since: 1.18
 **/


typedef HRESULT (WINAPI*D2D1CreateFactoryFunc)(
    D2D1_FACTORY_TYPE factoryType,
    REFIID iid,
    CONST D2D1_FACTORY_OPTIONS *pFactoryOptions,
    void **factory
);

#define CAIRO_INT_STATUS_SUCCESS (cairo_int_status_t)CAIRO_STATUS_SUCCESS

// Forward declarations
cairo_int_status_t
_dwrite_draw_glyphs_to_gdi_surface_d2d(cairo_win32_surface_t *surface,
           DWRITE_MATRIX *transform,
           DWRITE_GLYPH_RUN *run,
           COLORREF color,
           const RECT &area);

static cairo_int_status_t
_dwrite_draw_glyphs_to_gdi_surface_gdi(cairo_win32_surface_t *surface,
           DWRITE_MATRIX *transform,
           DWRITE_GLYPH_RUN *run,
           COLORREF color,
           cairo_dwrite_scaled_font_t *scaled_font,
           const RECT &area);

/**
 * _cairo_dwrite_error:
 * @hr HRESULT code
 * @context: context string to display along with the error
 *
 * Helper function to print a human readable form a HRESULT.
 *
 * Return value: A cairo status code for the error code
 **/

static cairo_int_status_t
_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,
    MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
    (LPWSTR) &lpMsgBuf,
    0, NULL)) {
 fprintf (stderr, "%s: Unknown DWrite error HRESULT=0x%08lx\n", context, (unsigned long)hr);
    } else {
 fprintf (stderr, "%s: %S\n", context, (wchar_t *)lpMsgBuf);
 LocalFree (lpMsgBuf);
    }
    fflush (stderr);

    return (cairo_int_status_t)_cairo_error (CAIRO_STATUS_DWRITE_ERROR);
}

class D2DFactory
{
public:
    static RefPtr<ID2D1Factory> Instance()
    {
 if (!mFactoryInstance) {
#ifdef __GNUC__
#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(d2d1, "D2D1CreateFactory");
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
     if (createD2DFactory) {
  D2D1_FACTORY_OPTIONS options;
  options.debugLevel = D2D1_DEBUG_LEVEL_NONE;
  createD2DFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED,
     __uuidof(ID2D1Factory),
     &options,
     (void**)&mFactoryInstance);
     }
 }
 return mFactoryInstance;
    }

    static RefPtr<IDWriteFactory4> Instance4()
    {
 if (!mFactoryInstance4) {
     if (Instance()) {
  Instance()->QueryInterface(&mFactoryInstance4);
     }
 }
 return mFactoryInstance4;
    }

    static RefPtr<ID2D1DCRenderTarget> RenderTarget()
    {
 if (!mRenderTarget) {
     if (!Instance()) {
  return NULL;
     }
     // Create a DC render target.
     D2D1_RENDER_TARGET_PROPERTIES props = D2D1::RenderTargetProperties(
  D2D1_RENDER_TARGET_TYPE_DEFAULT,
  D2D1::PixelFormat(
      DXGI_FORMAT_B8G8R8A8_UNORM,
      D2D1_ALPHA_MODE_PREMULTIPLIED),
  0,
  0,
  D2D1_RENDER_TARGET_USAGE_NONE,
  D2D1_FEATURE_LEVEL_DEFAULT
  );

     Instance()->CreateDCRenderTarget(&props, &mRenderTarget);
 }
 return mRenderTarget;
    }

private:
    static RefPtr<ID2D1Factory> mFactoryInstance;
    static RefPtr<IDWriteFactory4> mFactoryInstance4;
    static RefPtr<ID2D1DCRenderTarget> mRenderTarget;
};

class WICImagingFactory
{
public:
    static RefPtr<IWICImagingFactory> Instance()
    {
 if (!mFactoryInstance) {
     CoInitialize(NULL);
     CoCreateInstance(CLSID_WICImagingFactory,
        NULL,
        CLSCTX_INPROC_SERVER,
        IID_PPV_ARGS(&mFactoryInstance));
 }
 return mFactoryInstance;
    }
private:
    static RefPtr<IWICImagingFactory> mFactoryInstance;
};


RefPtr<IDWriteFactory> DWriteFactory::mFactoryInstance;
RefPtr<IDWriteFactory1> DWriteFactory::mFactoryInstance1;
RefPtr<IDWriteFactory2> DWriteFactory::mFactoryInstance2;
RefPtr<IDWriteFactory3> DWriteFactory::mFactoryInstance3;
RefPtr<IDWriteFactory4> DWriteFactory::mFactoryInstance4;

RefPtr<IWICImagingFactory> WICImagingFactory::mFactoryInstance;
RefPtr<IDWriteFontCollection> DWriteFactory::mSystemCollection;
RefPtr<IDWriteRenderingParams> DWriteFactory::mDefaultRenderingParams;

RefPtr<ID2D1Factory> D2DFactory::mFactoryInstance;
RefPtr<ID2D1DCRenderTarget> D2DFactory::mRenderTarget;

static RefPtr<IDWriteRenderingParams>
_create_rendering_params(IDWriteRenderingParams     *params,
    const cairo_font_options_t *options,
    cairo_antialias_t           antialias)
{
    if (!params)
 params = DWriteFactory::DefaultRenderingParams();
    FLOAT gamma = params->GetGamma();
    FLOAT enhanced_contrast = params->GetEnhancedContrast();
    FLOAT clear_type_level = params->GetClearTypeLevel();
    DWRITE_PIXEL_GEOMETRY pixel_geometry = params->GetPixelGeometry();
    DWRITE_RENDERING_MODE rendering_mode = params->GetRenderingMode();

    cairo_bool_t modified = FALSE;
    switch (antialias) {
    case CAIRO_ANTIALIAS_NONE:
 if (rendering_mode != DWRITE_RENDERING_MODE_ALIASED) {
     rendering_mode = DWRITE_RENDERING_MODE_ALIASED;
     modified = TRUE;
 }
 break;
    case CAIRO_ANTIALIAS_FAST:
    case CAIRO_ANTIALIAS_GRAY:
 if (clear_type_level) {
     clear_type_level = 0;
     modified = TRUE;
 }
 break;
    default:
 break;
    }
    auto subpixel_order = cairo_font_options_get_subpixel_order (options);
    switch (subpixel_order) {
    case CAIRO_SUBPIXEL_ORDER_RGB:
 if (pixel_geometry != DWRITE_PIXEL_GEOMETRY_RGB) {
     pixel_geometry = DWRITE_PIXEL_GEOMETRY_RGB;
     modified = TRUE;
 }
 break;
    case CAIRO_SUBPIXEL_ORDER_BGR:
 if (pixel_geometry != DWRITE_PIXEL_GEOMETRY_BGR) {
     pixel_geometry = DWRITE_PIXEL_GEOMETRY_BGR;
     modified = TRUE;
 }
 break;
    default:
 break;
    } 
    if (!modified)
 return params;

    HRESULT hr;
    RefPtr<IDWriteRenderingParams1> params1;
    hr = params->QueryInterface(¶ms1);
    if (FAILED(hr)) {
 RefPtr<IDWriteRenderingParams> ret;
 DWriteFactory::Instance()->CreateCustomRenderingParams(gamma, enhanced_contrast, clear_type_level, pixel_geometry, rendering_mode, &ret);
 return ret;
    }

    FLOAT grayscaleEnhancedContrast = params1->GetGrayscaleEnhancedContrast();
    RefPtr<IDWriteRenderingParams2> params2;
    hr = params->QueryInterface(¶ms2);
    if (FAILED(hr)) {
 RefPtr<IDWriteRenderingParams1> ret;
 DWriteFactory::Instance1()->CreateCustomRenderingParams(gamma, enhanced_contrast, grayscaleEnhancedContrast, clear_type_level, pixel_geometry, rendering_mode, &ret);
 return ret;
    }    

    DWRITE_GRID_FIT_MODE gridFitMode = params2->GetGridFitMode();
    RefPtr<IDWriteRenderingParams3> params3;
    hr = params->QueryInterface(¶ms3);
    if (FAILED(hr)) {
 RefPtr<IDWriteRenderingParams2> ret;
 DWriteFactory::Instance2()->CreateCustomRenderingParams(gamma, enhanced_contrast, grayscaleEnhancedContrast, clear_type_level, pixel_geometry, rendering_mode, gridFitMode, &ret);
 return ret;
    }    
    
    DWRITE_RENDERING_MODE1 rendering_mode1 = params3->GetRenderingMode1();
    if (antialias == CAIRO_ANTIALIAS_NONE)
 rendering_mode1 = DWRITE_RENDERING_MODE1_ALIASED;
    RefPtr<IDWriteRenderingParams3> ret;
    DWriteFactory::Instance3()->CreateCustomRenderingParams(gamma, enhanced_contrast, grayscaleEnhancedContrast, clear_type_level, pixel_geometry, rendering_mode1, gridFitMode, &ret);
    return ret;
}

/* Functions #cairo_font_face_backend_t */
static cairo_status_t
_cairo_dwrite_font_face_create_for_toy (cairo_toy_font_face_t   *toy_face,
     cairo_font_face_t      **font_face);
static cairo_bool_t
_cairo_dwrite_font_face_destroy (void *font_face);

static cairo_status_t
_cairo_dwrite_font_face_scaled_font_create (void   *abstract_face,
         const cairo_matrix_t *font_matrix,
         const cairo_matrix_t *ctm,
         const cairo_font_options_t *options,
         cairo_scaled_font_t **font);

const cairo_font_face_backend_t _cairo_dwrite_font_face_backend = {
    CAIRO_FONT_TYPE_DWRITE,
    _cairo_dwrite_font_face_create_for_toy,
    _cairo_dwrite_font_face_destroy,
    _cairo_dwrite_font_face_scaled_font_create
};

/* Functions #cairo_scaled_font_backend_t */

static void _cairo_dwrite_scaled_font_fini(void *scaled_font);

static cairo_warn cairo_int_status_t
_cairo_dwrite_scaled_glyph_init(void        *scaled_font,
    cairo_scaled_glyph_t      *scaled_glyph,
    cairo_scaled_glyph_info_t     info,
    const cairo_color_t          *foreground_color);

static cairo_int_status_t
_cairo_dwrite_load_truetype_table(void         *scaled_font,
      unsigned long         tag,
      long                  offset,
      unsigned char        *buffer,
      unsigned long        *length);

static unsigned long
_cairo_dwrite_ucs4_to_index(void         *scaled_font,
       uint32_t                    ucs4);

static cairo_int_status_t
_cairo_dwrite_is_synthetic(void                       *scaled_font,
      cairo_bool_t               *is_synthetic);

static cairo_bool_t
_cairo_dwrite_has_color_glyphs(void *scaled_font);

static const cairo_scaled_font_backend_t _cairo_dwrite_scaled_font_backend = {
    CAIRO_FONT_TYPE_DWRITE,
    _cairo_dwrite_scaled_font_fini,
    _cairo_dwrite_scaled_glyph_init,
    NULL, /* text_to_glyphs */
    _cairo_dwrite_ucs4_to_index,
    _cairo_dwrite_load_truetype_table,
    NULL, /* index_to_ucs4 */
    _cairo_dwrite_is_synthetic,
    NULL, /* index_to_glyph_name */
    NULL, /* load_type1_data */
    _cairo_dwrite_has_color_glyphs
};

/* Helper conversion functions */


/**
 * _cairo_dwrite_matrix_from_matrix:
 * Get a DirectWrite matrix from a cairo matrix. Note that DirectWrite uses row
 * vectors where cairo uses column vectors. Hence the transposition.
 *
 * \param Cairo matrix
 * \return DirectWrite matrix
 **/

static DWRITE_MATRIX
_cairo_dwrite_matrix_from_matrix(const cairo_matrix_t *matrix)
{
    DWRITE_MATRIX dwmat;
    dwmat.m11 = (FLOAT)matrix->xx;
    dwmat.m12 = (FLOAT)matrix->yx;
    dwmat.m21 = (FLOAT)matrix->xy;
    dwmat.m22 = (FLOAT)matrix->yy;
    dwmat.dx = (FLOAT)matrix->x0;
    dwmat.dy = (FLOAT)matrix->y0;
    return dwmat;
}

/* Helper functions for cairo_dwrite_scaled_glyph_init() */
static cairo_int_status_t
_cairo_dwrite_scaled_font_init_glyph_metrics
    (cairo_dwrite_scaled_font_t *scaled_font, cairo_scaled_glyph_t *scaled_glyph);

static cairo_int_status_t
_cairo_dwrite_scaled_font_init_glyph_color_surface(cairo_dwrite_scaled_font_t *scaled_font,
         cairo_scaled_glyph_t       *scaled_glyph,
         const cairo_color_t        *foreground_color);

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);

static cairo_int_status_t
_cairo_dwrite_scaled_font_init_glyph_path
    (cairo_dwrite_scaled_font_t *scaled_font, cairo_scaled_glyph_t *scaled_glyph);

/* implement the font backend interface */

static cairo_status_t
_cairo_dwrite_font_face_create_for_toy (cairo_toy_font_face_t   *toy_face,
     cairo_font_face_t      **font_face)
{
    WCHAR *face_name;
    int face_name_len;

    if (!DWriteFactory::Instance()) {
 return (cairo_status_t)CAIRO_INT_STATUS_UNSUPPORTED;
    }

    face_name_len = MultiByteToWideChar(CP_UTF8, 0, toy_face->family, -1, NULL, 0);
    face_name = new WCHAR[face_name_len];
    MultiByteToWideChar(CP_UTF8, 0, toy_face->family, -1, face_name, face_name_len);

    RefPtr<IDWriteFontFamily> family = DWriteFactory::FindSystemFontFamily(face_name);
    delete[] face_name;
    if (!family) {
 /* If the family is not found, use the default that should always exist. */
 face_name_len = MultiByteToWideChar(CP_UTF8, 0, CAIRO_FONT_FAMILY_DEFAULT, -1, NULL, 0);
 face_name = new WCHAR[face_name_len];
 MultiByteToWideChar(CP_UTF8, 0, CAIRO_FONT_FAMILY_DEFAULT, -1, face_name, face_name_len);

 family = DWriteFactory::FindSystemFontFamily(face_name);
 delete[] face_name;
 if (!family) {
     *font_face = (cairo_font_face_t*)&_cairo_font_face_nil;
     return (cairo_status_t)CAIRO_INT_STATUS_UNSUPPORTED;
 }
    }

    DWRITE_FONT_WEIGHT weight;
    switch (toy_face->weight) {
    case CAIRO_FONT_WEIGHT_BOLD:
 weight = DWRITE_FONT_WEIGHT_BOLD;
 break;
    case CAIRO_FONT_WEIGHT_NORMAL:
    default:
 weight = DWRITE_FONT_WEIGHT_NORMAL;
 break;
    }

    DWRITE_FONT_STYLE style;
    switch (toy_face->slant) {
    case CAIRO_FONT_SLANT_ITALIC:
 style = DWRITE_FONT_STYLE_ITALIC;
 break;
    case CAIRO_FONT_SLANT_OBLIQUE:
 style = DWRITE_FONT_STYLE_OBLIQUE;
 break;
    case CAIRO_FONT_SLANT_NORMAL:
    default:
 style = DWRITE_FONT_STYLE_NORMAL;
 break;
    }

    RefPtr<IDWriteFont> font;
    HRESULT hr = family->GetFirstMatchingFont(weight, DWRITE_FONT_STRETCH_NORMAL, style, &font);
    if (FAILED(hr))
 return (cairo_status_t)_cairo_dwrite_error (hr, "GetFirstMatchingFont failed");

    RefPtr<IDWriteFontFace> dwriteface;
    hr = font->CreateFontFace(&dwriteface);
    if (FAILED(hr))
 return (cairo_status_t)_cairo_dwrite_error (hr, "CreateFontFace failed");

    *font_face = cairo_dwrite_font_face_create_for_dwrite_fontface(dwriteface);
    return CAIRO_STATUS_SUCCESS;
}

static cairo_bool_t
_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();
    if (dwrite_font_face->rendering_params)
 dwrite_font_face->rendering_params->Release();
    return TRUE;
}

static inline unsigned short
read_short(const char *buf)
{
    return be16_to_cpu(*(unsigned short*)buf);
}

void
_cairo_dwrite_glyph_run_from_glyphs(cairo_glyph_t *glyphs,
        int num_glyphs,
        cairo_dwrite_scaled_font_t *scaled_font,
        AutoDWriteGlyphRun *run,
        cairo_bool_t *transformed)
{
    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);

    run->bidiLevel = 0;
    run->fontFace = scaled_font->dwriteface;
    run->glyphCount = num_glyphs;
    run->isSideways = FALSE;

    if (scaled_font->mat.xy == 0 && scaled_font->mat.yx == 0 &&
 scaled_font->mat.xx == scaled_font->base.font_matrix.xx &&
 scaled_font->mat.yy == scaled_font->base.font_matrix.yy) {
 // Fast route, don't actually use a transform but just
 // set the correct font size.
 *transformed = 0;

 run->fontEmSize = (FLOAT)scaled_font->base.font_matrix.yy;

 for (int i = 0; i < num_glyphs; i++) {
     indices[i] = (WORD) glyphs[i].index;

     offsets[i].ascenderOffset = -(FLOAT)(glyphs[i].y);
     offsets[i].advanceOffset = (FLOAT)(glyphs[i].x);
     advances[i] = 0.0;
 }
    } else {
 *transformed = 1;
        // Transforming positions by the inverse matrix, then by the original
        // matrix later may introduce small errors, especially because the
        // D2D matrix is single-precision whereas the cairo one is double.
        // This is a problem when glyph positions were originally at exactly
        // half-pixel locations, which eventually round to whole pixels for
        // GDI rendering - the errors introduced here cause them to round in
        // unpredictable directions, instead of all rounding in a consistent
        // way, leading to poor glyph spacing (bug 675383).
        // To mitigate this, nudge the positions by a tiny amount to try and
        // ensure that after the two transforms, they'll still round in a
        // consistent direction.
        const double EPSILON = 0.0001;
 for (int i = 0; i < num_glyphs; i++) {
     indices[i] = (WORD) glyphs[i].index;
     double x = glyphs[i].x + EPSILON;
     double y = glyphs[i].y;
     cairo_matrix_transform_point(&scaled_font->mat_inverse, &x, &y);
     // Since we will multiply by our ctm matrix later for rotation effects
     // and such, adjust positions by the inverse matrix now. Y-axis is
     // inverted! Therefor the offset is -y.
     offsets[i].ascenderOffset = -(FLOAT)y;
     offsets[i].advanceOffset = (FLOAT)x;
     advances[i] = 0.0;
 }
 // The font matrix takes care of the scaling if we have a transform,
 // emSize should be 1.
 run->fontEmSize = 1.0f;
    }
}

#define GASP_TAG 0x70736167
#define GASP_DOGRAY 0x2

static cairo_bool_t
do_grayscale(IDWriteFontFace *dwface, unsigned int ppem)
{
    void *tableContext;
    char *tableData;
    UINT32 tableSize;
    BOOL exists;
    dwface->TryGetFontTable(GASP_TAG, (const void**)&tableData, &tableSize, &tableContext, &exists);

    if (exists) {
 if (tableSize < 4) {
     dwface->ReleaseFontTable(tableContext);
     return true;
 }
 struct gaspRange {
     unsigned short maxPPEM; // Stored big-endian
     unsigned short behavior; // Stored big-endian
 };
 unsigned short numRanges = read_short(tableData + 2);
 if (tableSize < (UINT)4 + numRanges * 4) {
     dwface->ReleaseFontTable(tableContext);
     return true;
 }
 gaspRange *ranges = (gaspRange *)(tableData + 4);
 for (int i = 0; i < numRanges; i++) {
     if (be16_to_cpu(ranges[i].maxPPEM) > ppem) {
  if (!(be16_to_cpu(ranges[i].behavior) & GASP_DOGRAY)) {
      dwface->ReleaseFontTable(tableContext);
      return false;
  }
  break;
     }
 }
 dwface->ReleaseFontTable(tableContext);
    }
    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,
         const cairo_matrix_t *ctm,
         const cairo_font_options_t  *options,
         cairo_scaled_font_t **font)
{
    cairo_status_t status;
    cairo_dwrite_font_face_t *font_face = static_cast<cairo_dwrite_font_face_t*>(abstract_face);

    /* Must do malloc and not C++ new, since Cairo frees this. */
    cairo_dwrite_scaled_font_t *dwrite_font = (cairo_dwrite_scaled_font_t*)_cairo_calloc(
 sizeof(cairo_dwrite_scaled_font_t));
    if (unlikely(dwrite_font == NULL))
 return _cairo_error (CAIRO_STATUS_NO_MEMORY);

    *font = reinterpret_cast<cairo_scaled_font_t*>(dwrite_font);
    status = _cairo_scaled_font_init (&dwrite_font->base,
          &font_face->base,
          font_matrix,
          ctm,
          options,
          &_cairo_dwrite_scaled_font_backend);
    if (status) {
 free(dwrite_font);
 return status;
    }

    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);
    dwrite_font->mat_inverse = dwrite_font->mat;
    cairo_matrix_invert (&dwrite_font->mat_inverse);

    cairo_font_extents_t extents;

    DWRITE_FONT_METRICS metrics;
    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);
        dwrite_font->dwriteface->GetGdiCompatibleMetrics(11, &transform, &metrics);
    } else {
        dwrite_font->dwriteface->GetMetrics(&metrics);
    }

    extents.ascent = (FLOAT)metrics.ascent / metrics.designUnitsPerEm;
    extents.descent = (FLOAT)metrics.descent / metrics.designUnitsPerEm;
    extents.height = (FLOAT)(metrics.ascent + metrics.descent + metrics.lineGap) / metrics.designUnitsPerEm;
    extents.max_x_advance = 14.0;
    extents.max_y_advance = 0.0;

    cairo_antialias_t default_quality = CAIRO_ANTIALIAS_SUBPIXEL;

    // The following code detects the system quality at scaled_font creation time,
    // this means that if cleartype settings are changed but the scaled_fonts
    // are re-used, they might not adhere to the new system setting until re-
    // creation.
    switch (cairo_win32_get_system_text_quality()) {
 case CLEARTYPE_QUALITY:
     default_quality = CAIRO_ANTIALIAS_SUBPIXEL;
     break;
 case ANTIALIASED_QUALITY:
     default_quality = CAIRO_ANTIALIAS_GRAY;
     break;
 case DEFAULT_QUALITY:
     // _get_system_quality() seems to think aliased is default!
     default_quality = CAIRO_ANTIALIAS_NONE;
     break;
    }

    if (default_quality == CAIRO_ANTIALIAS_GRAY) {
        if (!do_grayscale(dwrite_font->dwriteface, (unsigned int)_cairo_round(font_matrix->yy))) {
     default_quality = CAIRO_ANTIALIAS_NONE;
 }
    }

    if (options->antialias == CAIRO_ANTIALIAS_DEFAULT) {
 dwrite_font->antialias_mode = default_quality;
    } else {
 dwrite_font->antialias_mode = options->antialias;
    }

    dwrite_font->rendering_params = _create_rendering_params(font_face->rendering_params, options, dwrite_font->antialias_mode).forget().drop();
    dwrite_font->measuring_mode = font_face->measuring_mode;

    return _cairo_scaled_font_set_metrics (*font, &extents);
}

/* Implementation #cairo_dwrite_scaled_font_backend_t */
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();
}

static cairo_int_status_t
_cairo_dwrite_scaled_glyph_init(void        *scaled_font,
    cairo_scaled_glyph_t      *scaled_glyph,
    cairo_scaled_glyph_info_t     info,
    const cairo_color_t          *foreground_color)
{
    cairo_dwrite_scaled_font_t *scaled_dwrite_font = static_cast<cairo_dwrite_scaled_font_t*>(scaled_font);
    cairo_int_status_t status = CAIRO_INT_STATUS_UNSUPPORTED;

    if ((info & CAIRO_SCALED_GLYPH_INFO_METRICS) != 0) {
 status = _cairo_dwrite_scaled_font_init_glyph_metrics (scaled_dwrite_font, scaled_glyph);
 if (status)
     return status;
    }

    if (info & CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE) {
 status = _cairo_dwrite_scaled_font_init_glyph_color_surface (scaled_dwrite_font, scaled_glyph, foreground_color);
 if (status)
     return status;
    }

    if (info & CAIRO_SCALED_GLYPH_INFO_SURFACE) {
 status = _cairo_dwrite_scaled_font_init_glyph_surface (scaled_dwrite_font, scaled_glyph);
 if (status)
     return status;
    }

    if ((info & CAIRO_SCALED_GLYPH_INFO_PATH) != 0) {
 status = _cairo_dwrite_scaled_font_init_glyph_path (scaled_dwrite_font, scaled_glyph);
 if (status)
     return status;
    }

    return CAIRO_INT_STATUS_SUCCESS;
}

static unsigned long
_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);
    UINT16 index = 0;

    dwritesf->dwriteface->GetGlyphIndicesA(&ucs4, 1, &index);
    return index;
}

/* cairo_dwrite_scaled_glyph_init() helper function bodies */
static cairo_int_status_t
_cairo_dwrite_scaled_font_init_glyph_metrics(cairo_dwrite_scaled_font_t *scaled_font,
          cairo_scaled_glyph_t *scaled_glyph)
{
    UINT16 charIndex = (UINT16)_cairo_scaled_glyph_index (scaled_glyph);
    cairo_dwrite_font_face_t *font_face = (cairo_dwrite_font_face_t*)scaled_font->base.font_face;
    cairo_text_extents_t extents;

    DWRITE_GLYPH_METRICS metrics;
    DWRITE_FONT_METRICS fontMetrics;
    HRESULT hr;
    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);
        scaled_font->dwriteface->GetGdiCompatibleMetrics(11, &transform, &fontMetrics);
 BOOL natural = font_face->measuring_mode == DWRITE_MEASURING_MODE_GDI_NATURAL;
        hr = scaled_font->dwriteface->GetGdiCompatibleGlyphMetrics (11, &transform, natural, &charIndex, 1, &metrics,&nbsp;FALSE);
    } else {
 scaled_font->dwriteface->GetMetrics(&fontMetrics);
        hr = scaled_font->dwriteface->GetDesignGlyphMetrics(&charIndex, 1, &metrics);
    }
    if (FAILED(hr)) {
 return CAIRO_INT_STATUS_UNSUPPORTED;
    }

    // GetGdiCompatibleMetrics may return a glyph metrics that yields a small nagative glyph height.
    INT32 glyph_width = metrics.advanceWidth - metrics.leftSideBearing - metrics.rightSideBearing;
    INT32 glyph_height = metrics.advanceHeight - metrics.topSideBearing - metrics.bottomSideBearing;
    glyph_width = MAX(glyph_width, 0);
    glyph_height = MAX(glyph_height, 0);

    // TODO: Treat swap_xy.
    extents.width = (FLOAT)glyph_width / fontMetrics.designUnitsPerEm;
    extents.height = (FLOAT)glyph_height / fontMetrics.designUnitsPerEm;
    extents.x_advance = (FLOAT)metrics.advanceWidth / fontMetrics.designUnitsPerEm;
    extents.x_bearing = (FLOAT)metrics.leftSideBearing / fontMetrics.designUnitsPerEm;
    extents.y_advance = 0.0;
    extents.y_bearing = (FLOAT)(metrics.topSideBearing - metrics.verticalOriginY) /
 fontMetrics.designUnitsPerEm;

    // We pad the extents here because GetDesignGlyphMetrics returns "ideal" metrics
    // for the glyph outline, without accounting for hinting/gridfitting/antialiasing,
    // and therefore it does not always cover all pixels that will actually be touched.
    if (extents.width > 0 && extents.height > 0) {
 double x = 1, y = 1;
 cairo_matrix_transform_distance (&scaled_font->mat_inverse, &x, &y);
 x = fabs(x);
 y = fabs(y);
 extents.width += x * 2;
 extents.x_bearing -= x;
 extents.height += y * 2;
 extents.y_bearing -= y;
    }

    _cairo_scaled_glyph_set_metrics (scaled_glyph,
         &scaled_font->base,
         &extents);
    return CAIRO_INT_STATUS_SUCCESS;
}

/*
 * Stack-based helper implementing IDWriteGeometrySink.
 * Used to determine the path of the glyphs.
 */


class GeometryRecorder final
    : public IDWriteGeometrySink
{
public:
    GeometryRecorder(cairo_path_fixed_t *aCairoPath, const cairo_matrix_t &matrix)
 : mCairoPath(aCairoPath)
 , mMatrix(matrix) {}

    IFACEMETHOD (QueryInterface)(IID const& iid, OUT void** ppObject) noexcept override
    {
        if (iid == __uuidof (IUnknown) ||
            iid == __uuidof (IDWriteGeometrySink))
        {
            AddRef();
            *ppObject = this;
            return S_OK;
        }

        *ppObject = nullptr;
        return E_NOINTERFACE;
    }

    IFACEMETHOD_(ULONG, AddRef)() noexcept override
    {
 return 1;
    }

    IFACEMETHOD_(ULONG, Release)() noexcept override
    {
 return 1;
    }

    IFACEMETHOD_(void, SetFillMode)(D2D1_FILL_MODE fillMode) noexcept override
    {
 return;
    }

    IFACEMETHOD (Close)() noexcept override
    {
 return S_OK;
    }

    IFACEMETHOD_(void, SetSegmentFlags)(D2D1_PATH_SEGMENT vertexFlags) noexcept override
    {
 return;
    }

    IFACEMETHOD_(void, BeginFigure)(
 D2D1_POINT_2F startPoint,
 D2D1_FIGURE_BEGIN figureBegin) noexcept override
    {
 double x = startPoint.x;
 double y = startPoint.y;
 cairo_matrix_transform_point(&mMatrix, &x, &y);
 mStartPointX = _cairo_fixed_from_double(x);
 mStartPointY = _cairo_fixed_from_double(y);
 cairo_status_t status = _cairo_path_fixed_move_to(mCairoPath,
         mStartPointX,
         mStartPointY);
 (void)status; /* squelch warning */
    }

    IFACEMETHOD_(void, EndFigure)(
 D2D1_FIGURE_END figureEnd) noexcept override
    {
 if (figureEnd == D2D1_FIGURE_END_CLOSED) {
     cairo_status_t status = _cairo_path_fixed_line_to(mCairoPath,
             mStartPointX,
             mStartPointY);
     (void)status; /* squelch warning */
 }
    }

    IFACEMETHOD_(void, AddBeziers)(
 const D2D1_BEZIER_SEGMENT *beziers,
 UINT beziersCount) noexcept override
    {
 for (unsigned int i = 0; i < beziersCount; i++) {
     double x1 = beziers[i].point1.x;
     double y1 = beziers[i].point1.y;
     double x2 = beziers[i].point2.x;
     double y2 = beziers[i].point2.y;
     double x3 = beziers[i].point3.x;
     double y3 = beziers[i].point3.y;
     cairo_matrix_transform_point(&mMatrix, &x1, &y1);
     cairo_matrix_transform_point(&mMatrix, &x2, &y2);
     cairo_matrix_transform_point(&mMatrix, &x3, &y3);
     cairo_status_t status = _cairo_path_fixed_curve_to(mCairoPath,
              _cairo_fixed_from_double(x1),
              _cairo_fixed_from_double(y1),
              _cairo_fixed_from_double(x2),
              _cairo_fixed_from_double(y2),
              _cairo_fixed_from_double(x3),
              _cairo_fixed_from_double(y3));
     (void)status; /* squelch warning */
 }
    }

    IFACEMETHOD_(void, AddLines)(
 const D2D1_POINT_2F *points,
 UINT pointsCount) noexcept override
    {
 for (unsigned int i = 0; i < pointsCount; i++) {
     double x = points[i].x;
     double y = points[i].y;
     cairo_matrix_transform_point(&mMatrix, &x, &y);
     cairo_status_t status = _cairo_path_fixed_line_to(mCairoPath,
             _cairo_fixed_from_double(x),
             _cairo_fixed_from_double(y));
     (void)status; /* squelch warning */
 }
    }

private:
    cairo_path_fixed_t *mCairoPath;
    const cairo_matrix_t &mMatrix;
    cairo_fixed_t mStartPointX;
    cairo_fixed_t mStartPointY;
};

static cairo_int_status_t
_cairo_dwrite_scaled_font_init_glyph_path(cairo_dwrite_scaled_font_t *scaled_font,
       cairo_scaled_glyph_t *scaled_glyph)
{
    cairo_int_status_t status;
    cairo_path_fixed_t *path;
    path = _cairo_path_fixed_create();
    GeometryRecorder recorder(path, scaled_font->base.scale);

    DWRITE_GLYPH_OFFSET offset;
    offset.advanceOffset = 0;
    offset.ascenderOffset = 0;
    UINT16 glyphId = (UINT16)_cairo_scaled_glyph_index(scaled_glyph);
    FLOAT advance = 0.0;

    HRESULT hr = scaled_font->dwriteface->GetGlyphRunOutline(1,
                                                             &glyphId,
                                                             &advance,
                                                             &offset,
                                                             1,
                                                             FALSE,
                                                             FALSE,
                                                             &recorder);
    if (!SUCCEEDED(hr))
 return _cairo_dwrite_error (hr, "GetGlyphRunOutline failed");

    status = (cairo_int_status_t)_cairo_path_fixed_close_path(path);

    _cairo_scaled_glyph_set_path (scaled_glyph,
      &scaled_font->base,
      path);
    return status;
}

static cairo_int_status_t
_cairo_dwrite_scaled_font_init_glyph_color_surface(cairo_dwrite_scaled_font_t *scaled_font,
         cairo_scaled_glyph_t       *scaled_glyph,
         const cairo_color_t        *foreground_color)
{
    int width, height;
    double x1, y1, x2, y2;
    cairo_bool_t uses_foreground_color = FALSE;

    cairo_dwrite_font_face_t *dwrite_font_face = (cairo_dwrite_font_face_t *)scaled_font->base.font_face;
    if (!dwrite_font_face->have_color) {
 scaled_glyph->color_glyph = FALSE;
 scaled_glyph->color_glyph_set = TRUE;
 return CAIRO_INT_STATUS_UNSUPPORTED;
    }

    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);

    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);
    DWRITE_MATRIX matrix;
    D2D1_POINT_2F origin = {00};
    RefPtr<IDWriteColorGlyphRunEnumerator1> run_enumerator;
    HRESULT hr;

    /*
     * 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.
     */

    cairo_matrix_transform_point(&scaled_font->mat_inverse, &x, &y);
    offset.advanceOffset = (FLOAT)x;
    /* Y-axis is inverted */
    offset.ascenderOffset = -(FLOAT)y;

    run.fontFace = scaled_font->dwriteface;
    run.fontEmSize = 1;
    run.glyphCount = 1;
    run.glyphIndices = &index;
    run.glyphAdvances = &advance;
    run.glyphOffsets = &offset;
    run.isSideways = FALSE;
    run.bidiLevel = 0;

    matrix = _cairo_dwrite_matrix_from_matrix(&scaled_font->mat);

    /* The list of glyph image formats this renderer is prepared to support. */
    DWRITE_GLYPH_IMAGE_FORMATS supported_formats = static_cast<DWRITE_GLYPH_IMAGE_FORMATS>(
        DWRITE_GLYPH_IMAGE_FORMATS_COLR |
        DWRITE_GLYPH_IMAGE_FORMATS_SVG |
        DWRITE_GLYPH_IMAGE_FORMATS_PNG |
        DWRITE_GLYPH_IMAGE_FORMATS_JPEG |
        DWRITE_GLYPH_IMAGE_FORMATS_TIFF |
        DWRITE_GLYPH_IMAGE_FORMATS_PREMULTIPLIED_B8G8R8A8);

    RefPtr<IDWriteFontFace2> fontFace2;
    UINT32 palette_count = 0;
    if (SUCCEEDED(scaled_font->dwriteface->QueryInterface(&fontFace2)))
 palette_count = fontFace2->GetColorPaletteCount();

    UINT32 palette_index = CAIRO_COLOR_PALETTE_DEFAULT;
    if (scaled_font->base.options.palette_index < palette_count)
 palette_index = scaled_font->base.options.palette_index;

    hr = DWriteFactory::Instance4()->TranslateColorGlyphRun(
 origin,
 &run,
 NULL, /* glyphRunDescription */
 supported_formats,
 dwrite_font_face->measuring_mode,
 &matrix,
 palette_index,
 &run_enumerator);

    if (hr == DWRITE_E_NOCOLOR) {
 /* No color glyphs */
 scaled_glyph->color_glyph = FALSE;
 scaled_glyph->color_glyph_set = TRUE;
 return CAIRO_INT_STATUS_UNSUPPORTED;
    }

    if (FAILED(hr))
 return _cairo_dwrite_error (hr, "TranslateColorGlyphRun failed");

    /* We have a color glyph(s). Use Direct2D to render it to a bitmap */
    if (!WICImagingFactory::Instance() || !D2DFactory::Instance())
 return _cairo_dwrite_error (hr, "Instance failed");

    RefPtr<IWICBitmap> bitmap;
    hr = WICImagingFactory::Instance()->CreateBitmap ((UINT)width,
            (UINT)height,
            GUID_WICPixelFormat32bppPBGRA,
            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_B8G8R8A8_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<ID2D1DeviceContext4> dc4;
    hr = rt->QueryInterface(&dc4);
    if (FAILED(hr))
 return _cairo_dwrite_error (hr, "QueryInterface(&dc4) failed");

    RefPtr<ID2D1SolidColorBrush> foreground_color_brush;
    dc4->CreateSolidColorBrush(
 D2D1::ColorF(foreground_color->red,
       foreground_color->green,
       foreground_color->blue,
       foreground_color->alpha), &foreground_color_brush);

    RefPtr<ID2D1SolidColorBrush> color_brush;
    dc4->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::Black), &color_brush);

    dc4->SetDpi(9696); /* 1 unit = 1 pixel */
    rt->SetTransform(D2D1::Matrix3x2F(matrix.m11,
          matrix.m12,
          matrix.m21,
          matrix.m22,
          matrix.dx,
          matrix.dy));

    dc4->BeginDraw();
    dc4->Clear(NULL); /* Transparent black */

    while (true) {
 BOOL have_run;
 hr = run_enumerator->MoveNext(&have_run);
 if (FAILED(hr) || !have_run)
     break;

 DWRITE_COLOR_GLYPH_RUN1_WORKAROUND const* color_run;
 hr = run_enumerator->GetCurrentRun(reinterpret_cast<const DWRITE_COLOR_GLYPH_RUN1**>(&color_run));
 if (FAILED(hr))
     return _cairo_dwrite_error (hr, "GetCurrentRun failed");

 switch (color_run->glyphImageFormat) {
     case DWRITE_GLYPH_IMAGE_FORMATS_PNG:
     case DWRITE_GLYPH_IMAGE_FORMATS_JPEG:
     case DWRITE_GLYPH_IMAGE_FORMATS_TIFF:
     case DWRITE_GLYPH_IMAGE_FORMATS_PREMULTIPLIED_B8G8R8A8:
  /* Bitmap glyphs */
  dc4->DrawColorBitmapGlyphRun(color_run->glyphImageFormat,
          origin,
          &color_run->glyphRun,
          dwrite_font_face->measuring_mode,
          D2D1_COLOR_BITMAP_GLYPH_SNAP_OPTION_DEFAULT);
  break;

     case DWRITE_GLYPH_IMAGE_FORMATS_SVG:
  /* SVG glyphs */
  dc4->DrawSvgGlyphRun(origin,
         &color_run->glyphRun,
         foreground_color_brush,
         nullptr,
         palette_index,
         dwrite_font_face->measuring_mode);
  uses_foreground_color = TRUE;
  break;
     case DWRITE_GLYPH_IMAGE_FORMATS_TRUETYPE:
     case DWRITE_GLYPH_IMAGE_FORMATS_CFF:
     case DWRITE_GLYPH_IMAGE_FORMATS_COLR:
  /* Outline glyphs */
  if (color_run->paletteIndex == 0xFFFF) {
      D2D1_COLOR_F color = foreground_color_brush->GetColor();
      color_brush->SetColor(&color);
      uses_foreground_color = TRUE;
  } else {
      double red, green, blue, alpha;
      cairo_status_t status;
      status = cairo_font_options_get_custom_palette_color (&scaled_font->base.options,
           color_run->paletteIndex,
           &red, &blue, &green, &alpha);
      if (status == CAIRO_STATUS_SUCCESS) {
   color_brush->SetColor(D2D1::ColorF(red, blue, green, alpha));
      } else {
   color_brush->SetColor(color_run->runColor);
      }
  }

  dc4->DrawGlyphRun(origin,
      &color_run->glyphRun,
      color_run->glyphRunDescription,
      color_brush,
      dwrite_font_face->measuring_mode);
     case DWRITE_GLYPH_IMAGE_FORMATS_NONE:
  break;
 }
    }

    hr = dc4->EndDraw();
    if (FAILED(hr))
 return _cairo_dwrite_error (hr, "EndDraw failed");

    cairo_surface_t *image = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
    cairo_status_t status = cairo_surface_status (image);
    if (_cairo_status_is_error (status)) {
        cairo_surface_destroy (image);
        return (cairo_int_status_t) status;
    }

    int stride = cairo_image_surface_get_stride (image);
    WICRect rect = { 00, width, height };
    bitmap->CopyPixels(&rect,
         stride,
         height * stride,
         cairo_image_surface_get_data (image));
    cairo_surface_mark_dirty (image);
    cairo_surface_set_device_offset (image, -x1, -y1);
    _cairo_scaled_glyph_set_color_surface (scaled_glyph,
        &scaled_font->base,
        (cairo_image_surface_t *) image,
        uses_foreground_color ? foreground_color : NULL);
    scaled_glyph->color_glyph = TRUE;
    scaled_glyph->color_glyph_set = TRUE;

    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({00}, 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;

    int stride = cairo_image_surface_get_stride (surface);
    WICRect rect = { 00, 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)
{
    HRESULT hr;

    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;

    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);

    /* 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. */

    cairo_matrix_transform_point(&scaled_font->mat_inverse, &x, &y);
    offset.advanceOffset = (FLOAT)x;
    offset.ascenderOffset = -(FLOAT)y; /* Y axis is inverted */

    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;
    run.fontEmSize = 1.0f;
    run.bidiLevel = 0;
    run.glyphIndices = &index;
    run.isSideways = FALSE;
    run.glyphOffsets = &offset;

    // 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;

    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;
            break;
        case CAIRO_HINT_STYLE_NONE:
            grid_fit_mode = DWRITE_GRID_FIT_MODE_DISABLED;
            break;
        case CAIRO_HINT_STYLE_SLIGHT:
        case CAIRO_HINT_STYLE_MEDIUM:
        case CAIRO_HINT_STYLE_FULL:
            grid_fit_mode = DWRITE_GRID_FIT_MODE_ENABLED;
            break;
    }

    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;
        }
    }

    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 {
        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,
                                                               scaled_font->measuring_mode,
                                                               0// baselineOriginX,
                                                               0// baselineOriginY,
                                                               &dwrite_glyph_run_analysis);
    }
    if (FAILED(hr))
       return CAIRO_INT_STATUS_UNSUPPORTED;

    cairo_format_t surface_format = antialias == ANTIALIAS_NONE ? CAIRO_FORMAT_A1 :
                                    antialias == ANTIALIAS_GRAY ? CAIRO_FORMAT_A8 :
                                    CAIRO_FORMAT_ARGB32;

    cairo_surface_t *surface = cairo_image_surface_create (surface_format, width, height);
    if (cairo_surface_status (surface))
        return CAIRO_INT_STATUS_UNSUPPORTED;

    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;
        }
    }

    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
_cairo_dwrite_load_truetype_table(void                 *scaled_font,
      unsigned long         tag,
      long                  offset,
      unsigned char        *buffer,
      unsigned long        *length)
{
    cairo_dwrite_scaled_font_t *dwritesf = static_cast<cairo_dwrite_scaled_font_t*>(scaled_font);

    const void *data;
    UINT32 size;
    void *tableContext;
    BOOL exists;
    HRESULT hr;
    hr = dwritesf->dwriteface->TryGetFontTable (be32_to_cpu (tag),
                                                &data,
                                                &size,
                                                &tableContext,
                                                &exists);
    if (FAILED(hr))
 return _cairo_dwrite_error (hr, "TryGetFontTable failed");

    if (!exists) {
 return CAIRO_INT_STATUS_UNSUPPORTED;
    }

    if (buffer && *length && (UINT32)offset < size) {
        size = MIN(size - (UINT32)offset, *length);
        memcpy(buffer, (const char*)data + offset, size);
    }
    *length = size;

    if (tableContext) {
        dwritesf->dwriteface->ReleaseFontTable(tableContext);
    }
    return (cairo_int_status_t)CAIRO_STATUS_SUCCESS;
}

static cairo_int_status_t
_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);
    HRESULT hr;
    cairo_int_status_t status;

    if (dwritesf->dwriteface->GetSimulations() != DWRITE_FONT_SIMULATIONS_NONE) {
 *is_synthetic = FALSE;
 return CAIRO_INT_STATUS_SUCCESS;
    }

    RefPtr<IDWriteFontFace5> fontFace5;
    if (FAILED(dwritesf->dwriteface->QueryInterface(&fontFace5))) {
 /* If IDWriteFontFace5 is not available, assume this version of
  * DirectWrite does not support variations.
 */

 *is_synthetic = FALSE;
 return CAIRO_INT_STATUS_SUCCESS;
    }

    if (!fontFace5->HasVariations()) {
 *is_synthetic = FALSE;
 return CAIRO_INT_STATUS_SUCCESS;
    }

    RefPtr<IDWriteFontResource> fontResource;
    hr = fontFace5->GetFontResource(&fontResource);
    if (FAILED(hr))
 return _cairo_dwrite_error (hr, "GetFontResource failed");

    UINT32 axis_count = fontResource->GetFontAxisCount();
    DWRITE_FONT_AXIS_VALUE *axis_defaults = new DWRITE_FONT_AXIS_VALUE[axis_count];
    DWRITE_FONT_AXIS_VALUE *axis_values = new DWRITE_FONT_AXIS_VALUE[axis_count];

    hr = fontResource->GetDefaultFontAxisValues(axis_defaults, axis_count);
    if (FAILED(hr)) {
 status = _cairo_dwrite_error (hr, "GetDefaultFontAxisValues failed");
 goto cleanup;
    }

    hr = fontFace5->GetFontAxisValues(axis_values, axis_count);
    if (FAILED(hr)) {
 status = _cairo_dwrite_error (hr, "GetFontAxisValues failed");
 goto cleanup;
    }

    /* The DirectWrite documentation does not state if the tags of the returned
     * defaults and values arrays are in the same order. So assume they are not.
     */

    *is_synthetic = FALSE;
    status = CAIRO_INT_STATUS_SUCCESS;
    for (UINT32 i = 0; i< axis_count; i++) {
 for (UINT32 j = 0; j < axis_count; j++) {
     if (axis_values[i].axisTag == axis_defaults[j].axisTag) {
  if (axis_values[i].value != axis_defaults[j].value) {
      *is_synthetic = TRUE;
      goto cleanup;
  }
  break;
     }
 }
    }

  cleanup:
    delete[] axis_defaults;
    delete[] axis_values;
    
    return status;
}

static cairo_bool_t
_cairo_dwrite_has_color_glyphs(void *scaled_font)
{
    cairo_dwrite_scaled_font_t *dwritesf = static_cast<cairo_dwrite_scaled_font_t*>(scaled_font);

    return ((cairo_dwrite_font_face_t *)dwritesf->base.font_face)->have_color;
}

/**
 * cairo_dwrite_font_face_create_for_dwrite_fontface:
 * @dwrite_font_face: A pointer to an #IDWriteFontFace specifying the
 * DWrite font to use.
 *
 * Creates a new font for the DWrite font backend based on a
 * DWrite font face. This font can then be used with
 * cairo_set_font_face() or cairo_scaled_font_create().
 *
 * Here is an example of how this function might be used:
 * <informalexample><programlisting><![CDATA[
 * #include <cairo-dwrite.h>
 * #include <dwrite.h>
 *
 * IDWriteFactory* dWriteFactory = NULL;
 * HRESULT hr = DWriteCreateFactory(
 *     DWRITE_FACTORY_TYPE_SHARED,
 *     __uuidof(IDWriteFactory),
 *    reinterpret_cast<IUnknown**>(&dWriteFactory));
 *
 * IDWriteFontCollection *systemCollection;
 * hr = dWriteFactory->GetSystemFontCollection(&systemCollection);
 *
 * UINT32 idx;
 * BOOL found;
 * systemCollection->FindFamilyName(L"Segoe UI Emoji", &idx, &found);
 *
 * IDWriteFontFamily *family;
 * systemCollection->GetFontFamily(idx, &family);
 *
 * IDWriteFont *dwritefont;
 * DWRITE_FONT_WEIGHT weight = DWRITE_FONT_WEIGHT_NORMAL;
 * DWRITE_FONT_STYLE style = DWRITE_FONT_STYLE_NORMAL;
 * hr = family->GetFirstMatchingFont(weight, DWRITE_FONT_STRETCH_NORMAL, style, &dwritefont);
 *
 * IDWriteFontFace *dwriteface;
 * hr = dwritefont->CreateFontFace(&dwriteface);
 *
 * cairo_font_face_t *face;
 * face = cairo_dwrite_font_face_create_for_dwrite_fontface(dwriteface);
 * cairo_set_font_face(cr, face);
 * cairo_set_font_size(cr, 70);
 * cairo_move_to(cr, 100, 100);
 * cairo_show_text(cr, "");
 * ]]></programlisting></informalexample>
 *
 * Note: When printing a DWrite font to a
 * #CAIRO_SURFACE_TYPE_WIN32_PRINTING surface, the printing surface
 * will substitute each DWrite font with a Win32 font created from the same
 * underlying font file. If the matching font file can not be found,
 * the #CAIRO_SURFACE_TYPE_WIN32_PRINTING surface will convert each
 * glyph to a filled path. If a DWrite font was not created from a system
 * font, it is recommended that the font used to create the DWrite
 * font be made available to GDI to avoid the undesirable fallback
 * to emitting paths. This can be achieved using the GDI font loading functions
 * such as AddFontMemResourceEx().
 *
 * Return value: a newly created #cairo_font_face_t. Free with
 *  cairo_font_face_destroy() when you are done using it.
 *
 * Since: 1.18
 **/

cairo_font_face_t *
cairo_dwrite_font_face_create_for_dwrite_fontface (IDWriteFontFace *dwrite_font_face)
{
    IDWriteFontFace *dwriteface = static_cast<IDWriteFontFace*>(dwrite_font_face);
    // Must do malloc and not C++ new, since Cairo frees this.
    cairo_dwrite_font_face_t *face = (cairo_dwrite_font_face_t *)_cairo_malloc(sizeof(cairo_dwrite_font_face_t));
    if (unlikely (face == NULL)) {
 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
 return (cairo_font_face_t*)&_cairo_font_face_nil;
    }

    dwriteface->AddRef();
    face->dwriteface = dwriteface;
    face->have_color = false;
    face->rendering_params = NULL;
    face->measuring_mode = DWRITE_MEASURING_MODE_NATURAL;

    /* Ensure IDWriteFactory4 is available before enabling color fonts */
    if (DWriteFactory::Instance4()) {
 RefPtr<IDWriteFontFace2> fontFace2;
 if (SUCCEEDED(dwriteface->QueryInterface(&fontFace2))) {
     if (fontFace2->IsColorFont())
  face->have_color = true;
 }
    }

    cairo_font_face_t *font_face;
    font_face = (cairo_font_face_t*)face;
    _cairo_font_face_init (&((cairo_dwrite_font_face_t*)font_face)->base, &_cairo_dwrite_font_face_backend);

    return font_face;
}

/**
 * cairo_dwrite_font_face_get_rendering_params:
 * @font_face: The #cairo_dwrite_font_face_t object to query
 *
 * Gets the #IDWriteRenderingParams object of @font_face.
 *
 * Return value: the #IDWriteRenderingParams object or %NULL if none.
 *
 * Since: 1.18
 **/

IDWriteRenderingParams *
cairo_dwrite_font_face_get_rendering_params (cairo_font_face_t *font_face)
{
    cairo_dwrite_font_face_t *dwface = reinterpret_cast<cairo_dwrite_font_face_t *>(font_face);
    return dwface->rendering_params;
}

/**
 * cairo_dwrite_font_face_set_rendering_params:
 * @font_face: The #cairo_dwrite_font_face_t object to modify
 * @params: The #IDWriteRenderingParams object
 *
 * Sets the #IDWriteRenderingParams object to @font_face.
 * This #IDWriteRenderingParams is used to render glyphs if default values of font options are used.
 * If non-defalut values of font options are specified when creating a #cairo_scaled_font_t,
 * cairo creates a new #IDWriteRenderingParams object for the #cairo_scaled_font_t object by overwriting the corresponding parameters.
 *
 * Since: 1.18
 **/

void
cairo_dwrite_font_face_set_rendering_params (cairo_font_face_t *font_face, IDWriteRenderingParams *params)
{
    cairo_dwrite_font_face_t *dwface = reinterpret_cast<cairo_dwrite_font_face_t *>(font_face);
    if (dwface->rendering_params)
 dwface->rendering_params->Release();
    dwface->rendering_params = params;
    if (dwface->rendering_params)
 dwface->rendering_params->AddRef();
}

/**
 * cairo_dwrite_font_face_get_measuring_mode:
 * @font_face: The #cairo_dwrite_font_face_t object to query
 *
 * Gets the #DWRITE_MEASURING_MODE enum of @font_face.
 *
 * Return value: The #DWRITE_MEASURING_MODE enum of @font_face.
 *
 * Since: 1.18
 **/

DWRITE_MEASURING_MODE
cairo_dwrite_font_face_get_measuring_mode (cairo_font_face_t *font_face)
{
    cairo_dwrite_font_face_t *dwface = reinterpret_cast<cairo_dwrite_font_face_t *>(font_face);
    return dwface->measuring_mode;
}

/**
 * cairo_dwrite_font_face_set_measuring_mode:
 * @font_face: The #cairo_dwrite_font_face_t object to modify
 * @mode: The #DWRITE_MEASURING_MODE enum.
 *
 * Sets the #DWRITE_MEASURING_MODE enum to @font_face.
 * 
 * Since: 1.18
 **/

void
cairo_dwrite_font_face_set_measuring_mode (cairo_font_face_t *font_face, DWRITE_MEASURING_MODE mode)
{
    cairo_dwrite_font_face_t *dwface = reinterpret_cast<cairo_dwrite_font_face_t *>(font_face);
    dwface->measuring_mode = mode;
}

static cairo_int_status_t
_dwrite_draw_glyphs_to_gdi_surface_gdi(cairo_win32_surface_t *surface,
           DWRITE_MATRIX *transform,
           DWRITE_GLYPH_RUN *run,
           COLORREF color,
           cairo_dwrite_scaled_font_t *scaled_font,
           const RECT &area)
{
    RefPtr<IDWriteGdiInterop> gdiInterop;
    DWriteFactory::Instance()->GetGdiInterop(&gdiInterop);
    RefPtr<IDWriteBitmapRenderTarget> rt;
    HRESULT hr;

    hr = gdiInterop->CreateBitmapRenderTarget(surface->dc,
           area.right - area.left,
           area.bottom - area.top,
           &rt);

    if (FAILED(hr)) {
 if (hr == E_OUTOFMEMORY) {
     return (cairo_int_status_t)CAIRO_STATUS_NO_MEMORY;
 } else {
     return CAIRO_INT_STATUS_UNSUPPORTED;
 }
    }

    /*
     * We set the number of pixels per DIP to 1.0. This is because we always want
     * to draw in device pixels, and not device independent pixels. On high DPI
     * systems this value will be higher than 1.0 and automatically upscale
     * fonts, we don't want this since we do our own upscaling for various reasons.
     */

    rt->SetPixelsPerDip(1.0);

    float x = 0, y = 0;
    if (transform) {
 DWRITE_MATRIX matrix = *transform;
 matrix.dx -= area.left;
 matrix.dy -= area.top;
 rt->SetCurrentTransform(&matrix);
    } else {
 x = (float) -area.left;
 y = (float) -area.top;
    }
    BitBlt(rt->GetMemoryDC(),
    00,
    area.right - area.left, area.bottom - area.top,
    surface->dc,
    area.left, area.top,
    SRCCOPY | NOMIRRORBITMAP);
    rt->DrawGlyphRun(x, y, scaled_font->measuring_mode, run, scaled_font->rendering_params, color);
    BitBlt(surface->dc,
    area.left, area.top,
    area.right - area.left, area.bottom - area.top,
    rt->GetMemoryDC(),
    00,
    SRCCOPY | NOMIRRORBITMAP);
    return CAIRO_INT_STATUS_SUCCESS;
}

cairo_int_status_t
_dwrite_draw_glyphs_to_gdi_surface_d2d(cairo_win32_surface_t *surface,
           DWRITE_MATRIX *transform,
           DWRITE_GLYPH_RUN *run,
           COLORREF color,
           const RECT &area)
{
    HRESULT hr;

    RefPtr<ID2D1DCRenderTarget> rt = D2DFactory::RenderTarget();

    // XXX don't we need to set RenderingParams on this RenderTarget?

    hr = rt->BindDC(surface->dc, &area);
    if (FAILED(hr))
 return CAIRO_INT_STATUS_UNSUPPORTED;

    // D2D uses 0x00RRGGBB not 0x00BBGGRR like COLORREF.
    color = (color & 0xFF) << 16 |
 (color & 0xFF00) |
 (color & 0xFF0000) >> 16;
    RefPtr<ID2D1SolidColorBrush> brush;
    hr = rt->CreateSolidColorBrush(D2D1::ColorF(color, 1.0), &brush);
    if (FAILED(hr))
 return CAIRO_INT_STATUS_UNSUPPORTED;

    if (transform) {
 rt->SetTransform(D2D1::Matrix3x2F(transform->m11,
       transform->m12,
       transform->m21,
       transform->m22,
       transform->dx,
       transform->dy));
    }
    rt->BeginDraw();
    rt->DrawGlyphRun(D2D1::Point2F(00), run, brush);
    hr = rt->EndDraw();
    if (transform) {
 rt->SetTransform(D2D1::Matrix3x2F::Identity());
    }
    if (FAILED(hr))
 return CAIRO_INT_STATUS_UNSUPPORTED;

    return CAIRO_INT_STATUS_SUCCESS;
}

/* Surface helper function */
cairo_int_status_t
_cairo_dwrite_show_glyphs_on_surface(void   *surface,
        cairo_operator_t  op,
        const cairo_pattern_t *source,
        cairo_glyph_t  *glyphs,
        int    num_glyphs,
        cairo_scaled_font_t *scaled_font,
        cairo_clip_t *clip)
{
    // TODO: Check font & surface for types.
    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;

    /* We can only handle opaque solid color sources */
    if (!_cairo_pattern_is_opaque_solid(source))
 return CAIRO_INT_STATUS_UNSUPPORTED;

    /* We can only handle operator SOURCE or OVER with the destination
     * having no alpha */

    if (op != CAIRO_OPERATOR_SOURCE && op != CAIRO_OPERATOR_OVER)
 return CAIRO_INT_STATUS_UNSUPPORTED;

    /* It is vital that dx values for dxy_buf are calculated from the delta of
     * _logical_ x coordinates (not user x coordinates) or else the sum of all
     * previous dx values may start to diverge from the current glyph's x
     * coordinate due to accumulated rounding error. As a result strings could
     * be painted shorter or longer than expected. */


    AutoDWriteGlyphRun run;
    run.allocate(num_glyphs);

    BOOL transform = FALSE;
    _cairo_dwrite_glyph_run_from_glyphs(glyphs, num_glyphs, dwritesf, &run, &transform);

    cairo_solid_pattern_t *solid_pattern = (cairo_solid_pattern_t *)source;
    COLORREF color = RGB(((int)solid_pattern->color.red_short) >> 8,
  ((int)solid_pattern->color.green_short) >> 8,
  ((int)solid_pattern->color.blue_short) >> 8);

    DWRITE_MATRIX matrix = _cairo_dwrite_matrix_from_matrix(&dwritesf->mat);

    DWRITE_MATRIX *mat;
    if (transform) {
 mat = &matrix;
    } else {
 mat = NULL;
    }

    RefPtr<IDWriteGlyphRunAnalysis> runAnalysis;
    HRESULT hr = DWriteFactory::Instance()->
 CreateGlyphRunAnalysis(&run, 1, mat,
          DWRITE_RENDERING_MODE_ALIASED,
          dwritesf->measuring_mode,
          0// baselineOriginX,
          0// baselineOriginY,
          &runAnalysis);
    if (FAILED(hr))
 return CAIRO_INT_STATUS_UNSUPPORTED;
    RECT fontArea;
    hr = runAnalysis->GetAlphaTextureBounds(DWRITE_TEXTURE_ALIASED_1x1, &fontArea);
    if (FAILED(hr))
 return CAIRO_INT_STATUS_UNSUPPORTED;
    InflateRect(&fontArea, 11);
    /* Needed to calculate bounding box for efficient blitting */
    RECT copyArea, dstArea = { 00, dst->extents.width, dst->extents.height };
    IntersectRect(©Area, &fontArea, &dstArea);

#ifdef CAIRO_TRY_D2D_TO_GDI
    status = _dwrite_draw_glyphs_to_gdi_surface_d2d(dst,
          mat,
          &run,
          color,
          copyArea);

    if (status == (cairo_status_t)CAIRO_INT_STATUS_UNSUPPORTED) {
#endif
 status = _dwrite_draw_glyphs_to_gdi_surface_gdi(dst,
       mat,
       &run,
       color,
       dwritesf,
       copyArea);

#ifdef CAIRO_TRY_D2D_TO_GDI
    }
#endif

    return status;
}

/* Check if a specific font table in a DWrite font and a scaled font is identical */
static cairo_int_status_t
compare_font_tables (cairo_dwrite_font_face_t *dwface,
       cairo_scaled_font_t      *scaled_font,
       unsigned long             tag,
       cairo_bool_t             *match)
{
    unsigned long size;
    cairo_int_status_t status;
    unsigned char *buffer = NULL;
    const void *dw_data;
    UINT32 dw_size;
    void *dw_tableContext = NULL;
    BOOL dw_exists = FALSE;
    HRESULT hr;

    hr = dwface->dwriteface->TryGetFontTable(be32_to_cpu (tag),
                                             &dw_data,
                                             &dw_size,
                                             &dw_tableContext,
                                             &dw_exists);
    if (FAILED(hr))
 return _cairo_dwrite_error (hr, "TryGetFontTable failed");

    if (!dw_exists) {
 *match = FALSE;
 status = CAIRO_INT_STATUS_SUCCESS;
 goto cleanup;
    }

    status = scaled_font->backend->load_truetype_table (scaled_font, tag, 0, NULL, &size);
    if (unlikely(status))
 goto cleanup;

    if (size != dw_size) {
 *match = FALSE;
 status = CAIRO_INT_STATUS_SUCCESS;
 goto cleanup;
    }

    buffer = (unsigned char *) _cairo_malloc (size);
    if (unlikely (buffer == NULL)) {
 status = (cairo_int_status_t) _cairo_error (CAIRO_STATUS_NO_MEMORY);
 goto cleanup;
    }

    status = scaled_font->backend->load_truetype_table (scaled_font, tag, 0, buffer, &size);
    if (unlikely(status))
 goto cleanup;

    *match = memcmp (dw_data, buffer, size) == 0;
    status = CAIRO_INT_STATUS_SUCCESS;

cleanup:
    free (buffer);
    if (dw_tableContext)
        dwface->dwriteface->ReleaseFontTable(dw_tableContext);

    return status;
}

/* Check if a DWrite font and a scaled font areis identical
 *
 * DWrite does not allow accessing the entire font data using tag=0 so we compare
 * two of the font tables:
 * - 'name' table
 * - 'head' table since this contains the checksum for the entire font
 */

static cairo_int_status_t
font_tables_match (cairo_dwrite_font_face_t *dwface,
     cairo_scaled_font_t      *scaled_font,
     cairo_bool_t             *match)
{
    cairo_int_status_t status;

    status = compare_font_tables (dwface, scaled_font, TT_TAG_name, match);
    if (unlikely(status))
 return status;

    if (!*match)
 return CAIRO_INT_STATUS_SUCCESS;

    status = compare_font_tables (dwface, scaled_font, TT_TAG_head, match);
    if (unlikely(status))
 return status;

    return CAIRO_INT_STATUS_SUCCESS;
}

/*
 * Helper for _cairo_win32_printing_surface_show_glyphs to create a win32 equivalent
 * of a dwrite scaled_font so that we can print using ExtTextOut instead of drawing
 * paths or blitting glyph bitmaps.
 */

cairo_int_status_t
_cairo_dwrite_scaled_font_create_win32_scaled_font (cairo_scaled_font_t *scaled_font,
                                                    cairo_scaled_font_t **new_font)
{
    if (cairo_scaled_font_get_type (scaled_font) != CAIRO_FONT_TYPE_DWRITE) {
        return CAIRO_INT_STATUS_UNSUPPORTED;
    }

    cairo_font_face_t *face = cairo_scaled_font_get_font_face (scaled_font);
    if (cairo_font_face_status (face) == CAIRO_STATUS_SUCCESS &&
 cairo_font_face_get_type (face) == CAIRO_FONT_TYPE_TOY)
    {
 face = ((cairo_toy_font_face_t *)face)->impl_face;
    }

    if (face == NULL || cairo_font_face_get_type (face) != CAIRO_FONT_TYPE_DWRITE) {
        return CAIRO_INT_STATUS_UNSUPPORTED;
    }

    cairo_dwrite_font_face_t *dwface = reinterpret_cast<cairo_dwrite_font_face_t*>(face);

    RefPtr<IDWriteGdiInterop> gdiInterop;
    DWriteFactory::Instance()->GetGdiInterop(&gdiInterop);
    if (!gdiInterop) {
        return CAIRO_INT_STATUS_UNSUPPORTED;
    }

    /* TODO: use scaled font? */

    LOGFONTW logfont;
    if (FAILED(gdiInterop->ConvertFontFaceToLOGFONT (dwface->dwriteface, &logfont))) {
 return CAIRO_INT_STATUS_UNSUPPORTED;
    }

    /* DWrite must have been using an outline font, so we want GDI to use the same,
     * even if there's also a bitmap face available
     */

    logfont.lfOutPrecision = OUT_OUTLINE_PRECIS;

    cairo_font_face_t *win32_face = cairo_win32_font_face_create_for_logfontw (&logfont);
    if (cairo_font_face_status (win32_face)) {
 cairo_font_face_destroy (win32_face);
        return CAIRO_INT_STATUS_UNSUPPORTED;
    }

    cairo_matrix_t font_matrix;
    cairo_scaled_font_get_font_matrix (scaled_font, &font_matrix);

    cairo_matrix_t ctm;
    cairo_scaled_font_get_ctm (scaled_font, &ctm);

    cairo_font_options_t options;
    _cairo_font_options_init_default (&options);
    cairo_scaled_font_get_font_options (scaled_font, &options);

    cairo_scaled_font_t *font = cairo_scaled_font_create (win32_face,
                                     &font_matrix,
                                     &ctm,
                                     &options);
    cairo_font_face_destroy (win32_face);

    if (cairo_scaled_font_status(font)) {
 cairo_scaled_font_destroy (font);
        return CAIRO_INT_STATUS_UNSUPPORTED;
    }

    cairo_bool_t match;
    cairo_int_status_t status;
    status = font_tables_match (dwface, font, &match);
    if (status) {
 cairo_scaled_font_destroy (font);
 return status;
    }

    /* If the font tables aren't equal, then GDI may have failed to
     * find the right font and substituted a different font.
     */

    if (!match) {
#if 0
 char *ps_name;
 char *font_name;
 status = _cairo_truetype_read_font_name (scaled_font, &ps_name, &font_name);
 printf("dwrite fontname: %s PS name: %s\n", font_name, ps_name);
 free (font_name);
 free (ps_name);
 status = _cairo_truetype_read_font_name (font, &ps_name, &font_name);
 printf("win32  fontname: %s PS name: %s\n", font_name, ps_name);
 free (font_name);
 free (ps_name);
#endif
 cairo_scaled_font_destroy (font);
        return CAIRO_INT_STATUS_UNSUPPORTED;
    }

    *new_font = font;
    return CAIRO_INT_STATUS_SUCCESS;
}

Messung V0.5 in Prozent
C=95 H=92 G=93

¤ Dauer der Verarbeitung: 0.39 Sekunden  (vorverarbeitet am  2026-08-26) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

letze Version des Elbe Quellennavigators


Jenseits des Üblichen ....

Besucher

Besucher

Statistik
#Sources=277311
#Domains=752002
 




Quellcode-Bibliothek  | Datei:   | Haftungsausschluß  | Download des  |   | © 2026 JDD |