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

#include "cairoint.h"

#include <dlfcn.h>

#include "cairo-image-surface-private.h"
#include "cairo-quartz.h"
#include "cairo-quartz-private.h"

#include "cairo-error-private.h"

//#define DEBUG /* Uncomment this to get debug messages on the console. */
/**
 * SECTION:cairo-quartz-fonts
 * @Title: Quartz (CGFont) Fonts
 * @Short_Description: Font support via Core Text on Apple operating systems.
 * @See_Also: #cairo_font_face_t
 *
 * Provide support for font faces via Core Text.
 **/

/**
 * CAIRO_HAS_QUARTZ_FONT:
 *
 * Defined if the Quartz font backend is available.
 * This macro can be used to conditionally compile backend-specific code.
 *
 * Since: 1.6
 **/

/* These are private functions */
static bool (*CGContextGetAllowsFontSmoothingPtr) (CGContextRef) = NULL;
static ATSFontRef (*FMGetATSFontRefFromFontPtr) (FMFont iFont) = NULL;

static cairo_bool_t _cairo_quartz_font_symbol_lookup_done = FALSE;
/* Cairo's transformations assume a unit-scaled font. */
static const CGFloat font_scale = 1.0;

/* Defined in 10.11 */
#define CGGLYPH_MAX ((CGGlyph) 0xFFFE) /* kCGFontIndexMax */
#define CGGLYPH_INVALID ((CGGlyph) 0xFFFF) /* kCGFontIndexInvalid */

#if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
#define FONT_ORIENTATION_HORIZONTAL kCTFontHorizontalOrientation
#define FONT_COLOR_GLYPHS kCTFontColorGlyphsTrait
#else
#define FONT_ORIENTATION_HORIZONTAL kCTFontOrientationHorizontal
#define FONT_COLOR_GLYPHS kCTFontTraitColorGlyphs
#endif

static void
quartz_font_ensure_symbols(void)
{
    if (_cairo_quartz_font_symbol_lookup_done)
	return;

    CGContextGetAllowsFontSmoothingPtr =
	dlsym (RTLD_DEFAULT, "CGContextGetAllowsFontSmoothing");

    FMGetATSFontRefFromFontPtr = dlsym(RTLD_DEFAULT, "FMGetATSFontRefFromFont");

    _cairo_quartz_font_symbol_lookup_done = TRUE;
}

typedef struct _cairo_quartz_font_face cairo_quartz_font_face_t;
typedef struct _cairo_quartz_scaled_font cairo_quartz_scaled_font_t;

struct _cairo_quartz_scaled_font {
    cairo_scaled_font_t base;
    CTFontRef ctFont;
};

struct _cairo_quartz_font_face {
    cairo_font_face_t base;

    CGFontRef cgFont;
};

/*
 * font face backend
 */

static cairo_status_t
_cairo_quartz_font_face_create_for_toy (cairo_toy_font_face_t   *toy_face,
					cairo_font_face_t      **font_face)
{
    const char *family;
    char *full_name;
    CFStringRef FontName = NULL;
    CGFontRef cgFont = NULL;
    int loop;

    family = toy_face->family;
    full_name = _cairo_malloc (strlen (family) + 64); // give us a bit of room to tack on Bold, Oblique, etc.
    /* handle CSS-ish faces */
    if (!strcmp(family, "serif") || !strcmp(family, "Times Roman"))
	family = "Times";
    else if (!strcmp(family, "sans-serif") || !strcmp(family, "sans"))
	family = "Helvetica";
    else if (!strcmp(family, "cursive"))
	family = "Apple Chancery";
    else if (!strcmp(family, "fantasy"))
	family = "Papyrus";
    else if (!strcmp(family, "monospace") || !strcmp(family, "mono"))
	family = "Courier";

    /* Try to build up the full name, e.g. "Helvetica Bold Oblique" first,
     * then drop the bold, then drop the slant, then drop both.. finally
     * just use "Helvetica".  And if Helvetica doesn't exist, give up.
     */
    for (loop = 0; loop < 5; loop++) {
	if (loop == 4)
	    family = "Helvetica";

	strcpy (full_name, family);

	if (loop < 3 && (loop & 1) == 0) {
	    if (toy_face->weight == CAIRO_FONT_WEIGHT_BOLD)
		strcat (full_name, "-Bold");
	}

	if (loop < 3 && (loop & 2) == 0) {
	    if (toy_face->slant == CAIRO_FONT_SLANT_ITALIC)
		strcat (full_name, "-Italic");
	    else if (toy_face->slant == CAIRO_FONT_SLANT_OBLIQUE)
		strcat (full_name, "-Oblique");
	}

	FontName = CFStringCreateWithCString (NULL, full_name, kCFStringEncodingASCII);
	cgFont = CGFontCreateWithFontName (FontName);
	CFRelease (FontName);

	if (!cgFont) {
            /* Attempt to create font by replacing hyphens for spaces in font name. */
            for (size_t i = 0; i < strlen (full_name); i++) {
                if (full_name[i] == '-')
                    full_name[i] = ' ';
            }
            FontName = CFStringCreateWithCString (NULL, full_name, kCFStringEncodingASCII);
            cgFont = CGFontCreateWithFontName (FontName);
            CFRelease (FontName);
	}

	if (cgFont)
	    break;
    }

    if (!cgFont) {
	/* Give up */
	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    }

    *font_face = cairo_quartz_font_face_create_for_cgfont (cgFont);
    CFRelease (cgFont);

    return CAIRO_STATUS_SUCCESS;
}

