Back to index

lightning-sunbird  0.9+nobinonly
cairo-win32-font.c
Go to the documentation of this file.
00001 /* cairo - a vector graphics library with display and print output
00002  *
00003  * Copyright © 2005 Red Hat, Inc
00004  *
00005  * This library is free software; you can redistribute it and/or
00006  * modify it either under the terms of the GNU Lesser General Public
00007  * License version 2.1 as published by the Free Software Foundation
00008  * (the "LGPL") or, at your option, under the terms of the Mozilla
00009  * Public License Version 1.1 (the "MPL"). If you do not alter this
00010  * notice, a recipient may use your version of this file under either
00011  * the MPL or the LGPL.
00012  *
00013  * You should have received a copy of the LGPL along with this library
00014  * in the file COPYING-LGPL-2.1; if not, write to the Free Software
00015  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
00016  * You should have received a copy of the MPL along with this library
00017  * in the file COPYING-MPL-1.1
00018  *
00019  * The contents of this file are subject to the Mozilla Public License
00020  * Version 1.1 (the "License"); you may not use this file except in
00021  * compliance with the License. You may obtain a copy of the License at
00022  * http://www.mozilla.org/MPL/
00023  *
00024  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
00025  * OF ANY KIND, either express or implied. See the LGPL or the MPL for
00026  * the specific language governing rights and limitations.
00027  *
00028  * The Original Code is the cairo graphics library.
00029  *
00030  * The Initial Developer of the Original Code is Red Hat, Inc.
00031  *
00032  * Contributor(s):
00033  */
00034 
00035 #include <string.h>
00036 #include <stdio.h>
00037 #include "cairoint.h"
00038 #include "cairo-win32-private.h"
00039 
00040 #ifndef SPI_GETFONTSMOOTHINGTYPE 
00041 #define SPI_GETFONTSMOOTHINGTYPE 0x200a
00042 #endif
00043 #ifndef FE_FONTSMOOTHINGCLEARTYPE
00044 #define FE_FONTSMOOTHINGCLEARTYPE 2
00045 #endif
00046 #ifndef CLEARTYPE_QUALITY
00047 #define CLEARTYPE_QUALITY 5
00048 #endif
00049 #ifndef TT_PRIM_CSPLINE
00050 #define TT_PRIM_CSPLINE 3
00051 #endif
00052 
00053 const cairo_scaled_font_backend_t cairo_win32_scaled_font_backend;
00054 
00055 #define LOGICAL_SCALE 32
00056 
00057 typedef struct {
00058     cairo_scaled_font_t base;
00059 
00060     LOGFONTW logfont;
00061 
00062     BYTE quality;
00063 
00064     /* We do drawing and metrics computation in a "logical space" which
00065      * is similar to font space, except that it is scaled by a factor
00066      * of the (desired font size) * (LOGICAL_SCALE). The multiplication
00067      * by LOGICAL_SCALE allows for sub-pixel precision.
00068      */
00069     double logical_scale;
00070 
00071     /* The size we should actually request the font at from Windows; differs
00072      * from the logical_scale because it is quantized for orthogonal
00073      * transformations
00074      */
00075     double logical_size;
00076 
00077     /* Transformations from device <=> logical space
00078      */
00079     cairo_matrix_t logical_to_device;
00080     cairo_matrix_t device_to_logical;
00081 
00082     /* We special case combinations of 90-degree-rotations, scales and
00083      * flips ... that is transformations that take the axes to the
00084      * axes. If preserve_axes is true, then swap_axes/swap_x/swap_y
00085      * encode the 8 possibilities for orientation (4 rotation angles with
00086      * and without a flip), and scale_x, scale_y the scale components.
00087      */
00088     cairo_bool_t preserve_axes;
00089     cairo_bool_t swap_axes;
00090     cairo_bool_t swap_x;
00091     cairo_bool_t swap_y;
00092     double x_scale;
00093     double y_scale;
00094   
00095     /* The size of the design unit of the font
00096      */
00097     int em_square;
00098 
00099     HFONT scaled_hfont;
00100     HFONT unscaled_hfont;
00101     
00102 } cairo_win32_scaled_font_t;
00103 
00104 #define NEARLY_ZERO(d) (fabs(d) < (1. / 65536.))
00105 
00106 static void
00107 _compute_transform (cairo_win32_scaled_font_t *scaled_font,
00108                   cairo_matrix_t            *sc)
00109 {
00110     cairo_status_t status;
00111 
00112     if (NEARLY_ZERO (sc->yx) && NEARLY_ZERO (sc->xy)) {
00113        scaled_font->preserve_axes = TRUE;
00114        scaled_font->x_scale = sc->xx;
00115        scaled_font->swap_x = (sc->xx < 0);
00116        scaled_font->y_scale = sc->yy;
00117        scaled_font->swap_y = (sc->yy < 0);
00118        scaled_font->swap_axes = FALSE;
00119        
00120     } else if (NEARLY_ZERO (sc->xx) && NEARLY_ZERO (sc->yy)) {
00121        scaled_font->preserve_axes = TRUE;
00122        scaled_font->x_scale = sc->yx;
00123        scaled_font->swap_x = (sc->yx < 0);
00124        scaled_font->y_scale = sc->xy;
00125        scaled_font->swap_y = (sc->xy < 0);
00126        scaled_font->swap_axes = TRUE;
00127 
00128     } else {
00129        scaled_font->preserve_axes = FALSE;
00130        scaled_font->swap_x = scaled_font->swap_y = scaled_font->swap_axes = FALSE;
00131     }
00132 
00133     if (scaled_font->preserve_axes) {
00134        if (scaled_font->swap_x)
00135            scaled_font->x_scale = - scaled_font->x_scale;
00136        if (scaled_font->swap_y)
00137            scaled_font->y_scale = - scaled_font->y_scale;
00138        
00139        scaled_font->logical_scale = LOGICAL_SCALE * scaled_font->y_scale;
00140        scaled_font->logical_size = LOGICAL_SCALE * floor (scaled_font->y_scale + 0.5);
00141     }
00142 
00143     /* The font matrix has x and y "scale" components which we extract and
00144      * use as character scale values.
00145      */
00146     cairo_matrix_init (&scaled_font->logical_to_device,
00147                      sc->xx, sc->yx, sc->xy, sc->yy, 0, 0);
00148 
00149     if (!scaled_font->preserve_axes) {
00150        _cairo_matrix_compute_scale_factors (&scaled_font->logical_to_device,
00151                                         &scaled_font->x_scale, &scaled_font->y_scale,
00152                                         TRUE);   /* XXX: Handle vertical text */
00153 
00154        scaled_font->logical_size = floor (LOGICAL_SCALE * scaled_font->y_scale + 0.5);
00155        scaled_font->logical_scale = LOGICAL_SCALE * scaled_font->y_scale;
00156     }
00157 
00158     cairo_matrix_scale (&scaled_font->logical_to_device,
00159                      1.0 / scaled_font->logical_scale, 1.0 / scaled_font->logical_scale);
00160 
00161     scaled_font->device_to_logical = scaled_font->logical_to_device;
00162     
00163     status = cairo_matrix_invert (&scaled_font->device_to_logical);
00164     if (status)
00165        cairo_matrix_init_identity (&scaled_font->device_to_logical);
00166 }
00167 
00168 static cairo_bool_t
00169 _have_cleartype_quality (void)
00170 {
00171     OSVERSIONINFO version_info;
00172     
00173     version_info.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
00174     
00175     if (!GetVersionEx (&version_info)) {
00176        _cairo_win32_print_gdi_error ("_have_cleartype_quality");
00177        return FALSE;
00178     }
00179     
00180     return (version_info.dwMajorVersion > 5 ||
00181            (version_info.dwMajorVersion == 5 &&
00182             version_info.dwMinorVersion >= 1));  /* XP or newer */
00183 }
00184 
00185 
00186 static BYTE
00187 _get_system_quality (void)
00188 {
00189     BOOL font_smoothing;
00190     UINT smoothing_type;
00191 
00192     if (!SystemParametersInfo (SPI_GETFONTSMOOTHING, 0, &font_smoothing, 0)) {
00193        _cairo_win32_print_gdi_error ("_get_system_quality");
00194        return DEFAULT_QUALITY;
00195     }
00196 
00197     if (font_smoothing) {
00198        if (_have_cleartype_quality ()) {
00199            if (!SystemParametersInfo (SPI_GETFONTSMOOTHINGTYPE,
00200                                    0, &smoothing_type, 0)) {
00201               _cairo_win32_print_gdi_error ("_get_system_quality");
00202               return DEFAULT_QUALITY;
00203            }
00204 
00205            if (smoothing_type == FE_FONTSMOOTHINGCLEARTYPE)
00206               return CLEARTYPE_QUALITY;
00207        }
00208 
00209        return ANTIALIASED_QUALITY;
00210     } else {
00211        return DEFAULT_QUALITY;
00212     }
00213 }
00214 
00215 static cairo_scaled_font_t *
00216 _win32_scaled_font_create (LOGFONTW                   *logfont,
00217                         cairo_font_face_t       *font_face,
00218                         const cairo_matrix_t       *font_matrix,
00219                         const cairo_matrix_t       *ctm,
00220                         const cairo_font_options_t *options)                   
00221 {
00222     cairo_win32_scaled_font_t *f;
00223     cairo_matrix_t scale;
00224 
00225     f = malloc (sizeof(cairo_win32_scaled_font_t));
00226     if (f == NULL)
00227        return NULL;
00228 
00229     f->logfont = *logfont;
00230 
00231     /* We don't have any control over the hinting style or subpixel
00232      * order in the Win32 font API, so we ignore those parts of
00233      * cairo_font_options_t. We use the 'antialias' field to set
00234      * the 'quality'.
00235      * 
00236      * XXX: The other option we could pay attention to, but don't
00237      *      here is the hint_metrics options.
00238      */
00239     if (options->antialias == CAIRO_ANTIALIAS_DEFAULT)
00240        f->quality = _get_system_quality ();
00241     else {
00242        switch (options->antialias) {
00243        case CAIRO_ANTIALIAS_NONE:
00244            f->quality = NONANTIALIASED_QUALITY;
00245            break;
00246        case CAIRO_ANTIALIAS_GRAY:
00247            f->quality = ANTIALIASED_QUALITY;
00248            break;
00249        case CAIRO_ANTIALIAS_SUBPIXEL:
00250            if (_have_cleartype_quality ())
00251               f->quality = CLEARTYPE_QUALITY;
00252            else
00253               f->quality = ANTIALIASED_QUALITY;
00254            break;
00255        }
00256     }
00257     
00258     f->em_square = 0;
00259     f->scaled_hfont = NULL;
00260     f->unscaled_hfont = NULL;
00261 
00262     cairo_matrix_multiply (&scale, font_matrix, ctm);
00263     _compute_transform (f, &scale);
00264 
00265     _cairo_scaled_font_init (&f->base, font_face,
00266                           font_matrix, ctm, options,
00267                           &cairo_win32_scaled_font_backend);
00268 
00269     return &f->base;
00270 }
00271 
00272 static cairo_status_t
00273 _win32_scaled_font_set_world_transform (cairo_win32_scaled_font_t *scaled_font,
00274                                    HDC                        hdc)
00275 {
00276     XFORM xform;
00277     
00278     xform.eM11 = scaled_font->logical_to_device.xx;
00279     xform.eM21 = scaled_font->logical_to_device.xy;
00280     xform.eM12 = scaled_font->logical_to_device.yx;
00281     xform.eM22 = scaled_font->logical_to_device.yy;
00282     xform.eDx = scaled_font->logical_to_device.x0;
00283     xform.eDy = scaled_font->logical_to_device.y0;
00284 
00285     if (!SetWorldTransform (hdc, &xform))
00286        return _cairo_win32_print_gdi_error ("_win32_scaled_font_set_world_transform");
00287 
00288     return CAIRO_STATUS_SUCCESS;
00289 }
00290 
00291 static cairo_status_t
00292 _win32_scaled_font_set_identity_transform (HDC hdc)
00293 {
00294     if (!ModifyWorldTransform (hdc, NULL, MWT_IDENTITY))
00295        return _cairo_win32_print_gdi_error ("_win32_scaled_font_set_identity_transform");
00296 
00297     return CAIRO_STATUS_SUCCESS;
00298 }
00299 
00300 static HDC
00301 _get_global_font_dc (void)
00302 {
00303     static HDC hdc;
00304 
00305     if (!hdc) {
00306        hdc = CreateCompatibleDC (NULL);
00307        if (!hdc) {
00308            _cairo_win32_print_gdi_error ("_get_global_font_dc");
00309            return NULL;
00310        }
00311 
00312        if (!SetGraphicsMode (hdc, GM_ADVANCED)) {
00313            _cairo_win32_print_gdi_error ("_get_global_font_dc");
00314            DeleteDC (hdc);
00315            return NULL;
00316        }
00317     }
00318 
00319     return hdc;
00320 }
00321 
00322 static HFONT
00323 _win32_scaled_font_get_scaled_hfont (cairo_win32_scaled_font_t *scaled_font)
00324 {
00325     if (!scaled_font->scaled_hfont) {
00326        LOGFONTW logfont = scaled_font->logfont;
00327        logfont.lfHeight = -scaled_font->logical_size;
00328        logfont.lfWidth = 0;
00329        logfont.lfEscapement = 0;
00330        logfont.lfOrientation = 0;
00331        logfont.lfQuality = scaled_font->quality;
00332 
00333        scaled_font->scaled_hfont = CreateFontIndirectW (&logfont);
00334        if (!scaled_font->scaled_hfont) {
00335            _cairo_win32_print_gdi_error ("_win32_scaled_font_get_scaled_hfont");
00336            return NULL;
00337        }
00338     }
00339 
00340     return scaled_font->scaled_hfont;
00341 }
00342 
00343 static HFONT
00344 _win32_scaled_font_get_unscaled_hfont (cairo_win32_scaled_font_t *scaled_font,
00345                                    HDC                        hdc)
00346 {
00347     if (!scaled_font->unscaled_hfont) {
00348        OUTLINETEXTMETRIC *otm;
00349        unsigned int otm_size;
00350        HFONT scaled_hfont;
00351        LOGFONTW logfont;
00352 
00353        scaled_hfont = _win32_scaled_font_get_scaled_hfont (scaled_font);
00354        if (!scaled_hfont)
00355            return NULL;
00356 
00357        if (!SelectObject (hdc, scaled_hfont)) {
00358            _cairo_win32_print_gdi_error ("_win32_scaled_font_get_unscaled_hfont:SelectObject");
00359            return NULL;
00360        }
00361 
00362        otm_size = GetOutlineTextMetrics (hdc, 0, NULL);
00363        if (!otm_size) {
00364            _cairo_win32_print_gdi_error ("_win32_scaled_font_get_unscaled_hfont:GetOutlineTextMetrics");
00365            return NULL;
00366        }
00367        
00368        otm = malloc (otm_size);
00369        if (!otm)
00370            return NULL;
00371 
00372        if (!GetOutlineTextMetrics (hdc, otm_size, otm)) {
00373            _cairo_win32_print_gdi_error ("_win32_scaled_font_get_unscaled_hfont:GetOutlineTextMetrics");
00374            free (otm);
00375            return NULL;
00376        }
00377 
00378        scaled_font->em_square = otm->otmEMSquare;
00379        free (otm);
00380        
00381        logfont = scaled_font->logfont;
00382        logfont.lfHeight = -scaled_font->em_square;
00383        logfont.lfWidth = 0;
00384        logfont.lfEscapement = 0;
00385        logfont.lfOrientation = 0;
00386        logfont.lfQuality = scaled_font->quality;
00387        
00388        scaled_font->unscaled_hfont = CreateFontIndirectW (&logfont);
00389        if (!scaled_font->unscaled_hfont) {
00390            _cairo_win32_print_gdi_error ("_win32_scaled_font_get_unscaled_hfont:CreateIndirect");
00391            return NULL;
00392        }
00393     }
00394 
00395     return scaled_font->unscaled_hfont;
00396 }
00397 
00398 static cairo_status_t
00399 _cairo_win32_scaled_font_select_unscaled_font (cairo_scaled_font_t *scaled_font,
00400                                           HDC                  hdc)
00401 {
00402     cairo_status_t status;
00403     HFONT hfont;
00404     HFONT old_hfont = NULL;
00405 
00406     hfont = _win32_scaled_font_get_unscaled_hfont ((cairo_win32_scaled_font_t *)scaled_font, hdc);
00407     if (!hfont)
00408        return CAIRO_STATUS_NO_MEMORY;
00409 
00410     old_hfont = SelectObject (hdc, hfont);
00411     if (!old_hfont)
00412        return _cairo_win32_print_gdi_error ("_cairo_win32_scaled_font_select_unscaled_font");
00413 
00414     status = _win32_scaled_font_set_identity_transform (hdc);
00415     if (status) {
00416        SelectObject (hdc, old_hfont);
00417        return status;
00418     }
00419 
00420     SetMapMode (hdc, MM_TEXT);
00421 
00422     return CAIRO_STATUS_SUCCESS;
00423 }
00424 
00425 static void
00426 _cairo_win32_scaled_font_done_unscaled_font (cairo_scaled_font_t *scaled_font)
00427 {
00428 }
00429 
00430 /* implement the font backend interface */
00431 
00432 static cairo_status_t
00433 _cairo_win32_scaled_font_create_toy (cairo_toy_font_face_t *toy_face,
00434                                  const cairo_matrix_t        *font_matrix,
00435                                  const cairo_matrix_t        *ctm,
00436                                  const cairo_font_options_t  *options,
00437                                  cairo_scaled_font_t        **scaled_font_out)
00438 {
00439     LOGFONTW logfont;
00440     cairo_scaled_font_t *scaled_font;
00441     uint16_t *face_name;
00442     int face_name_len;
00443     cairo_status_t status;
00444 
00445     status = _cairo_utf8_to_utf16 (toy_face->family, -1,
00446                                &face_name, &face_name_len);
00447     if (status)
00448        return status;
00449 
00450     if (face_name_len > LF_FACESIZE - 1) {
00451        free (face_name);
00452        return CAIRO_STATUS_INVALID_STRING;
00453     }
00454 
00455     memcpy (logfont.lfFaceName, face_name, sizeof (uint16_t) * (face_name_len + 1));
00456     free (face_name);
00457 
00458     logfont.lfHeight = 0;   /* filled in later */
00459     logfont.lfWidth = 0;    /* filled in later */
00460     logfont.lfEscapement = 0;      /* filled in later */
00461     logfont.lfOrientation = 0;     /* filled in later */
00462 
00463     switch (toy_face->weight) {
00464     case CAIRO_FONT_WEIGHT_NORMAL:
00465     default:
00466        logfont.lfWeight = FW_NORMAL;
00467        break;
00468     case CAIRO_FONT_WEIGHT_BOLD:
00469        logfont.lfWeight = FW_BOLD;
00470        break;
00471     }
00472 
00473     switch (toy_face->slant) {
00474     case CAIRO_FONT_SLANT_NORMAL:
00475     default:
00476        logfont.lfItalic = FALSE;
00477        break;
00478     case CAIRO_FONT_SLANT_ITALIC:
00479     case CAIRO_FONT_SLANT_OBLIQUE:
00480        logfont.lfItalic = TRUE;
00481        break;
00482     }
00483 
00484     logfont.lfUnderline = FALSE;
00485     logfont.lfStrikeOut = FALSE;
00486     /* The docs for LOGFONT discourage using this, since the
00487      * interpretation is locale-specific, but it's not clear what
00488      * would be a better alternative.
00489      */
00490     logfont.lfCharSet = DEFAULT_CHARSET; 
00491     logfont.lfOutPrecision = OUT_DEFAULT_PRECIS;
00492     logfont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
00493     logfont.lfQuality = DEFAULT_QUALITY; /* filled in later */
00494     logfont.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
00495 
00496     if (!logfont.lfFaceName)
00497        return CAIRO_STATUS_NO_MEMORY;
00498     
00499     scaled_font = _win32_scaled_font_create (&logfont, toy_face,
00500                                         font_matrix, ctm, options);
00501     if (!scaled_font)
00502        return CAIRO_STATUS_NO_MEMORY;
00503 
00504     *scaled_font_out = scaled_font;
00505 
00506     return CAIRO_STATUS_SUCCESS;
00507 }
00508 
00509 static void 
00510 _cairo_win32_scaled_font_fini (void *abstract_font)
00511 {
00512     cairo_win32_scaled_font_t *scaled_font = abstract_font;
00513 
00514     if (scaled_font == NULL)
00515        return;
00516 
00517     if (scaled_font->scaled_hfont)
00518        DeleteObject (scaled_font->scaled_hfont);
00519 
00520     if (scaled_font->unscaled_hfont)
00521        DeleteObject (scaled_font->unscaled_hfont);
00522 }
00523 
00524 static void
00525 _cairo_win32_scaled_font_get_glyph_cache_key (void                    *abstract_font,
00526                                          cairo_glyph_cache_key_t *key)
00527 {
00528 }
00529 
00530 static cairo_status_t 
00531 _cairo_win32_scaled_font_text_to_glyphs (void           *abstract_font,
00532                                     const char   *utf8,
00533                                     cairo_glyph_t **glyphs, 
00534                                     int          *num_glyphs)
00535 {
00536     cairo_win32_scaled_font_t *scaled_font = abstract_font;
00537     uint16_t *utf16;
00538     int n16;
00539     GCP_RESULTSW gcp_results;
00540     unsigned int buffer_size, i;
00541     WCHAR *glyph_indices = NULL;
00542     int *dx = NULL;
00543     cairo_status_t status = CAIRO_STATUS_SUCCESS;
00544     double x_pos;
00545     HDC hdc = NULL;
00546 
00547     status = _cairo_utf8_to_utf16 (utf8, -1, &utf16, &n16);
00548     if (status)
00549        return status;
00550 
00551     gcp_results.lStructSize = sizeof (GCP_RESULTS);
00552     gcp_results.lpOutString = NULL;
00553     gcp_results.lpOrder = NULL;
00554     gcp_results.lpCaretPos = NULL;
00555     gcp_results.lpClass = NULL;
00556     
00557     buffer_size = MAX (n16 * 1.2, 16);           /* Initially guess number of chars plus a few */
00558     if (buffer_size > INT_MAX) {
00559        status = CAIRO_STATUS_NO_MEMORY;
00560        goto FAIL1;
00561     }
00562     
00563     hdc = _get_global_font_dc ();
00564     if (!hdc) {
00565        status = CAIRO_STATUS_NO_MEMORY;
00566        goto FAIL1;
00567     }
00568 
00569     status = cairo_win32_scaled_font_select_font (&scaled_font->base, hdc);
00570     if (status)
00571        goto FAIL1;
00572     
00573     while (TRUE) {
00574        if (glyph_indices) {
00575            free (glyph_indices);
00576            glyph_indices = NULL;
00577        }
00578        if (dx) {
00579            free (dx);
00580            dx = NULL;
00581        }
00582        
00583        glyph_indices = malloc (sizeof (WCHAR) * buffer_size);
00584        dx = malloc (sizeof (int) * buffer_size);
00585        if (!glyph_indices || !dx) {
00586            status = CAIRO_STATUS_NO_MEMORY;
00587            goto FAIL2;
00588        }
00589 
00590        gcp_results.nGlyphs = buffer_size;
00591        gcp_results.lpDx = dx;
00592        gcp_results.lpGlyphs = glyph_indices;
00593 
00594        if (!GetCharacterPlacementW (hdc, utf16, n16,
00595                                  0,
00596                                  &gcp_results, 
00597                                  GCP_DIACRITIC | GCP_LIGATE | GCP_GLYPHSHAPE | GCP_REORDER)) {
00598            status = _cairo_win32_print_gdi_error ("_cairo_win32_scaled_font_text_to_glyphs");
00599            goto FAIL2;
00600        }
00601 
00602        if (gcp_results.lpDx && gcp_results.lpGlyphs)
00603            break;
00604 
00605        /* Too small a buffer, try again */
00606        
00607        buffer_size *= 1.5;
00608        if (buffer_size > INT_MAX) {
00609            status = CAIRO_STATUS_NO_MEMORY;
00610            goto FAIL2;
00611        }
00612     }
00613 
00614     *num_glyphs = gcp_results.nGlyphs;
00615     *glyphs = malloc (sizeof (cairo_glyph_t) * gcp_results.nGlyphs);
00616     if (!*glyphs) {
00617        status = CAIRO_STATUS_NO_MEMORY;
00618        goto FAIL2;
00619     }
00620 
00621     x_pos = 0;
00622     for (i = 0; i < gcp_results.nGlyphs; i++) {
00623        (*glyphs)[i].index = glyph_indices[i];
00624        (*glyphs)[i].x = x_pos ;
00625        (*glyphs)[i].y = 0;
00626 
00627        x_pos += dx[i] / scaled_font->logical_scale;
00628     }
00629 
00630  FAIL2:
00631     if (glyph_indices)
00632        free (glyph_indices);
00633     if (dx)
00634        free (dx);
00635    
00636     cairo_win32_scaled_font_done_font (&scaled_font->base);
00637     
00638  FAIL1:
00639     free (utf16);
00640    
00641     return status;
00642 }
00643 
00644 static cairo_status_t 
00645 _cairo_win32_scaled_font_font_extents (void                 *abstract_font,
00646                                    cairo_font_extents_t *extents)
00647 {
00648     cairo_win32_scaled_font_t *scaled_font = abstract_font;
00649     cairo_status_t status;
00650     TEXTMETRIC metrics;
00651     HDC hdc;
00652 
00653     hdc = _get_global_font_dc ();
00654     if (!hdc)
00655        return CAIRO_STATUS_NO_MEMORY;
00656 
00657     if (scaled_font->preserve_axes) {
00658        /* For 90-degree rotations (including 0), we get the metrics
00659         * from the GDI in logical space, then convert back to font space
00660         */
00661        status = cairo_win32_scaled_font_select_font (&scaled_font->base, hdc);
00662        if (status)
00663            return status;
00664        GetTextMetrics (hdc, &metrics);
00665        cairo_win32_scaled_font_done_font (&scaled_font->base);
00666 
00667        extents->ascent = metrics.tmAscent / scaled_font->logical_scale;
00668        extents->descent = metrics.tmDescent / scaled_font->logical_scale;
00669 
00670        extents->height = (metrics.tmHeight + metrics.tmExternalLeading) / scaled_font->logical_scale;
00671        extents->max_x_advance = metrics.tmMaxCharWidth / scaled_font->logical_scale;
00672        extents->max_y_advance = 0;
00673 
00674     } else {
00675        /* For all other transformations, we use the design metrics
00676         * of the font. The GDI results from GetTextMetrics() on a
00677         * transformed font are inexplicably large and we want to
00678         * avoid them.
00679         */
00680        status = _cairo_win32_scaled_font_select_unscaled_font (&scaled_font->base, hdc);
00681        if (status)
00682            return status;
00683        GetTextMetrics (hdc, &metrics);
00684        _cairo_win32_scaled_font_done_unscaled_font (&scaled_font->base);
00685 
00686        extents->ascent = (double)metrics.tmAscent / scaled_font->em_square;
00687        extents->descent = metrics.tmDescent * scaled_font->em_square;
00688        extents->height = (double)(metrics.tmHeight + metrics.tmExternalLeading) / scaled_font->em_square;
00689        extents->max_x_advance = (double)(metrics.tmMaxCharWidth) / scaled_font->em_square;
00690        extents->max_y_advance = 0;
00691        
00692     }
00693 
00694     return CAIRO_STATUS_SUCCESS;
00695 }
00696 
00697 static cairo_status_t 
00698 _cairo_win32_scaled_font_glyph_extents (void                 *abstract_font,
00699                                    cairo_glyph_t      *glyphs, 
00700                                    int                 num_glyphs,
00701                                    cairo_text_extents_t *extents)
00702 {
00703     cairo_win32_scaled_font_t *scaled_font = abstract_font;
00704     static const MAT2 matrix = { { 0, 1 }, { 0, 0 }, { 0, 0 }, { 0, 1 } };
00705     GLYPHMETRICS metrics;
00706     cairo_status_t status;
00707     HDC hdc;
00708 
00709     hdc = _get_global_font_dc ();
00710     if (!hdc)
00711        return CAIRO_STATUS_NO_MEMORY;
00712 
00713     /* We handle only the case num_glyphs == 1, glyphs[i].x == glyphs[0].y == 0.
00714      * This is all that the calling code triggers, and the backend interface
00715      * will eventually be changed to match
00716      */
00717     assert (num_glyphs == 1);
00718 
00719     if (scaled_font->preserve_axes) {
00720        /* If we aren't rotating / skewing the axes, then we get the metrics
00721         * from the GDI in device space and convert to font space.
00722         */
00723        status = cairo_win32_scaled_font_select_font (&scaled_font->base, hdc);
00724        if (status)
00725            return status;
00726        if (GetGlyphOutlineW (hdc, glyphs[0].index, GGO_METRICS | GGO_GLYPH_INDEX,
00727                            &metrics, 0, NULL, &matrix) == GDI_ERROR) {
00728          memset (&metrics, 0, sizeof (GLYPHMETRICS));
00729        }
00730        cairo_win32_scaled_font_done_font (&scaled_font->base);
00731 
00732        if (scaled_font->swap_axes) {
00733            extents->x_bearing = - metrics.gmptGlyphOrigin.y / scaled_font->y_scale;
00734            extents->y_bearing = metrics.gmptGlyphOrigin.x / scaled_font->x_scale;
00735            extents->width = metrics.gmBlackBoxY / scaled_font->y_scale;
00736            extents->height = metrics.gmBlackBoxX / scaled_font->x_scale;
00737            extents->x_advance = metrics.gmCellIncY / scaled_font->x_scale;
00738            extents->y_advance = metrics.gmCellIncX / scaled_font->y_scale;
00739        } else {
00740            extents->x_bearing = metrics.gmptGlyphOrigin.x / scaled_font->x_scale;
00741            extents->y_bearing = - metrics.gmptGlyphOrigin.y / scaled_font->y_scale;
00742            extents->width = metrics.gmBlackBoxX / scaled_font->x_scale;
00743            extents->height = metrics.gmBlackBoxY / scaled_font->y_scale;
00744            extents->x_advance = metrics.gmCellIncX / scaled_font->x_scale;
00745            extents->y_advance = metrics.gmCellIncY / scaled_font->y_scale;
00746        }
00747 
00748        if (scaled_font->swap_x) {
00749            extents->x_bearing = (- extents->x_bearing - extents->width);
00750            extents->x_advance = - extents->x_advance;
00751        }
00752 
00753        if (scaled_font->swap_y) {
00754            extents->y_bearing = (- extents->y_bearing - extents->height);
00755            extents->y_advance = - extents->y_advance;
00756        }
00757        
00758     } else {
00759        /* For all other transformations, we use the design metrics
00760         * of the font.
00761         */
00762        status = _cairo_win32_scaled_font_select_unscaled_font (&scaled_font->base, hdc);
00763        if (GetGlyphOutlineW (hdc, glyphs[0].index, GGO_METRICS | GGO_GLYPH_INDEX,
00764                            &metrics, 0, NULL, &matrix) == GDI_ERROR) {
00765          memset (&metrics, 0, sizeof (GLYPHMETRICS));
00766        }
00767        _cairo_win32_scaled_font_done_unscaled_font (&scaled_font->base);
00768 
00769        extents->x_bearing = (double)metrics.gmptGlyphOrigin.x / scaled_font->em_square;
00770        extents->y_bearing = - (double)metrics.gmptGlyphOrigin.y / scaled_font->em_square;
00771        extents->width = (double)metrics.gmBlackBoxX / scaled_font->em_square;
00772        extents->height = (double)metrics.gmBlackBoxY / scaled_font->em_square;
00773        extents->x_advance = (double)metrics.gmCellIncX / scaled_font->em_square;
00774        extents->y_advance = (double)metrics.gmCellIncY / scaled_font->em_square;
00775     }
00776 
00777     return CAIRO_STATUS_SUCCESS;
00778 }
00779 
00780 
00781 static cairo_status_t 
00782 _cairo_win32_scaled_font_glyph_bbox (void         *abstract_font,
00783                                  const cairo_glyph_t *glyphs,
00784                                  int                  num_glyphs,
00785                                  cairo_box_t         *bbox)
00786 {
00787     static const MAT2 matrix = { { 0, 1 }, { 0, 0 }, { 0, 0 }, { 0, 1 } };
00788     cairo_win32_scaled_font_t *scaled_font = abstract_font;
00789     int x1 = 0, x2 = 0, y1 = 0, y2 = 0;
00790 
00791     if (num_glyphs > 0) {
00792        HDC hdc = _get_global_font_dc ();
00793        GLYPHMETRICS metrics;
00794        cairo_status_t status;
00795        int i;
00796 
00797        if (!hdc)
00798            return CAIRO_STATUS_NO_MEMORY;
00799 
00800        status = cairo_win32_scaled_font_select_font (&scaled_font->base, hdc);
00801        if (status)
00802            return status;
00803 
00804        for (i = 0; i < num_glyphs; i++) {
00805            int x = floor (0.5 + glyphs[i].x);
00806            int y = floor (0.5 + glyphs[i].y);
00807 
00808            GetGlyphOutlineW (hdc, glyphs[i].index, GGO_METRICS | GGO_GLYPH_INDEX,
00809                           &metrics, 0, NULL, &matrix);
00810 
00811            if (i == 0 || x1 > x + metrics.gmptGlyphOrigin.x)
00812               x1 = x + metrics.gmptGlyphOrigin.x;
00813            if (i == 0 || y1 > y - metrics.gmptGlyphOrigin.y)
00814               y1 = y - metrics.gmptGlyphOrigin.y;
00815            if (i == 0 || x2 < x + metrics.gmptGlyphOrigin.x + (int)metrics.gmBlackBoxX)
00816               x2 = x + metrics.gmptGlyphOrigin.x + (int)metrics.gmBlackBoxX;
00817            if (i == 0 || y2 < y - metrics.gmptGlyphOrigin.y + (int)metrics.gmBlackBoxY)
00818               y2 = y - metrics.gmptGlyphOrigin.y + (int)metrics.gmBlackBoxY;
00819        }
00820 
00821        cairo_win32_scaled_font_done_font (&scaled_font->base);
00822     }
00823 
00824     bbox->p1.x = _cairo_fixed_from_int (x1);
00825     bbox->p1.y = _cairo_fixed_from_int (y1);
00826     bbox->p2.x = _cairo_fixed_from_int (x2);
00827     bbox->p2.y = _cairo_fixed_from_int (y2);
00828 
00829     return CAIRO_STATUS_SUCCESS;
00830 }
00831 
00832 typedef struct {
00833     cairo_win32_scaled_font_t *scaled_font;
00834     HDC hdc;
00835     
00836     cairo_array_t glyphs;
00837     cairo_array_t dx;
00838 
00839     int start_x;
00840     int last_x;
00841     int last_y;
00842 } cairo_glyph_state_t;
00843 
00844 static void
00845 _start_glyphs (cairo_glyph_state_t        *state,
00846               cairo_win32_scaled_font_t  *scaled_font,
00847               HDC                         hdc)
00848 {
00849     state->hdc = hdc;
00850     state->scaled_font = scaled_font;
00851 
00852     _cairo_array_init (&state->glyphs, sizeof (WCHAR));
00853     _cairo_array_init (&state->dx, sizeof (int));
00854 }
00855 
00856 static cairo_status_t
00857 _flush_glyphs (cairo_glyph_state_t *state)
00858 {
00859     int dx = 0;
00860     if (!_cairo_array_append (&state->dx, &dx, 1))
00861        return CAIRO_STATUS_NO_MEMORY;
00862     
00863     if (!ExtTextOutW (state->hdc,
00864                     state->start_x, state->last_y,
00865                     ETO_GLYPH_INDEX,
00866                     NULL,
00867                     (WCHAR *)state->glyphs.elements,
00868                     state->glyphs.num_elements,
00869                     (int *)state->dx.elements)) {
00870        return _cairo_win32_print_gdi_error ("_flush_glyphs");
00871     }
00872     
00873     _cairo_array_truncate (&state->glyphs, 0);
00874     _cairo_array_truncate (&state->dx, 0);
00875 
00876     return CAIRO_STATUS_SUCCESS;
00877 }
00878 
00879 static cairo_status_t
00880 _add_glyph (cairo_glyph_state_t *state,
00881            unsigned long        index,
00882            double               device_x,
00883            double               device_y)
00884 {
00885     double user_x = device_x;
00886     double user_y = device_y;
00887     WCHAR glyph_index = index;
00888     int logical_x, logical_y;
00889 
00890     cairo_matrix_transform_point (&state->scaled_font->device_to_logical, &user_x, &user_y);
00891 
00892     logical_x = floor (user_x + 0.5);
00893     logical_y = floor (user_y + 0.5);
00894 
00895     if (state->glyphs.num_elements > 0) {
00896        int dx;
00897        
00898        if (logical_y != state->last_y) {
00899            cairo_status_t status = _flush_glyphs (state);
00900            if (status)
00901               return status;
00902            state->start_x = logical_x;
00903        }
00904        
00905        dx = logical_x - state->last_x;
00906        if (!_cairo_array_append (&state->dx, &dx, 1))
00907            return CAIRO_STATUS_NO_MEMORY;
00908     } else {
00909        state->start_x = logical_x;
00910     }
00911 
00912     state->last_x = logical_x;
00913     state->last_y = logical_y;
00914     
00915     _cairo_array_append (&state->glyphs, &glyph_index, 1);
00916 
00917     return CAIRO_STATUS_SUCCESS;
00918 }
00919 
00920 static void
00921 _finish_glyphs (cairo_glyph_state_t *state)
00922 {
00923     _flush_glyphs (state);
00924 
00925     _cairo_array_fini (&state->glyphs);
00926     _cairo_array_fini (&state->dx);
00927 }
00928 
00929 static cairo_status_t
00930 _draw_glyphs_on_surface (cairo_win32_surface_t     *surface,
00931                       cairo_win32_scaled_font_t *scaled_font,
00932                       COLORREF                   color,
00933                       int                        x_offset,
00934                       int                        y_offset,
00935                       const cairo_glyph_t       *glyphs,
00936                       int                            num_glyphs)
00937 {
00938     cairo_glyph_state_t state;
00939     cairo_status_t status = CAIRO_STATUS_SUCCESS;
00940     int i;
00941 
00942     if (!SaveDC (surface->dc))
00943        return _cairo_win32_print_gdi_error ("_draw_glyphs_on_surface:SaveDC");
00944 
00945     status = cairo_win32_scaled_font_select_font (&scaled_font->base, surface->dc);
00946     if (status)
00947        goto FAIL1;
00948 
00949     SetTextColor (surface->dc, color);
00950     SetTextAlign (surface->dc, TA_BASELINE | TA_LEFT);
00951     SetBkMode (surface->dc, TRANSPARENT);
00952     
00953     _start_glyphs (&state, scaled_font, surface->dc);
00954 
00955     for (i = 0; i < num_glyphs; i++) {
00956        status = _add_glyph (&state, glyphs[i].index,
00957                           glyphs[i].x - x_offset, glyphs[i].y - y_offset);
00958        if (status)
00959            goto FAIL2;
00960     }
00961 
00962  FAIL2:
00963     _finish_glyphs (&state);
00964     cairo_win32_scaled_font_done_font (&scaled_font->base);
00965  FAIL1:
00966     RestoreDC (surface->dc, -1);
00967     
00968     return status;
00969 }
00970               
00971 /* Duplicate the green channel of a 4-channel mask in the alpha channel, then
00972  * invert the whole mask.
00973  */
00974 static void
00975 _compute_argb32_mask_alpha (cairo_win32_surface_t *mask_surface)
00976 {
00977     cairo_image_surface_t *image = (cairo_image_surface_t *)mask_surface->src_image;
00978     int i, j;
00979 
00980     for (i = 0; i < image->height; i++) {
00981        uint32_t *p = (uint32_t *) (image->data + i * image->stride);
00982        for (j = 0; j < image->width; j++) {
00983            *p = 0xffffffff ^ (*p | ((*p & 0x0000ff00) << 16));
00984            p++;
00985        }
00986     }
00987 }
00988 
00989 /* Invert a mask
00990  */
00991 static void
00992 _invert_argb32_mask (cairo_win32_surface_t *mask_surface)
00993 {
00994     cairo_image_surface_t *image = (cairo_image_surface_t *)mask_surface->src_image;
00995     int i, j;
00996 
00997     for (i = 0; i < image->height; i++) {
00998        uint32_t *p = (uint32_t *) (image->data + i * image->stride);
00999        for (j = 0; j < image->width; j++) {
01000            *p = 0xffffffff ^ *p;
01001            p++;
01002        }
01003     }
01004 }
01005 
01006 /* Compute an alpha-mask from a monochrome RGB24 image
01007  */
01008 static cairo_surface_t *
01009 _compute_a8_mask (cairo_win32_surface_t *mask_surface)
01010 {
01011     cairo_image_surface_t *image24 = (cairo_image_surface_t *)mask_surface->src_image;
01012     cairo_image_surface_t *image8;
01013     int i, j;
01014 
01015     image8 = (cairo_image_surface_t *)cairo_image_surface_create (CAIRO_FORMAT_A8,
01016                                                           image24->width, image24->height);
01017     if (image8->base.status)
01018        return NULL;
01019 
01020     for (i = 0; i < image24->height; i++) {
01021        uint32_t *p = (uint32_t *) (image24->data + i * image24->stride);
01022        unsigned char *q = (unsigned char *) (image8->data + i * image8->stride);
01023        
01024        for (j = 0; j < image24->width; j++) {
01025            *q = 255 - ((*p & 0x0000ff00) >> 8);
01026            p++;
01027            q++;
01028        }
01029     }
01030 
01031     return &image8->base;
01032 }
01033 
01034 static cairo_status_t 
01035 _cairo_win32_scaled_font_show_glyphs (void                     *abstract_font,
01036                                   cairo_operator_t      operator,
01037                                   cairo_pattern_t          *pattern,
01038                                   cairo_surface_t          *generic_surface,
01039                                   int                   source_x,
01040                                   int                   source_y,
01041                                   int                   dest_x,
01042                                   int                   dest_y,
01043                                   unsigned int          width,
01044                                   unsigned int          height,
01045                                   const cairo_glyph_t      *glyphs,
01046                                   int                   num_glyphs)
01047 {
01048     cairo_win32_scaled_font_t *scaled_font = abstract_font;
01049     cairo_win32_surface_t *surface = (cairo_win32_surface_t *)generic_surface;
01050     cairo_status_t status;
01051 
01052     if (width == 0 || height == 0)
01053        return CAIRO_STATUS_SUCCESS;
01054 
01055     if (_cairo_surface_is_win32 (generic_surface) &&
01056        surface->format == CAIRO_FORMAT_RGB24 &&
01057        operator == CAIRO_OPERATOR_OVER &&
01058        _cairo_pattern_is_opaque_solid (pattern)) {
01059 
01060        cairo_solid_pattern_t *solid_pattern = (cairo_solid_pattern_t *)pattern;
01061 
01062        /* When compositing OVER on a GDI-understood surface, with a
01063         * solid opaque color, we can just call ExtTextOut directly.
01064         */
01065        COLORREF new_color;
01066        
01067        new_color = RGB (((int)solid_pattern->color.red_short) >> 8,
01068                       ((int)solid_pattern->color.green_short) >> 8,
01069                       ((int)solid_pattern->color.blue_short) >> 8);
01070 
01071        status = _draw_glyphs_on_surface (surface, scaled_font, new_color,
01072                                      0, 0,
01073                                      glyphs, num_glyphs);
01074        
01075        return status;
01076     } else {
01077        /* Otherwise, we need to draw using software fallbacks. We create a mask 
01078         * surface by drawing the the glyphs onto a DIB, black-on-white then
01079         * inverting. GDI outputs gamma-corrected images so inverted black-on-white
01080         * is very different from white-on-black. We favor the more common
01081         * case where the final output is dark-on-light.
01082         */
01083        cairo_win32_surface_t *tmp_surface;
01084        cairo_surface_t *mask_surface;
01085        cairo_surface_pattern_t mask;
01086        RECT r;
01087 
01088        tmp_surface = (cairo_win32_surface_t *)_cairo_win32_surface_create_dib (CAIRO_FORMAT_ARGB32, width, height);
01089        if (tmp_surface->base.status)
01090            return CAIRO_STATUS_NO_MEMORY;
01091 
01092        r.left = 0;
01093        r.top = 0;
01094        r.right = width;
01095        r.bottom = height;
01096        FillRect (tmp_surface->dc, &r, GetStockObject (WHITE_BRUSH));
01097 
01098        _draw_glyphs_on_surface (tmp_surface, scaled_font, RGB (0, 0, 0),
01099                              dest_x, dest_y,
01100                              glyphs, num_glyphs);
01101 
01102        if (scaled_font->quality == CLEARTYPE_QUALITY) {
01103            /* For ClearType, we need a 4-channel mask. If we are compositing on
01104             * a surface with alpha, we need to compute the alpha channel of
01105             * the mask (we just copy the green channel). But for a destination
01106             * surface without alpha the alpha channel of the mask is ignored
01107             */
01108 
01109            if (surface->format != CAIRO_FORMAT_RGB24)
01110               _compute_argb32_mask_alpha (tmp_surface);
01111            else
01112               _invert_argb32_mask (tmp_surface);
01113            
01114            mask_surface = &tmp_surface->base;
01115 
01116            /* XXX: Hacky, should expose this in cairo_image_surface */
01117            pixman_image_set_component_alpha (((cairo_image_surface_t *)tmp_surface->src_image)->pixman_image, TRUE);
01118            
01119        } else {
01120            mask_surface = _compute_a8_mask (tmp_surface);
01121            cairo_surface_destroy (&tmp_surface->base);
01122            if (!mask_surface)
01123               return CAIRO_STATUS_NO_MEMORY;
01124        }
01125 
01126        /* For operator == OVER, no-cleartype, a possible optimization here is to
01127         * draw onto an intermediate ARGB32 surface and alpha-blend that with the
01128         * destination
01129         */
01130        _cairo_pattern_init_for_surface (&mask, mask_surface);
01131 
01132        status = _cairo_surface_composite (operator, pattern, 
01133                                       &mask.base,
01134                                       &surface->base,
01135                                       source_x, source_y,
01136                                       0, 0,
01137                                       dest_x, dest_y,
01138                                       width, height);
01139 
01140        _cairo_pattern_fini (&mask.base);
01141        
01142        cairo_surface_destroy (mask_surface);
01143 
01144        return status;
01145     }
01146 }
01147 
01148 static cairo_fixed_t
01149 _cairo_fixed_from_FIXED (FIXED f)
01150 {
01151     return *((cairo_fixed_t *)&f);
01152 }
01153 
01154 static cairo_status_t 
01155 _cairo_win32_scaled_font_glyph_path (void               *abstract_font,
01156                                      cairo_glyph_t      *glyphs, 
01157                                      int                 num_glyphs,
01158                                      cairo_path_fixed_t *path)
01159 {
01160     static const MAT2 matrix = { { 0, 1 }, { 0, 0 }, { 0, 0 }, { 0, -1 } };
01161     cairo_win32_scaled_font_t *scaled_font = abstract_font;
01162     cairo_status_t status;
01163     GLYPHMETRICS metrics;
01164     HDC hdc;
01165     int i;
01166 
01167     hdc = _get_global_font_dc ();
01168     if (!hdc)
01169         return CAIRO_STATUS_NO_MEMORY;
01170 
01171     status = cairo_win32_scaled_font_select_font (&scaled_font->base, hdc);
01172     if (status)
01173         return status;
01174 
01175     for (i = 0; i < num_glyphs; i++)
01176     {
01177         DWORD bytesGlyph;
01178         unsigned char *buffer, *ptr;
01179 
01180         cairo_fixed_t x = _cairo_fixed_from_double (glyphs[i].x);
01181         cairo_fixed_t y = _cairo_fixed_from_double (glyphs[i].y);
01182 
01183         bytesGlyph = GetGlyphOutlineW (hdc, glyphs[i].index,
01184                                        GGO_NATIVE | GGO_GLYPH_INDEX,
01185                                        &metrics, 0, NULL, &matrix);
01186 
01187         if (bytesGlyph == GDI_ERROR) {
01188             status = _cairo_win32_print_gdi_error ("_cairo_win32_scaled_font_glyph_path");
01189             goto FAIL;
01190         }
01191 
01192         ptr = buffer = malloc (bytesGlyph);
01193 
01194         if (!buffer) {
01195             status = CAIRO_STATUS_NO_MEMORY;
01196             goto FAIL;
01197         }
01198 
01199         if (GetGlyphOutlineW (hdc, glyphs[i].index,
01200                               GGO_NATIVE | GGO_GLYPH_INDEX,
01201                               &metrics, bytesGlyph, buffer, &matrix) == GDI_ERROR) {
01202             status = _cairo_win32_print_gdi_error ("_cairo_win32_scaled_font_glyph_path");
01203             free (buffer);
01204             goto FAIL;
01205         }
01206         
01207         while (ptr < buffer + bytesGlyph) {
01208             TTPOLYGONHEADER *header = (TTPOLYGONHEADER *)ptr;
01209             unsigned char *endPoly = ptr + header->cb;
01210 
01211             ptr += sizeof (TTPOLYGONHEADER);
01212 
01213             _cairo_path_fixed_move_to (path,
01214                                        _cairo_fixed_from_FIXED (header->pfxStart.x) + x,
01215                                        _cairo_fixed_from_FIXED (header->pfxStart.y) + y);
01216 
01217             while (ptr < endPoly) {
01218                 TTPOLYCURVE *curve = (TTPOLYCURVE *)ptr;
01219                 POINTFX *points = curve->apfx;
01220                 int i;
01221                 switch (curve->wType) {
01222                 case TT_PRIM_LINE:
01223                     for (i = 0; i < curve->cpfx; i++) {
01224                         _cairo_path_fixed_line_to (path,
01225                                                    _cairo_fixed_from_FIXED (points[i].x) + x,
01226                                                    _cairo_fixed_from_FIXED (points[i].y) + y);
01227                     }
01228                     break;
01229                 case TT_PRIM_QSPLINE:
01230                     for (i = 0; i < curve->cpfx - 1; i++) {
01231                         cairo_fixed_t p1x, p1y, p2x, p2y, cx, cy, c1x, c1y, c2x, c2y;
01232                         _cairo_path_fixed_get_current_point (path, &p1x, &p1y);
01233                         cx = _cairo_fixed_from_FIXED (points[i].x) + x;
01234                         cy = _cairo_fixed_from_FIXED (points[i].y) + y;
01235 
01236                         if (i + 1 == curve->cpfx - 1) {
01237                             p2x = _cairo_fixed_from_FIXED (points[i + 1].x) + x;
01238                             p2y = _cairo_fixed_from_FIXED (points[i + 1].y) + y;
01239                         } else {
01240                             /* records with more than one curve use interpolation for
01241                                control points, per http://support.microsoft.com/kb/q87115/ */
01242                             p2x = (cx + _cairo_fixed_from_FIXED (points[i + 1].x) + x) / 2;
01243                             p2y = (cy + _cairo_fixed_from_FIXED (points[i + 1].y) + y) / 2;
01244                         }
01245 
01246                         c1x = 2 * cx / 3 + p1x / 3;
01247                         c1y = 2 * cy / 3 + p1y / 3;
01248                         c2x = 2 * cx / 3 + p2x / 3;
01249                         c2y = 2 * cy / 3 + p2y / 3;
01250 
01251                         _cairo_path_fixed_curve_to (path, c1x, c1y, c2x, c2y, p2x, p2y);
01252                     }
01253                     break;
01254                 case TT_PRIM_CSPLINE:
01255                     for (i = 0; i < curve->cpfx - 2; i += 2) {
01256                         _cairo_path_fixed_curve_to (path,
01257                                                     _cairo_fixed_from_FIXED (points[i].x) + x,
01258                                                     _cairo_fixed_from_FIXED (points[i].y) + y,
01259                                                     _cairo_fixed_from_FIXED (points[i + 1].x) + x,
01260                                                     _cairo_fixed_from_FIXED (points[i + 1].y) + y,
01261                                                     _cairo_fixed_from_FIXED (points[i + 2].x) + x,
01262                                                     _cairo_fixed_from_FIXED (points[i + 2].y) + y);
01263                     }
01264                     break;
01265                 }
01266                 ptr += sizeof(TTPOLYCURVE) + sizeof (POINTFX) * (curve->cpfx - 1);
01267             }
01268             _cairo_path_fixed_close_path (path);
01269         }
01270         free(buffer);
01271     }
01272 
01273 FAIL:
01274 
01275     cairo_win32_scaled_font_done_font (&scaled_font->base);
01276 
01277     return status;
01278 }
01279 
01280 const cairo_scaled_font_backend_t cairo_win32_scaled_font_backend = {
01281     _cairo_win32_scaled_font_create_toy,
01282     _cairo_win32_scaled_font_fini,
01283     _cairo_win32_scaled_font_font_extents,
01284     _cairo_win32_scaled_font_text_to_glyphs,
01285     _cairo_win32_scaled_font_glyph_extents,
01286     _cairo_win32_scaled_font_glyph_bbox,
01287     _cairo_win32_scaled_font_show_glyphs,
01288     _cairo_win32_scaled_font_glyph_path,
01289     _cairo_win32_scaled_font_get_glyph_cache_key
01290 };
01291 
01292 /* cairo_win32_font_face_t */
01293 
01294 typedef struct _cairo_win32_font_face cairo_win32_font_face_t;
01295 
01296 struct _cairo_win32_font_face {
01297     cairo_font_face_t base;
01298     LOGFONTW logfont;
01299 };
01300 
01301 /* implement the platform-specific interface */
01302 
01303 static void
01304 _cairo_win32_font_face_destroy (void *abstract_face)
01305 {
01306 }
01307 
01308 static cairo_status_t
01309 _cairo_win32_font_face_scaled_font_create (void                *abstract_face,
01310                                       const cairo_matrix_t     *font_matrix,
01311                                       const cairo_matrix_t     *ctm,
01312                                       const cairo_font_options_t *options,
01313                                       cairo_scaled_font_t **font)
01314 {
01315     cairo_win32_font_face_t *font_face = abstract_face;
01316 
01317     *font = _win32_scaled_font_create (&font_face->logfont,
01318                                    font_face,
01319                                    font_matrix, ctm, options);
01320     if (*font)
01321        return CAIRO_STATUS_SUCCESS;
01322     else
01323        return CAIRO_STATUS_NO_MEMORY;
01324 }
01325 
01326 static const cairo_font_face_backend_t _cairo_win32_font_face_backend = {
01327     _cairo_win32_font_face_destroy,
01328     _cairo_win32_font_face_scaled_font_create
01329 };
01330 
01346 cairo_font_face_t *
01347 cairo_win32_font_face_create_for_logfontw (LOGFONTW *logfont)
01348 {
01349     cairo_win32_font_face_t *font_face;
01350 
01351     font_face = malloc (sizeof (cairo_win32_font_face_t));
01352     if (!font_face) {
01353        _cairo_error (CAIRO_STATUS_NO_MEMORY);
01354        return (cairo_font_face_t *)&_cairo_font_face_nil;
01355     }
01356     
01357     font_face->logfont = *logfont;
01358     
01359     _cairo_font_face_init (&font_face->base, &_cairo_win32_font_face_backend);
01360 
01361     return &font_face->base;
01362 }
01363 
01388 cairo_status_t
01389 cairo_win32_scaled_font_select_font (cairo_scaled_font_t *scaled_font,
01390                                  HDC                  hdc)
01391 {
01392     cairo_status_t status;
01393     HFONT hfont;
01394     HFONT old_hfont = NULL;
01395     int old_mode;
01396 
01397     if (scaled_font->status)
01398        return scaled_font->status;
01399 
01400     hfont = _win32_scaled_font_get_scaled_hfont ((cairo_win32_scaled_font_t *)scaled_font);
01401     if (!hfont)
01402        return CAIRO_STATUS_NO_MEMORY;
01403 
01404     old_hfont = SelectObject (hdc, hfont);
01405     if (!old_hfont)
01406        return _cairo_win32_print_gdi_error ("cairo_win32_scaled_font_select_font");
01407 
01408     old_mode = SetGraphicsMode (hdc, GM_ADVANCED);
01409     if (!old_mode) {
01410        status = _cairo_win32_print_gdi_error ("cairo_win32_scaled_font_select_font");
01411        SelectObject (hdc, old_hfont);
01412        return status;
01413     }
01414 
01415     status = _win32_scaled_font_set_world_transform ((cairo_win32_scaled_font_t *)scaled_font, hdc);
01416     if (status) {
01417        SetGraphicsMode (hdc, old_mode);
01418        SelectObject (hdc, old_hfont);
01419        return status;
01420     }
01421 
01422     SetMapMode (hdc, MM_TEXT);
01423 
01424     return CAIRO_STATUS_SUCCESS;
01425 }
01426 
01433 void
01434 cairo_win32_scaled_font_done_font (cairo_scaled_font_t *scaled_font)
01435 {
01436 }
01437 
01450 double
01451 cairo_win32_scaled_font_get_metrics_factor (cairo_scaled_font_t *scaled_font)
01452 {
01453     return 1. / ((cairo_win32_scaled_font_t *)scaled_font)->logical_scale;
01454 }