Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
  2. /* cairo - a vector graphics library with display and print output
  3.  *
  4.  * Copyright � 2008 Mozilla Corporation
  5.  *
  6.  * This library is free software; you can redistribute it and/or
  7.  * modify it either under the terms of the GNU Lesser General Public
  8.  * License version 2.1 as published by the Free Software Foundation
  9.  * (the "LGPL") or, at your option, under the terms of the Mozilla
  10.  * Public License Version 1.1 (the "MPL"). If you do not alter this
  11.  * notice, a recipient may use your version of this file under either
  12.  * the MPL or the LGPL.
  13.  *
  14.  * You should have received a copy of the LGPL along with this library
  15.  * in the file COPYING-LGPL-2.1; if not, write to the Free Software
  16.  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
  17.  * You should have received a copy of the MPL along with this library
  18.  * in the file COPYING-MPL-1.1
  19.  *
  20.  * The contents of this file are subject to the Mozilla Public License
  21.  * Version 1.1 (the "License"); you may not use this file except in
  22.  * compliance with the License. You may obtain a copy of the License at
  23.  * http://www.mozilla.org/MPL/
  24.  *
  25.  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
  26.  * OF ANY KIND, either express or implied. See the LGPL or the MPL for
  27.  * the specific language governing rights and limitations.
  28.  *
  29.  * The Original Code is the cairo graphics library.
  30.  *
  31.  * The Initial Developer of the Original Code is Mozilla Foundation.
  32.  *
  33.  * Contributor(s):
  34.  *      Vladimir Vukicevic <vladimir@mozilla.com>
  35.  */
  36.  
  37. #include "cairoint.h"
  38.  
  39. #include <dlfcn.h>
  40.  
  41. #include "cairo-image-surface-private.h"
  42. #include "cairo-quartz.h"
  43. #include "cairo-quartz-private.h"
  44.  
  45. #include "cairo-error-private.h"
  46.  
  47. /**
  48.  * SECTION:cairo-quartz-fonts
  49.  * @Title: Quartz (CGFont) Fonts
  50.  * @Short_Description: Font support via CGFont on OS X
  51.  * @See_Also: #cairo_font_face_t
  52.  *
  53.  * The Quartz font backend is primarily used to render text on Apple
  54.  * MacOS X systems.  The CGFont API is used for the internal
  55.  * implementation of the font backend methods.
  56.  **/
  57.  
  58. /**
  59.  * CAIRO_HAS_QUARTZ_FONT:
  60.  *
  61.  * Defined if the Quartz font backend is available.
  62.  * This macro can be used to conditionally compile backend-specific code.
  63.  *
  64.  * Since: 1.6
  65.  **/
  66.  
  67. static CFDataRef (*CGFontCopyTableForTagPtr) (CGFontRef font, uint32_t tag) = NULL;
  68.  
  69. /* CreateWithFontName exists in 10.5, but not in 10.4; CreateWithName isn't public in 10.4 */
  70. static CGFontRef (*CGFontCreateWithFontNamePtr) (CFStringRef) = NULL;
  71. static CGFontRef (*CGFontCreateWithNamePtr) (const char *) = NULL;
  72.  
  73. /* These aren't public before 10.5, and some have different names in 10.4 */
  74. static int (*CGFontGetUnitsPerEmPtr) (CGFontRef) = NULL;
  75. static bool (*CGFontGetGlyphAdvancesPtr) (CGFontRef, const CGGlyph[], size_t, int[]) = NULL;
  76. static bool (*CGFontGetGlyphBBoxesPtr) (CGFontRef, const CGGlyph[], size_t, CGRect[]) = NULL;
  77. static CGRect (*CGFontGetFontBBoxPtr) (CGFontRef) = NULL;
  78.  
  79. /* Not public, but present */
  80. static void (*CGFontGetGlyphsForUnicharsPtr) (CGFontRef, const UniChar[], const CGGlyph[], size_t) = NULL;
  81. static void (*CGContextSetAllowsFontSmoothingPtr) (CGContextRef, bool) = NULL;
  82. static bool (*CGContextGetAllowsFontSmoothingPtr) (CGContextRef) = NULL;
  83.  
  84. /* Not public in the least bit */
  85. static CGPathRef (*CGFontGetGlyphPathPtr) (CGFontRef fontRef, CGAffineTransform *textTransform, int unknown, CGGlyph glyph) = NULL;
  86.  
  87. /* CGFontGetHMetrics isn't public, but the other functions are public/present in 10.5 */
  88. typedef struct {
  89.     int ascent;
  90.     int descent;
  91.     int leading;
  92. } quartz_CGFontMetrics;
  93. static quartz_CGFontMetrics* (*CGFontGetHMetricsPtr) (CGFontRef fontRef) = NULL;
  94. static int (*CGFontGetAscentPtr) (CGFontRef fontRef) = NULL;
  95. static int (*CGFontGetDescentPtr) (CGFontRef fontRef) = NULL;
  96. static int (*CGFontGetLeadingPtr) (CGFontRef fontRef) = NULL;
  97.  
  98. /* Not public anymore in 64-bits nor in 10.7 */
  99. static ATSFontRef (*FMGetATSFontRefFromFontPtr) (FMFont iFont) = NULL;
  100.  
  101. static cairo_bool_t _cairo_quartz_font_symbol_lookup_done = FALSE;
  102. static cairo_bool_t _cairo_quartz_font_symbols_present = FALSE;
  103.  
  104. static void
  105. quartz_font_ensure_symbols(void)
  106. {
  107.     if (_cairo_quartz_font_symbol_lookup_done)
  108.         return;
  109.  
  110.     CGFontCopyTableForTagPtr = dlsym(RTLD_DEFAULT, "CGFontCopyTableForTag");
  111.  
  112.     /* Look for the 10.5 versions first */
  113.     CGFontGetGlyphBBoxesPtr = dlsym(RTLD_DEFAULT, "CGFontGetGlyphBBoxes");
  114.     if (!CGFontGetGlyphBBoxesPtr)
  115.         CGFontGetGlyphBBoxesPtr = dlsym(RTLD_DEFAULT, "CGFontGetGlyphBoundingBoxes");
  116.  
  117.     CGFontGetGlyphsForUnicharsPtr = dlsym(RTLD_DEFAULT, "CGFontGetGlyphsForUnichars");
  118.     if (!CGFontGetGlyphsForUnicharsPtr)
  119.         CGFontGetGlyphsForUnicharsPtr = dlsym(RTLD_DEFAULT, "CGFontGetGlyphsForUnicodes");
  120.  
  121.     CGFontGetFontBBoxPtr = dlsym(RTLD_DEFAULT, "CGFontGetFontBBox");
  122.  
  123.     /* We just need one of these two */
  124.     CGFontCreateWithFontNamePtr = dlsym(RTLD_DEFAULT, "CGFontCreateWithFontName");
  125.     CGFontCreateWithNamePtr = dlsym(RTLD_DEFAULT, "CGFontCreateWithName");
  126.  
  127.     /* These have the same name in 10.4 and 10.5 */
  128.     CGFontGetUnitsPerEmPtr = dlsym(RTLD_DEFAULT, "CGFontGetUnitsPerEm");
  129.     CGFontGetGlyphAdvancesPtr = dlsym(RTLD_DEFAULT, "CGFontGetGlyphAdvances");
  130.     CGFontGetGlyphPathPtr = dlsym(RTLD_DEFAULT, "CGFontGetGlyphPath");
  131.  
  132.     CGFontGetHMetricsPtr = dlsym(RTLD_DEFAULT, "CGFontGetHMetrics");
  133.     CGFontGetAscentPtr = dlsym(RTLD_DEFAULT, "CGFontGetAscent");
  134.     CGFontGetDescentPtr = dlsym(RTLD_DEFAULT, "CGFontGetDescent");
  135.     CGFontGetLeadingPtr = dlsym(RTLD_DEFAULT, "CGFontGetLeading");
  136.  
  137.     CGContextGetAllowsFontSmoothingPtr = dlsym(RTLD_DEFAULT, "CGContextGetAllowsFontSmoothing");
  138.     CGContextSetAllowsFontSmoothingPtr = dlsym(RTLD_DEFAULT, "CGContextSetAllowsFontSmoothing");
  139.  
  140.     FMGetATSFontRefFromFontPtr = dlsym(RTLD_DEFAULT, "FMGetATSFontRefFromFont");
  141.  
  142.     if ((CGFontCreateWithFontNamePtr || CGFontCreateWithNamePtr) &&
  143.         CGFontGetGlyphBBoxesPtr &&
  144.         CGFontGetGlyphsForUnicharsPtr &&
  145.         CGFontGetUnitsPerEmPtr &&
  146.         CGFontGetGlyphAdvancesPtr &&
  147.         CGFontGetGlyphPathPtr &&
  148.         (CGFontGetHMetricsPtr || (CGFontGetAscentPtr && CGFontGetDescentPtr && CGFontGetLeadingPtr)))
  149.         _cairo_quartz_font_symbols_present = TRUE;
  150.  
  151.     _cairo_quartz_font_symbol_lookup_done = TRUE;
  152. }
  153.  
  154. typedef struct _cairo_quartz_font_face cairo_quartz_font_face_t;
  155. typedef struct _cairo_quartz_scaled_font cairo_quartz_scaled_font_t;
  156.  
  157. struct _cairo_quartz_scaled_font {
  158.     cairo_scaled_font_t base;
  159. };
  160.  
  161. struct _cairo_quartz_font_face {
  162.     cairo_font_face_t base;
  163.  
  164.     CGFontRef cgFont;
  165. };
  166.  
  167. /*
  168.  * font face backend
  169.  */
  170.  
  171. static cairo_status_t
  172. _cairo_quartz_font_face_create_for_toy (cairo_toy_font_face_t   *toy_face,
  173.                                         cairo_font_face_t      **font_face)
  174. {
  175.     const char *family;
  176.     char *full_name;
  177.     CFStringRef cgFontName = NULL;
  178.     CGFontRef cgFont = NULL;
  179.     int loop;
  180.  
  181.     quartz_font_ensure_symbols();
  182.     if (! _cairo_quartz_font_symbols_present)
  183.         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
  184.  
  185.     family = toy_face->family;
  186.     full_name = malloc (strlen (family) + 64); // give us a bit of room to tack on Bold, Oblique, etc.
  187.     /* handle CSS-ish faces */
  188.     if (!strcmp(family, "serif") || !strcmp(family, "Times Roman"))
  189.         family = "Times";
  190.     else if (!strcmp(family, "sans-serif") || !strcmp(family, "sans"))
  191.         family = "Helvetica";
  192.     else if (!strcmp(family, "cursive"))
  193.         family = "Apple Chancery";
  194.     else if (!strcmp(family, "fantasy"))
  195.         family = "Papyrus";
  196.     else if (!strcmp(family, "monospace") || !strcmp(family, "mono"))
  197.         family = "Courier";
  198.  
  199.     /* Try to build up the full name, e.g. "Helvetica Bold Oblique" first,
  200.      * then drop the bold, then drop the slant, then drop both.. finally
  201.      * just use "Helvetica".  And if Helvetica doesn't exist, give up.
  202.      */
  203.     for (loop = 0; loop < 5; loop++) {
  204.         if (loop == 4)
  205.             family = "Helvetica";
  206.  
  207.         strcpy (full_name, family);
  208.  
  209.         if (loop < 3 && (loop & 1) == 0) {
  210.             if (toy_face->weight == CAIRO_FONT_WEIGHT_BOLD)
  211.                 strcat (full_name, " Bold");
  212.         }
  213.  
  214.         if (loop < 3 && (loop & 2) == 0) {
  215.             if (toy_face->slant == CAIRO_FONT_SLANT_ITALIC)
  216.                 strcat (full_name, " Italic");
  217.             else if (toy_face->slant == CAIRO_FONT_SLANT_OBLIQUE)
  218.                 strcat (full_name, " Oblique");
  219.         }
  220.  
  221.         if (CGFontCreateWithFontNamePtr) {
  222.             cgFontName = CFStringCreateWithCString (NULL, full_name, kCFStringEncodingASCII);
  223.             cgFont = CGFontCreateWithFontNamePtr (cgFontName);
  224.             CFRelease (cgFontName);
  225.         } else {
  226.             cgFont = CGFontCreateWithNamePtr (full_name);
  227.         }
  228.  
  229.         if (cgFont)
  230.             break;
  231.     }
  232.  
  233.     if (!cgFont) {
  234.         /* Give up */
  235.         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
  236.     }
  237.  
  238.     *font_face = cairo_quartz_font_face_create_for_cgfont (cgFont);
  239.     CGFontRelease (cgFont);
  240.  
  241.     return CAIRO_STATUS_SUCCESS;
  242. }
  243.  
  244. static void
  245. _cairo_quartz_font_face_destroy (void *abstract_face)
  246. {
  247.     cairo_quartz_font_face_t *font_face = (cairo_quartz_font_face_t*) abstract_face;
  248.  
  249.     CGFontRelease (font_face->cgFont);
  250. }
  251.  
  252. static const cairo_scaled_font_backend_t _cairo_quartz_scaled_font_backend;
  253.  
  254. static cairo_status_t
  255. _cairo_quartz_font_face_scaled_font_create (void *abstract_face,
  256.                                             const cairo_matrix_t *font_matrix,
  257.                                             const cairo_matrix_t *ctm,
  258.                                             const cairo_font_options_t *options,
  259.                                             cairo_scaled_font_t **font_out)
  260. {
  261.     cairo_quartz_font_face_t *font_face = abstract_face;
  262.     cairo_quartz_scaled_font_t *font = NULL;
  263.     cairo_status_t status;
  264.     cairo_font_extents_t fs_metrics;
  265.     double ems;
  266.     CGRect bbox;
  267.  
  268.     quartz_font_ensure_symbols();
  269.     if (!_cairo_quartz_font_symbols_present)
  270.         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
  271.  
  272.     font = malloc(sizeof(cairo_quartz_scaled_font_t));
  273.     if (font == NULL)
  274.         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
  275.  
  276.     memset (font, 0, sizeof(cairo_quartz_scaled_font_t));
  277.  
  278.     status = _cairo_scaled_font_init (&font->base,
  279.                                       &font_face->base, font_matrix, ctm, options,
  280.                                       &_cairo_quartz_scaled_font_backend);
  281.     if (status)
  282.         goto FINISH;
  283.  
  284.     ems = CGFontGetUnitsPerEmPtr (font_face->cgFont);
  285.  
  286.     /* initialize metrics */
  287.     if (CGFontGetFontBBoxPtr && CGFontGetAscentPtr) {
  288.         fs_metrics.ascent = (CGFontGetAscentPtr (font_face->cgFont) / ems);
  289.         fs_metrics.descent = - (CGFontGetDescentPtr (font_face->cgFont) / ems);
  290.         fs_metrics.height = fs_metrics.ascent + fs_metrics.descent +
  291.             (CGFontGetLeadingPtr (font_face->cgFont) / ems);
  292.  
  293.         bbox = CGFontGetFontBBoxPtr (font_face->cgFont);
  294.         fs_metrics.max_x_advance = CGRectGetMaxX(bbox) / ems;
  295.         fs_metrics.max_y_advance = 0.0;
  296.     } else {
  297.         CGGlyph wGlyph;
  298.         UniChar u;
  299.  
  300.         quartz_CGFontMetrics *m;
  301.         m = CGFontGetHMetricsPtr (font_face->cgFont);
  302.  
  303.         /* On OX 10.4, GetHMetricsPtr sometimes returns NULL for unknown reasons */
  304.         if (!m) {
  305.             status = _cairo_error(CAIRO_STATUS_NULL_POINTER);
  306.             goto FINISH;
  307.         }
  308.  
  309.         fs_metrics.ascent = (m->ascent / ems);
  310.         fs_metrics.descent = - (m->descent / ems);
  311.         fs_metrics.height = fs_metrics.ascent + fs_metrics.descent + (m->leading / ems);
  312.  
  313.         /* We kind of have to guess here; W's big, right? */
  314.         u = (UniChar) 'W';
  315.         CGFontGetGlyphsForUnicharsPtr (font_face->cgFont, &u, &wGlyph, 1);
  316.         if (wGlyph && CGFontGetGlyphBBoxesPtr (font_face->cgFont, &wGlyph, 1, &bbox)) {
  317.             fs_metrics.max_x_advance = CGRectGetMaxX(bbox) / ems;
  318.             fs_metrics.max_y_advance = 0.0;
  319.         } else {
  320.             fs_metrics.max_x_advance = 0.0;
  321.             fs_metrics.max_y_advance = 0.0;
  322.         }
  323.     }
  324.  
  325.     status = _cairo_scaled_font_set_metrics (&font->base, &fs_metrics);
  326.  
  327. FINISH:
  328.     if (status != CAIRO_STATUS_SUCCESS) {
  329.         free (font);
  330.     } else {
  331.         *font_out = (cairo_scaled_font_t*) font;
  332.     }
  333.  
  334.     return status;
  335. }
  336.  
  337. const cairo_font_face_backend_t _cairo_quartz_font_face_backend = {
  338.     CAIRO_FONT_TYPE_QUARTZ,
  339.     _cairo_quartz_font_face_create_for_toy,
  340.     _cairo_quartz_font_face_destroy,
  341.     _cairo_quartz_font_face_scaled_font_create
  342. };
  343.  
  344. /**
  345.  * cairo_quartz_font_face_create_for_cgfont:
  346.  * @font: a #CGFontRef obtained through a method external to cairo.
  347.  *
  348.  * Creates a new font for the Quartz font backend based on a
  349.  * #CGFontRef.  This font can then be used with
  350.  * cairo_set_font_face() or cairo_scaled_font_create().
  351.  *
  352.  * Return value: a newly created #cairo_font_face_t. Free with
  353.  *  cairo_font_face_destroy() when you are done using it.
  354.  *
  355.  * Since: 1.6
  356.  **/
  357. cairo_font_face_t *
  358. cairo_quartz_font_face_create_for_cgfont (CGFontRef font)
  359. {
  360.     cairo_quartz_font_face_t *font_face;
  361.  
  362.     quartz_font_ensure_symbols();
  363.  
  364.     font_face = malloc (sizeof (cairo_quartz_font_face_t));
  365.     if (!font_face) {
  366.         cairo_status_t ignore_status;
  367.         ignore_status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
  368.         return (cairo_font_face_t *)&_cairo_font_face_nil;
  369.     }
  370.  
  371.     font_face->cgFont = CGFontRetain (font);
  372.  
  373.     _cairo_font_face_init (&font_face->base, &_cairo_quartz_font_face_backend);
  374.  
  375.     return &font_face->base;
  376. }
  377.  
  378. /*
  379.  * scaled font backend
  380.  */
  381.  
  382. static cairo_quartz_font_face_t *
  383. _cairo_quartz_scaled_to_face (void *abstract_font)
  384. {
  385.     cairo_quartz_scaled_font_t *sfont = (cairo_quartz_scaled_font_t*) abstract_font;
  386.     cairo_font_face_t *font_face = sfont->base.font_face;
  387.     assert (font_face->backend->type == CAIRO_FONT_TYPE_QUARTZ);
  388.     return (cairo_quartz_font_face_t*) font_face;
  389. }
  390.  
  391. static void
  392. _cairo_quartz_scaled_font_fini(void *abstract_font)
  393. {
  394. }
  395.  
  396. #define INVALID_GLYPH 0x00
  397.  
  398. static inline CGGlyph
  399. _cairo_quartz_scaled_glyph_index (cairo_scaled_glyph_t *scaled_glyph) {
  400.     unsigned long index = _cairo_scaled_glyph_index (scaled_glyph);
  401.     if (index > 0xffff)
  402.         return INVALID_GLYPH;
  403.     return (CGGlyph) index;
  404. }
  405.  
  406. static cairo_int_status_t
  407. _cairo_quartz_init_glyph_metrics (cairo_quartz_scaled_font_t *font,
  408.                                   cairo_scaled_glyph_t *scaled_glyph)
  409. {
  410.     cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
  411.  
  412.     cairo_quartz_font_face_t *font_face = _cairo_quartz_scaled_to_face(font);
  413.     cairo_text_extents_t extents = {0, 0, 0, 0, 0, 0};
  414.     CGGlyph glyph = _cairo_quartz_scaled_glyph_index (scaled_glyph);
  415.     int advance;
  416.     CGRect bbox;
  417.     double emscale = CGFontGetUnitsPerEmPtr (font_face->cgFont);
  418.     double xmin, ymin, xmax, ymax;
  419.  
  420.     if (glyph == INVALID_GLYPH)
  421.         goto FAIL;
  422.  
  423.     if (!CGFontGetGlyphAdvancesPtr (font_face->cgFont, &glyph, 1, &advance) ||
  424.         !CGFontGetGlyphBBoxesPtr (font_face->cgFont, &glyph, 1, &bbox))
  425.         goto FAIL;
  426.  
  427.     /* broken fonts like Al Bayan return incorrect bounds for some null characters,
  428.        see https://bugzilla.mozilla.org/show_bug.cgi?id=534260 */
  429.     if (unlikely (bbox.origin.x == -32767 &&
  430.                   bbox.origin.y == -32767 &&
  431.                   bbox.size.width == 65534 &&
  432.                   bbox.size.height == 65534)) {
  433.         bbox.origin.x = bbox.origin.y = 0;
  434.         bbox.size.width = bbox.size.height = 0;
  435.     }
  436.  
  437.     bbox = CGRectMake (bbox.origin.x / emscale,
  438.                        bbox.origin.y / emscale,
  439.                        bbox.size.width / emscale,
  440.                        bbox.size.height / emscale);
  441.  
  442.     /* Should we want to always integer-align glyph extents, we can do so in this way */
  443. #if 0
  444.     {
  445.         CGAffineTransform textMatrix;
  446.         textMatrix = CGAffineTransformMake (font->base.scale.xx,
  447.                                             -font->base.scale.yx,
  448.                                             -font->base.scale.xy,
  449.                                             font->base.scale.yy,
  450.                                             0.0f, 0.0f);
  451.  
  452.         bbox = CGRectApplyAffineTransform (bbox, textMatrix);
  453.         bbox = CGRectIntegral (bbox);
  454.         bbox = CGRectApplyAffineTransform (bbox, CGAffineTransformInvert (textMatrix));
  455.     }
  456. #endif
  457.  
  458. #if 0
  459.     fprintf (stderr, "[0x%04x] bbox: %f %f %f %f\n", glyph,
  460.              bbox.origin.x / emscale, bbox.origin.y / emscale,
  461.              bbox.size.width / emscale, bbox.size.height / emscale);
  462. #endif
  463.  
  464.     xmin = CGRectGetMinX(bbox);
  465.     ymin = CGRectGetMinY(bbox);
  466.     xmax = CGRectGetMaxX(bbox);
  467.     ymax = CGRectGetMaxY(bbox);
  468.  
  469.     extents.x_bearing = xmin;
  470.     extents.y_bearing = - ymax;
  471.     extents.width = xmax - xmin;
  472.     extents.height = ymax - ymin;
  473.  
  474.     extents.x_advance = (double) advance / emscale;
  475.     extents.y_advance = 0.0;
  476.  
  477. #if 0
  478.     fprintf (stderr, "[0x%04x] extents: bearings: %f %f dim: %f %f adv: %f\n\n", glyph,
  479.              extents.x_bearing, extents.y_bearing, extents.width, extents.height, extents.x_advance);
  480. #endif
  481.  
  482.   FAIL:
  483.     _cairo_scaled_glyph_set_metrics (scaled_glyph,
  484.                                      &font->base,
  485.                                      &extents);
  486.  
  487.     return status;
  488. }
  489.  
  490. static void
  491. _cairo_quartz_path_apply_func (void *info, const CGPathElement *el)
  492. {
  493.     cairo_path_fixed_t *path = (cairo_path_fixed_t *) info;
  494.     cairo_status_t status;
  495.  
  496.     switch (el->type) {
  497.         case kCGPathElementMoveToPoint:
  498.             status = _cairo_path_fixed_move_to (path,
  499.                                                 _cairo_fixed_from_double(el->points[0].x),
  500.                                                 _cairo_fixed_from_double(el->points[0].y));
  501.             assert(!status);
  502.             break;
  503.         case kCGPathElementAddLineToPoint:
  504.             status = _cairo_path_fixed_line_to (path,
  505.                                                 _cairo_fixed_from_double(el->points[0].x),
  506.                                                 _cairo_fixed_from_double(el->points[0].y));
  507.             assert(!status);
  508.             break;
  509.         case kCGPathElementAddQuadCurveToPoint: {
  510.             cairo_fixed_t fx, fy;
  511.             double x, y;
  512.             if (!_cairo_path_fixed_get_current_point (path, &fx, &fy))
  513.                 fx = fy = 0;
  514.             x = _cairo_fixed_to_double (fx);
  515.             y = _cairo_fixed_to_double (fy);
  516.  
  517.             status = _cairo_path_fixed_curve_to (path,
  518.                                                  _cairo_fixed_from_double((x + el->points[0].x * 2.0) / 3.0),
  519.                                                  _cairo_fixed_from_double((y + el->points[0].y * 2.0) / 3.0),
  520.                                                  _cairo_fixed_from_double((el->points[0].x * 2.0 + el->points[1].x) / 3.0),
  521.                                                  _cairo_fixed_from_double((el->points[0].y * 2.0 + el->points[1].y) / 3.0),
  522.                                                  _cairo_fixed_from_double(el->points[1].x),
  523.                                                  _cairo_fixed_from_double(el->points[1].y));
  524.         }
  525.             assert(!status);
  526.             break;
  527.         case kCGPathElementAddCurveToPoint:
  528.             status = _cairo_path_fixed_curve_to (path,
  529.                                                  _cairo_fixed_from_double(el->points[0].x),
  530.                                                  _cairo_fixed_from_double(el->points[0].y),
  531.                                                  _cairo_fixed_from_double(el->points[1].x),
  532.                                                  _cairo_fixed_from_double(el->points[1].y),
  533.                                                  _cairo_fixed_from_double(el->points[2].x),
  534.                                                  _cairo_fixed_from_double(el->points[2].y));
  535.             assert(!status);       
  536.             break;
  537.         case kCGPathElementCloseSubpath:
  538.             status = _cairo_path_fixed_close_path (path);
  539.             assert(!status);
  540.             break;
  541.     }
  542. }
  543.  
  544. static cairo_int_status_t
  545. _cairo_quartz_init_glyph_path (cairo_quartz_scaled_font_t *font,
  546.                                cairo_scaled_glyph_t *scaled_glyph)
  547. {
  548.     cairo_quartz_font_face_t *font_face = _cairo_quartz_scaled_to_face(font);
  549.     CGGlyph glyph = _cairo_quartz_scaled_glyph_index (scaled_glyph);
  550.     CGAffineTransform textMatrix;
  551.     CGPathRef glyphPath;
  552.     cairo_path_fixed_t *path;
  553.  
  554.     if (glyph == INVALID_GLYPH) {
  555.         _cairo_scaled_glyph_set_path (scaled_glyph, &font->base, _cairo_path_fixed_create());
  556.         return CAIRO_STATUS_SUCCESS;
  557.     }
  558.  
  559.     /* scale(1,-1) * font->base.scale */
  560.     textMatrix = CGAffineTransformMake (font->base.scale.xx,
  561.                                         font->base.scale.yx,
  562.                                         -font->base.scale.xy,
  563.                                         -font->base.scale.yy,
  564.                                         0, 0);
  565.  
  566.     glyphPath = CGFontGetGlyphPathPtr (font_face->cgFont, &textMatrix, 0, glyph);
  567.     if (!glyphPath)
  568.         return CAIRO_INT_STATUS_UNSUPPORTED;
  569.  
  570.     path = _cairo_path_fixed_create ();
  571.     if (!path) {
  572.         CGPathRelease (glyphPath);
  573.         return _cairo_error(CAIRO_STATUS_NO_MEMORY);
  574.     }
  575.  
  576.     CGPathApply (glyphPath, path, _cairo_quartz_path_apply_func);
  577.  
  578.     CGPathRelease (glyphPath);
  579.  
  580.     _cairo_scaled_glyph_set_path (scaled_glyph, &font->base, path);
  581.  
  582.     return CAIRO_STATUS_SUCCESS;
  583. }
  584.  
  585. static cairo_int_status_t
  586. _cairo_quartz_init_glyph_surface (cairo_quartz_scaled_font_t *font,
  587.                                   cairo_scaled_glyph_t *scaled_glyph)
  588. {
  589.     cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
  590.  
  591.     cairo_quartz_font_face_t *font_face = _cairo_quartz_scaled_to_face(font);
  592.  
  593.     cairo_image_surface_t *surface = NULL;
  594.  
  595.     CGGlyph glyph = _cairo_quartz_scaled_glyph_index (scaled_glyph);
  596.  
  597.     int advance;
  598.     CGRect bbox;
  599.     double width, height;
  600.     double emscale = CGFontGetUnitsPerEmPtr (font_face->cgFont);
  601.  
  602.     CGContextRef cgContext = NULL;
  603.     CGAffineTransform textMatrix;
  604.     CGRect glyphRect, glyphRectInt;
  605.     CGPoint glyphOrigin;
  606.  
  607.     //fprintf (stderr, "scaled_glyph: %p surface: %p\n", scaled_glyph, scaled_glyph->surface);
  608.  
  609.     /* Create blank 2x2 image if we don't have this character.
  610.      * Maybe we should draw a better missing-glyph slug or something,
  611.      * but this is ok for now.
  612.      */
  613.     if (glyph == INVALID_GLYPH) {
  614.         surface = (cairo_image_surface_t*) cairo_image_surface_create (CAIRO_FORMAT_A8, 2, 2);
  615.         status = cairo_surface_status ((cairo_surface_t *) surface);
  616.         if (status)
  617.             return status;
  618.  
  619.         _cairo_scaled_glyph_set_surface (scaled_glyph,
  620.                                          &font->base,
  621.                                          surface);
  622.         return CAIRO_STATUS_SUCCESS;
  623.     }
  624.  
  625.     if (!CGFontGetGlyphAdvancesPtr (font_face->cgFont, &glyph, 1, &advance) ||
  626.         !CGFontGetGlyphBBoxesPtr (font_face->cgFont, &glyph, 1, &bbox))
  627.     {
  628.         return CAIRO_INT_STATUS_UNSUPPORTED;
  629.     }
  630.  
  631.     /* scale(1,-1) * font->base.scale * scale(1,-1) */
  632.     textMatrix = CGAffineTransformMake (font->base.scale.xx,
  633.                                         -font->base.scale.yx,
  634.                                         -font->base.scale.xy,
  635.                                         font->base.scale.yy,
  636.                                         0, -0);
  637.     glyphRect = CGRectMake (bbox.origin.x / emscale,
  638.                             bbox.origin.y / emscale,
  639.                             bbox.size.width / emscale,
  640.                             bbox.size.height / emscale);
  641.  
  642.     glyphRect = CGRectApplyAffineTransform (glyphRect, textMatrix);
  643.  
  644.     /* Round the rectangle outwards, so that we don't have to deal
  645.      * with non-integer-pixel origins or dimensions.
  646.      */
  647.     glyphRectInt = CGRectIntegral (glyphRect);
  648.  
  649. #if 0
  650.     fprintf (stderr, "glyphRect[o]: %f %f %f %f\n",
  651.              glyphRect.origin.x, glyphRect.origin.y, glyphRect.size.width, glyphRect.size.height);
  652.     fprintf (stderr, "glyphRectInt: %f %f %f %f\n",
  653.              glyphRectInt.origin.x, glyphRectInt.origin.y, glyphRectInt.size.width, glyphRectInt.size.height);
  654. #endif
  655.  
  656.     glyphOrigin = glyphRectInt.origin;
  657.  
  658.     //textMatrix = CGAffineTransformConcat (textMatrix, CGAffineTransformInvert (ctm));
  659.  
  660.     width = glyphRectInt.size.width;
  661.     height = glyphRectInt.size.height;
  662.  
  663.     //fprintf (stderr, "glyphRect[n]: %f %f %f %f\n", glyphRect.origin.x, glyphRect.origin.y, glyphRect.size.width, glyphRect.size.height);
  664.  
  665.     surface = (cairo_image_surface_t*) cairo_image_surface_create (CAIRO_FORMAT_A8, width, height);
  666.     if (surface->base.status)
  667.         return surface->base.status;
  668.  
  669.     if (surface->width != 0 && surface->height != 0) {
  670.         cgContext = CGBitmapContextCreate (surface->data,
  671.                                            surface->width,
  672.                                            surface->height,
  673.                                            8,
  674.                                            surface->stride,
  675.                                            NULL,
  676.                                            kCGImageAlphaOnly);
  677.  
  678.         if (cgContext == NULL) {
  679.             cairo_surface_destroy (&surface->base);
  680.             return _cairo_error (CAIRO_STATUS_NO_MEMORY);
  681.         }
  682.  
  683.         CGContextSetFont (cgContext, font_face->cgFont);
  684.         CGContextSetFontSize (cgContext, 1.0);
  685.         CGContextSetTextMatrix (cgContext, textMatrix);
  686.  
  687.         switch (font->base.options.antialias) {
  688.         case CAIRO_ANTIALIAS_SUBPIXEL:
  689.         case CAIRO_ANTIALIAS_BEST:
  690.             CGContextSetShouldAntialias (cgContext, TRUE);
  691.             CGContextSetShouldSmoothFonts (cgContext, TRUE);
  692.             if (CGContextSetAllowsFontSmoothingPtr &&
  693.                 !CGContextGetAllowsFontSmoothingPtr (cgContext))
  694.                 CGContextSetAllowsFontSmoothingPtr (cgContext, TRUE);
  695.             break;
  696.         case CAIRO_ANTIALIAS_NONE:
  697.             CGContextSetShouldAntialias (cgContext, FALSE);
  698.             break;
  699.         case CAIRO_ANTIALIAS_GRAY:
  700.         case CAIRO_ANTIALIAS_GOOD:
  701.         case CAIRO_ANTIALIAS_FAST:
  702.             CGContextSetShouldAntialias (cgContext, TRUE);
  703.             CGContextSetShouldSmoothFonts (cgContext, FALSE);
  704.             break;
  705.         case CAIRO_ANTIALIAS_DEFAULT:
  706.         default:
  707.             /* Don't do anything */
  708.             break;
  709.         }
  710.  
  711.         CGContextSetAlpha (cgContext, 1.0);
  712.         CGContextShowGlyphsAtPoint (cgContext, - glyphOrigin.x, - glyphOrigin.y, &glyph, 1);
  713.  
  714.         CGContextRelease (cgContext);
  715.     }
  716.  
  717.     cairo_surface_set_device_offset (&surface->base,
  718.                                      - glyphOrigin.x,
  719.                                      height + glyphOrigin.y);
  720.  
  721.     _cairo_scaled_glyph_set_surface (scaled_glyph, &font->base, surface);
  722.  
  723.     return status;
  724. }
  725.  
  726. static cairo_int_status_t
  727. _cairo_quartz_scaled_glyph_init (void *abstract_font,
  728.                                  cairo_scaled_glyph_t *scaled_glyph,
  729.                                  cairo_scaled_glyph_info_t info)
  730. {
  731.     cairo_quartz_scaled_font_t *font = (cairo_quartz_scaled_font_t *) abstract_font;
  732.     cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
  733.  
  734.     if (!status && (info & CAIRO_SCALED_GLYPH_INFO_METRICS))
  735.         status = _cairo_quartz_init_glyph_metrics (font, scaled_glyph);
  736.  
  737.     if (!status && (info & CAIRO_SCALED_GLYPH_INFO_PATH))
  738.         status = _cairo_quartz_init_glyph_path (font, scaled_glyph);
  739.  
  740.     if (!status && (info & CAIRO_SCALED_GLYPH_INFO_SURFACE))
  741.         status = _cairo_quartz_init_glyph_surface (font, scaled_glyph);
  742.  
  743.     return status;
  744. }
  745.  
  746. static unsigned long
  747. _cairo_quartz_ucs4_to_index (void *abstract_font,
  748.                              uint32_t ucs4)
  749. {
  750.     cairo_quartz_scaled_font_t *font = (cairo_quartz_scaled_font_t*) abstract_font;
  751.     cairo_quartz_font_face_t *ffont = _cairo_quartz_scaled_to_face(font);
  752.     UniChar u = (UniChar) ucs4;
  753.     CGGlyph glyph;
  754.  
  755.     CGFontGetGlyphsForUnicharsPtr (ffont->cgFont, &u, &glyph, 1);
  756.  
  757.     return glyph;
  758. }
  759.  
  760. static cairo_int_status_t
  761. _cairo_quartz_load_truetype_table (void             *abstract_font,
  762.                                    unsigned long     tag,
  763.                                    long              offset,
  764.                                    unsigned char    *buffer,
  765.                                    unsigned long    *length)
  766. {
  767.     cairo_quartz_font_face_t *font_face = _cairo_quartz_scaled_to_face (abstract_font);
  768.     CFDataRef data = NULL;
  769.  
  770.     if (likely (CGFontCopyTableForTagPtr))
  771.         data = CGFontCopyTableForTagPtr (font_face->cgFont, tag);
  772.  
  773.     if (!data)
  774.         return CAIRO_INT_STATUS_UNSUPPORTED;
  775.  
  776.     if (buffer == NULL) {
  777.         *length = CFDataGetLength (data);
  778.         CFRelease (data);
  779.         return CAIRO_STATUS_SUCCESS;
  780.     }
  781.  
  782.     if (CFDataGetLength (data) < offset + (long) *length) {
  783.         CFRelease (data);
  784.         return CAIRO_INT_STATUS_UNSUPPORTED;
  785.     }
  786.  
  787.     CFDataGetBytes (data, CFRangeMake (offset, *length), buffer);
  788.     CFRelease (data);
  789.  
  790.     return CAIRO_STATUS_SUCCESS;
  791. }
  792.  
  793. static const cairo_scaled_font_backend_t _cairo_quartz_scaled_font_backend = {
  794.     CAIRO_FONT_TYPE_QUARTZ,
  795.     _cairo_quartz_scaled_font_fini,
  796.     _cairo_quartz_scaled_glyph_init,
  797.     NULL, /* text_to_glyphs */
  798.     _cairo_quartz_ucs4_to_index,
  799.     _cairo_quartz_load_truetype_table,
  800.     NULL, /* map_glyphs_to_unicode */
  801. };
  802.  
  803. /*
  804.  * private methods that the quartz surface uses
  805.  */
  806.  
  807. CGFontRef
  808. _cairo_quartz_scaled_font_get_cg_font_ref (cairo_scaled_font_t *abstract_font)
  809. {
  810.     cairo_quartz_font_face_t *ffont = _cairo_quartz_scaled_to_face(abstract_font);
  811.  
  812.     return ffont->cgFont;
  813. }
  814.  
  815. /*
  816.  * compat with old ATSUI backend
  817.  */
  818.  
  819. /**
  820.  * cairo_quartz_font_face_create_for_atsu_font_id:
  821.  * @font_id: an ATSUFontID for the font.
  822.  *
  823.  * Creates a new font for the Quartz font backend based on an
  824.  * #ATSUFontID. This font can then be used with
  825.  * cairo_set_font_face() or cairo_scaled_font_create().
  826.  *
  827.  * Return value: a newly created #cairo_font_face_t. Free with
  828.  *  cairo_font_face_destroy() when you are done using it.
  829.  *
  830.  * Since: 1.6
  831.  **/
  832. cairo_font_face_t *
  833. cairo_quartz_font_face_create_for_atsu_font_id (ATSUFontID font_id)
  834. {
  835.     quartz_font_ensure_symbols();
  836.  
  837.     if (FMGetATSFontRefFromFontPtr != NULL) {
  838.         ATSFontRef atsFont = FMGetATSFontRefFromFontPtr (font_id);
  839.         CGFontRef cgFont = CGFontCreateWithPlatformFont (&atsFont);
  840.         cairo_font_face_t *ff;
  841.  
  842.         ff = cairo_quartz_font_face_create_for_cgfont (cgFont);
  843.  
  844.         CGFontRelease (cgFont);
  845.  
  846.         return ff;
  847.     } else {
  848.         _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
  849.         return (cairo_font_face_t *)&_cairo_font_face_nil;
  850.     }
  851. }
  852.  
  853. /* This is the old name for the above function, exported for compat purposes */
  854. cairo_font_face_t *cairo_atsui_font_face_create_for_atsu_font_id (ATSUFontID font_id);
  855.  
  856. cairo_font_face_t *
  857. cairo_atsui_font_face_create_for_atsu_font_id (ATSUFontID font_id)
  858. {
  859.     return cairo_quartz_font_face_create_for_atsu_font_id (font_id);
  860. }
  861.