static cairo_bool_t
_cairo_quartz_font_face_destroy (void *abstract_face)
{
    cairo_quartz_font_face_t *font_face = (cairo_quartz_font_face_t*) abstract_face;

    CGFontRelease (font_face->cgFont);
    return TRUE;
}

static const cairo_scaled_font_backend_t _cairo_quartz_scaled_font_backend;

#ifdef DEBUG
static void
_cairo_quartz_debug_font_characteristics (cairo_quartz_scaled_font_t *font)
{
    CGRect ct_bbox = CTFontGetBoundingBox (font->ctFont);
    CGFloat ct_ascent = CTFontGetAscent (font->ctFont);
    CGFloat ct_descent = CTFontGetDescent (font->ctFont);
    CGFloat ct_leading = CTFontGetLeading (font->ctFont);
    CGFloat ct_capheight = CTFontGetCapHeight (font->ctFont);
    CGFloat ct_xheight = CTFontGetXHeight (font->ctFont);
    char chars[] = "ymMW";
    CGGlyph glyphs[4];
    UniChar *utf16 = NULL;
    CGSize ct_advances[4];
    CGRect ct_gbbox[4], ct_gobox[4], ct_rbbox, ct_robox;
    double ct_radvance;
    int converted;
    cairo_status_t rv;

    rv = _cairo_utf8_to_utf16 (chars, 4, &utf16, &converted);
    if (rv) return;
    CTFontGetGlyphsForCharacters (font->ctFont, utf16, glyphs, 4);
    free (utf16);
    ct_rbbox = CTFontGetBoundingRectsForGlyphs (font->ctFont, FONT_ORIENTATION_HORIZONTAL, glyphs, ct_gbbox, 4);
    ct_robox = CTFontGetOpticalBoundsForGlyphs (font->ctFont, glyphs, ct_gobox, 4, 0);
    ct_radvance = CTFontGetAdvancesForGlyphs (font->ctFont, FONT_ORIENTATION_HORIZONTAL, glyphs, ct_advances, 4);

    fprintf (stderr, "\nCTFont Bounding Box: %f %f %f %f\nAscent %f Descent %f Leading %f Cap Height %f X-Height %f\n",
	     ct_bbox.origin.x, ct_bbox.origin.y, ct_bbox.size.width, ct_bbox.size.height, ct_ascent, ct_descent,
	     ct_leading, ct_capheight, ct_xheight);
    fprintf (stderr, "CTFont string\n\t bounding box %f %f %f %f advance %f\n\toptical box %f %f %f %f\n\n",
	     ct_rbbox.origin.x, ct_rbbox.origin.y, ct_rbbox.size.width, ct_rbbox.size.height, ct_radvance,
	     ct_robox.origin.x, ct_robox.origin.y, ct_robox.size.width, ct_robox.size.height);
    for (int i = 0; i < 4; ++i)
    {
	fprintf (stderr, "Character %c\n", chars[i]);
	fprintf (stderr, "\tbox %f %f %f %f\n\toptical %f %f %f %f advance %f %f\n",
		 ct_gbbox[i].origin.x, ct_gbbox[i].origin.y, ct_gbbox[i].size.width, ct_gbbox[i].size.height,
		 ct_advances[i].width, ct_advances[i].height,
		 ct_gobox[i].origin.x, ct_gobox[i].origin.y, ct_gobox[i].size.width, ct_gobox[i].size.height);
    }
    fprintf (stderr, "\n");
}
#endif

static cairo_status_t
_cairo_quartz_font_face_scaled_font_create (void *abstract_face,
					    const cairo_matrix_t *font_matrix,
					    const cairo_matrix_t *ctm,
					    const cairo_font_options_t *options,
					    cairo_scaled_font_t **font_out)
{
    cairo_quartz_font_face_t *font_face = abstract_face;
    cairo_quartz_scaled_font_t *font = NULL;
    cairo_status_t status;
    cairo_font_extents_t fs_metrics;
    CTFontRef ctFont;
    CGRect bbox;

    font = _cairo_calloc (sizeof(cairo_quartz_scaled_font_t));
    if (font == NULL)
	return _cairo_error (CAIRO_STATUS_NO_MEMORY);

    memset (font, 0, sizeof(cairo_quartz_scaled_font_t));

    status = _cairo_scaled_font_init (&font->base,
				      &font_face->base, font_matrix, ctm, options,
				      &_cairo_quartz_scaled_font_backend);
    if (status)
	goto FINISH;

    ctFont = CTFontCreateWithGraphicsFont (font_face->cgFont, font_scale, NULL, NULL);
    /* initialize metrics */
    fs_metrics.ascent = CTFontGetAscent (ctFont);
    fs_metrics.descent = CTFontGetDescent (ctFont);
    fs_metrics.height = fs_metrics.ascent + fs_metrics.descent +
	CTFontGetLeading (ctFont);

    bbox = CTFontGetBoundingBox (ctFont);
    fs_metrics.max_x_advance = CGRectGetMaxX(bbox);
    fs_metrics.max_y_advance = 0.0;
    font->ctFont = CFRetain (ctFont);
    status = _cairo_scaled_font_set_metrics (&font->base, &fs_metrics);
#ifdef DEBUG
    {
	CFStringRef fontFullName = CTFontCopyFullName (ctFont);
	const char* font_full_name = CFStringGetCStringPtr(fontFullName, kCFStringEncodingUTF8);

	fprintf (stderr, "Create scaled font %s with scale %f ascent %f, descent %f, height %f, x-advance %f\n",
		 font_full_name, fs_metrics.ascent, fs_metrics.descent, fs_metrics.height,
		 fs_metrics.max_x_advance);
	_cairo_quartz_debug_font_characteristics (font);
    }
#endif

FINISH:
    if (status != CAIRO_STATUS_SUCCESS) {
	free (font);
    } else {
	*font_out = (cairo_scaled_font_t*) font;
    }

    return status;
}

const cairo_font_face_backend_t _cairo_quartz_font_face_backend = {
    CAIRO_FONT_TYPE_QUARTZ,
    _cairo_quartz_font_face_create_for_toy,
    _cairo_quartz_font_face_destroy,
    _cairo_quartz_font_face_scaled_font_create
};

static inline cairo_quartz_font_face_t*
_cairo_quartz_font_face_create ()
{
    cairo_quartz_font_face_t *font_face =
	_cairo_calloc (sizeof (cairo_quartz_font_face_t));

    if (!font_face) {
	cairo_status_t ignore_status;
	ignore_status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
	return (cairo_quartz_font_face_t *)&_cairo_font_face_nil;
    }

    _cairo_font_face_init (&font_face->base, &_cairo_quartz_font_face_backend);

    return font_face;
}

/**
 * cairo_quartz_font_face_create_for_cgfont:
 * @font: a #CGFontRef obtained through a method external to cairo.
 *
 * Creates a new font for the Quartz font backend based on a
 * #CGFontRef.  This font can then be used with
 * cairo_set_font_face() or cairo_scaled_font_create().
 *
 * Return value: a newly created #cairo_font_face_t. Free with
 *  cairo_font_face_destroy() when you are done using it.
 *
 * Since: 1.6
 **/
cairo_font_face_t *
cairo_quartz_font_face_create_for_cgfont (CGFontRef font)
{
    cairo_quartz_font_face_t* font_face = _cairo_quartz_font_face_create ();

    if (cairo_font_face_status (&font_face->base))
	return &font_face->base;

    font_face->cgFont = CGFontRetain (font);

    return &font_face->base;
}

/*
 * scaled font backend
 */

static cairo_quartz_font_face_t *
_cairo_quartz_scaled_to_face (void *abstract_font)
{
    cairo_quartz_scaled_font_t *sfont = (cairo_quartz_scaled_font_t*) abstract_font;
    cairo_font_face_t *font_face = sfont->base.font_face;
    assert (font_face->backend->type == CAIRO_FONT_TYPE_QUARTZ);
    return (cairo_quartz_font_face_t*) font_face;
}

static void
_cairo_quartz_scaled_font_fini(void *abstract_font)
{
    cairo_quartz_scaled_font_t* font = (cairo_quartz_scaled_font_t*)abstract_font;
    CFRelease (font->ctFont);
}

static inline CGGlyph
_cairo_quartz_scaled_glyph_index (cairo_scaled_glyph_t *scaled_glyph) {
    unsigned long index = _cairo_scaled_glyph_index (scaled_glyph);
    return index <= CGGLYPH_MAX ? index : CGGLYPH_INVALID;
}

static cairo_int_status_t
_cairo_quartz_init_glyph_metrics (cairo_quartz_scaled_font_t *font,
				  cairo_scaled_glyph_t *scaled_glyph)
{
    cairo_int_status_t status = CAIRO_STATUS_SUCCESS;

    cairo_text_extents_t extents = {0, 0, 0, 0, 0, 0};
    CGGlyph glyph = _cairo_quartz_scaled_glyph_index (scaled_glyph);
    CGSize advance;
    CGRect bbox;
    double xmin, ymin, xmax, ymax;

    if (unlikely (glyph == CGGLYPH_INVALID))
	goto FAIL;

    CTFontGetAdvancesForGlyphs (font->ctFont, FONT_ORIENTATION_HORIZONTAL, &glyph, &advance, 1);
    CTFontGetBoundingRectsForGlyphs (font->ctFont, FONT_ORIENTATION_HORIZONTAL, &glyph, &bbox, 1);
    /* broken fonts like Al Bayan return incorrect bounds for some null characters,
       see https://bugzilla.mozilla.org/show_bug.cgi?id=534260 */
    if (unlikely (bbox.origin.x == -32767 &&
                  bbox.origin.y == -32767 &&
                  bbox.size.width == 65534 &&
                  bbox.size.height == 65534)) {
        bbox.origin.x = bbox.origin.y = 0;
        bbox.size.width = bbox.size.height = 0;
    }

#ifdef DEBUG
    fprintf (stderr, "[0x%04x] bbox: x %f y %f width %f height %f\n", glyph,
	     bbox.origin.x, bbox.origin.y, bbox.size.width, bbox.size.height);
#endif

    xmin = CGRectGetMinX(bbox);
    ymin = CGRectGetMinY(bbox);
    xmax = CGRectGetMaxX(bbox);
    ymax = CGRectGetMaxY(bbox);

    extents.x_bearing = xmin;
    extents.y_bearing = - ymax;
    extents.width = xmax - xmin;
    extents.height = ymax - ymin;
/* At the necessary 1.0pt ctFont size some glyphs get a reduced
 * advance that causes overlaps when scaled up. We can avoid that by
 * using the width instead if it's wider. Since cairo doesn't support
 * vertical font layout we don't do the same for y_advance.
 */
    extents.x_advance = MAX(extents.width, advance.width);
    extents.y_advance = advance.height;

#ifdef DEBUG
    fprintf (stderr, "[0x%04x] extents: bearings: %f %f dim: %f %f adv: %f %f\n\n", glyph,
	     extents.x_bearing, extents.y_bearing, extents.width, extents.height, extents.x_advance, extents.y_advance);
#endif

  FAIL:
    _cairo_scaled_glyph_set_metrics (scaled_glyph,
				     &font->base,
				     &extents);

    return status;
}

static void
_cairo_quartz_path_apply_func (void *info, const CGPathElement *el)
{
    cairo_path_fixed_t *path = (cairo_path_fixed_t *) info;
    cairo_status_t status;

    switch (el->type) {
	case kCGPathElementMoveToPoint:
	    status = _cairo_path_fixed_move_to (path,
						_cairo_fixed_from_double(el->points[0].x),
						_cairo_fixed_from_double(el->points[0].y));
	    assert(!status);
	    break;
	case kCGPathElementAddLineToPoint:
	    status = _cairo_path_fixed_line_to (path,
						_cairo_fixed_from_double(el->points[0].x),
						_cairo_fixed_from_double(el->points[0].y));
	    assert(!status);
	    break;
	case kCGPathElementAddQuadCurveToPoint: {
	    cairo_fixed_t fx, fy;
	    double x, y;
	    if (!_cairo_path_fixed_get_current_point (path, &fx, &fy))
		fx = fy = 0;
	    x = _cairo_fixed_to_double (fx);
	    y = _cairo_fixed_to_double (fy);

	    status = _cairo_path_fixed_curve_to (path,
						 _cairo_fixed_from_double((x + el->points[0].x * 2.0) / 3.0),
						 _cairo_fixed_from_double((y + el->points[0].y * 2.0) / 3.0),
						 _cairo_fixed_from_double((el->points[0].x * 2.0 + el->points[1].x) / 3.0),
						 _cairo_fixed_from_double((el->points[0].y * 2.0 + el->points[1].y) / 3.0),
						 _cairo_fixed_from_double(el->points[1].x),
						 _cairo_fixed_from_double(el->points[1].y));
	}
	    assert(!status);
	    break;
	case kCGPathElementAddCurveToPoint:
	    status = _cairo_path_fixed_curve_to (path,
						 _cairo_fixed_from_double(el->points[0].x),
						 _cairo_fixed_from_double(el->points[0].y),
						 _cairo_fixed_from_double(el->points[1].x),
						 _cairo_fixed_from_double(el->points[1].y),
						 _cairo_fixed_from_double(el->points[2].x),
						 _cairo_fixed_from_double(el->points[2].y));
	    assert(!status);
	    break;
	case kCGPathElementCloseSubpath:
	    status = _cairo_path_fixed_close_path (path);
	    assert(!status);
	    break;
    }
}

static cairo_int_status_t
_cairo_quartz_init_glyph_path (cairo_quartz_scaled_font_t *font,
			       cairo_scaled_glyph_t *scaled_glyph)
{
    CGGlyph glyph = _cairo_quartz_scaled_glyph_index (scaled_glyph);
    CGAffineTransform textMatrix;
    CGPathRef glyphPath;
    cairo_path_fixed_t *path;

    if (unlikely (glyph == CGGLYPH_INVALID)) {
	_cairo_scaled_glyph_set_path (scaled_glyph, &font->base, _cairo_path_fixed_create());
	return CAIRO_STATUS_SUCCESS;
    }

    /* scale(1,-1) * font->base.scale */
    textMatrix = CGAffineTransformMake (font->base.scale.xx,
					font->base.scale.yx,
					-font->base.scale.xy,
					-font->base.scale.yy,
					0, 0);

    glyphPath = CTFontCreatePathForGlyph (font->ctFont, glyph, &textMatrix);

    if (!glyphPath)
	return CAIRO_INT_STATUS_UNSUPPORTED;

    path = _cairo_path_fixed_create ();
    if (!path) {
	CGPathRelease (glyphPath);
	return _cairo_error(CAIRO_STATUS_NO_MEMORY);
    }

    CGPathApply (glyphPath, path, _cairo_quartz_path_apply_func);

    CGPathRelease (glyphPath);

    _cairo_scaled_glyph_set_path (scaled_glyph, &font->base, path);

    return CAIRO_STATUS_SUCCESS;
}

