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


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 <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_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
     D2D1CreateFactoryFunc createD2DFactory = (D2D1CreateFactoryFunc)
  GetProcAddress(LoadLibraryW(L"d2d1.dll"), "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 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,
    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);

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

    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);
 font_face->dwriteface->GetGdiCompatibleMetrics(1, 1, &transform, &metrics);
    } else {
 font_face->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(font_face->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);
    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);
    cairo_dwrite_font_face_t *face = reinterpret_cast<cairo_dwrite_font_face_t*>(dwritesf->base.font_face);

    UINT16 index;
    face->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);
 font_face->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,&nbsp;FALSE);
    } else {
 font_face->dwriteface->GetMetrics(&fontMetrics);
 hr = font_face->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 : public IDWriteGeometrySink
{
public:
    GeometryRecorder(cairo_path_fixed_t *aCairoPath, const cairo_matrix_t &matrix)
 : mCairoPath(aCairoPath)
 , mMatrix(matrix) {}

    // IUnknown interface
    IFACEMETHOD(QueryInterface)(IID const& iid, OUT void** ppObject)
    {
 if (iid != __uuidof(IDWriteGeometrySink))
     return E_NOINTERFACE;

 *ppObject = static_cast<IDWriteGeometrySink*>(this);

 return S_OK;
    }

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

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

    IFACEMETHODIMP_(void) SetFillMode(D2D1_FILL_MODE fillMode)
    {
 return;
    }

    STDMETHODIMP Close()
    {
 return S_OK;
    }

    IFACEMETHODIMP_(void) SetSegmentFlags(D2D1_PATH_SEGMENT vertexFlags)
    {
 return;
    }

    IFACEMETHODIMP_(void) BeginFigure(
 D2D1_POINT_2F startPoint,
 D2D1_FIGURE_BEGIN figureBegin)
    {
 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 */
    }

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

    IFACEMETHODIMP_(void) AddBeziers(
 const D2D1_BEZIER_SEGMENT *beziers,
 UINT beziersCount)
    {
 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 */
 }
    }

    IFACEMETHODIMP_(void) AddLines(
 const D2D1_POINT_2F *points,
 UINT pointsCount)
    {
 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;
    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);
    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 = {0, 0};
    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 = dwrite_font_face->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 =
        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(dwrite_font_face->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(96, 96); /* 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);
    int stride = cairo_image_surface_get_stride (image);
    WICRect rect = { 0, 0, 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;
}

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_int_status_t status;
    cairo_win32_surface_t *surface;
    cairo_t *cr;
    cairo_surface_t *image;
    int width, height;
    double x1, y1, x2, y2;

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

    area.top = 0;
    area.bottom = height;
    area.left = 0;
    area.right = width;

    run.glyphCount = 1;
    run.glyphAdvances = &advance;
    run.fontFace = ((cairo_dwrite_font_face_t*)scaled_font->base.font_face)->dwriteface;
    run.fontEmSize = 1.0f;
    run.bidiLevel = 0;
    run.glyphIndices = &index;
    run.isSideways = FALSE;
    run.glyphOffsets = &offset;

    matrix = _cairo_dwrite_matrix_from_matrix(&scaled_font->mat);

    status = _dwrite_draw_glyphs_to_gdi_surface_gdi (surface, &matrix, &run,
            RGB(0,0,0), scaled_font, area);
    if (status)
 goto FAIL;

    GdiFlush();

    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_surface_set_device_offset (image, -x1, -y1);
    _cairo_scaled_glyph_set_surface (scaled_glyph,
         &scaled_font->base,
         (cairo_image_surface_t *) image);

  FAIL:
    cairo_surface_destroy (&surface->base);

    return status;
}

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);
    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);
    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) {
 face->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);
    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) {
 *is_synthetic = FALSE;
 return CAIRO_INT_STATUS_SUCCESS;
    }

    RefPtr<IDWriteFontFace5> fontFace5;
    if (FAILED(face->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(),
    0, 0,
    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(),
    0, 0,
    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;

    float x = 0, y = 0;
    if (transform) {
 rt->SetTransform(D2D1::Matrix3x2F(transform->m11,
       transform->m12,
       transform->m21,
       transform->m22,
       transform->dx,
       transform->dy));
    }
    rt->BeginDraw();
    rt->DrawGlyphRun(D2D1::Point2F(0, 0), 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_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 */
    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);

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

    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, 1, 1);
    /* Needed to calculate bounding box for efficient blitting */
    RECT copyArea, dstArea = { 0, 0, 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;
    }

    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
C=96 H=95 G=95

¤ Dauer der Verarbeitung: 0.10 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

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

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge