From 075cf23cdc071b170e591fd07ff6c272d561d3ee Mon Sep 17 00:00:00 2001 From: Owen Taylor Date: Thu, 21 Jul 2005 06:52:13 +0000 Subject: [PATCH] src/cairo-font-options.c src/cairo.h src/cairoint.h src/Makefile.am: Add an opaque cairo_font_options_t structure. src/cairo-font.c src/cairo.h src/cairoint.h: Add a cairo_font_options_t object to cairo_scaled_font_create(). src/cairo-surface.c src/cairoint.h: Add virtualized cairo_surface_get_font_options() to get the font options for a surface. Adapt to cairo_scaled_font_create() change. Add an implementation of get_font_options() that turns off metrics hinting. src/cairo-xlib-screen.c src/cairo-xlib-private.h: Add a "screen info" structure that holds (for now) information about the default font options for the screen. Implement get_font_options() src/cairo-ft-font.c src/cairo-ft.h: Add functions to apply a cairo_font_options_t to a FcPattern or get the load flags for a cairo_font_options_t. Adapt to font options additions. Add support for non-antialiased rendering of scalable fonts. Add support for turning off metrics hinting. Adapt to font options additions. doc/public/Makefile.am doc/public/cairo-sections.txt: Update. reviewed by: cworth --- ChangeLog | 37 +++ doc/public/Makefile.am | 3 + doc/public/cairo-sections.txt | 29 +- doc/public/tmpl/cairo-font.sgml | 184 +++++++++++ doc/public/tmpl/cairo-ft.sgml | 9 + doc/public/tmpl/cairo-pattern.sgml | 23 ++ doc/public/tmpl/cairo-surface.sgml | 13 +- doc/public/tmpl/cairo.sgml | 27 +- src/Makefile.am | 3 +- src/cairo-font-options.c | 352 ++++++++++++++++++++ src/cairo-font.c | 32 +- src/cairo-ft-font.c | 504 +++++++++++++++++++++-------- src/cairo-ft.h | 3 + src/cairo-gstate.c | 5 +- src/cairo-pdf-surface.c | 13 +- src/cairo-surface.c | 27 ++ src/cairo-win32-font.c | 101 ++++-- src/cairo-xlib-private.h | 54 ++++ src/cairo-xlib-screen.c | 345 ++++++++++++++++++++ src/cairo-xlib-surface.c | 22 +- src/cairo.h | 154 ++++++++- src/cairoint.h | 17 + 22 files changed, 1762 insertions(+), 195 deletions(-) create mode 100644 src/cairo-font-options.c create mode 100644 src/cairo-xlib-private.h create mode 100644 src/cairo-xlib-screen.c diff --git a/ChangeLog b/ChangeLog index 8b960e7c9..66ead6b74 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,40 @@ +2005-07-13 Owen Taylor + + reviewed by: cworth + + * src/cairo-font-options.c src/cairo.h src/cairoint.h + src/Makefile.am: Add an opaque cairo_font_options_t structure. + + * src/cairo-font.c src/cairo.h src/cairoint.h: Add a + cairo_font_options_t object to cairo_scaled_font_create(). + + * src/cairo-surface.c src/cairoint.h: Add virtualized + cairo_surface_get_font_options() to get the font options for + a surface. + + * src/cairo-gstate.c: Adapt to cairo_scaled_font_create() change. + + * src/cairo-pdf-surface.c: Add an implementation of + get_font_options() that turns off metrics hinting. + + * src/cairo-xlib-screen.c src/cairo-xlib-private.h: Add + a "screen info" structure that holds (for now) information + about the default font options for the screen. + + * src/cairo-xlib-surface.c: Implement get_font_options() + + * src/cairo-ft-font.c src/cairo-ft.h: Add functions to apply + a cairo_font_options_t to a FcPattern or get the load flags + for a cairo_font_options_t. + + * src/cairo-ft-font.c: Adapt to font options additions. + Add support for non-antialiased rendering of scalable fonts. + Add support for turning off metrics hinting. + + * src/cairo-win32-font.c: Adapt to font options additions. + + * doc/public/Makefile.am doc/public/cairo-sections.txt: Update. + 2005-07-21 Carl Worth * src/cairo-glitz-surface.c: diff --git a/doc/public/Makefile.am b/doc/public/Makefile.am index 9e4c10365..7251042a9 100644 --- a/doc/public/Makefile.am +++ b/doc/public/Makefile.am @@ -21,8 +21,11 @@ CFILE_GLOB=$(top_srcdir)/src/*.c $(top_srcdir)/src/*.h # Headers to ignore IGNORE_HFILES= \ cairo-features.h \ + cairo-font-subset-private.h \ cairo-ft-private.h \ cairo-gstate-private.h \ + cairo-hash-private.h \ + cairo-meta-surface-private.h \ cairo-path-fixed-private.h \ cairo-private.h \ cairo-win32-private.h \ diff --git a/doc/public/cairo-sections.txt b/doc/public/cairo-sections.txt index 4db600b2a..2a3106dce 100644 --- a/doc/public/cairo-sections.txt +++ b/doc/public/cairo-sections.txt @@ -1,6 +1,7 @@
cairo-ft FreeType Fonts +cairo_ft_font_options_substitute cairo_ft_font_face_create_for_pattern cairo_ft_font_face_create_for_ft_face cairo_ft_scaled_font_lock_face @@ -90,6 +91,7 @@ cairo_surface_create_similar cairo_surface_reference cairo_surface_destroy cairo_surface_finish +cairo_surface_get_font_options cairo_surface_set_user_data cairo_surface_get_user_data cairo_surface_set_device_offset @@ -99,6 +101,8 @@ cairo_surface_set_device_offset cairo-pattern cairo_pattern_t cairo_pattern_t +cairo_pattern_create_rgb +cairo_pattern_create_rgba cairo_pattern_create_for_surface cairo_pattern_create_linear cairo_pattern_create_radial @@ -150,6 +154,26 @@ cairo_font_extents_t cairo_scaled_font_extents cairo_text_extents_t cairo_scaled_font_glyph_extents +cairo_font_options_t +cairo_font_options_create +cairo_font_options_copy +cairo_font_options_destroy +cairo_font_options_status +cairo_font_options_merge +cairo_font_options_hash +cairo_font_options_equal +cairo_antialias_t +cairo_font_options_set_antialias +cairo_font_options_get_antialias +cairo_subpixel_order_t +cairo_font_options_set_subpixel_order +cairo_font_options_get_subpixel_order +cairo_hint_style_t +cairo_font_options_set_hint_style +cairo_font_options_get_hint_style +cairo_hint_metrics_t +cairo_font_options_set_hint_metrics +cairo_font_options_get_hint_metrics
@@ -161,7 +185,10 @@ cairo_reference cairo_destroy cairo_save cairo_restore +cairo_content_t +CAIRO_CONTENT_VALID cairo_format_t +CAIRO_FORMAT_VALID cairo_operator_t cairo_set_operator cairo_set_source_rgb @@ -255,8 +282,6 @@ cairo_status_t cairo_status cairo_status_string cairo_status_to_string -cairo_error_notify_func_t -cairo_set_error_notify cairo_filter_t cairo_image_surface_create cairo_image_surface_create_for_data diff --git a/doc/public/tmpl/cairo-font.sgml b/doc/public/tmpl/cairo-font.sgml index d6c7043d2..0c81b7ae5 100644 --- a/doc/public/tmpl/cairo-font.sgml +++ b/doc/public/tmpl/cairo-font.sgml @@ -75,6 +75,7 @@ Font Handling @font_face: @font_matrix: @ctm: +@options: @Returns: @@ -138,3 +139,186 @@ Font Handling @extents: + + + + + + + + + + + +@Returns: + + + + + + + +@original: +@Returns: + + + + + + + +@options: + + + + + + + +@options: +@Returns: + + + + + + + +@options: +@other: + + + + + + + +@options: +@Returns: + + + + + + + +@options: +@other: +@Returns: + + + + + + + +@CAIRO_ANTIALIAS_DEFAULT: +@CAIRO_ANTIALIAS_NONE: +@CAIRO_ANTIALIAS_GRAY: +@CAIRO_ANTIALIAS_SUBPIXEL: + + + + + + +@options: +@antialias: + + + + + + + +@options: +@Returns: + + + + + + + +@CAIRO_SUBPIXEL_ORDER_DEFAULT: +@CAIRO_SUBPIXEL_ORDER_RGB: +@CAIRO_SUBPIXEL_ORDER_BGR: +@CAIRO_SUBPIXEL_ORDER_VRGB: +@CAIRO_SUBPIXEL_ORDER_VBGR: + + + + + + +@options: +@subpixel_order: + + + + + + + +@options: +@Returns: + +@option: + + + + + + + +@CAIRO_HINT_STYLE_DEFAULT: +@CAIRO_HINT_STYLE_NONE: +@CAIRO_HINT_STYLE_SLIGHT: +@CAIRO_HINT_STYLE_MEDIUM: +@CAIRO_HINT_STYLE_FULL: + + + + + + +@options: +@hint_style: + + + + + + + +@options: +@Returns: + + + + + + + +@CAIRO_HINT_METRICS_DEFAULT: +@CAIRO_HINT_METRICS_OFF: +@CAIRO_HINT_METRICS_ON: + + + + + + +@options: +@hint_metrics: + + + + + + + +@options: +@Returns: + + diff --git a/doc/public/tmpl/cairo-ft.sgml b/doc/public/tmpl/cairo-ft.sgml index d9f7cbfc1..383cf1935 100644 --- a/doc/public/tmpl/cairo-ft.sgml +++ b/doc/public/tmpl/cairo-ft.sgml @@ -17,6 +17,15 @@ FreeType Fonts + + + + + +@options: +@pattern: + + diff --git a/doc/public/tmpl/cairo-pattern.sgml b/doc/public/tmpl/cairo-pattern.sgml index dadd7870c..a837252c6 100644 --- a/doc/public/tmpl/cairo-pattern.sgml +++ b/doc/public/tmpl/cairo-pattern.sgml @@ -23,6 +23,29 @@ cairo_pattern_t + + + + + +@red: +@green: +@blue: +@Returns: + + + + + + + +@red: +@green: +@blue: +@alpha: +@Returns: + + diff --git a/doc/public/tmpl/cairo-surface.sgml b/doc/public/tmpl/cairo-surface.sgml index fab1306f6..480ff0579 100644 --- a/doc/public/tmpl/cairo-surface.sgml +++ b/doc/public/tmpl/cairo-surface.sgml @@ -29,10 +29,12 @@ cairo_surface_t @other: -@format: +@content: @width: @height: @Returns: + +@format: @@ -60,6 +62,15 @@ cairo_surface_t @Returns: + + + + + +@surface: +@options: + + diff --git a/doc/public/tmpl/cairo.sgml b/doc/public/tmpl/cairo.sgml index 992ace500..7200b4415 100644 --- a/doc/public/tmpl/cairo.sgml +++ b/doc/public/tmpl/cairo.sgml @@ -74,6 +74,23 @@ Drawing contexts. @cr: + + + + + +@CAIRO_CONTENT_COLOR: +@CAIRO_CONTENT_ALPHA: +@CAIRO_CONTENT_COLOR_ALPHA: + + + + + + +@content: + + @@ -84,6 +101,14 @@ Drawing contexts. @CAIRO_FORMAT_A8: @CAIRO_FORMAT_A1: + + + + + +@format: + + @@ -942,7 +967,7 @@ Drawing contexts. @CAIRO_STATUS_INVALID_POP_GROUP: @CAIRO_STATUS_NO_CURRENT_POINT: @CAIRO_STATUS_INVALID_MATRIX: -@CAIRO_STATUS_NO_TARGET_SURFACE: +@CAIRO_STATUS_INVALID_STATUS: @CAIRO_STATUS_NULL_POINTER: @CAIRO_STATUS_INVALID_STRING: @CAIRO_STATUS_INVALID_PATH_DATA: diff --git a/src/Makefile.am b/src/Makefile.am index 888105503..16cbb1c50 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -17,7 +17,7 @@ endif if CAIRO_HAS_XLIB_SURFACE libcairo_xlib_headers = cairo-xlib.h cairo-xlib-xrender.h -libcairo_xlib_sources = cairo-xlib-surface.c cairo-xlib-test.h +libcairo_xlib_sources = cairo-xlib-surface.c cairo-xlib-screen.c cairo-xlib-private.h cairo-xlib-test.h endif if CAIRO_HAS_QUARTZ_SURFACE @@ -88,6 +88,7 @@ libcairo_la_SOURCES = \ cairo-color.c \ cairo-fixed.c \ cairo-font.c \ + cairo-font-options.c \ cairo-gstate.c \ cairo-gstate-private.h \ cairo-hull.c \ diff --git a/src/cairo-font-options.c b/src/cairo-font-options.c new file mode 100644 index 000000000..b4535b7c2 --- /dev/null +++ b/src/cairo-font-options.c @@ -0,0 +1,352 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2005 Red Hat Inc. + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Owen Taylor + */ + +#include "cairoint.h" + +static const cairo_font_options_t cairo_font_options_nil = { + CAIRO_ANTIALIAS_DEFAULT, + CAIRO_SUBPIXEL_ORDER_DEFAULT, + CAIRO_HINT_STYLE_DEFAULT, + CAIRO_HINT_METRICS_DEFAULT +}; + +/** + * _cairo_font_options_init_default: + * @options: a #cairo_font_options_t + * + * Initializes all fileds of the font options object to default values. + **/ +void +_cairo_font_options_init_default (cairo_font_options_t *options) +{ + if (options == (cairo_font_options_t *)&cairo_font_options_nil) + return; + + options->antialias = CAIRO_ANTIALIAS_DEFAULT; + options->subpixel_order = CAIRO_SUBPIXEL_ORDER_DEFAULT; + options->hint_style = CAIRO_HINT_STYLE_DEFAULT; + options->hint_metrics = CAIRO_HINT_METRICS_DEFAULT; +} + +/** + * cairo_font_options_create: + * + * Allocates a new font options object with all options initialized + * to default values. + * + * Return value: a newly allocated #cairo_font_options_t. Free with + * cairo_font_options_destroy(). This function always returns a + * valid pointer; if memory cannot be allocated, then a special + * error object is returned where all operations on the object do nothing. + * You can check for this with cairo_font_options_status(). + **/ +cairo_font_options_t * +cairo_font_options_create (void) +{ + cairo_font_options_t *options = malloc (sizeof (cairo_font_options_t)); + + if (!options) + return (cairo_font_options_t *)&cairo_font_options_nil; + + _cairo_font_options_init_default (options); + + return options; +} + +/** + * cairo_font_options_copy: + * @original: a #cairo_font_options_t + * + * Allocates a new font options object copying the option values from + * @original. + * + * Return value: a newly allocated #cairo_font_options_t. Free with + * cairo_font_options_destroy(). This function always returns a + * valid pointer; if memory cannot be allocated, then a special + * error object is returned where all operations on the object do nothing. + * You can check for this with cairo_font_options_status(). + **/ +cairo_font_options_t * +cairo_font_options_copy (const cairo_font_options_t *original) +{ + cairo_font_options_t *options = malloc (sizeof (cairo_font_options_t)); + + if (!options) + return (cairo_font_options_t *)&cairo_font_options_nil; + + *options = *original; + + return options; +} + +/** + * cairo_font_options_destroy: + * @options: a #cairo_font_options_t + * + * Destroys a #cairo_font_options_t object created with with + * cairo_font_options_create() or cairo_font_options_copy(). + **/ +void +cairo_font_options_destroy (cairo_font_options_t *options) +{ + if (options == (cairo_font_options_t *)&cairo_font_options_nil) + return; + + free (options); +} + +/** + * cairo_font_options_status: + * @options: a #cairo_font_options_t + * + * Checks whether an error has previously occurred for this + * font options object + * + * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY + **/ +cairo_status_t +cairo_font_options_status (cairo_font_options_t *options) +{ + if (options == (cairo_font_options_t *)&cairo_font_options_nil) + return CAIRO_STATUS_NO_MEMORY; + else + return CAIRO_STATUS_SUCCESS; +} + +/** + * cairo_font_options_merge: + * @options: a #cairo_font_options_t + * @other: another #cairo_font_options_t + * + * Merges non-default options from @other into @options, replacing + * existing values. This operation can be thought of as somewhat + * similar to compositing @other onto @options with the operation + * of %CAIRO_OPERATION_OVER. + **/ +void +cairo_font_options_merge (cairo_font_options_t *options, + const cairo_font_options_t *other) +{ + if (options == (cairo_font_options_t *)&cairo_font_options_nil) + return; + + if (other->antialias != CAIRO_ANTIALIAS_DEFAULT) + options->antialias = other->antialias; + if (other->subpixel_order != CAIRO_SUBPIXEL_ORDER_DEFAULT) + options->subpixel_order = other->subpixel_order; + if (other->hint_style != CAIRO_HINT_STYLE_DEFAULT) + options->hint_style = other->hint_style; + if (other->hint_metrics != CAIRO_HINT_METRICS_DEFAULT) + options->hint_metrics = other->hint_metrics; +} + +/** + * cairo_font_options_equual: + * @options: a #cairo_font_options_t + * @other: another #cairo_font_options_t + * + * Compares two font options objects for equality. + * + * Return value: %TRUE if all fields of the two font options objects match + **/ +cairo_bool_t +cairo_font_options_equal (const cairo_font_options_t *options, + const cairo_font_options_t *other) +{ + return (options->antialias == other->antialias && + options->subpixel_order == other->subpixel_order && + options->hint_style == other->hint_style && + options->hint_metrics == other->hint_metrics); +} + +/** + * cairo_font_options_hash: + * @options: a #cairo_font_options_t + * + * Compute a hash for the font options object; this value will + * be useful when storing an object containing a cairo_font_options_t + * in a hash table. + * + * Return value: the hash value for the font options object. + * The return value can be cast to a 32-bit type if a + * 32-bit hash value is needed. + **/ +unsigned long +cairo_font_options_hash (const cairo_font_options_t *options) +{ + return ((options->antialias) | + (options->subpixel_order << 4) | + (options->hint_style << 8) | + (options->hint_metrics << 16)); +} + +/** + * cairo_font_options_set_antialias: + * @options: a #cairo_font_options_t + * @antialias: the new antialiasing mode + * + * Sets the antiliasing mode for the font options object. This + * specifies the type of antialiasing to do when rendering text. + **/ +void +cairo_font_options_set_antialias (cairo_font_options_t *options, + cairo_antialias_t antialias) +{ + if (options == (cairo_font_options_t *)&cairo_font_options_nil) + return; + + options->antialias = antialias; +} + +/** + * cairo_font_options_get_antialias: + * @options: a #cairo_font_options_t + * + * Gets the antialising mode for the font options object. + * + * Return value: the antialiasing mode + **/ +cairo_antialias_t +cairo_font_options_get_antialias (const cairo_font_options_t *options) +{ + return options->antialias; +} + +/** + * cairo_font_options_set_subpixel_order: + * @options: a #cairo_font_options_t + * @subpixel_order: the new subpixel order + * + * Sets the subpixel order for the font options object. The subpixel + * order specifies the order of color elements within each pixel on + * the display device when rendering with an antialiasing mode of + * %CAIRO_ANTIALIAS_SUBPIXEL. See the documentation for + * #cairo_subpixel_order_t for full details. + **/ +void +cairo_font_options_set_subpixel_order (cairo_font_options_t *options, + cairo_subpixel_order_t subpixel_order) +{ + if (options == (cairo_font_options_t *)&cairo_font_options_nil) + return; + + options->subpixel_order = subpixel_order; +} + +/** + * cairo_font_options_get_subpixel_order: + * @options: a #cairo_font_options_t + * + * Gets the subpixel order for the font options object. + * See the documentation for #cairo_subpixel_order_t for full details. + * + * Return value: the subpixel order for the font options object + **/ +cairo_subpixel_order_t +cairo_font_options_get_subpixel_order (const cairo_font_options_t *options) +{ + return options->subpixel_order; +} + +/** + * cairo_font_options_set_hint_style: + * @options: a #cairo_font_options_t + * @hint_style: the new hint style + * + * Sets the hint style for font outlines for the font options object. + * This controls whether to fit font outlines to the pixel grid, + * and if so, whether to optimize for fidelity or contrast. + * See the documentation for #cairo_hint_style_t for full details. + **/ +void +cairo_font_options_set_hint_style (cairo_font_options_t *options, + cairo_hint_style_t hint_style) +{ + if (options == (cairo_font_options_t *)&cairo_font_options_nil) + return; + + options->hint_style = hint_style; +} + +/** + * cairo_font_options_get_hint_style: + * @options: a #cairo_font_options_t + * + * Gets the hint style for font outlines for the font options object. + * See the documentation for #cairo_hint_style_t for full details. + * + * Return value: the hint style for the font options object + **/ +cairo_hint_style_t +cairo_font_options_get_hint_style (const cairo_font_options_t *options) +{ + return options->hint_style; +} + +/** + * cairo_font_options_set_hint_metrics: + * @options: a #cairo_font_options_t + * @hint_metrics: the new metrics hinting mode + * + * Sets the metrics hinting mode for the font options object. This + * controls whether metrics are quantized to integer values in + * device units. + * See the documentation for #cairo_hint_metrics_t for full details. + **/ +void +cairo_font_options_set_hint_metrics (cairo_font_options_t *options, + cairo_hint_metrics_t hint_metrics) +{ + if (options == (cairo_font_options_t *)&cairo_font_options_nil) + return; + + options->hint_metrics = hint_metrics; +} + +/** + * cairo_font_options_get_hint_metrics: + * @options: a #cairo_font_options_t + * + * Gets the metrics hinting mode for the font options object. + * See the documentation for #cairo_hint_metrics_t for full details. + * + * Return value: the metrics hinting mode for the font options object + **/ +cairo_hint_metrics_t +cairo_font_options_get_hint_metrics (const cairo_font_options_t *options) +{ + return options->hint_metrics; +} diff --git a/src/cairo-font.c b/src/cairo-font.c index a74cac453..c568e6584 100644 --- a/src/cairo-font.c +++ b/src/cairo-font.c @@ -355,17 +355,18 @@ _cairo_simple_font_face_destroy (void *abstract_face) } static cairo_status_t -_cairo_simple_font_face_create_font (void *abstract_face, - const cairo_matrix_t *font_matrix, - const cairo_matrix_t *ctm, - cairo_scaled_font_t **scaled_font) +_cairo_simple_font_face_create_font (void *abstract_face, + const cairo_matrix_t *font_matrix, + const cairo_matrix_t *ctm, + const cairo_font_options_t *options, + cairo_scaled_font_t **scaled_font) { const cairo_scaled_font_backend_t * backend = CAIRO_SCALED_FONT_BACKEND_DEFAULT; cairo_simple_font_face_t *simple_face = abstract_face; return backend->create (simple_face->family, simple_face->slant, simple_face->weight, - font_matrix, ctm, scaled_font); + font_matrix, ctm, options, scaled_font); } static const cairo_font_face_backend_t _cairo_simple_font_face_backend = { @@ -444,6 +445,7 @@ typedef struct { cairo_font_face_t *font_face; const cairo_matrix_t *font_matrix; const cairo_matrix_t *ctm; + cairo_font_options_t options; } cairo_font_cache_key_t; typedef struct { @@ -554,7 +556,9 @@ _cairo_font_cache_hash (void *cache, void *key) sizeof(double) * 4, hash); - return hash ^ (unsigned long)k->font_face; + return (hash ^ + (unsigned long)k->font_face ^ + cairo_font_options_hash (&k->options)); } static int @@ -573,7 +577,8 @@ _cairo_font_cache_keys_equal (void *cache, sizeof(double) * 4) == 0 && memcmp ((unsigned char *)(&a->ctm->xx), (unsigned char *)(&b->ctm->xx), - sizeof(double) * 4) == 0); + sizeof(double) * 4) == 0 && + cairo_font_options_equal (&a->options, &b->options)); } /* The cache lookup failed in the outer cache, so we pull @@ -614,6 +619,7 @@ _cairo_outer_font_cache_create_entry (void *cache, entry->key.font_face = entry->scaled_font->font_face; entry->key.font_matrix = &entry->scaled_font->font_matrix; entry->key.ctm = &entry->scaled_font->ctm; + entry->key.options = ((cairo_font_cache_key_t *) key)->options; *return_entry = entry; @@ -650,6 +656,7 @@ _cairo_inner_font_cache_create_entry (void *cache, status = k->font_face->backend->create_font (k->font_face, k->font_matrix, k->ctm, + &k->options, &entry->scaled_font); if (status) { free (entry); @@ -663,6 +670,7 @@ _cairo_inner_font_cache_create_entry (void *cache, entry->key.font_face = k->font_face; entry->key.font_matrix = &entry->scaled_font->font_matrix; entry->key.ctm = &entry->scaled_font->ctm; + entry->key.options = k->options; *return_entry = entry; @@ -712,6 +720,8 @@ static const cairo_cache_backend_t _cairo_inner_font_cache_backend = { * cairo_set_font_matrix(). * @ctm: user to device transformation matrix with which the font will * be used. + * @options: options to use when getting metrics for the font and + * rendering with it. * * Creates a #cairo_scaled_font_t object from a font face and matrices that * describe the size of the font and the environment in which it will @@ -721,9 +731,10 @@ static const cairo_cache_backend_t _cairo_inner_font_cache_backend = { * cairo_scaled_font_destroy() **/ cairo_scaled_font_t * -cairo_scaled_font_create (cairo_font_face_t *font_face, - const cairo_matrix_t *font_matrix, - const cairo_matrix_t *ctm) +cairo_scaled_font_create (cairo_font_face_t *font_face, + const cairo_matrix_t *font_matrix, + const cairo_matrix_t *ctm, + const cairo_font_options_t *options) { cairo_font_cache_entry_t *entry; cairo_font_cache_key_t key; @@ -733,6 +744,7 @@ cairo_scaled_font_create (cairo_font_face_t *font_face, key.font_face = font_face; key.font_matrix = font_matrix; key.ctm = ctm; + key.options = *options; _lock_global_font_cache (); cache = _get_outer_font_cache (); diff --git a/src/cairo-ft-font.c b/src/cairo-ft-font.c index 99776764b..680ab1548 100644 --- a/src/cairo-ft-font.c +++ b/src/cairo-ft-font.c @@ -51,6 +51,19 @@ #define DOUBLE_TO_16_16(d) ((FT_Fixed)((d) * 65536.0)) #define DOUBLE_FROM_16_16(t) ((double)(t) / 65536.0) +/* We pack some of our own information into the bits unused + * by FreeType's load flags. If FreeType ever uses up all + * the load flag bits, we'll have to do something else. + * (probably just store what we care about in load_flags + * then convert into FreeType terms. + */ +#define PRIVATE_FLAG_HINT_METRICS (0x01 << 24) +#define PRIVATE_FLAGS_MASK (0xff << 24) + + /* This is the max number of FT_face objects we keep open at once + */ + #define MAX_OPEN_FACES 10 + /* This is the max number of FT_face objects we keep open at once */ #define MAX_OPEN_FACES 10 @@ -551,6 +564,87 @@ _cairo_ft_unscaled_font_destroy (void *abstract_font) } } +/* Fills in val->image with an image surface created from @bitmap + */ +static cairo_status_t +_get_bitmap_surface (cairo_image_glyph_cache_entry_t *val, + FT_Bitmap *bitmap, + cairo_bool_t own_buffer) +{ + int width, height, stride; + unsigned char *data; + int i, j; + + width = bitmap->width; + height = bitmap->rows; + + if (width * height == 0) { + if (own_buffer && bitmap->buffer) + free (bitmap->buffer); + + val->image = NULL; + } else { + switch (bitmap->pixel_mode) { + case FT_PIXEL_MODE_MONO: + stride = (width + 3) & ~3; + data = calloc (stride * height, 1); + if (!data) + return CAIRO_STATUS_NO_MEMORY; + for (j = 0; j < height; j++) { + const unsigned char *p = bitmap->buffer + j * bitmap->pitch; + unsigned char *q = data + j * stride; + for (i = 0; i < width; i++) { + /* FreeType bitmaps are always stored MSB */ + unsigned char byte = p[i >> 3]; + unsigned char bit = 1 << (7 - (i % 8)); + + if (byte & bit) + q[i] = 0xff; + } + } + if (own_buffer) + free (bitmap->buffer); + break; + case FT_PIXEL_MODE_GRAY: + stride = bitmap->pitch; + if (own_buffer) { + data = bitmap->buffer; + } else { + data = malloc (stride * height); + if (!data) + return CAIRO_STATUS_NO_MEMORY; + memcpy (data, bitmap->buffer, stride * height); + } + break; + case FT_PIXEL_MODE_GRAY2: + case FT_PIXEL_MODE_GRAY4: + /* These could be triggered by very rare types of TrueType fonts */ + case FT_PIXEL_MODE_LCD: + case FT_PIXEL_MODE_LCD_V: + /* These should never be triggered unless we ask for them */ + default: + return CAIRO_STATUS_NO_MEMORY; + } + + val->image = (cairo_image_surface_t *) + cairo_image_surface_create_for_data (data, + CAIRO_FORMAT_A8, + width, height, stride); + if (val->image == NULL) { + free (data); + + return CAIRO_STATUS_NO_MEMORY; + } + + _cairo_image_surface_assume_ownership_of_data (val->image); + } + + val->size.width = width; + val->size.height = height; + + return CAIRO_STATUS_SUCCESS; +} + /* Converts an outline FT_GlyphSlot into an image * * This could go through _render_glyph_bitmap as well, letting @@ -586,17 +680,23 @@ _render_glyph_outline (FT_Face face, width = (unsigned int) ((cbox.xMax - cbox.xMin) >> 6); height = (unsigned int) ((cbox.yMax - cbox.yMin) >> 6); - stride = (width + 3) & -4; if (width * height == 0) { val->image = NULL; } else { - bitmap.pixel_mode = FT_PIXEL_MODE_GRAY; - bitmap.num_grays = 256; + if ((val->key.flags & FT_LOAD_MONOCHROME) != 0) { + bitmap.pixel_mode = FT_PIXEL_MODE_MONO; + bitmap.num_grays = 1; + stride = ((width + 31) & -32) >> 3; + } else { + bitmap.pixel_mode = FT_PIXEL_MODE_GRAY; + bitmap.num_grays = 256; + stride = (width + 3) & -4; + } + bitmap.pitch = stride; bitmap.width = width; bitmap.rows = height; - bitmap.pitch = stride; bitmap.buffer = calloc (1, stride * height); if (bitmap.buffer == NULL) { @@ -609,17 +709,10 @@ _render_glyph_outline (FT_Face face, free (bitmap.buffer); return CAIRO_STATUS_NO_MEMORY; } - - val->image = (cairo_image_surface_t *) - cairo_image_surface_create_for_data (bitmap.buffer, - CAIRO_FORMAT_A8, - width, height, stride); - if (val->image == NULL) { - free (bitmap.buffer); - return CAIRO_STATUS_NO_MEMORY; - } - - _cairo_image_surface_assume_ownership_of_data (val->image); + + status = _get_bitmap_surface (val, &bitmap, TRUE); + if (status) + return status; } /* @@ -627,8 +720,6 @@ _render_glyph_outline (FT_Face face, * Y coordinate of the control box needs to be negated. */ - val->size.width = (unsigned short) width; - val->size.height = (unsigned short) height; val->size.x = (short) (cbox.xMin >> 6); val->size.y = - (short) (cbox.yMax >> 6); @@ -655,12 +746,8 @@ _render_glyph_bitmap (FT_Face face, cairo_image_glyph_cache_entry_t *val) { FT_GlyphSlot glyphslot = face->glyph; - FT_Bitmap *bitmap; cairo_status_t status = CAIRO_STATUS_SUCCESS; - int width, height, stride; - unsigned char *data; FT_Error error; - int i, j; /* According to the FreeType docs, glyphslot->format could be * something other than FT_GLYPH_FORMAT_OUTLINE or @@ -673,64 +760,8 @@ _render_glyph_bitmap (FT_Face face, if (error) return CAIRO_STATUS_NO_MEMORY; - bitmap = &glyphslot->bitmap; + _get_bitmap_surface (val, &glyphslot->bitmap, FALSE); - width = bitmap->width; - height = bitmap->rows; - - if (width * height == 0) { - val->image = NULL; - } else { - switch (bitmap->pixel_mode) { - case FT_PIXEL_MODE_MONO: - stride = (width + 3) & ~3; - data = calloc (stride * height, 1); - if (!data) - return CAIRO_STATUS_NO_MEMORY; - for (j = 0; j < height; j++) { - const unsigned char *p = bitmap->buffer + j * bitmap->pitch; - unsigned char *q = data + j * stride; - for (i = 0; i < width; i++) { - /* FreeType bitmaps are always stored MSB */ - unsigned char byte = p[i >> 3]; - unsigned char bit = 1 << (7 - (i % 8)); - - if (byte & bit) - q[i] = 0xff; - } - } - break; - case FT_PIXEL_MODE_GRAY: - stride = bitmap->pitch; - data = malloc (stride * height); - if (!data) - return CAIRO_STATUS_NO_MEMORY; - memcpy (data, bitmap->buffer, stride * height); - break; - case FT_PIXEL_MODE_GRAY2: - case FT_PIXEL_MODE_GRAY4: - /* These could be triggered by very rare types of TrueType fonts */ - case FT_PIXEL_MODE_LCD: - case FT_PIXEL_MODE_LCD_V: - /* These should never be triggered unless we ask for them */ - default: - return CAIRO_STATUS_NO_MEMORY; - } - - val->image = (cairo_image_surface_t *) - cairo_image_surface_create_for_data (data, - CAIRO_FORMAT_A8, - width, height, stride); - if (val->image == NULL) { - free (data); - return CAIRO_STATUS_NO_MEMORY; - } - - _cairo_image_surface_assume_ownership_of_data (val->image); - } - - val->size.width = width; - val->size.height = height; val->size.x = - glyphslot->bitmap_left; val->size.y = - glyphslot->bitmap_top; @@ -875,7 +906,7 @@ _cairo_ft_unscaled_font_create_glyph (void *abstract_ _ft_unscaled_font_set_scale (unscaled, &val->key.scale); - if (FT_Load_Glyph (face, val->key.index, val->key.flags) != 0) { + if (FT_Load_Glyph (face, val->key.index, val->key.flags & ~PRIVATE_FLAGS_MASK) != 0) { status = CAIRO_STATUS_NO_MEMORY; goto FAIL; } @@ -886,22 +917,46 @@ _cairo_ft_unscaled_font_create_glyph (void *abstract_ * * Scale metrics back to glyph space from the scaled glyph space returned * by FreeType + * + * If we want hinted metrics but aren't asking for hinted glyphs from + * FreeType, then we need to do the metric hinting ourselves. */ - - val->extents.x_bearing = DOUBLE_FROM_26_6 (metrics->horiBearingX) / unscaled->x_scale; - val->extents.y_bearing = -DOUBLE_FROM_26_6 (metrics->horiBearingY) / unscaled->y_scale; - - val->extents.width = DOUBLE_FROM_26_6 (metrics->width) / unscaled->x_scale; - val->extents.height = DOUBLE_FROM_26_6 (metrics->height) / unscaled->y_scale; - - /* - * use untransformed advance values - * XXX uses horizontal advance only at present; - should provide FT_LOAD_VERTICAL_LAYOUT - */ - - val->extents.x_advance = DOUBLE_FROM_26_6 (face->glyph->metrics.horiAdvance) / unscaled->x_scale; - val->extents.y_advance = 0 / unscaled->y_scale; + + if ((val->key.flags & PRIVATE_FLAG_HINT_METRICS) && + (val->key.flags & FT_LOAD_NO_HINTING)) { + FT_Pos x1, x2; + FT_Pos y1, y2; + FT_Pos advance; + + x1 = (metrics->horiBearingX) & -64; + x2 = (metrics->horiBearingX + metrics->width + 63) & -64; + y1 = (metrics->horiBearingY) & -64; + y2 = (metrics->horiBearingY + metrics->height + 63) & -64; + + advance = ((metrics->horiAdvance + 32) & -64); + + val->extents.x_bearing = DOUBLE_FROM_26_6 (x1) / unscaled->x_scale; + val->extents.y_bearing = -DOUBLE_FROM_26_6 (y1) / unscaled->y_scale; + + val->extents.width = DOUBLE_FROM_26_6 (x2 - x1) / unscaled->x_scale; + val->extents.height = DOUBLE_FROM_26_6 (y2 - y1) / unscaled->y_scale; + + /* + * use untransformed advance values + * XXX uses horizontal advance only at present; should provide FT_LOAD_VERTICAL_LAYOUT + */ + val->extents.x_advance = DOUBLE_FROM_26_6 (advance) / unscaled->x_scale; + val->extents.y_advance = 0; + } else { + val->extents.x_bearing = DOUBLE_FROM_26_6 (metrics->horiBearingX) / unscaled->x_scale; + val->extents.y_bearing = -DOUBLE_FROM_26_6 (metrics->horiBearingY) / unscaled->y_scale; + + val->extents.width = DOUBLE_FROM_26_6 (metrics->width) / unscaled->x_scale; + val->extents.height = DOUBLE_FROM_26_6 (metrics->height) / unscaled->y_scale; + + val->extents.x_advance = DOUBLE_FROM_26_6 (face->glyph->metrics.horiAdvance) / unscaled->x_scale; + val->extents.y_advance = 0 / unscaled->y_scale; + } if (glyphslot->format == FT_GLYPH_FORMAT_OUTLINE) status = _render_glyph_outline (face, val); @@ -933,23 +988,19 @@ const cairo_unscaled_font_backend_t cairo_ft_unscaled_font_backend = { typedef struct { cairo_scaled_font_t base; int load_flags; + cairo_font_options_t options; ft_unscaled_font_t *unscaled; } cairo_ft_scaled_font_t; const cairo_scaled_font_backend_t cairo_ft_scaled_font_backend; -/* for compatibility with older freetype versions */ -#ifndef FT_LOAD_TARGET_MONO -#define FT_LOAD_TARGET_MONO FT_LOAD_MONOCHROME -#endif - /* The load flags passed to FT_Load_Glyph control aspects like hinting and * antialiasing. Here we compute them from the fields of a FcPattern. */ static int -_get_load_flags (FcPattern *pattern) +_get_pattern_load_flags (FcPattern *pattern) { - FcBool antialias, hinting, autohint; + FcBool antialias, vertical_layout, hinting, autohint; #ifdef FC_HINT_STYLE int hintstyle; #endif @@ -959,17 +1010,17 @@ _get_load_flags (FcPattern *pattern) if (FcPatternGetBool (pattern, FC_ANTIALIAS, 0, &antialias) != FcResultMatch) antialias = FcTrue; - + if (antialias) load_flags |= FT_LOAD_NO_BITMAP; else - load_flags |= FT_LOAD_TARGET_MONO; + load_flags |= FT_LOAD_MONOCHROME; /* disable hinting if requested */ if (FcPatternGetBool (pattern, FC_HINTING, 0, &hinting) != FcResultMatch) hinting = FcTrue; - + #ifdef FC_HINT_STYLE if (FcPatternGetInteger (pattern, FC_HINT_STYLE, 0, &hintstyle) != FcResultMatch) hintstyle = FC_HINT_FULL; @@ -977,20 +1028,26 @@ _get_load_flags (FcPattern *pattern) if (!hinting || hintstyle == FC_HINT_NONE) load_flags |= FT_LOAD_NO_HINTING; - switch (hintstyle) { - case FC_HINT_SLIGHT: - case FC_HINT_MEDIUM: - load_flags |= FT_LOAD_TARGET_LIGHT; - break; - default: - load_flags |= FT_LOAD_TARGET_NORMAL; - break; + if (antialias) { + switch (hintstyle) { + case FC_HINT_SLIGHT: + case FC_HINT_MEDIUM: + load_flags |= FT_LOAD_TARGET_LIGHT; + break; + default: + load_flags |= FT_LOAD_TARGET_NORMAL; + break; + } + } else { +#ifdef FT_LOAD_TARGET_MONO + load_flags |= FT_LOAD_TARGET_MONO; +#endif } #else /* !FC_HINT_STYLE */ if (!hinting) load_flags |= FT_LOAD_NO_HINTING; #endif /* FC_FHINT_STYLE */ - + /* force autohinting if requested */ if (FcPatternGetBool (pattern, FC_AUTOHINT, 0, &autohint) != FcResultMatch) @@ -999,14 +1056,51 @@ _get_load_flags (FcPattern *pattern) if (autohint) load_flags |= FT_LOAD_FORCE_AUTOHINT; + if (FcPatternGetBool (pattern, + FC_VERTICAL_LAYOUT, 0, &vertical_layout) != FcResultMatch) + vertical_layout = FcFalse; + + if (vertical_layout) + load_flags |= FT_LOAD_VERTICAL_LAYOUT; + + return load_flags; +} + +static int +_get_options_load_flags (const cairo_font_options_t *options) +{ + int load_flags = 0; + + /* disable antialiasing if requested */ + if (options->antialias == CAIRO_ANTIALIAS_NONE) + load_flags |= FT_LOAD_TARGET_MONO; + else + load_flags |= FT_LOAD_NO_BITMAP; + + /* disable hinting if requested */ + switch (options->hint_style) { + case CAIRO_HINT_STYLE_NONE: + load_flags |= FT_LOAD_NO_HINTING; + break; + case CAIRO_HINT_STYLE_SLIGHT: + case CAIRO_HINT_STYLE_MEDIUM: + load_flags |= FT_LOAD_TARGET_LIGHT; + break; + case CAIRO_HINT_STYLE_FULL: + default: + load_flags |= FT_LOAD_TARGET_NORMAL; + break; + } + return load_flags; } static cairo_scaled_font_t * -_ft_scaled_font_create (ft_unscaled_font_t *unscaled, - int load_flags, - const cairo_matrix_t *font_matrix, - const cairo_matrix_t *ctm) +_ft_scaled_font_create (ft_unscaled_font_t *unscaled, + const cairo_matrix_t *font_matrix, + const cairo_matrix_t *ctm, + const cairo_font_options_t *options, + int load_flags) { cairo_ft_scaled_font_t *f = NULL; @@ -1017,6 +1111,11 @@ _ft_scaled_font_create (ft_unscaled_font_t *unscaled, f->unscaled = unscaled; _cairo_unscaled_font_reference (&unscaled->base); + f->options = *options; + + if (options->hint_metrics != CAIRO_HINT_METRICS_OFF) + load_flags |= PRIVATE_FLAG_HINT_METRICS; + f->load_flags = load_flags; _cairo_scaled_font_init (&f->base, font_matrix, ctm, &cairo_ft_scaled_font_backend); @@ -1031,12 +1130,13 @@ _cairo_scaled_font_is_ft (cairo_scaled_font_t *scaled_font) } static cairo_status_t -_cairo_ft_scaled_font_create (const char *family, - cairo_font_slant_t slant, - cairo_font_weight_t weight, - const cairo_matrix_t *font_matrix, - const cairo_matrix_t *ctm, - cairo_scaled_font_t **font) +_cairo_ft_scaled_font_create (const char *family, + cairo_font_slant_t slant, + cairo_font_weight_t weight, + const cairo_matrix_t *font_matrix, + const cairo_matrix_t *ctm, + const cairo_font_options_t *options, + cairo_scaled_font_t **font) { FcPattern *pattern, *resolved; ft_unscaled_font_t *unscaled; @@ -1089,6 +1189,7 @@ _cairo_ft_scaled_font_create (const char *family, FcPatternAddInteger (pattern, FC_PIXEL_SIZE, sf.y_scale); FcConfigSubstitute (NULL, pattern, FcMatchPattern); + cairo_ft_font_options_substitute (options, pattern); FcDefaultSubstitute (pattern); resolved = FcFontMatch (NULL, pattern, &result); @@ -1099,8 +1200,9 @@ _cairo_ft_scaled_font_create (const char *family, if (!unscaled) goto FREE_RESOLVED; - new_font = _ft_scaled_font_create (unscaled, _get_load_flags (pattern), - font_matrix, ctm); + new_font = _ft_scaled_font_create (unscaled, + font_matrix, ctm, + options, _get_pattern_load_flags (pattern)); _cairo_unscaled_font_destroy (&unscaled->base); FcPatternDestroy (resolved); @@ -1230,15 +1332,24 @@ _cairo_ft_scaled_font_font_extents (void *abstract_font, metrics = &face->size->metrics; _ft_unscaled_font_set_scale (scaled_font->unscaled, &scaled_font->base.scale); - + /* * Get to unscaled metrics so that the upper level can get back to * user space */ - extents->ascent = DOUBLE_FROM_26_6(metrics->ascender) / scaled_font->unscaled->y_scale; - extents->descent = DOUBLE_FROM_26_6(- metrics->descender) / scaled_font->unscaled->y_scale; - extents->height = DOUBLE_FROM_26_6(metrics->height) / scaled_font->unscaled->y_scale; - extents->max_x_advance = DOUBLE_FROM_26_6(metrics->max_advance) / scaled_font->unscaled->x_scale; + if (scaled_font->options.hint_metrics != CAIRO_HINT_METRICS_OFF) { + extents->ascent = DOUBLE_FROM_26_6(metrics->ascender) / scaled_font->unscaled->y_scale; + extents->descent = DOUBLE_FROM_26_6(- metrics->descender) / scaled_font->unscaled->y_scale; + extents->height = DOUBLE_FROM_26_6(metrics->height) / scaled_font->unscaled->y_scale; + extents->max_x_advance = DOUBLE_FROM_26_6(metrics->max_advance) / scaled_font->unscaled->x_scale; + } else { + double scale = face->units_per_EM; + + extents->ascent = face->ascender / scale; + extents->descent = - face->descender / scale; + extents->height = face->height / scale; + extents->max_x_advance = face->max_advance_width / scale; + } /* FIXME: this doesn't do vertical layout atm. */ extents->max_y_advance = 0.0; @@ -1688,16 +1799,32 @@ _ft_font_face_destroy (void *abstract_face) } static cairo_status_t -_ft_font_face_create_font (void *abstract_face, - const cairo_matrix_t *font_matrix, - const cairo_matrix_t *ctm, - cairo_scaled_font_t **scaled_font) +_ft_font_face_create_font (void *abstract_face, + const cairo_matrix_t *font_matrix, + const cairo_matrix_t *ctm, + const cairo_font_options_t *options, + cairo_scaled_font_t **scaled_font) { ft_font_face_t *font_face = abstract_face; + int load_flags; + + /* The handling of font options is different depending on how the + * font face was created. When the user creates a font face with + * cairo_ft_font_face_create_for_ft_face(), then the load flags + * passed in augment the load flags for the options. But for + * cairo_ft_font_face_create_for_pattern(), the load flags are + * derived from a pattern where the user has called + * cairo_ft_font_options_substitute(), so *just* use those load + * flags and ignore the options. + */ + if (font_face->unscaled->from_face) + load_flags = _get_options_load_flags (options) | font_face->load_flags; + else + load_flags = font_face->load_flags; *scaled_font = _ft_scaled_font_create (font_face->unscaled, - font_face->load_flags, - font_matrix, ctm); + font_matrix, ctm, + options, load_flags); if (*scaled_font) return CAIRO_STATUS_SUCCESS; else @@ -1743,6 +1870,92 @@ _ft_font_face_create (ft_unscaled_font_t *unscaled, /* implement the platform-specific interface */ +/** + * cairo_ft_font_options_substitute: + * @options: a #cairo_font_options_t object + * + * Add options to a #FcPattern based on a #cairo_font_options_t font + * options object. Options that are already in the pattern, are not + * overriden, so you should call this function after calling FcConfigSubstitute() + * (the user's settings should override options based on the surface type), + * but before calling FcDefaultSubstitute(). + **/ +void +cairo_ft_font_options_substitute (const cairo_font_options_t *options, + FcPattern *pattern) +{ + FcValue v; + + if (options->antialias != CAIRO_ANTIALIAS_DEFAULT) + { + if (FcPatternGet (pattern, FC_ANTIALIAS, 0, &v) == FcResultNoMatch) + { + FcPatternAddBool (pattern, FC_ANTIALIAS, options->antialias != CAIRO_ANTIALIAS_NONE); + } + } + + if (options->antialias != CAIRO_ANTIALIAS_DEFAULT) + { + if (FcPatternGet (pattern, FC_RGBA, 0, &v) == FcResultNoMatch) + { + int rgba; + + if (options->antialias == CAIRO_ANTIALIAS_SUBPIXEL) { + switch (options->subpixel_order) { + case CAIRO_SUBPIXEL_ORDER_DEFAULT: + case CAIRO_SUBPIXEL_ORDER_RGB: + default: + rgba = FC_RGBA_RGB; + break; + case CAIRO_SUBPIXEL_ORDER_BGR: + rgba = FC_RGBA_BGR; + break; + case CAIRO_SUBPIXEL_ORDER_VRGB: + rgba = FC_RGBA_VRGB; + break; + case CAIRO_SUBPIXEL_ORDER_VBGR: + rgba = FC_RGBA_VBGR; + break; + } + } else { + rgba = FC_RGBA_NONE; + } + + FcPatternAddInteger (pattern, FC_RGBA, rgba); + } + } + + if (options->hint_style != CAIRO_HINT_STYLE_DEFAULT) + { + if (FcPatternGet (pattern, FC_HINTING, 0, &v) == FcResultNoMatch) + { + FcPatternAddBool (pattern, FC_HINTING, options->hint_style != CAIRO_HINT_STYLE_NONE); + } + +#ifdef FC_HINT_STYLE + if (FcPatternGet (pattern, FC_HINT_STYLE, 0, &v) == FcResultNoMatch) + { + int hint_style; + + switch (options->hint_style) { + case CAIRO_HINT_STYLE_SLIGHT: + hint_style = FC_HINT_SLIGHT; + break; + case CAIRO_HINT_STYLE_MEDIUM: + hint_style = FC_HINT_MEDIUM; + break; + case CAIRO_HINT_STYLE_FULL: + default: + hint_style = FC_HINT_FULL; + break; + } + + FcPatternAddInteger (pattern, FC_HINT_STYLE, hint_style); + } +#endif + } +} + /** * cairo_ft_font_face_create_for_pattern: * @pattern: A fully resolved fontconfig @@ -1759,6 +1972,12 @@ _ft_font_face_create (ft_unscaled_font_t *unscaled, * returned from cairo_font_create() is also for the FreeType backend * and can be used with functions such as cairo_ft_font_lock_face(). * + * Font rendering options are representated both here and when you + * call cairo_scaled_font_create(). Font options that have a representation + * in a #FcPattern must be passed in here; to modify #FcPattern + * appropriately to reflect the options in a #cairo_font_options_t, call + * cairo_ft_font_options_substitute(). + * * Return value: a newly created #cairo_font_face_t. Free with * cairo_font_face_destroy() when you are done using it. **/ @@ -1772,7 +1991,7 @@ cairo_ft_font_face_create_for_pattern (FcPattern *pattern) if (unscaled == NULL) return NULL; - font_face = _ft_font_face_create (unscaled, _get_load_flags (pattern)); + font_face = _ft_font_face_create (unscaled, _get_pattern_load_flags (pattern)); _cairo_unscaled_font_destroy (&unscaled->base); return font_face; @@ -1786,10 +2005,13 @@ cairo_ft_font_face_create_for_pattern (FcPattern *pattern) * internally to Cairo, the best way to determine when it * is safe to free the face is to pass a * #cairo_destroy_func_t to cairo_font_face_set_user_data() - * @load_flags: The flags to pass to FT_Load_Glyph when loading - * glyphs from the font. These flags control aspects of - * rendering such as hinting and antialiasing. See the FreeType - * docs for full information. + * @load_flags: flags to pass to FT_Load_Glyph when loading + * glyphs from the font. These flags are OR'ed together with + * the flags derived from the #cairo_font_options_t passed + * to cairo_scaled_font_create(), so only a few values such + * as %FT_LOAD_VERTICAL_LAYOUT, and %FT_LOAD_FORCE_AUTOHINT + * are useful. You should not pass any of the flags affecting + * the load target, such as %FT_LOAD_TARGET_LIGHT. * * Creates a new font face for the FreeType font backend from a pre-opened * FreeType face. This font can then be used with diff --git a/src/cairo-ft.h b/src/cairo-ft.h index 4e8b8bcdb..3a065c02e 100644 --- a/src/cairo-ft.h +++ b/src/cairo-ft.h @@ -52,6 +52,9 @@ CAIRO_BEGIN_DECLS cairo_font_face_t * cairo_ft_font_face_create_for_pattern (FcPattern *pattern); +void cairo_ft_font_options_substitute (const cairo_font_options_t *options, + FcPattern *pattern); + cairo_font_face_t * cairo_ft_font_face_create_for_ft_face (FT_Face face, int load_flags); diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c index ed6210cfb..86223d846 100644 --- a/src/cairo-gstate.c +++ b/src/cairo-gstate.c @@ -1974,6 +1974,7 @@ static cairo_status_t _cairo_gstate_ensure_font (cairo_gstate_t *gstate) { cairo_status_t status; + cairo_font_options_t options; if (gstate->scaled_font) return CAIRO_STATUS_SUCCESS; @@ -1982,9 +1983,11 @@ _cairo_gstate_ensure_font (cairo_gstate_t *gstate) if (status) return status; + cairo_surface_get_font_options (gstate->target, &options); gstate->scaled_font = cairo_scaled_font_create (gstate->font_face, &gstate->font_matrix, - &gstate->ctm); + &gstate->ctm, + &options); if (!gstate->scaled_font) return CAIRO_STATUS_NO_MEMORY; diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c index 1c5026ce3..2b4b6ad29 100644 --- a/src/cairo-pdf-surface.c +++ b/src/cairo-pdf-surface.c @@ -1379,6 +1379,16 @@ _cairo_pdf_surface_intersect_clip_path (void *dst, return status; } +static void +_cairo_pdf_surface_get_font_options (void *abstract_surface, + cairo_font_options_t *options) +{ + _cairo_font_options_init_default (options); + + cairo_font_options_set_hint_style (options, CAIRO_HINT_STYLE_NONE); + cairo_font_options_set_hint_metrics (options, CAIRO_HINT_METRICS_OFF); +} + static const cairo_surface_backend_t cairo_pdf_surface_backend = { _cairo_pdf_surface_create_similar, _cairo_pdf_surface_finish, @@ -1396,7 +1406,8 @@ static const cairo_surface_backend_t cairo_pdf_surface_backend = { _cairo_pdf_surface_intersect_clip_path, _cairo_pdf_surface_get_extents, _cairo_pdf_surface_show_glyphs, - _cairo_pdf_surface_fill_path + _cairo_pdf_surface_fill_path, + _cairo_pdf_surface_get_font_options }; static cairo_pdf_document_t * diff --git a/src/cairo-surface.c b/src/cairo-surface.c index 75f887c1f..7714fcc25 100644 --- a/src/cairo-surface.c +++ b/src/cairo-surface.c @@ -256,6 +256,33 @@ cairo_surface_set_user_data (cairo_surface_t *surface, key, user_data, destroy); } +/** + * cairo_surface_get_font_options: + * @surface: a #cairo_surface_t + * @options: a #cairo_font_options_t object into which to store + * the retrieved options. All existing values are overwritten + * + * Retrieves the default font rendering options for the surface. + * This allows display surfaces to report the correct subpixel order + * for rendering on them, print surfaces to disable hinting of + * metrics and so forth. The result can then be used with + * cairo_scaled_font_create(). + **/ +void +cairo_surface_get_font_options (cairo_surface_t *surface, + cairo_font_options_t *options) +{ + + if (!surface->finished && surface->backend->get_font_options) { + surface->backend->get_font_options (surface, options); + } else { + options->antialias = CAIRO_ANTIALIAS_DEFAULT; + options->subpixel_order = CAIRO_SUBPIXEL_ORDER_DEFAULT; + options->hint_style = CAIRO_HINT_STYLE_DEFAULT; + options->hint_metrics = CAIRO_HINT_METRICS_DEFAULT; + } +} + /** * cairo_surface_set_device_offset: * @surface: a #cairo_surface_t diff --git a/src/cairo-win32-font.c b/src/cairo-win32-font.c index 385297ee2..5493650eb 100644 --- a/src/cairo-win32-font.c +++ b/src/cairo-win32-font.c @@ -55,6 +55,7 @@ typedef struct { cairo_scaled_font_t base; LOGFONTW logfont; + cairo_font_options_t options; BYTE quality; @@ -162,6 +163,24 @@ _compute_transform (cairo_win32_scaled_font_t *scaled_font, cairo_matrix_init_identity (&scaled_font->device_to_logical); } +static cairo_bool_t +_have_cleartype_quality (void) +{ + OSVERSIONINFO version_info; + + version_info.dwOSVersionInfoSize = sizeof (OSVERSIONINFO); + + if (!GetVersionEx (&version_info)) { + _cairo_win32_print_gdi_error ("_have_cleartype_quality"); + return FALSE; + } + + return (version_info.dwMajorVersion > 5 || + (version_info.dwMajorVersion == 5 && + version_info.dwMinorVersion >= 1)); /* XP or newer */ +} + + static BYTE _get_system_quality (void) { @@ -169,28 +188,15 @@ _get_system_quality (void) if (!SystemParametersInfo (SPI_GETFONTSMOOTHING, 0, &font_smoothing, 0)) { _cairo_win32_print_gdi_error ("_get_system_quality"); - return FALSE; + return DEFAULT_QUALITY; } if (font_smoothing) { - OSVERSIONINFO version_info; - - version_info.dwOSVersionInfoSize = sizeof (OSVERSIONINFO); - - if (!GetVersionEx (&version_info)) { - _cairo_win32_print_gdi_error ("_get_system_quality"); - return FALSE; - } - - if (version_info.dwMajorVersion > 5 || - (version_info.dwMajorVersion == 5 && - version_info.dwMinorVersion >= 1)) { /* XP or newer */ - UINT smoothing_type; - + if (_have_cleartype_quality ()) { if (!SystemParametersInfo (SPI_GETFONTSMOOTHINGTYPE, 0, &smoothing_type, 0)) { _cairo_win32_print_gdi_error ("_get_system_quality"); - return FALSE; + return DEFAULT_QUALITY; } if (smoothing_type == FE_FONTSMOOTHINGCLEARTYPE) @@ -204,9 +210,10 @@ _get_system_quality (void) } static cairo_scaled_font_t * -_win32_scaled_font_create (LOGFONTW *logfont, - const cairo_matrix_t *font_matrix, - const cairo_matrix_t *ctm) +_win32_scaled_font_create (LOGFONTW *logfont, + const cairo_matrix_t *font_matrix, + const cairo_matrix_t *ctm, + const cairo_font_options_t *options) { cairo_win32_scaled_font_t *f; cairo_matrix_t scale; @@ -216,7 +223,35 @@ _win32_scaled_font_create (LOGFONTW *logfont, return NULL; f->logfont = *logfont; - f->quality = _get_system_quality (); + f->options = *options; + + /* We don't have any control over the hinting style or subpixel + * order in the Win32 font API, so we ignore those parts of + * cairo_font_options_t. We use the 'antialias' field to set + * the 'quality'. + * + * XXX: The other option we could pay attention to, but don't + * here is the hint_metrics options. + */ + if (options->antialias == CAIRO_ANTIALIAS_DEFAULT) + f->quality = _get_system_quality (); + else { + switch (options->antialias) { + case CAIRO_ANTIALIAS_NONE: + f->quality = NONANTIALIASED_QUALITY; + break; + case CAIRO_ANTIALIAS_GRAY: + f->quality = ANTIALIASED_QUALITY; + break; + case CAIRO_ANTIALIAS_SUBPIXEL: + if (_have_cleartype_quality ()) + f->quality = CLEARTYPE_QUALITY; + else + f->quality = ANTIALIASED_QUALITY; + break; + } + } + f->em_square = 0; f->scaled_hfont = NULL; f->unscaled_hfont = NULL; @@ -390,12 +425,13 @@ _cairo_win32_scaled_font_done_unscaled_font (cairo_scaled_font_t *scaled_font) /* implement the font backend interface */ static cairo_status_t -_cairo_win32_scaled_font_create (const char *family, - cairo_font_slant_t slant, - cairo_font_weight_t weight, - const cairo_matrix_t *font_matrix, - const cairo_matrix_t *ctm, - cairo_scaled_font_t **scaled_font_out) +_cairo_win32_scaled_font_create (const char *family, + cairo_font_slant_t slant, + cairo_font_weight_t weight, + const cairo_matrix_t *font_matrix, + const cairo_matrix_t *ctm, + const cairo_font_options_t *options, + cairo_scaled_font_t **scaled_font_out) { LOGFONTW logfont; cairo_scaled_font_t *scaled_font; @@ -456,7 +492,7 @@ _cairo_win32_scaled_font_create (const char *family, if (!logfont.lfFaceName) return CAIRO_STATUS_NO_MEMORY; - scaled_font = _win32_scaled_font_create (&logfont, font_matrix, ctm); + scaled_font = _win32_scaled_font_create (&logfont, font_matrix, ctm, options); if (!scaled_font) return CAIRO_STATUS_NO_MEMORY; @@ -1262,15 +1298,16 @@ _cairo_win32_font_face_destroy (void *abstract_face) } static cairo_status_t -_cairo_win32_font_face_create_font (void *abstract_face, - const cairo_matrix_t *font_matrix, - const cairo_matrix_t *ctm, - cairo_scaled_font_t **font) +_cairo_win32_font_face_create_font (void *abstract_face, + const cairo_matrix_t *font_matrix, + const cairo_matrix_t *ctm, + const cairo_font_options_t *options, + cairo_scaled_font_t **font) { cairo_win32_font_face_t *font_face = abstract_face; *font = _win32_scaled_font_create (&font_face->logfont, - font_matrix, ctm); + font_matrix, ctm, options); if (*font) return CAIRO_STATUS_SUCCESS; else diff --git a/src/cairo-xlib-private.h b/src/cairo-xlib-private.h new file mode 100644 index 000000000..ad8af4338 --- /dev/null +++ b/src/cairo-xlib-private.h @@ -0,0 +1,54 @@ +/* Cairo - a vector graphics library with display and print output + * + * Copyright © 2005 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + */ + +#ifndef CAIRO_XLIB_PRIVATE_H +#define CAIRO_XLIB_PRIVATE_H + +#include "cairoint.h" +#include "cairo-xlib.h" + +typedef struct _cairo_xlib_screen_info cairo_xlib_screen_info_t; + +struct _cairo_xlib_screen_info { + cairo_xlib_screen_info_t *next; + + Display *display; + int screen; + cairo_bool_t has_render; + + cairo_font_options_t font_options; +}; + +cairo_private cairo_xlib_screen_info_t * +_cairo_xlib_screen_info_get (Display *display, int screen); + +#endif /* CAIRO_XLIB_PRIVATE_H */ diff --git a/src/cairo-xlib-screen.c b/src/cairo-xlib-screen.c new file mode 100644 index 000000000..3300b182b --- /dev/null +++ b/src/cairo-xlib-screen.c @@ -0,0 +1,345 @@ +/* Cairo - a vector graphics library with display and print output + * + * Copyright © 2005 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Partially on code from xftdpy.c + * + * Copyright © 2000 Keith Packard + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of Keith Packard not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Keith Packard makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +#include +#include + +#include "cairo-xlib-private.h" + +#include + +#include /* For XESetCloseDisplay */ +#include + +static int +parse_boolean (const char *v) +{ + char c0, c1; + + c0 = *v; + if (c0 == 't' || c0 == 'T' || c0 == 'y' || c0 == 'Y' || c0 == '1') + return 1; + if (c0 == 'f' || c0 == 'F' || c0 == 'n' || c0 == 'N' || c0 == '0') + return 0; + if (c0 == 'o') + { + c1 = v[1]; + if (c1 == 'n' || c1 == 'N') + return 1; + if (c1 == 'f' || c1 == 'F') + return 0; + } + + return -1; +} + +static cairo_bool_t +get_boolean_default (Display *dpy, + const char *option, + cairo_bool_t *value) +{ + char *v; + int i; + + v = XGetDefault (dpy, "Xft", option); + if (v) { + i = parse_boolean (v); + if (i >= 0) { + *value = i; + return TRUE; + } + } + + return FALSE; +} + +static cairo_bool_t +get_integer_default (Display *dpy, + const char *option, + int *value) +{ + int i; + char *v, *e; + + v = XGetDefault (dpy, "Xft", option); + if (v) { + if (FcNameConstant ((FcChar8 *) v, value)) + return TRUE; + + i = strtol (v, &e, 0); + if (e != v) + return TRUE; + } + + return FALSE; +} + +/* Old versions of fontconfig didn't have these options */ +#ifndef FC_HINT_NONE +#define FC_HINT_NONE 0 +#define FC_HINT_SLIGHT 1 +#define FC_HINT_MEDIUM 2 +#define FC_HINT_FULL 3 +#endif + +static void +_cairo_xlib_init_screen_font_options (cairo_xlib_screen_info_t *info) +{ + cairo_bool_t xft_hinting; + cairo_bool_t xft_antialias; + int xft_hintstyle; + int xft_rgba; + cairo_antialias_t antialias; + cairo_subpixel_order_t subpixel_order; + cairo_hint_style_t hint_style; + + if (!get_boolean_default (info->display, "antialias", &xft_antialias)) + xft_antialias = TRUE; + + if (!get_boolean_default (info->display, "hinting", &xft_hinting)) + xft_hinting = TRUE; + + if (!get_integer_default (info->display, "hintstyle", &xft_hintstyle)) + xft_hintstyle = FC_HINT_FULL; + + if (!get_integer_default (info->display, "rgba", &xft_rgba)) + { + xft_rgba = FC_RGBA_UNKNOWN; + +#if RENDER_MAJOR > 0 || RENDER_MINOR >= 6 + if (info->has_render) + { + int render_order = XRenderQuerySubpixelOrder (info->display, info->screen); + + switch (render_order) + { + default: + case SubPixelUnknown: + xft_rgba = FC_RGBA_UNKNOWN; + break; + case SubPixelHorizontalRGB: + xft_rgba = FC_RGBA_RGB; + break; + case SubPixelHorizontalBGR: + xft_rgba = FC_RGBA_BGR; + break; + case SubPixelVerticalRGB: + xft_rgba = FC_RGBA_VRGB; + break; + case SubPixelVerticalBGR: + xft_rgba = FC_RGBA_VBGR; + break; + case SubPixelNone: + xft_rgba = FC_RGBA_NONE; + break; + } + } +#endif + } + + if (xft_hinting) { + switch (xft_hintstyle) { + case FC_HINT_NONE: + hint_style = CAIRO_HINT_STYLE_NONE; + break; + case FC_HINT_SLIGHT: + hint_style = CAIRO_HINT_STYLE_SLIGHT; + break; + case FC_HINT_MEDIUM: + hint_style = CAIRO_HINT_STYLE_MEDIUM; + break; + case FC_HINT_FULL: + hint_style = CAIRO_HINT_STYLE_FULL; + break; + default: + hint_style = CAIRO_HINT_STYLE_DEFAULT; + } + } else { + hint_style = CAIRO_HINT_STYLE_NONE; + } + + switch (xft_rgba) { + case FC_RGBA_RGB: + subpixel_order = CAIRO_SUBPIXEL_ORDER_RGB; + break; + case FC_RGBA_BGR: + subpixel_order = CAIRO_SUBPIXEL_ORDER_BGR; + break; + case FC_RGBA_VRGB: + subpixel_order = CAIRO_SUBPIXEL_ORDER_VRGB; + break; + case FC_RGBA_VBGR: + subpixel_order = CAIRO_SUBPIXEL_ORDER_VBGR; + break; + case FC_RGBA_UNKNOWN: + case FC_RGBA_NONE: + default: + subpixel_order = CAIRO_SUBPIXEL_ORDER_DEFAULT; + } + + if (xft_antialias) { + if (subpixel_order != CAIRO_SUBPIXEL_ORDER_DEFAULT) + antialias = CAIRO_ANTIALIAS_GRAY; + else + antialias = CAIRO_ANTIALIAS_SUBPIXEL; + } else { + antialias = CAIRO_ANTIALIAS_NONE; + } + + _cairo_font_options_init_default (&info->font_options); + cairo_font_options_set_hint_style (&info->font_options, hint_style); + cairo_font_options_set_antialias (&info->font_options, antialias); + cairo_font_options_set_subpixel_order (&info->font_options, subpixel_order); +} + +CAIRO_MUTEX_DECLARE(_xlib_screen_mutex); + +static cairo_xlib_screen_info_t *_cairo_xlib_screen_list; + +static int +_cairo_xlib_close_display (Display *dpy, XExtCodes *codes) +{ + cairo_xlib_screen_info_t *info; + cairo_xlib_screen_info_t **prev; + + /* + * Unhook from the global list + */ + CAIRO_MUTEX_LOCK (_xlib_screen_mutex); + + for (prev = &_cairo_xlib_screen_list; (info = *prev); prev = &(*prev)->next) { + if (info->display == dpy) { + *prev = info->next; + free (info); + if (!*prev) + break; + } + } + CAIRO_MUTEX_UNLOCK (_xlib_screen_mutex); + + return 0; +} + + +cairo_private cairo_xlib_screen_info_t * +_cairo_xlib_screen_info_get (Display *dpy, int screen) +{ + cairo_xlib_screen_info_t *info; + cairo_xlib_screen_info_t **prev; + int event_base, error_base; + XExtCodes *codes; + cairo_bool_t seen_display = FALSE; + + /* There is an apparent deadlock between this mutex and the + * mutex for the display, but it's actually safe. For the + * app to call XCloseDisplay() while any other thread is + * inside this function would be an error in the logic + * app, and the CloseDisplay hook is the only other place we + * acquire this mutex. + */ + CAIRO_MUTEX_LOCK (_xlib_screen_mutex); + + for (prev = &_cairo_xlib_screen_list; (info = *prev); prev = &(*prev)->next) + { + if (info->display == dpy) { + seen_display = TRUE; + if (info->screen == screen) + { + /* + * MRU the list + */ + if (prev != &_cairo_xlib_screen_list) + { + *prev = info->next; + info->next = _cairo_xlib_screen_list; + _cairo_xlib_screen_list = info; + } + break; + } + } + } + + if (info) + goto out; + + info = malloc (sizeof (cairo_xlib_screen_info_t)); + if (!info) + goto out; + + if (!seen_display) { + codes = XAddExtension (dpy); + if (!codes) { + free (info); + info = NULL; + goto out; + } + + XESetCloseDisplay (dpy, codes->extension, _cairo_xlib_close_display); + } + + info->display = dpy; + info->screen = screen; + info->has_render = (XRenderQueryExtension (dpy, &event_base, &error_base) && + (XRenderFindVisualFormat (dpy, DefaultVisual (dpy, DefaultScreen (dpy))) != 0)); + + _cairo_xlib_init_screen_font_options (info); + + info->next = _cairo_xlib_screen_list; + _cairo_xlib_screen_list = info; + + out: + CAIRO_MUTEX_UNLOCK (_xlib_screen_mutex); + + return info; +} + diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c index 83553140e..1d579955d 100644 --- a/src/cairo-xlib-surface.c +++ b/src/cairo-xlib-surface.c @@ -38,6 +38,7 @@ #include "cairo-xlib.h" #include "cairo-xlib-xrender.h" #include "cairo-xlib-test.h" +#include "cairo-xlib-private.h" #include /* Xlib doesn't define a typedef, so define one ourselves */ @@ -70,6 +71,8 @@ struct _cairo_xlib_surface { cairo_surface_t base; Display *dpy; + cairo_xlib_screen_info_t *screen_info; + GC gc; Drawable drawable; Screen *screen; @@ -1321,6 +1324,15 @@ _cairo_xlib_surface_get_extents (void *abstract_surface, return CAIRO_STATUS_SUCCESS; } +static void +_cairo_xlib_surface_get_font_options (void *abstract_surface, + cairo_font_options_t *options) +{ + cairo_xlib_surface_t *surface = abstract_surface; + + *options = surface->screen_info->font_options; +} + static cairo_int_status_t _cairo_xlib_surface_show_glyphs (cairo_scaled_font_t *scaled_font, cairo_operator_t operator, @@ -1351,7 +1363,9 @@ static const cairo_surface_backend_t cairo_xlib_surface_backend = { _cairo_xlib_surface_set_clip_region, NULL, /* intersect_clip_path */ _cairo_xlib_surface_get_extents, - _cairo_xlib_surface_show_glyphs + _cairo_xlib_surface_show_glyphs, + NULL, /* fill_path */ + _cairo_xlib_surface_get_font_options }; /** @@ -1379,6 +1393,11 @@ _cairo_xlib_surface_create_internal (Display *dpy, int depth) { cairo_xlib_surface_t *surface; + cairo_xlib_screen_info_t *screen_info; + + screen_info = _cairo_xlib_screen_info_get (dpy, DefaultScreen (dpy)); + if (!screen_info) + return NULL; surface = malloc (sizeof (cairo_xlib_surface_t)); if (surface == NULL) @@ -1387,6 +1406,7 @@ _cairo_xlib_surface_create_internal (Display *dpy, _cairo_surface_init (&surface->base, &cairo_xlib_surface_backend); surface->dpy = dpy; + surface->screen_info = screen_info; surface->gc = NULL; surface->drawable = drawable; diff --git a/src/cairo.h b/src/cairo.h index d1bdc36bb..85825e1e5 100644 --- a/src/cairo.h +++ b/src/cairo.h @@ -635,7 +635,148 @@ typedef enum _cairo_font_weight { CAIRO_FONT_WEIGHT_NORMAL, CAIRO_FONT_WEIGHT_BOLD } cairo_font_weight_t; - + +/** + * cairo_antialias_t: + * @CAIRO_ANTIALIAS_DEFAULT: Use the default antialiasing for + * the font subsystem and target device + * @CAIRO_ANTIALIAS_NONE: Do no antialiasing of fonts; use bilevel text + * @CAIRO_ANTIALIAS_GRAY: Perform single-color antialiasing (using + * shades of gray for black text on a white background, for example). + * @CAIRO_ANTIALIAS_SUBPIXEL: Perform antialiasing by taking + * advantage of the order of subpixel elements on devices + * such as LCD panels + * + * Specifies the type of antialiasing to do when rendering text. + **/ +typedef enum _cairo_antialias { + CAIRO_ANTIALIAS_DEFAULT, + CAIRO_ANTIALIAS_NONE, + CAIRO_ANTIALIAS_GRAY, + CAIRO_ANTIALIAS_SUBPIXEL +} cairo_antialias_t; + +/** + * cairo_subpixel_order_t: + * @CAIRO_SUBPIXEL_ORDER_DEFAULT: Use the default subpixel order for + * for the target device + * @CAIRO_SUBPIXEL_ORDER_RGB: Subpixel elements are arranged horizontally + * with red at the left + * @CAIRO_SUBPIXEL_ORDER_BGR: Subpixel elements are arranged horizontally + * with blue at the left + * @CAIRO_SUBPIXEL_ORDER_VRGB: Subpixel elements are arranged vertically + * with red at the top + * @CAIRO_SUBPIXEL_ORDER_VBGR: Subpixel elements are arranged vertically + * with blue at the top + * + * The subpixel order specifies the order of color elements within + * each pixel on the display device when rendering with an + * antialiasing mode of %CAIRO_ANTIALIAS_SUBPIXEL. + **/ +typedef enum _cairo_subpixel_order { + CAIRO_SUBPIXEL_ORDER_DEFAULT, + CAIRO_SUBPIXEL_ORDER_RGB, + CAIRO_SUBPIXEL_ORDER_BGR, + CAIRO_SUBPIXEL_ORDER_VRGB, + CAIRO_SUBPIXEL_ORDER_VBGR +} cairo_subpixel_order_t; + +/** + * cairo_hint_style_t: + * @CAIRO_HINT_STYLE_DEFAULT: Use the default hint style for + * for font backend and target device + * @CAIRO_HINT_STYLE_NONE: Do not hint outlines + * @CAIRO_HINT_STYLE_SLIGHT: Hint outlines slightly to improve + * contrast while retaining good fidelity to the original + * shapes. + * @CAIRO_HINT_STYLE_MEDIUM: Hint outlines with medium strength + * giving a compromise between fidelity to the original shapes + * and contrast + * @CAIRO_HINT_STYLE_FULL: Hint outlines to maximize contrast + * + * Specifies the type of hinting to do on font outlines. Hinting + * is the process of fitting outlines to the pixel grid in order + * to improve the appearance of the result. Since hinting outlines + * involves distorting them, it also reduces the faithfulness + * to the original outline shapes. Not all of the outline hinting + * styles are supported by all font backends. + */ +typedef enum _cairo_hint_style { + CAIRO_HINT_STYLE_DEFAULT, + CAIRO_HINT_STYLE_NONE, + CAIRO_HINT_STYLE_SLIGHT, + CAIRO_HINT_STYLE_MEDIUM, + CAIRO_HINT_STYLE_FULL +} cairo_hint_style_t; + +/** + * cairo_hint_metrics_t: + * @CAIRO_HINT_METRICS_DEFAULT: Hint metrics in the default + * manner for the font backend and target device + * @CAIRO_HINT_METRICS_OFF: Do not hint font metrics + * @CAIRO_HINT_METRICS_ON: Hint font metrics + * + * Specifies whether to hint font metrics; hinting font metrics + * means quantizing them so that they are integer values in + * device space. Doing this improves the consistency of + * letter and line spacing, however it also means that text + * will be laid out differently at different zoom factors. + */ +typedef enum _cairo_hint_metrics { + CAIRO_HINT_METRICS_DEFAULT, + CAIRO_HINT_METRICS_OFF, + CAIRO_HINT_METRICS_ON +} cairo_hint_metrics_t; + +typedef struct _cairo_font_options cairo_font_options_t; + +cairo_font_options_t * +cairo_font_options_create (void); + +cairo_font_options_t * +cairo_font_options_copy (const cairo_font_options_t *original); + +void +cairo_font_options_destroy (cairo_font_options_t *options); + +cairo_status_t +cairo_font_options_status (cairo_font_options_t *options); + +void +cairo_font_options_merge (cairo_font_options_t *options, + const cairo_font_options_t *other); +cairo_bool_t +cairo_font_options_equal (const cairo_font_options_t *options, + const cairo_font_options_t *other); + +unsigned long +cairo_font_options_hash (const cairo_font_options_t *options); + +void +cairo_font_options_set_antialias (cairo_font_options_t *options, + cairo_antialias_t antialias); +cairo_antialias_t +cairo_font_options_get_antialias (const cairo_font_options_t *options); + +void +cairo_font_options_set_subpixel_order (cairo_font_options_t *options, + cairo_subpixel_order_t subpixel_order); +cairo_subpixel_order_t +cairo_font_options_get_subpixel_order (const cairo_font_options_t *options); + +void +cairo_font_options_set_hint_style (cairo_font_options_t *options, + cairo_hint_style_t hint_style); +cairo_hint_style_t +cairo_font_options_get_hint_style (const cairo_font_options_t *options); + +void +cairo_font_options_set_hint_metrics (cairo_font_options_t *options, + cairo_hint_metrics_t hint_metrics); +cairo_hint_metrics_t +cairo_font_options_get_hint_metrics (const cairo_font_options_t *options); + + /* This interface is for dealing with text as text, not caring about the font object inside the the cairo_t. */ @@ -710,9 +851,10 @@ cairo_font_face_set_user_data (cairo_font_face_t *font_face, /* Portable interface to general font features. */ cairo_scaled_font_t * -cairo_scaled_font_create (cairo_font_face_t *font_face, - const cairo_matrix_t *font_matrix, - const cairo_matrix_t *ctm); +cairo_scaled_font_create (cairo_font_face_t *font_face, + const cairo_matrix_t *font_matrix, + const cairo_matrix_t *ctm, + const cairo_font_options_t *options); void cairo_scaled_font_reference (cairo_scaled_font_t *scaled_font); @@ -951,6 +1093,10 @@ cairo_surface_set_user_data (cairo_surface_t *surface, void *user_data, cairo_destroy_func_t destroy); +void +cairo_surface_get_font_options (cairo_surface_t *surface, + cairo_font_options_t *options); + void cairo_surface_set_device_offset (cairo_surface_t *surface, double x_offset, diff --git a/src/cairoint.h b/src/cairoint.h index bd8072c5d..01cd5f249 100644 --- a/src/cairoint.h +++ b/src/cairoint.h @@ -476,6 +476,13 @@ struct _cairo_font_face { const cairo_font_face_backend_t *backend; }; +struct _cairo_font_options { + cairo_antialias_t antialias; + cairo_subpixel_order_t subpixel_order; + cairo_hint_style_t hint_style; + cairo_hint_metrics_t hint_metrics; +}; + /* cairo_font.c is responsible for a global glyph cache: * * - glyph entries: [[[base], cairo_unscaled_font_t, scale, flags, index], @@ -534,6 +541,7 @@ struct _cairo_scaled_font_backend { cairo_font_weight_t weight, const cairo_matrix_t *font_matrix, const cairo_matrix_t *ctm, + const cairo_font_options_t *options, cairo_scaled_font_t **font); void (*destroy) (void *font); @@ -585,6 +593,7 @@ struct _cairo_font_face_backend { cairo_status_t (*create_font) (void *font_face, const cairo_matrix_t *font_matrix, const cairo_matrix_t *ctm, + const cairo_font_options_t *options, cairo_scaled_font_t **scaled_font); }; @@ -766,6 +775,9 @@ typedef struct _cairo_surface_backend { cairo_fill_rule_t fill_rule, double tolerance); + void + (*get_font_options) (void *surface, + cairo_font_options_t *options); } cairo_surface_backend_t; typedef struct _cairo_format_masks { @@ -1348,6 +1360,11 @@ cairo_private void _cairo_scaled_font_get_glyph_cache_key (cairo_scaled_font_t *scaled_font, cairo_glyph_cache_key_t *key); +/* cairo-font-options.c */ + +cairo_private void +_cairo_font_options_init_default (cairo_font_options_t *options); + /* cairo_hull.c */ cairo_private cairo_status_t _cairo_hull_compute (cairo_pen_vertex_t *vertices, int *num_vertices);