static cairo_bool_t
_cairo_quartz_font_has_color_glyphs (void *abstract_font)
{
    cairo_quartz_scaled_font_t *face = (cairo_quartz_scaled_font_t*)abstract_font;
    CTFontSymbolicTraits traits = CTFontGetSymbolicTraits (face->ctFont);
    return traits & FONT_COLOR_GLYPHS;
}

static cairo_int_status_t
_cairo_quartz_init_glyph_surface (cairo_quartz_scaled_font_t *font,
				  cairo_scaled_glyph_t *scaled_glyph,
				  cairo_scaled_glyph_info_t info,
				 const cairo_color_t *fg_color)
{
    cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
    cairo_image_surface_t *surface = NULL;

    CGGlyph glyph = _cairo_quartz_scaled_glyph_index (scaled_glyph);
    cairo_text_extents_t metrics = scaled_glyph->fs_metrics;
    CGRect bbox = CGRectMake (metrics.x_bearing, -(metrics.y_bearing + metrics.height),
			      metrics.width, metrics.height);
    double width, height;

    CGAffineTransform textMatrix;
    CGRect glyphRect, glyphRectInt;
    CGPoint glyphOrigin;
    cairo_bool_t is_color = info & CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE;
    cairo_format_t format =  is_color ? CAIRO_FORMAT_ARGB32 : CAIRO_FORMAT_A8;

#ifdef DEBUG
    fprintf (stderr, "[0x%04x] bearing: %f %f width %f height %f advances %f %f\n",
	     glyph, metrics.x_bearing, metrics.y_bearing, metrics.width, metrics.height,
	     metrics.x_advance, metrics.y_advance);
    fprintf (stderr, "[0x%04x] bounds: origin %f %f, size %f %f\n", glyph, bbox.origin.x,
	     bbox.origin.y, bbox.size.width, bbox.size.height);
#endif
    /* Create blank 2x2 image if we don't have this character.
     * Maybe we should draw a better missing-glyph slug or something,
     * but this is ok for now.
     */
    if (unlikely (glyph == CGGLYPH_INVALID)) {
	surface = (cairo_image_surface_t*) cairo_image_surface_create (CAIRO_FORMAT_A8, 2, 2);
	status = cairo_surface_status ((cairo_surface_t *) surface);
	if (status)
	    return status;

	_cairo_scaled_glyph_set_surface (scaled_glyph,
					 &font->base,
					 surface);
	return CAIRO_STATUS_SUCCESS;
    }

/* Note: Certain opentype color fonts have the ability to provide a
 * mixture of color and not-color glyphs. The Core Text API doesn't
 * expose a way to query individual glyphs and at the level that that
 * API is written it's not supposed to matter. The following code will
 * cheerfully render any glyph requested onto the image surface. If
 * the font is capable of color and
 * COLOR_SCALED_GLYPH_INFO_COLOR_SURFACE is set then you get back a
 * CAIRO_FORMAT_ARGB32 surface. If a foreground color is provided then
 * the glyph will be drawn in that color, otherwise it will be black.
 */
    if (unlikely (is_color && ! _cairo_quartz_font_has_color_glyphs (font)))
	return CAIRO_INT_STATUS_UNSUPPORTED;

    /* scale(1,-1) * font->base.scale * scale(1,-1) */
    textMatrix = CGAffineTransformMake (font->base.scale.xx,
					-font->base.scale.yx,
					-font->base.scale.xy,
					font->base.scale.yy,
					0, 0);
    glyphRect = CGRectApplyAffineTransform (bbox, textMatrix);

    /* Round the rectangle outwards, so that we don't have to deal
     * with non-integer-pixel origins or dimensions.
     */
    glyphRectInt = CGRectIntegral (glyphRect);

#ifdef DEBUG
    fprintf (stderr, "glyphRect[o]: %f %f %f %f\n",
	     glyphRect.origin.x, glyphRect.origin.y, glyphRect.size.width, glyphRect.size.height);
    fprintf (stderr, "glyphRectInt: %f %f %f %f\n",
	     glyphRectInt.origin.x, glyphRectInt.origin.y, glyphRectInt.size.width, glyphRectInt.size.height);
#endif

    glyphOrigin = glyphRectInt.origin;

    width = glyphRectInt.size.width;
    height = glyphRectInt.size.height;

    surface = (cairo_image_surface_t*) cairo_image_surface_create (format, width, height);
    if (surface->base.status)
	return surface->base.status;

    if (surface->width != 0 && surface->height != 0) {
	CGColorSpaceRef colorspace = is_color ? CGColorSpaceCreateDeviceRGB () : NULL;
	CGBitmapInfo bitinfo = is_color ? kCGBitmapByteOrder32Host | kCGImageAlphaPremultipliedFirst : kCGImageAlphaOnly;

	CGContextRef cgContext = CGBitmapContextCreate (surface->data,
							surface->width,
							surface->height,
							8,
							surface->stride,
							colorspace,
							bitinfo);

	if (cgContext == NULL) {
	    cairo_surface_destroy (&surface->base);
	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
	}

	if (fg_color)
	    CGContextSetRGBFillColor (cgContext, fg_color->red, fg_color->green, fg_color->blue, fg_color->alpha);
	_cairo_quartz_set_antialiasing (cgContext, font->base.options.antialias);
	CGContextSetAlpha (cgContext, 1.0);
	CGContextTranslateCTM (cgContext, -glyphOrigin.x, -glyphOrigin.y);
	CGContextConcatCTM (cgContext, textMatrix);
	CTFontDrawGlyphs (font->ctFont, &glyph, &CGPointZero, 1, cgContext);
	CGContextRelease (cgContext);
	CGColorSpaceRelease (colorspace);
    }

    cairo_surface_set_device_offset (&surface->base,
				     - glyphOrigin.x,
				     height + glyphOrigin.y);
    cairo_surface_mark_dirty (&surface->base);

    if (is_color)
	_cairo_scaled_glyph_set_color_surface (scaled_glyph, &font->base, surface, fg_color);
    else
	_cairo_scaled_glyph_set_surface (scaled_glyph, &font->base, surface);

    return status;
}

static cairo_int_status_t
_cairo_quartz_scaled_glyph_init (void *abstract_font,
				 cairo_scaled_glyph_t *scaled_glyph,
				 cairo_scaled_glyph_info_t info,
				 const cairo_color_t *foreground_color)
{
    cairo_quartz_scaled_font_t *font = (cairo_quartz_scaled_font_t *) abstract_font;
    cairo_int_status_t status = CAIRO_STATUS_SUCCESS;

    if (!status && (info & CAIRO_SCALED_GLYPH_INFO_METRICS))
	status = _cairo_quartz_init_glyph_metrics (font, scaled_glyph);

    if (!status && (info & CAIRO_SCALED_GLYPH_INFO_PATH))
	status = _cairo_quartz_init_glyph_path (font, scaled_glyph);

    if (!status && (info & (CAIRO_SCALED_GLYPH_INFO_SURFACE |
			    CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE )))
	status = _cairo_quartz_init_glyph_surface (font, scaled_glyph,
						   info, foreground_color);

    return status;
}

static unsigned long
_cairo_quartz_ucs4_to_index (void *abstract_font,
			     uint32_t ucs4)
{
    cairo_quartz_scaled_font_t *font = (cairo_quartz_scaled_font_t*) abstract_font;
    CGGlyph glyph[2];
    UniChar utf16[2];

    int len = _cairo_ucs4_to_utf16 (ucs4, utf16);
    CTFontGetGlyphsForCharacters (font->ctFont, utf16, glyph, len);
    return glyph[0];
}

static cairo_int_status_t
_cairo_quartz_load_truetype_table (void	            *abstract_font,
				   unsigned long     tag,
				   long              offset,
				   unsigned char    *buffer,
				   unsigned long    *length)
{
    cairo_quartz_scaled_font_t *font = (cairo_quartz_scaled_font_t*) abstract_font;
    CFDataRef data = CTFontCopyTable (font->ctFont, tag, kCTFontTableOptionNoOptions);

    if (!data)
        return CAIRO_INT_STATUS_UNSUPPORTED;

    if (buffer == NULL) {
	*length = CFDataGetLength (data);
	CFRelease (data);
	return CAIRO_STATUS_SUCCESS;
    }

    if (CFDataGetLength (data) < offset + (long) *length) {
	CFRelease (data);
	return CAIRO_INT_STATUS_UNSUPPORTED;
    }

    CFDataGetBytes (data, CFRangeMake (offset, *length), buffer);
    CFRelease (data);

    return CAIRO_STATUS_SUCCESS;
}

static const cairo_scaled_font_backend_t _cairo_quartz_scaled_font_backend = {
    CAIRO_FONT_TYPE_QUARTZ,
    _cairo_quartz_scaled_font_fini,
    _cairo_quartz_scaled_glyph_init,
    NULL, /* text_to_glyphs */
    _cairo_quartz_ucs4_to_index,
    _cairo_quartz_load_truetype_table,
    NULL, /*index_to_ucs4*/
    NULL, /* is_synthetic */
    NULL, /* index_to_glyph_name */
    NULL, /* load_type1_data */
    _cairo_quartz_font_has_color_glyphs
};
/*
 * private methods that the quartz surface uses
 */

CGFontRef
_cairo_quartz_scaled_font_get_cg_font_ref (cairo_scaled_font_t *abstract_font)
{
    cairo_quartz_font_face_t *ffont = _cairo_quartz_scaled_to_face(abstract_font);

    return ffont->cgFont;
}

CTFontRef
_cairo_quartz_scaled_font_get_ct_font (cairo_scaled_font_t *abstract_font)
{
    cairo_quartz_scaled_font_t *font = (cairo_quartz_scaled_font_t*) abstract_font;

    return font->ctFont;
}

 void
 _cairo_quartz_set_antialiasing (CGContextRef cgContext, cairo_antialias_t antialias)
{
	switch (antialias) {
	case CAIRO_ANTIALIAS_SUBPIXEL:
	case CAIRO_ANTIALIAS_BEST:
	    CGContextSetShouldAntialias (cgContext, TRUE);
	    CGContextSetShouldSmoothFonts (cgContext, TRUE);
	    quartz_font_ensure_symbols ();
	    if (CGContextGetAllowsFontSmoothingPtr &&
		!CGContextGetAllowsFontSmoothingPtr (cgContext))
		CGContextSetAllowsFontSmoothing (cgContext, TRUE);
	    break;
	case CAIRO_ANTIALIAS_NONE:
	    CGContextSetShouldAntialias (cgContext, FALSE);
	    break;
	case CAIRO_ANTIALIAS_GRAY:
	case CAIRO_ANTIALIAS_GOOD:
	case CAIRO_ANTIALIAS_FAST:
	    CGContextSetShouldAntialias (cgContext, TRUE);
	    CGContextSetShouldSmoothFonts (cgContext, FALSE);
	    break;
	case CAIRO_ANTIALIAS_DEFAULT:
	default:
	    /* Don't do anything */
	    break;
	}

}
/*
 * compat with old ATSUI backend
 */

/**
 * cairo_quartz_font_face_create_for_atsu_font_id:
 * @font_id: an ATSUFontID for the font.
 *
 * Creates a new font for the Quartz font backend based on an
 * #ATSUFontID. This font can then be used with
 * cairo_set_font_face() or cairo_scaled_font_create().
 *
 * Return value: a newly created #cairo_font_face_t. Free with
 *  cairo_font_face_destroy() when you are done using it.
 *
 * Since: 1.6
 **/
cairo_font_face_t *
cairo_quartz_font_face_create_for_atsu_font_id (ATSUFontID font_id)
{
    quartz_font_ensure_symbols();

    if (FMGetATSFontRefFromFontPtr != NULL) {
	ATSFontRef atsFont = FMGetATSFontRefFromFontPtr (font_id);
	CGFontRef cgFont = CGFontCreateWithPlatformFont (&atsFont);
	cairo_font_face_t *ff;

	ff = cairo_quartz_font_face_create_for_cgfont (cgFont);

	CGFontRelease (cgFont);

	return ff;
    } else {
	_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
	return (cairo_font_face_t *)&_cairo_font_face_nil;
    }
}

/* This is the old name for the above function, exported for compat purposes */
cairo_font_face_t *cairo_atsui_font_face_create_for_atsu_font_id (ATSUFontID font_id);

cairo_font_face_t *
cairo_atsui_font_face_create_for_atsu_font_id (ATSUFontID font_id)
{
    return cairo_quartz_font_face_create_for_atsu_font_id (font_id);
}
