src/cairo_unicode.c src/cairoint.h src/Makefile.am: Add _cairo_utf8_to_utf16(), _cairo_utf8_to_ucs4() based on code from GLib.

Add CAIRO_STATUS_INVALID_STRING
Use _cairo_utf8_to_ucs4().
Add cairo_bool_t
Add TRUE/FALSE definitions.
src/cairo.[ch] src/cairoint.h src/cairo_gstate.c: switch cairo_in_stroke/cairo_in_fill and all the functions used to implement them over to cairo_bool_t.
This commit is contained in:
Owen Taylor 2005-02-01 15:06:33 +00:00
parent f4ccbb4615
commit 711d7965c8
19 changed files with 1471 additions and 518 deletions

View file

@ -1,3 +1,20 @@
2005-02-01 Owen Taylor <otaylor@redhat.com>
* src/cairo_unicode.c src/cairoint.h src/Makefile.am: Add
_cairo_utf8_to_utf16(), _cairo_utf8_to_ucs4() based on code from GLib.
* src/cairo.[ch]: Add CAIRO_STATUS_INVALID_STRING
* src/cairo_ft_font.c: Use _cairo_utf8_to_ucs4().
* src/cairo.h: Add cairo_bool_t
* src/cairoint.h: Add TRUE/FALSE definitions.
* src/cairo.[ch] src/cairoint.h src/cairo_gstate.c: switch
cairo_in_stroke/cairo_in_fill and all the functions used to
implement them over to cairo_bool_t.
2005-01-31 Owen Taylor <otaylor@redhat.com>
* configure.in src/cairo-features.h.in: Add a check for the

View file

@ -171,6 +171,7 @@ cairo_copy_page
cairo_show_page
cairo_in_stroke
cairo_in_fill
cairo_bool_t
cairo_stroke_extents
cairo_fill_extents
cairo_init_clip

View file

@ -539,6 +539,12 @@ Drawing contexts.
@Returns:
<!-- ##### TYPEDEF cairo_bool_t ##### -->
<para>
</para>
<!-- ##### FUNCTION cairo_stroke_extents ##### -->
<para>
@ -946,6 +952,7 @@ Drawing contexts.
@CAIRO_STATUS_INVALID_MATRIX:
@CAIRO_STATUS_NO_TARGET_SURFACE:
@CAIRO_STATUS_NULL_POINTER:
@CAIRO_STATUS_INVALID_STRING:
<!-- ##### FUNCTION cairo_status ##### -->
<para>

View file

@ -1,20 +0,0 @@
Makefile
Makefile.in
aclocal.m4
autom4te.cache
cairo.pc
config.cache
config.guess
config.h
config.h.in
config.log
config.status
config.sub
configure
libtool
ltmain.sh
stamp-h
stamp-h1
stamp-h.in
*~

View file

@ -100,6 +100,7 @@ libcairo_la_SOURCES = \
cairo_surface.c \
cairo_traps.c \
cairo_pattern.c \
cairo_unicode.c \
cairo_wideint.c \
cairo-wideint.h \
$(libcairo_atsui_sources)\

View file

@ -706,40 +706,6 @@ _cairo_ft_font_destroy_unscaled_font (void *abstract_font)
free (unscaled);
}
static void
_utf8_to_ucs4 (char const *utf8,
FT_ULong **ucs4,
int *nchars)
{
int len = 0, step = 0;
int n = 0, alloc = 0;
FcChar32 u = 0;
if (utf8 == NULL || ucs4 == NULL || nchars == NULL)
return;
len = strlen (utf8);
alloc = len;
*ucs4 = malloc (sizeof (FT_ULong) * alloc);
if (*ucs4 == NULL)
return;
while (len && (step = FcUtf8ToUcs4(utf8, &u, len)) > 0)
{
if (n == alloc)
{
alloc *= 2;
*ucs4 = realloc (*ucs4, sizeof (FT_ULong) * alloc);
if (*ucs4 == NULL)
return;
}
(*ucs4)[n++] = u;
len -= step;
utf8 += step;
}
*nchars = n;
}
static void
_cairo_ft_font_get_glyph_cache_key (void *abstract_font,
cairo_glyph_cache_key_t *key)
@ -759,16 +725,19 @@ _cairo_ft_font_text_to_glyphs (void *abstract_font,
{
double x = 0., y = 0.;
size_t i;
FT_ULong *ucs4 = NULL;
uint32_t *ucs4 = NULL;
cairo_ft_font_t *font = abstract_font;
FT_Face face;
cairo_glyph_cache_key_t key;
cairo_image_glyph_cache_entry_t *val;
cairo_cache_t *cache;
cairo_status_t status;
_cairo_ft_font_get_glyph_cache_key (font, &key);
_utf8_to_ucs4 (utf8, &ucs4, nglyphs);
status = _cairo_utf8_to_ucs4 (utf8, -1, &ucs4, nglyphs);
if (!CAIRO_OK (status))
return status;
if (ucs4 == NULL)
return CAIRO_STATUS_NO_MEMORY;

View file

@ -1364,7 +1364,7 @@ cairo_status_t
_cairo_gstate_in_stroke (cairo_gstate_t *gstate,
double x,
double y,
int *inside_ret)
cairo_bool_t *inside_ret)
{
cairo_status_t status = CAIRO_STATUS_SUCCESS;
cairo_traps_t traps;
@ -1617,7 +1617,7 @@ cairo_status_t
_cairo_gstate_in_fill (cairo_gstate_t *gstate,
double x,
double y,
int *inside_ret)
cairo_bool_t *inside_ret)
{
cairo_status_t status = CAIRO_STATUS_SUCCESS;
cairo_traps_t traps;

View file

@ -667,32 +667,32 @@ _cairo_traps_tessellate_polygon (cairo_traps_t *traps,
return CAIRO_STATUS_SUCCESS;
}
static int
static cairo_bool_t
_cairo_trap_contains (cairo_trapezoid_t *t, cairo_point_t *pt)
{
cairo_slope_t slope_left, slope_pt, slope_right;
if (t->top > pt->y)
return 0;
return FALSE;
if (t->bottom < pt->y)
return 0;
return FALSE;
_cairo_slope_init (&slope_left, &t->left.p1, &t->left.p2);
_cairo_slope_init (&slope_pt, &t->left.p1, pt);
if (_cairo_slope_compare (&slope_left, &slope_pt) < 0)
return 0;
return FALSE;
_cairo_slope_init (&slope_right, &t->right.p1, &t->right.p2);
_cairo_slope_init (&slope_pt, &t->right.p1, pt);
if (_cairo_slope_compare (&slope_pt, &slope_right) < 0)
return 0;
return FALSE;
return 1;
return TRUE;
}
int
cairo_bool_t
_cairo_traps_contain (cairo_traps_t *traps, double x, double y)
{
int i;
@ -703,10 +703,10 @@ _cairo_traps_contain (cairo_traps_t *traps, double x, double y)
for (i = 0; i < traps->num_traps; i++) {
if (_cairo_trap_contains (&traps->traps[i], &point))
return 1;
return TRUE;
}
return 0;
return FALSE;
}
void

View file

@ -1,153 +1,144 @@
/*
* Copyright © 2005 Red Hat Inc.
/* cairo - a vector graphics library with display and print output
*
* 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 Red Hat Inc. not be used
* in advertising or publicity pertaining to distribution of the software
* without specific, written prior permission. Red Hat Inc. makes no
* representations about the suitability of this software for any purpose.
* It is provided "as is" without express or implied warranty.
* Copyright © 2005 Red Hat, Inc
*
* RED HAT INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL RED HAT INC. 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.
* 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.
*
* Author: Owen Taylor <otaylor@redhat.com>
* 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.
*
* Contributor(s):
*/
#include "cairoint.h"
#include "cairo-win32-private.h"
const cairo_font_backend_t cairo_ft_font_backend;
/*
* The simple 2x2 matrix is converted into separate scale and shape
* factors so that hinting works right
*/
#define LOGICAL_SCALE 32
typedef struct {
double x_scale, y_scale;
double shape[2][2];
} ft_font_transform_t;
cairo_font_t base;
LOGFONT logfont;
BYTE quality;
/* We do drawing and metrics computation in a "logical space" which
* is similar to font space, except that it is scaled by a factor
* of the (desired font size) * (LOGICAL_SCALE). The multiplication
* by LOGICAL_SCALE allows for sub-pixel precision.
*/
double logical_scale;
/* The size we should actually request the font at from Windows; differs
* from the logical_scale because it is quantized for orthogonal
* transformations
*/
double logical_size;
/* Transformations from device <=> logical space
*/
cairo_matrix_t logical_to_device;
cairo_matrix_t device_to_logical;
/* We special case combinations of 90-degree-rotations, scales and
* flips ... that is transformations that take the axes to the
* axes. If preserve_axes is true, then swap_axes/swap_x/swap_y
* encode the 8 possibilities for orientation (4 rotation angles with
* and without a flip), and scale_x, scale_y the scale components.
*/
cairo_bool_t preserve_axes;
cairo_bool_t swap_axes;
cairo_bool_t swap_x;
cairo_bool_t swap_y;
double x_scale;
double y_scale;
} cairo_win32_font_t;
static void
_compute_transform (ft_font_transform_t *sf,
cairo_font_scale_t *sc)
_compute_transform (cairo_win32_font_t *font,
cairo_font_scale_t *sc)
{
cairo_matrix_t normalized;
double tx, ty;
/* The font matrix has x and y "scale" components which we extract and
* use as character scale values. These influence the way freetype
* chooses hints, as well as selecting different bitmaps in
* hand-rendered fonts. We also copy the normalized matrix to
* freetype's transformation.
*/
int pixel_size;
cairo_matrix_set_affine (&normalized,
if (NEARLY_ZERO (sc->matrix[0][1]) && NEARLY_ZERO (sc->matrix[1][0])) {
font->preserve_axes = TRUE;
font->x_scale = sc->matrix[0][0];
font->swap_x = (sc->matrix[0][0] < 0);
font->y_scale = sc->matrix[1][1];
font->swap_y = (sc->matrix[1][1] < 0);
font->swap_axes = FALSE;
} else if (NEARLY_ZERO (sc->matrix[0][0]) && NEARLY_ZERO (sc->matrix[1][1])) {
font->preserve_axes = TRUE;
font->x_scale = sc->matrix[0][1];
font->swap_x = (sc->matrix[0][1] < 0);
font->y_scale = sc->matrix[1][0];
font->swap_y = (sc->matrix[1][0] < 0);
font->swap_axes = TRUE;
}
if (font->preserve_axes) {
if (font->swap_x)
font->x_scale = - font->x_scale;
if (font->swap_y)
font->y_scale = - font->y_scale;
font->logical_scale = LOGICAL_SCALE * font->y_scale;
font->logical_size = LOGICAL_SCALE * floor (font->y_scale + 0.5);
}
/* The font matrix has x and y "scale" components which we extract and
* use as character scale values.
*/
cairo_matrix_set_affine (&font->logical_to_device,
sc->matrix[0][0],
sc->matrix[0][1],
sc->matrix[1][0],
sc->matrix[1][1],
0, 0);
_cairo_matrix_compute_scale_factors (&normalized,
&sf->x_scale, &sf->y_scale,
/* XXX */ 1);
cairo_matrix_scale (&normalized, 1.0 / sf->x_scale, 1.0 / sf->y_scale);
cairo_matrix_get_affine (&normalized,
&sf->shape[0][0], &sf->shape[0][1],
&sf->shape[1][0], &sf->shape[1][1],
&tx, &ty);
}
/* Temporarily scales an unscaled font to the give scale. We catch
* scaling to the same size, since changing a FT_Face is expensive.
*/
static void
_ft_unscaled_font_set_scale (ft_unscaled_font_t *unscaled,
cairo_font_scale_t *scale)
{
int need_scale;
ft_font_transform_t sf;
FT_Matrix mat;
assert (unscaled->face != NULL);
if (scale->matrix[0][0] == unscaled->current_scale.matrix[0][0] &&
scale->matrix[0][1] == unscaled->current_scale.matrix[0][1] &&
scale->matrix[1][0] == unscaled->current_scale.matrix[1][0] &&
scale->matrix[1][1] == unscaled->current_scale.matrix[1][1])
return;
unscaled->current_scale = *scale;
if (!font->preserve_axes) {
double x_scale, y_scale;
_compute_transform (&sf, scale);
_cairo_matrix_compute_scale_factors (&font->logical_to_device,
&font->x_scale, &font->y_scale,
TRUE); /* XXX: Handle vertical text */
unscaled->x_scale = sf.x_scale;
unscaled->y_scale = sf.y_scale;
mat.xx = DOUBLE_TO_16_16(sf.shape[0][0]);
mat.yx = - DOUBLE_TO_16_16(sf.shape[0][1]);
mat.xy = - DOUBLE_TO_16_16(sf.shape[1][0]);
mat.yy = DOUBLE_TO_16_16(sf.shape[1][1]);
if (need_scale) {
FT_Set_Transform(unscaled->face, &mat, NULL);
FT_Set_Pixel_Sizes(unscaled->face,
(FT_UInt) sf.x_scale,
(FT_UInt) sf.y_scale);
font->logical_size = floor (LOGICAL_SCALE * y_scale + 0.5);
font->logical_scale = LOGICAL_SCALE * y_scale + 0.5;
}
}
/* implement the font backend interface */
cairo_matrix_scale (&font->logical_to_device,
1.0 / (LOGICAL_SCALE * font->y_scale),
1.0 / (LOGICAL_SCALE * font->y_scale));
typedef struct {
cairo_font_t base;
FcPattern *pattern;
int load_flags;
ft_unscaled_font_t *unscaled;
} cairo_ft_font_t;
static void
_utf8_to_ucs4 (char const *utf8,
FT_ULong **ucs4,
size_t *nchars)
{
int len = 0, step = 0;
size_t n = 0, alloc = 0;
FcChar32 u = 0;
if (utf8 == NULL || ucs4 == NULL || nchars == NULL)
return;
len = strlen (utf8);
alloc = len;
*ucs4 = malloc (sizeof (FT_ULong) * alloc);
if (*ucs4 == NULL)
return;
while (len && (step = FcUtf8ToUcs4(utf8, &u, len)) > 0)
{
if (n == alloc)
{
alloc *= 2;
*ucs4 = realloc (*ucs4, sizeof (FT_ULong) * alloc);
if (*ucs4 == NULL)
return;
}
(*ucs4)[n++] = u;
len -= step;
utf8 += step;
}
*nchars = n;
font->device_to_logical = font->logical_to_device;
if (!CAIRO_OK (cairo_matrix_invert (&font->device_to_logical)))
cairo_matrix_set_identity (font->device_to_logical);
}
static BYTE
@ -156,7 +147,7 @@ _get_system_quality (void)
BOOL font_smoothing;
if (!SystemParametersInfo (SPI_GETFONTSMOOTHING, 0, &font_smoothing, 0)) {
_print_gdi_error ();
_cairo_win32_print_gdi_error ();
return FALSE;
}
@ -166,7 +157,7 @@ _get_system_quality (void)
version_info.size = sizeof (OSVERSIONINFO);
if (!GetVersionEx (&version_info)) {
_print_gdi_error ();
_cairo_win32_print_gdi_error ();
return FALSE;
}
@ -177,7 +168,7 @@ _get_system_quality (void)
if (!SystemParametersInfo (SPI_GETFONTSMOOTHINGTYPE,
0, &smoothing_type, 0)) {
_print_gdi_error ();
_cairo_win32_print_gdi_error ();
return FALSE;
}
@ -192,6 +183,29 @@ _get_system_quality (void)
}
static cairo_font_t *
_win32_font_create (LOGFONT *logfont,
cairo_font_scale_t *scale)
{
cairo_win32_font_t *f;
ft_font_transform_t sf,
f = malloc (sizeof(cairo_win32_font_t));
if (f == NULL)
return NULL;
f->logfont = *logfont;
f->quality = _get_system_quality ();
_compute_transform (f, scale);
_cairo_font_init ((cairo_font_t *)f, &sc, &cairo_win32_font_backend);
return (cairo_font_t *)f;
}
/* implement the font backend interface */
static cairo_status_t
_cairo_ft_font_create (const char *family,
cairo_font_slant_t slant,
@ -245,7 +259,7 @@ _cairo_ft_font_create (const char *family,
if (!logfont.lfFaceName)
return CAIRO_STATUS_NO_MEMORY;
font = cairo_win32_font_create_for_logfont (logfont, scale);
font = _win32_font_create (logfont, scale);
if (!font)
return CAIRO_STATUS_NO_MEMORY;
@ -269,6 +283,107 @@ _cairo_ft_font_get_glyph_cache_key (void *abstract_font,
return CAIRO_STATUS_NO_MEMORY;
}
/* Taken from fontconfig sources, Copyright © 2000 Keith Packard */
int
_utf8_to_ucs4 (const char *src_orig,
unsigned long *dst,
int len)
{
const FcChar8 *src = src_orig;
FcChar8 s;
int extra;
FcChar32 result;
if (len == 0)
return 0;
s = *src++;
len--;
if (!(s & 0x80))
{
result = s;
extra = 0;
}
else if (!(s & 0x40))
{
return -1;
}
else if (!(s & 0x20))
{
result = s & 0x1f;
extra = 1;
}
else if (!(s & 0x10))
{
result = s & 0xf;
extra = 2;
}
else if (!(s & 0x08))
{
result = s & 0x07;
extra = 3;
}
else if (!(s & 0x04))
{
result = s & 0x03;
extra = 4;
}
else if ( ! (s & 0x02))
{
result = s & 0x01;
extra = 5;
}
else
{
return -1;
}
if (extra > len)
return -1;
while (extra--)
{
result <<= 6;
s = *src++;
if ((s & 0xc0) != 0x80)
return -1;
result |= s & 0x3f;
}
*dst = result;
return src - src_orig;
}
static cairo_status_t
_utf8_to_utf16 (char const *utf8,
FT_ULong **ucs4,
size_t *nchars)
{
int len = 0, step = 0;
size_t n = 0, alloc = 0;
FcChar32 u = 0;
if (utf8 == NULL || ucs4 == NULL || nchars == NULL)
return;
len = strlen (utf8);
alloc = len;
*ucs4 = malloc (sizeof (FT_ULong) * alloc);
if (*ucs4 == NULL)
return;
while (len && (step = FcUtf8ToUcs4(utf8, &u, len)) > 0)
{
(*ucs4)[n++] = u;
len -= step;
utf8 += step;
}
*nchars = n;
return CAIRO_STATUS_NO_MEMORY;
}
static cairo_status_t
_cairo_ft_font_text_to_glyphs (void *abstract_font,
const unsigned char *utf8,
@ -276,26 +391,145 @@ _cairo_ft_font_text_to_glyphs (void *abstract_font,
int *nglyphs)
{
cairo_win32_font_t *font = abstract_font;
cairo_status_t status;
GCP_RESULTSW results;
WCHAR glyphs[1024];
int dx[1024];
DWORD ret;
status =
results.lStructSize = sizeof (GCP_RESULTS);
results.lpOutString = NULL;
results.lpOrder = NULL;
results.lpDx = dx;
results.lpCaretPos = NULL;
results.lpClass = NULL;
results.lpGlyphs = glyphs;
results.nGlyphs = 1024;
ret = GetCharacterPlacementW (hdc, strs[i], wcslen(strs[i]),
0,
&results,
GCP_DIACRITIC | GCP_LIGATE | GCP_GLYPHSHAPE | GCP_REORDER);
if (!ret)
_print_gdi_error ("GetCharacterPlacement");
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_ft_font_font_extents (void *abstract_font,
cairo_font_extents_t *extents)
_cairo_win32_font_font_extents (void *abstract_font,
cairo_font_extents_t *extents)
{
cairo_win32_font_t *font = abstract_font;
TEXTMETRIC metrics;
HDC hdc;
if (font->preserve_axes) {
/* For 90-degree rotations (including 0), we get the metrics
* from the GDI in logical space, then convert back to font space
*/
hdc = _cairo_win32_font_acquire_scaled_dc (font);
GetTextMetrics (hdc, &metrics);
_cairo_win32_font_release_scaled_dc (font);
extents->ascent = metrics.tmAscent / font->logical_scale;
extents->descent = metrics.tmDescent / font->logical_scale;
extents->height = (metrics.tmHeight + metrics.tmExternalLeading) / font->logical_scale;
extents->max_x_advance = metrics.tmMaxCharWidth / font->logical_scale;
extents->max_y_advance = 0;
} else {
/* For all other transformations, we use the design metrics
* of the font. The GDI results from GetTextMetrics() on a
* transformed font are inexplicably large and we want to
* avoid them.
*/
hdc = _cairo_win32_font_acquire_unscaled_dc (font);
GetTextMetrics (hdc, &metrics);
_cairo_win32_font_release_unscaled_dc (font);
extents->ascent = (double)metrics.tmAscent / font->em_square;
extents->descent = metrics.tmDescent * font->em_square;
extents->height = (double)(metrics.tmHeight + mertrics.tmExternalLeading) / font->em_square;
extents->max_x_advance = (double)(metrics.tmMaxCharWidth) / font->em_square;
extents->max_y_advance = 0;
}
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_ft_font_glyph_extents (void *abstract_font,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_text_extents_t *extents)
_cairo_win32_font_glyph_extents (void *abstract_font,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_text_extents_t *extents)
{
cairo_win32_font_t *font = abstract_font;
static const MAT2 matrix = { { 0, 1 }, { 0, 0 }, { 0, 0 }, { 0, 1 } };
GLYPHMETRICS metrics;
HDC hdc;
/* We handle only the case num_glyphs == 1, glyphs[i].x == glyphs[0].y == 0.
* This is all that the calling code triggers, and the backend interface
* will eventually be changed to match
*/
assert (num_glyphs == 1);
if (font->preserve_axes) {
/* If we aren't rotating / skewing the axes, then we get the metrics
* from the GDI in device space and convert to font space.
*/
hdc = _cairo_win32_font_acquire_scaled_dc (font);
GetGlyphOutline(hdc, str[i], GGO_METRICS, &glyph_metrics, 0, NULL, &matrix);
_cairo_win32_font_release_scaled_dc (font);
if (font->swap_axes) {
extents->x_bearing = metrics.gmptGlyphOrigin.y / font->y_scale;
extents->y_bearing = metrics.gmptGlyphOrigin.x / font->x_scale;
extents->width = metrics.gmBlackBoxY / font->y_scale;
extents->height = metrics.gmBlackBoxX / font->x_scale;
extents->x_advance = metrics.gmCellIncY / font->x_scale;
extents->y_advance = metrics.gmCellIncX / font->y_scale;
} else {
extents->x_bearing = metrics.gmptGlyphOrigin.x / font->x_scale;
extents->y_bearing = metrics.gmptGlyphOrigin.y / font->y_scale;
extents->width = metrics.gmBlackBoxX / font->x_scale;
extents->height = metrics.gmBlackBoxY / font->y_scale;
extents->x_advance = metrics.gmCellIncX / font->x_scale;
extents->y_advance = metrics.gmCellIncY / font->y_scale;
}
if (font->swap_x) {
extents->x_bearing = (- extents->x_bearing - extents->width);
extents->x_advance = - extents->x_advance;
}
if (font->swap_y) {
extents->y_bearing = (- extents->y_bearing - extents->height);
extents->y_advance = - extents->y_advance;
}
} else {
/* For all other transformations, we use the design metrics
* of the font.
*/
hdc = _cairo_win32_font_acquire_unscaled_dc (font);
GetGlyphOutline(hdc, str[i], GGO_METRICS, &glyph_metrics, 0, NULL, &matrix);
_cairo_win32_font_release_unscaled_dc (font);
extents->x_bearing = (double)metrics.gmptGlyphOrigin.x / font->em_square;
extents->y_bearing = (double)metrics.gmptGlyphOrigin.y / font->em_square;
extents->width = (double)metrics.gmBlackBoxX / font->em_square;
extents->height = (double)metrics.gmBlackBoxY / font->em_square;
extents->x_advance = (double)metrics.gmCellIncX / font->em_square;
extents->y_advance = (double)metrics.gmCellIncY / font->em_square;
}
return CAIRO_STATUS_SUCCESS;
}
@ -304,26 +538,277 @@ _cairo_ft_font_glyph_extents (void *abstract_font,
static cairo_status_t
_cairo_ft_font_glyph_bbox (void *abstract_font,
const cairo_glyph_t *glyphs,
int num_glyphs,
int num_glyphs,
cairo_box_t *bbox)
{
static const MAT2 matrix = { { 0, 1 }, { 0, 0 }, { 0, 0 }, { 0, 1 } };
cairo_win32_font_t *font = abstract_font;
int x1 = 0, x2 = 0, y1 = 0, y2 = 0;
if (num_glyphs > 0) {
HDC hdc = _cairo_win32_font_acquire_scaled_dc (font);
int i;
for (i = 0; i < num_glyphs; i++) {
int x = floor (0.5 + glyphs[i].x);
int y = floor (0.5 + glyphs[i].y);
GetGlyphOutline (hdc, glyphs[i], GGO_METRICS | GGO_GLYPH_INDEX,
&glyph_metrics, 0, NULL, &matrix);
if (i == 0 || x1 > x + metrics.gmptGlyphOrigin.x)
x1 = x + metrics.gmptGlyphOrigin.x;
if (i == 0 || y1 > y + metrics.gmptGlyphOrigin.y)
y1 = x + metrics.gmptGlyphOrigin.y;
if (i == 0 || x2 < x + metrics.gmptGlyphOrigin.x + metrics.gmBlackBoxX)
x2 = x + metrics.gmptGlyphOrigin.x + metrics.gmBlackBoxX;
if (i == 0 || y2 < y + metrics.gmptGlyphOrigin.y + metrics.gmBlackBoxY)
y2 = y + metrics.gmptGlyphOrigin.x + metrics.gmBlackBoxY;
}
_cairo_win32_font_release_scaled_dc (font);
}
bbox->p1.x = _cairo_fixed_from_int (x1);
bbox->p1.y = _cairo_fixed_from_int (y1);
bbox->p2.x = _cairo_fixed_from_int (x2);
bbox->p2.y = _cairo_fixed_from_int (y2);
return CAIRO_STATUS_SUCCESS;
}
#define FIXED_BUF_SIZE 1024
typedef struct {
cairo_win32_font_t *font;
HDC dc;
cairo_array_t glyphs;
cairo_array_t dx;
int last_x;
int last_y;
} cairo_glyph_state_t;
static void
_start_glyphs (cairo_glyph_state_t *state,
cairo_win32_font_t *font,
HDC dc)
{
state->dc = dc;
state->font = font;
_cairo_array_init (&state->glyphs, sizeof (WCHAR));
_cairo_array_init (&state->dx, sizeof (int));
}
static void
_flush_glyphs (cairo_glyph_state_t *state)
{
ExtTextOutW (state->dc,
state->start_x, state->last_y,
ETO_CLIPPED,
NULL,
(WCHAR *)state->glyphs.elements,
state->glyphs.num_elements,
(int *)state->dx.elements);
_cairo_array_truncate (&state->glyphs, 0);
_cairo_array_truncate (&state->dx, 0);
}
static void
_add_glyph (cairo_glyph_state_t *state,
unsigned long index,
double device_x,
double device_y)
{
double user_x = device_x;
double user_y = device_y;
WCHAR glyph_index = index;
int logical_x, logical_y;
cairo_matrix_transform_point (&state->font->device_to_logical, &user_x, &user_y);
logical_x = DOUBLE_TO_LOGICAL (user_x);
logical_y = DOUBLE_TO_LOGICAL (user_y);
if (state->glyphs.num_elements > 0) {
int dx;
if (logical_y != state->last_y) {
_flush_glyphs (state);
state->start_x = logical_x;
}
dx = logical_x - state->last_x;
_cairo_array_append (&state->dx, &logical_x, 1);
} else {
state->start_x = logical_x;
}
state->last_x = logical_x;
state->last_y = logical_y;
_cairo_array_append (&state->glyphs, &glyph_index, 1);
}
static void
_finish_glyphs (cairo_glyph_state_t *state,
HDC dc)
{
state->dc = dc;
_flush_glyphs (state);
_cairo_array_fini (&state->glyphs);
_cairo_array_init (&state->dx);
}
static cairo_status_t
_draw_glyphs_on_surface (cairo_win32_surface_t *surface,
HBRUSH brush,
int x_offset,
int y_offset,
const cairo_glyph_t *glyphs,
int num_glyphs)
{
cairo_glyph_state_t state;
cairo_status status;
int prev_mode;
XFORM xform;
XFORM prev_xform;
BRUSH old_brush;
old_brush = SelectObject (tmp_surface->dc, brush);
if (!old_brush)
return _print_gdi_error ();l
prev_mode = GetGraphicsMode (surface->dc);
SetGraphicsMode (surface->dc, GM_ADVANCED);
GetWorldTransform (surface->dc, &prev_xform);
xForm.eM11 = font->logical_to_device->m[0][0];
xForm.eM21 = font->logical_to_device->m[1][0];
xForm.eM12 = font->logical_to_device->m[0][1];
xForm.eM22 = font->logical_to_device->m[1][1];
xForm.eDx = matrix->m[2][0];
xForm.eDy = matrix->m[2][1];
SetWorldTransform (surface->dc, &xform);
_start_glyphs (&glyph_state, tmp_surface->dc);
for (i = 0; i < num_glyphs; i++) {
status = _add_glyph (&glyph_state, glyphs[i].glyph, glyphs[i].x - x, glyphs[i].y - y);
if (!CAIRO_OK (status))
goto FAIL;
}
FAIL:
_finish_glyphs (&glyph_state);
SetWorldTransform (surface>dc, &prev_xform);
SetGraphicsMode (surface->dc, prev_mode);
SelectObject (tmp_surface->dc, old_brush);
}
static cairo_status_t
_cairo_ft_font_show_glyphs (void *abstract_font,
cairo_operator_t operator,
cairo_surface_t *source,
cairo_surface_t *surface,
int source_x,
int source_y,
const cairo_glyph_t *glyphs,
int num_glyphs)
_cairo_win32_font_show_glyphs (void *abstract_font,
cairo_operator_t operator,
cairo_pattern_t *pattern,
cairo_surface_t *surface,
int source_x,
int source_y,
int dest_x,
int dest_y,
unsigned int width,
unsigned int height,
const cairo_glyph_t *glyphs,
int num_glyphs)
{
cairo_win32_font_t *font = abstract_font;
cairo_bbox_t bbox;
cairo_win32_surface_t *win32_surface = (cairo_win32_surface_t *)surface;
cairo_win32_surface_t *tmp_surface;
int i;
RECT r;
if (_cairo_surface_is_win32 (surface) &&
win32_surface->format == CAIRO_FORMAT_RGB24 &&
operator == CAIRO_OPERATOR_OVER &&
pattern->type == CAIRO_PATTERN_SOLID &&
(pattern->color.alpha_short >> 8) == 255) {
/* When compositing OVER on a GDI-understood surface, with a
* solid opaque color, we can just call ExtTextOut directly.
*/
COLORREF new_color;
HBRUSH brush;
new_color = RGB (pattern->color.red_short >> 8,
pattern->color.green_short >> 8,
pattern->color.blue_short >> 8);
brush = CreateSolidBrush (new_color);
if (!brush)
return _cairo_win32_print_gdi_error ("_cairo_win32_font_show_glyphs");
_draw_glyphs_on_surface (win32_surface, brush, glyphs, num_glyphs, 0, 0);
DeleteObject (new_brush);
} else {
/* Otherwise, we need to draw using software fallbacks. We create a mask
/* surface by drawing the the glyphs onto a DIB, white-on-black.
*/
tmp_surface = (cairo_win32_surface_t *)_cairo_win32_surface_create_dib (CAIRO_FORMAT_ARGB32, width, height);
r.left = 0;
r.top = 0;
r.right = width;
r.height = height;
FillRect (hdc, &r, GetStockObject (BLACK_BRUSH));
_draw_glyphs_on_surface (win32_surface, GetStockObject (WHITE_BRUSH),
glyphs, num_glyphs, x, y);
if (font->quality == CLEARTYPE_QUALITY) {
/* For ClearType, we need a 4-channel mask. If we are compositing on
* a surface with alpha, we need to compute the alpha channel of
* the mask as the average of the other channels. But for a destination
* surface without alpha the alpha channel of the mask is ignored
*/
if (win32_surface->format != CAIRO_FORMAT_ARGB24)
_compute_argb32_mask_alpha (tmp_surface);
mask_surface = tmp_surface;
} else {
mask_surface = _compute_a8_mask (tmp_surface);
cairo_suface_destroy (tmp_surface);
}
/* For operator == OVER, no-cleartype, a possible optimization here is to
* draw onto an intermediate ARGB32 surface and alpha-blend that with the
* destination
*/
status = _cairo_surface_composite (operator, pattern,
&(mask_surface->base),
surface,
source_x, source_y,
0, 0,
x, y,
width, height);
cairo_surface_destroy (mask_surface);
}
return CAIRO_STATUS_SUCCESS;
}
@ -365,16 +850,12 @@ cairo_font_t *
cairo_win32_font_create_for_logfont (LOGFONT *logfont,
cairo_matrix_t *scale)
{
cairo_win32_font_t *f;
cairo_font_scale_t sc;
cairo_matrix_get_affine (scale,
&sc.matrix[0][0], &sc.matrix[0][1],
&sc.matrix[1][0], &sc.matrix[1][1],
NULL, NULL);
f = malloc (sizeof(cairo_win32_font_t));
if (f == NULL)
return NULL;
f->logfont = *logfont;
_cairo_font_init ((cairo_font_t *)f, &sc, &cairo_win32_font_backend);
return (cairo_font_t *)f;
return _win32_font_create (logfont, &sc);
}

View file

@ -47,8 +47,17 @@
static const cairo_surface_backend_t cairo_win32_surface_backend;
static void
_print_gdi_error (const char *context)
/**
* _cairo_win32_print_gdi_error:
* @context: context string to display along with the error
*
* Helper function to dump out a human readable form of the
* current error code.
*
* Return value: A Cairo status code for the error code
**/
cairo_status_t
_cairo_win32_print_gdi_error (const char *context)
{
void *lpMsgBuf;
DWORD last_error = GetLastError ();
@ -66,12 +75,8 @@ _print_gdi_error (const char *context)
LocalFree (lpMsgBuf);
}
}
static cairo_status_t
_get_cairo_error (void)
{
/* We should switch off of GetLastError, but we'd either return
/* We should switch off of last_status, but we'd either return
* CAIRO_STATUS_NO_MEMORY or CAIRO_STATUS_UNKNOWN_ERROR and there
* is no CAIRO_STATUS_UNKNOWN_ERROR.
*/
@ -79,6 +84,11 @@ _get_cairo_error (void)
return CAIRO_STATUS_NO_MEMORY;
}
static cairo_status_t
_get_cairo_error (void)
{
}
void
cairo_set_target_win32 (cairo_t *cr,
HDC hdc)
@ -130,6 +140,7 @@ _create_dc_and_bitmap (HDC original_dc,
{
HDC dc = NULL;
HBITMAP bitmap = NULL;
cairo_status_t status;
BITMAPINFO *bitmap_info = NULL;
struct {
@ -257,7 +268,7 @@ _create_dc_and_bitmap (HDC original_dc,
return CAIRO_STATUS_SUCCESS;
FAIL:
_print_gdi_error ("_create_dc_and_bitmap");
status = _cairo_win32_print_gdi_error ("_create_dc_and_bitmap");
if (bitmap_info && num_palette > 2)
free (bitmap_info);
@ -268,7 +279,7 @@ _create_dc_and_bitmap (HDC original_dc,
if (dc)
DeleteDC (dc);
return _get_cairo_error ();
return status;
}
static cairo_surface_t *
@ -360,6 +371,7 @@ _cairo_win32_surface_get_subimage (cairo_win32_surface_t *surface,
cairo_win32_surface_t **local_out)
{
cairo_win32_surface_t *local;
cairo_status_t status;
local =
(cairo_win32_surface_t *) _cairo_win32_surface_create_similar (surface,
@ -382,12 +394,12 @@ _cairo_win32_surface_get_subimage (cairo_win32_surface_t *surface,
return CAIRO_STATUS_SUCCESS;
FAIL:
_print_gdi_error ("_cairo_win32_surface_get_subimage");
status = _cairo_win32_print_gdi_error ("_cairo_win32_surface_get_subimage");
if (local)
cairo_surface_destroy (&local->base);
return _get_cairo_error ();
return status;
}
static cairo_status_t
@ -457,10 +469,8 @@ _cairo_win32_surface_acquire_dest_image (void *abstract_surfa
return CAIRO_STATUS_SUCCESS;
}
if (GetClipBox (surface->dc, &clip_box) == ERROR) {
_print_gdi_error ("_cairo_win3_surface_acquire_dest_image");
return _get_cairo_error ();
}
if (GetClipBox (surface->dc, &clip_box) == ERROR)
return _cairo_win32_print_gdi_error ("_cairo_win3_surface_acquire_dest_image");
x1 = clip_box.left;
x2 = clip_box.right;
@ -517,9 +527,8 @@ _cairo_win32_surface_release_dest_image (void *abstract_surfac
image_rect->width, image_rect->height,
local->dc,
0, 0,
SRCCOPY)) {
_print_gdi_error ("_cairo_win32_surface_release_dest_image");
}
SRCCOPY))
_cairo_win32_print_gdi_error ("_cairo_win32_surface_release_dest_image");
cairo_surface_destroy ((cairo_surface_t *)local);
}
@ -613,10 +622,8 @@ _cairo_win32_surface_composite (cairo_operator_t operator,
width, height,
src->dc,
src_x + itx, src_y + ity,
SRCCOPY)) {
_print_gdi_error ("_cairo_win32_surface_composite");
return _get_cairo_error ();
}
SRCCOPY))
return _cairo_win32_print_gdi_error ("_cairo_win32_surface_composite");
return CAIRO_STATUS_SUCCESS;
@ -641,10 +648,8 @@ _cairo_win32_surface_composite (cairo_operator_t operator,
src->dc,
src_x + itx, src_y + ity,
width, height,
blend_function)) {
_print_gdi_error ("_cairo_win32_surface_composite");
return _get_cairo_error ();
}
blend_function))
return _cairo_win32_print_gdi_error ("_cairo_win32_surface_composite");
return CAIRO_STATUS_SUCCESS;
}
@ -660,6 +665,7 @@ _cairo_win32_surface_fill_rectangles (void *abstract_surface,
int num_rects)
{
cairo_win32_surface_t *surface = abstract_surface;
cairo_status_t status;
COLORREF new_color;
HBRUSH new_brush;
int i;
@ -681,10 +687,8 @@ _cairo_win32_surface_fill_rectangles (void *abstract_surface,
new_color = RGB (color->red_short >> 8, color->green_short >> 8, color->blue_short >> 8);
new_brush = CreateSolidBrush (new_color);
if (!new_brush) {
_print_gdi_error ("_cairo_win32_surface_fill_rectangles");
return _get_cairo_error ();
}
if (!new_brush)
return _cairo_win32_print_gdi_error ("_cairo_win32_surface_fill_rectangles");
for (i = 0; i < num_rects; i++) {
RECT rect;
@ -703,11 +707,11 @@ _cairo_win32_surface_fill_rectangles (void *abstract_surface,
return CAIRO_STATUS_SUCCESS;
FAIL:
_print_gdi_error ("_cairo_win32_surface_fill_rectangles");
status = _cairo_win32_print_gdi_error ("_cairo_win32_surface_fill_rectangles");
DeleteObject (new_brush);
return _get_cairo_error ();
return status;
}
static cairo_int_status_t
@ -744,6 +748,7 @@ _cairo_win32_surface_set_clip_region (void *abstract_surface,
pixman_region16_t *region)
{
cairo_win32_surface_t *surface = abstract_surface;
cairo_status_t status;
/* If we are in-memory, then we set the clip on the image surface
* as well as on the underlying GDI surface.
@ -761,10 +766,8 @@ _cairo_win32_surface_set_clip_region (void *abstract_surface,
/* Clear any clip set by Cairo, return to the original */
if (surface->set_clip) {
if (SelectClipRgn (surface->dc, surface->saved_clip) == ERROR) {
_print_gdi_error ("_cairo_win32_surface_set_clip_region");
return _get_cairo_error ();
}
if (SelectClipRgn (surface->dc, surface->saved_clip) == ERROR)
return _cairo_win32_print_gdi_error ("_cairo_win32_surface_set_clip_region");
if (surface->saved_clip) {
DeleteObject (surface->saved_clip);
@ -851,9 +854,9 @@ _cairo_win32_surface_set_clip_region (void *abstract_surface,
return CAIRO_STATUS_SUCCESS;
FAIL:
_print_gdi_error ("_cairo_win32_surface_set_clip_region");
status = _cairo_win32_print_gdi_error ("_cairo_win32_surface_set_clip_region");
DeleteObject (gdi_region);
return _get_cairo_error ();
return status;
}
}
@ -883,7 +886,7 @@ cairo_win32_surface_create (HDC hdc)
/* Try to figure out the drawing bounds for the Device context
*/
if (GetClipBox (hdc, &rect) == ERROR) {
_print_gdi_error ("cairo_win32_surface_create");
_cairo_win32_print_gdi_error ("cairo_win32_surface_create");
return NULL;
}

View file

@ -37,16 +37,12 @@
#include <cairo.h>
#ifdef __cplusplus
extern "C" {
#endif
#ifndef CAIRO_HAS_WIN32_SURFACE
#error "cairo-win32.h included in a Cairo without the Win32 backend"
#endif
#ifdef CAIRO_HAS_WIN32_SURFACE
#include <windows.h>
CAIRO_BEGIN_DECLS
void
cairo_set_target_win32 (cairo_t *cr,
HDC hdc);
@ -54,8 +50,12 @@ cairo_set_target_win32 (cairo_t *cr,
cairo_surface_t *
cairo_win32_surface_create (HDC hdc);
#ifdef __cplusplus
}
#endif
cairo_font_t *
cairo_win32_font_create_for_logfont (LOGFONT *logfont,
cairo_matrix_t *scale);
#endif /* CAIRO_HAS_WIN32_SURFACE */
CAIRO_END_DECLS
#endif /* _CAIRO_WIN32_H_ */

View file

@ -923,7 +923,7 @@ cairo_show_page (cairo_t *cr)
CAIRO_CHECK_SANITY (cr);
}
int
cairo_bool_t
cairo_in_stroke (cairo_t *cr, double x, double y)
{
int inside;
@ -1414,6 +1414,8 @@ cairo_status_string (cairo_t *cr)
return "no target surface has been set";
case CAIRO_STATUS_NULL_POINTER:
return "NULL pointer";
case CAIRO_STATUS_INVALID_STRING:
return "input string not valid UTF-8";
}
return "<unknown error status>";

View file

@ -50,6 +50,22 @@
CAIRO_BEGIN_DECLS
/**
* cairo_bool_t:
*
* #cairo_bool_t is used for boolean values. Returns of type
* #cairo_bool_t will always be either 0 or 1, but testing against
* these values explicitely is not encouraged; just use the
* value as a boolean condition.
*
* <informalexample><programlisting>
* if (cairo_in_stroke (cr, x, y)) {
* /<!-- -->* do something *<!-- -->/
* }
* </programlisting></informalexample>
*/
typedef int cairo_bool_t;
/**
* cairo_t:
*
@ -388,10 +404,10 @@ void
cairo_show_page (cairo_t *cr);
/* Insideness testing */
int
cairo_bool_t
cairo_in_stroke (cairo_t *cr, double x, double y);
int
cairo_bool_t
cairo_in_fill (cairo_t *cr, double x, double y);
/* Rectangular extents */
@ -674,7 +690,8 @@ typedef enum cairo_status {
CAIRO_STATUS_NO_CURRENT_POINT,
CAIRO_STATUS_INVALID_MATRIX,
CAIRO_STATUS_NO_TARGET_SURFACE,
CAIRO_STATUS_NULL_POINTER
CAIRO_STATUS_NULL_POINTER,
CAIRO_STATUS_INVALID_STRING
} cairo_status_t;
cairo_status_t

View file

@ -706,40 +706,6 @@ _cairo_ft_font_destroy_unscaled_font (void *abstract_font)
free (unscaled);
}
static void
_utf8_to_ucs4 (char const *utf8,
FT_ULong **ucs4,
int *nchars)
{
int len = 0, step = 0;
int n = 0, alloc = 0;
FcChar32 u = 0;
if (utf8 == NULL || ucs4 == NULL || nchars == NULL)
return;
len = strlen (utf8);
alloc = len;
*ucs4 = malloc (sizeof (FT_ULong) * alloc);
if (*ucs4 == NULL)
return;
while (len && (step = FcUtf8ToUcs4(utf8, &u, len)) > 0)
{
if (n == alloc)
{
alloc *= 2;
*ucs4 = realloc (*ucs4, sizeof (FT_ULong) * alloc);
if (*ucs4 == NULL)
return;
}
(*ucs4)[n++] = u;
len -= step;
utf8 += step;
}
*nchars = n;
}
static void
_cairo_ft_font_get_glyph_cache_key (void *abstract_font,
cairo_glyph_cache_key_t *key)
@ -759,16 +725,19 @@ _cairo_ft_font_text_to_glyphs (void *abstract_font,
{
double x = 0., y = 0.;
size_t i;
FT_ULong *ucs4 = NULL;
uint32_t *ucs4 = NULL;
cairo_ft_font_t *font = abstract_font;
FT_Face face;
cairo_glyph_cache_key_t key;
cairo_image_glyph_cache_entry_t *val;
cairo_cache_t *cache;
cairo_status_t status;
_cairo_ft_font_get_glyph_cache_key (font, &key);
_utf8_to_ucs4 (utf8, &ucs4, nglyphs);
status = _cairo_utf8_to_ucs4 (utf8, -1, &ucs4, nglyphs);
if (!CAIRO_OK (status))
return status;
if (ucs4 == NULL)
return CAIRO_STATUS_NO_MEMORY;

View file

@ -1364,7 +1364,7 @@ cairo_status_t
_cairo_gstate_in_stroke (cairo_gstate_t *gstate,
double x,
double y,
int *inside_ret)
cairo_bool_t *inside_ret)
{
cairo_status_t status = CAIRO_STATUS_SUCCESS;
cairo_traps_t traps;
@ -1617,7 +1617,7 @@ cairo_status_t
_cairo_gstate_in_fill (cairo_gstate_t *gstate,
double x,
double y,
int *inside_ret)
cairo_bool_t *inside_ret)
{
cairo_status_t status = CAIRO_STATUS_SUCCESS;
cairo_traps_t traps;

View file

@ -667,32 +667,32 @@ _cairo_traps_tessellate_polygon (cairo_traps_t *traps,
return CAIRO_STATUS_SUCCESS;
}
static int
static cairo_bool_t
_cairo_trap_contains (cairo_trapezoid_t *t, cairo_point_t *pt)
{
cairo_slope_t slope_left, slope_pt, slope_right;
if (t->top > pt->y)
return 0;
return FALSE;
if (t->bottom < pt->y)
return 0;
return FALSE;
_cairo_slope_init (&slope_left, &t->left.p1, &t->left.p2);
_cairo_slope_init (&slope_pt, &t->left.p1, pt);
if (_cairo_slope_compare (&slope_left, &slope_pt) < 0)
return 0;
return FALSE;
_cairo_slope_init (&slope_right, &t->right.p1, &t->right.p2);
_cairo_slope_init (&slope_pt, &t->right.p1, pt);
if (_cairo_slope_compare (&slope_pt, &slope_right) < 0)
return 0;
return FALSE;
return 1;
return TRUE;
}
int
cairo_bool_t
_cairo_traps_contain (cairo_traps_t *traps, double x, double y)
{
int i;
@ -703,10 +703,10 @@ _cairo_traps_contain (cairo_traps_t *traps, double x, double y)
for (i = 0; i < traps->num_traps; i++) {
if (_cairo_trap_contains (&traps->traps[i], &point))
return 1;
return TRUE;
}
return 0;
return FALSE;
}
void

View file

@ -1,153 +1,144 @@
/*
* Copyright © 2005 Red Hat Inc.
/* cairo - a vector graphics library with display and print output
*
* 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 Red Hat Inc. not be used
* in advertising or publicity pertaining to distribution of the software
* without specific, written prior permission. Red Hat Inc. makes no
* representations about the suitability of this software for any purpose.
* It is provided "as is" without express or implied warranty.
* Copyright © 2005 Red Hat, Inc
*
* RED HAT INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL RED HAT INC. 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.
* 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.
*
* Author: Owen Taylor <otaylor@redhat.com>
* 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.
*
* Contributor(s):
*/
#include "cairoint.h"
#include "cairo-win32-private.h"
const cairo_font_backend_t cairo_ft_font_backend;
/*
* The simple 2x2 matrix is converted into separate scale and shape
* factors so that hinting works right
*/
#define LOGICAL_SCALE 32
typedef struct {
double x_scale, y_scale;
double shape[2][2];
} ft_font_transform_t;
cairo_font_t base;
LOGFONT logfont;
BYTE quality;
/* We do drawing and metrics computation in a "logical space" which
* is similar to font space, except that it is scaled by a factor
* of the (desired font size) * (LOGICAL_SCALE). The multiplication
* by LOGICAL_SCALE allows for sub-pixel precision.
*/
double logical_scale;
/* The size we should actually request the font at from Windows; differs
* from the logical_scale because it is quantized for orthogonal
* transformations
*/
double logical_size;
/* Transformations from device <=> logical space
*/
cairo_matrix_t logical_to_device;
cairo_matrix_t device_to_logical;
/* We special case combinations of 90-degree-rotations, scales and
* flips ... that is transformations that take the axes to the
* axes. If preserve_axes is true, then swap_axes/swap_x/swap_y
* encode the 8 possibilities for orientation (4 rotation angles with
* and without a flip), and scale_x, scale_y the scale components.
*/
cairo_bool_t preserve_axes;
cairo_bool_t swap_axes;
cairo_bool_t swap_x;
cairo_bool_t swap_y;
double x_scale;
double y_scale;
} cairo_win32_font_t;
static void
_compute_transform (ft_font_transform_t *sf,
cairo_font_scale_t *sc)
_compute_transform (cairo_win32_font_t *font,
cairo_font_scale_t *sc)
{
cairo_matrix_t normalized;
double tx, ty;
/* The font matrix has x and y "scale" components which we extract and
* use as character scale values. These influence the way freetype
* chooses hints, as well as selecting different bitmaps in
* hand-rendered fonts. We also copy the normalized matrix to
* freetype's transformation.
*/
int pixel_size;
cairo_matrix_set_affine (&normalized,
if (NEARLY_ZERO (sc->matrix[0][1]) && NEARLY_ZERO (sc->matrix[1][0])) {
font->preserve_axes = TRUE;
font->x_scale = sc->matrix[0][0];
font->swap_x = (sc->matrix[0][0] < 0);
font->y_scale = sc->matrix[1][1];
font->swap_y = (sc->matrix[1][1] < 0);
font->swap_axes = FALSE;
} else if (NEARLY_ZERO (sc->matrix[0][0]) && NEARLY_ZERO (sc->matrix[1][1])) {
font->preserve_axes = TRUE;
font->x_scale = sc->matrix[0][1];
font->swap_x = (sc->matrix[0][1] < 0);
font->y_scale = sc->matrix[1][0];
font->swap_y = (sc->matrix[1][0] < 0);
font->swap_axes = TRUE;
}
if (font->preserve_axes) {
if (font->swap_x)
font->x_scale = - font->x_scale;
if (font->swap_y)
font->y_scale = - font->y_scale;
font->logical_scale = LOGICAL_SCALE * font->y_scale;
font->logical_size = LOGICAL_SCALE * floor (font->y_scale + 0.5);
}
/* The font matrix has x and y "scale" components which we extract and
* use as character scale values.
*/
cairo_matrix_set_affine (&font->logical_to_device,
sc->matrix[0][0],
sc->matrix[0][1],
sc->matrix[1][0],
sc->matrix[1][1],
0, 0);
_cairo_matrix_compute_scale_factors (&normalized,
&sf->x_scale, &sf->y_scale,
/* XXX */ 1);
cairo_matrix_scale (&normalized, 1.0 / sf->x_scale, 1.0 / sf->y_scale);
cairo_matrix_get_affine (&normalized,
&sf->shape[0][0], &sf->shape[0][1],
&sf->shape[1][0], &sf->shape[1][1],
&tx, &ty);
}
/* Temporarily scales an unscaled font to the give scale. We catch
* scaling to the same size, since changing a FT_Face is expensive.
*/
static void
_ft_unscaled_font_set_scale (ft_unscaled_font_t *unscaled,
cairo_font_scale_t *scale)
{
int need_scale;
ft_font_transform_t sf;
FT_Matrix mat;
assert (unscaled->face != NULL);
if (scale->matrix[0][0] == unscaled->current_scale.matrix[0][0] &&
scale->matrix[0][1] == unscaled->current_scale.matrix[0][1] &&
scale->matrix[1][0] == unscaled->current_scale.matrix[1][0] &&
scale->matrix[1][1] == unscaled->current_scale.matrix[1][1])
return;
unscaled->current_scale = *scale;
if (!font->preserve_axes) {
double x_scale, y_scale;
_compute_transform (&sf, scale);
_cairo_matrix_compute_scale_factors (&font->logical_to_device,
&font->x_scale, &font->y_scale,
TRUE); /* XXX: Handle vertical text */
unscaled->x_scale = sf.x_scale;
unscaled->y_scale = sf.y_scale;
mat.xx = DOUBLE_TO_16_16(sf.shape[0][0]);
mat.yx = - DOUBLE_TO_16_16(sf.shape[0][1]);
mat.xy = - DOUBLE_TO_16_16(sf.shape[1][0]);
mat.yy = DOUBLE_TO_16_16(sf.shape[1][1]);
if (need_scale) {
FT_Set_Transform(unscaled->face, &mat, NULL);
FT_Set_Pixel_Sizes(unscaled->face,
(FT_UInt) sf.x_scale,
(FT_UInt) sf.y_scale);
font->logical_size = floor (LOGICAL_SCALE * y_scale + 0.5);
font->logical_scale = LOGICAL_SCALE * y_scale + 0.5;
}
}
/* implement the font backend interface */
cairo_matrix_scale (&font->logical_to_device,
1.0 / (LOGICAL_SCALE * font->y_scale),
1.0 / (LOGICAL_SCALE * font->y_scale));
typedef struct {
cairo_font_t base;
FcPattern *pattern;
int load_flags;
ft_unscaled_font_t *unscaled;
} cairo_ft_font_t;
static void
_utf8_to_ucs4 (char const *utf8,
FT_ULong **ucs4,
size_t *nchars)
{
int len = 0, step = 0;
size_t n = 0, alloc = 0;
FcChar32 u = 0;
if (utf8 == NULL || ucs4 == NULL || nchars == NULL)
return;
len = strlen (utf8);
alloc = len;
*ucs4 = malloc (sizeof (FT_ULong) * alloc);
if (*ucs4 == NULL)
return;
while (len && (step = FcUtf8ToUcs4(utf8, &u, len)) > 0)
{
if (n == alloc)
{
alloc *= 2;
*ucs4 = realloc (*ucs4, sizeof (FT_ULong) * alloc);
if (*ucs4 == NULL)
return;
}
(*ucs4)[n++] = u;
len -= step;
utf8 += step;
}
*nchars = n;
font->device_to_logical = font->logical_to_device;
if (!CAIRO_OK (cairo_matrix_invert (&font->device_to_logical)))
cairo_matrix_set_identity (font->device_to_logical);
}
static BYTE
@ -156,7 +147,7 @@ _get_system_quality (void)
BOOL font_smoothing;
if (!SystemParametersInfo (SPI_GETFONTSMOOTHING, 0, &font_smoothing, 0)) {
_print_gdi_error ();
_cairo_win32_print_gdi_error ();
return FALSE;
}
@ -166,7 +157,7 @@ _get_system_quality (void)
version_info.size = sizeof (OSVERSIONINFO);
if (!GetVersionEx (&version_info)) {
_print_gdi_error ();
_cairo_win32_print_gdi_error ();
return FALSE;
}
@ -177,7 +168,7 @@ _get_system_quality (void)
if (!SystemParametersInfo (SPI_GETFONTSMOOTHINGTYPE,
0, &smoothing_type, 0)) {
_print_gdi_error ();
_cairo_win32_print_gdi_error ();
return FALSE;
}
@ -192,6 +183,29 @@ _get_system_quality (void)
}
static cairo_font_t *
_win32_font_create (LOGFONT *logfont,
cairo_font_scale_t *scale)
{
cairo_win32_font_t *f;
ft_font_transform_t sf,
f = malloc (sizeof(cairo_win32_font_t));
if (f == NULL)
return NULL;
f->logfont = *logfont;
f->quality = _get_system_quality ();
_compute_transform (f, scale);
_cairo_font_init ((cairo_font_t *)f, &sc, &cairo_win32_font_backend);
return (cairo_font_t *)f;
}
/* implement the font backend interface */
static cairo_status_t
_cairo_ft_font_create (const char *family,
cairo_font_slant_t slant,
@ -245,7 +259,7 @@ _cairo_ft_font_create (const char *family,
if (!logfont.lfFaceName)
return CAIRO_STATUS_NO_MEMORY;
font = cairo_win32_font_create_for_logfont (logfont, scale);
font = _win32_font_create (logfont, scale);
if (!font)
return CAIRO_STATUS_NO_MEMORY;
@ -269,6 +283,107 @@ _cairo_ft_font_get_glyph_cache_key (void *abstract_font,
return CAIRO_STATUS_NO_MEMORY;
}
/* Taken from fontconfig sources, Copyright © 2000 Keith Packard */
int
_utf8_to_ucs4 (const char *src_orig,
unsigned long *dst,
int len)
{
const FcChar8 *src = src_orig;
FcChar8 s;
int extra;
FcChar32 result;
if (len == 0)
return 0;
s = *src++;
len--;
if (!(s & 0x80))
{
result = s;
extra = 0;
}
else if (!(s & 0x40))
{
return -1;
}
else if (!(s & 0x20))
{
result = s & 0x1f;
extra = 1;
}
else if (!(s & 0x10))
{
result = s & 0xf;
extra = 2;
}
else if (!(s & 0x08))
{
result = s & 0x07;
extra = 3;
}
else if (!(s & 0x04))
{
result = s & 0x03;
extra = 4;
}
else if ( ! (s & 0x02))
{
result = s & 0x01;
extra = 5;
}
else
{
return -1;
}
if (extra > len)
return -1;
while (extra--)
{
result <<= 6;
s = *src++;
if ((s & 0xc0) != 0x80)
return -1;
result |= s & 0x3f;
}
*dst = result;
return src - src_orig;
}
static cairo_status_t
_utf8_to_utf16 (char const *utf8,
FT_ULong **ucs4,
size_t *nchars)
{
int len = 0, step = 0;
size_t n = 0, alloc = 0;
FcChar32 u = 0;
if (utf8 == NULL || ucs4 == NULL || nchars == NULL)
return;
len = strlen (utf8);
alloc = len;
*ucs4 = malloc (sizeof (FT_ULong) * alloc);
if (*ucs4 == NULL)
return;
while (len && (step = FcUtf8ToUcs4(utf8, &u, len)) > 0)
{
(*ucs4)[n++] = u;
len -= step;
utf8 += step;
}
*nchars = n;
return CAIRO_STATUS_NO_MEMORY;
}
static cairo_status_t
_cairo_ft_font_text_to_glyphs (void *abstract_font,
const unsigned char *utf8,
@ -276,26 +391,145 @@ _cairo_ft_font_text_to_glyphs (void *abstract_font,
int *nglyphs)
{
cairo_win32_font_t *font = abstract_font;
cairo_status_t status;
GCP_RESULTSW results;
WCHAR glyphs[1024];
int dx[1024];
DWORD ret;
status =
results.lStructSize = sizeof (GCP_RESULTS);
results.lpOutString = NULL;
results.lpOrder = NULL;
results.lpDx = dx;
results.lpCaretPos = NULL;
results.lpClass = NULL;
results.lpGlyphs = glyphs;
results.nGlyphs = 1024;
ret = GetCharacterPlacementW (hdc, strs[i], wcslen(strs[i]),
0,
&results,
GCP_DIACRITIC | GCP_LIGATE | GCP_GLYPHSHAPE | GCP_REORDER);
if (!ret)
_print_gdi_error ("GetCharacterPlacement");
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_ft_font_font_extents (void *abstract_font,
cairo_font_extents_t *extents)
_cairo_win32_font_font_extents (void *abstract_font,
cairo_font_extents_t *extents)
{
cairo_win32_font_t *font = abstract_font;
TEXTMETRIC metrics;
HDC hdc;
if (font->preserve_axes) {
/* For 90-degree rotations (including 0), we get the metrics
* from the GDI in logical space, then convert back to font space
*/
hdc = _cairo_win32_font_acquire_scaled_dc (font);
GetTextMetrics (hdc, &metrics);
_cairo_win32_font_release_scaled_dc (font);
extents->ascent = metrics.tmAscent / font->logical_scale;
extents->descent = metrics.tmDescent / font->logical_scale;
extents->height = (metrics.tmHeight + metrics.tmExternalLeading) / font->logical_scale;
extents->max_x_advance = metrics.tmMaxCharWidth / font->logical_scale;
extents->max_y_advance = 0;
} else {
/* For all other transformations, we use the design metrics
* of the font. The GDI results from GetTextMetrics() on a
* transformed font are inexplicably large and we want to
* avoid them.
*/
hdc = _cairo_win32_font_acquire_unscaled_dc (font);
GetTextMetrics (hdc, &metrics);
_cairo_win32_font_release_unscaled_dc (font);
extents->ascent = (double)metrics.tmAscent / font->em_square;
extents->descent = metrics.tmDescent * font->em_square;
extents->height = (double)(metrics.tmHeight + mertrics.tmExternalLeading) / font->em_square;
extents->max_x_advance = (double)(metrics.tmMaxCharWidth) / font->em_square;
extents->max_y_advance = 0;
}
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_ft_font_glyph_extents (void *abstract_font,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_text_extents_t *extents)
_cairo_win32_font_glyph_extents (void *abstract_font,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_text_extents_t *extents)
{
cairo_win32_font_t *font = abstract_font;
static const MAT2 matrix = { { 0, 1 }, { 0, 0 }, { 0, 0 }, { 0, 1 } };
GLYPHMETRICS metrics;
HDC hdc;
/* We handle only the case num_glyphs == 1, glyphs[i].x == glyphs[0].y == 0.
* This is all that the calling code triggers, and the backend interface
* will eventually be changed to match
*/
assert (num_glyphs == 1);
if (font->preserve_axes) {
/* If we aren't rotating / skewing the axes, then we get the metrics
* from the GDI in device space and convert to font space.
*/
hdc = _cairo_win32_font_acquire_scaled_dc (font);
GetGlyphOutline(hdc, str[i], GGO_METRICS, &glyph_metrics, 0, NULL, &matrix);
_cairo_win32_font_release_scaled_dc (font);
if (font->swap_axes) {
extents->x_bearing = metrics.gmptGlyphOrigin.y / font->y_scale;
extents->y_bearing = metrics.gmptGlyphOrigin.x / font->x_scale;
extents->width = metrics.gmBlackBoxY / font->y_scale;
extents->height = metrics.gmBlackBoxX / font->x_scale;
extents->x_advance = metrics.gmCellIncY / font->x_scale;
extents->y_advance = metrics.gmCellIncX / font->y_scale;
} else {
extents->x_bearing = metrics.gmptGlyphOrigin.x / font->x_scale;
extents->y_bearing = metrics.gmptGlyphOrigin.y / font->y_scale;
extents->width = metrics.gmBlackBoxX / font->x_scale;
extents->height = metrics.gmBlackBoxY / font->y_scale;
extents->x_advance = metrics.gmCellIncX / font->x_scale;
extents->y_advance = metrics.gmCellIncY / font->y_scale;
}
if (font->swap_x) {
extents->x_bearing = (- extents->x_bearing - extents->width);
extents->x_advance = - extents->x_advance;
}
if (font->swap_y) {
extents->y_bearing = (- extents->y_bearing - extents->height);
extents->y_advance = - extents->y_advance;
}
} else {
/* For all other transformations, we use the design metrics
* of the font.
*/
hdc = _cairo_win32_font_acquire_unscaled_dc (font);
GetGlyphOutline(hdc, str[i], GGO_METRICS, &glyph_metrics, 0, NULL, &matrix);
_cairo_win32_font_release_unscaled_dc (font);
extents->x_bearing = (double)metrics.gmptGlyphOrigin.x / font->em_square;
extents->y_bearing = (double)metrics.gmptGlyphOrigin.y / font->em_square;
extents->width = (double)metrics.gmBlackBoxX / font->em_square;
extents->height = (double)metrics.gmBlackBoxY / font->em_square;
extents->x_advance = (double)metrics.gmCellIncX / font->em_square;
extents->y_advance = (double)metrics.gmCellIncY / font->em_square;
}
return CAIRO_STATUS_SUCCESS;
}
@ -304,26 +538,277 @@ _cairo_ft_font_glyph_extents (void *abstract_font,
static cairo_status_t
_cairo_ft_font_glyph_bbox (void *abstract_font,
const cairo_glyph_t *glyphs,
int num_glyphs,
int num_glyphs,
cairo_box_t *bbox)
{
static const MAT2 matrix = { { 0, 1 }, { 0, 0 }, { 0, 0 }, { 0, 1 } };
cairo_win32_font_t *font = abstract_font;
int x1 = 0, x2 = 0, y1 = 0, y2 = 0;
if (num_glyphs > 0) {
HDC hdc = _cairo_win32_font_acquire_scaled_dc (font);
int i;
for (i = 0; i < num_glyphs; i++) {
int x = floor (0.5 + glyphs[i].x);
int y = floor (0.5 + glyphs[i].y);
GetGlyphOutline (hdc, glyphs[i], GGO_METRICS | GGO_GLYPH_INDEX,
&glyph_metrics, 0, NULL, &matrix);
if (i == 0 || x1 > x + metrics.gmptGlyphOrigin.x)
x1 = x + metrics.gmptGlyphOrigin.x;
if (i == 0 || y1 > y + metrics.gmptGlyphOrigin.y)
y1 = x + metrics.gmptGlyphOrigin.y;
if (i == 0 || x2 < x + metrics.gmptGlyphOrigin.x + metrics.gmBlackBoxX)
x2 = x + metrics.gmptGlyphOrigin.x + metrics.gmBlackBoxX;
if (i == 0 || y2 < y + metrics.gmptGlyphOrigin.y + metrics.gmBlackBoxY)
y2 = y + metrics.gmptGlyphOrigin.x + metrics.gmBlackBoxY;
}
_cairo_win32_font_release_scaled_dc (font);
}
bbox->p1.x = _cairo_fixed_from_int (x1);
bbox->p1.y = _cairo_fixed_from_int (y1);
bbox->p2.x = _cairo_fixed_from_int (x2);
bbox->p2.y = _cairo_fixed_from_int (y2);
return CAIRO_STATUS_SUCCESS;
}
#define FIXED_BUF_SIZE 1024
typedef struct {
cairo_win32_font_t *font;
HDC dc;
cairo_array_t glyphs;
cairo_array_t dx;
int last_x;
int last_y;
} cairo_glyph_state_t;
static void
_start_glyphs (cairo_glyph_state_t *state,
cairo_win32_font_t *font,
HDC dc)
{
state->dc = dc;
state->font = font;
_cairo_array_init (&state->glyphs, sizeof (WCHAR));
_cairo_array_init (&state->dx, sizeof (int));
}
static void
_flush_glyphs (cairo_glyph_state_t *state)
{
ExtTextOutW (state->dc,
state->start_x, state->last_y,
ETO_CLIPPED,
NULL,
(WCHAR *)state->glyphs.elements,
state->glyphs.num_elements,
(int *)state->dx.elements);
_cairo_array_truncate (&state->glyphs, 0);
_cairo_array_truncate (&state->dx, 0);
}
static void
_add_glyph (cairo_glyph_state_t *state,
unsigned long index,
double device_x,
double device_y)
{
double user_x = device_x;
double user_y = device_y;
WCHAR glyph_index = index;
int logical_x, logical_y;
cairo_matrix_transform_point (&state->font->device_to_logical, &user_x, &user_y);
logical_x = DOUBLE_TO_LOGICAL (user_x);
logical_y = DOUBLE_TO_LOGICAL (user_y);
if (state->glyphs.num_elements > 0) {
int dx;
if (logical_y != state->last_y) {
_flush_glyphs (state);
state->start_x = logical_x;
}
dx = logical_x - state->last_x;
_cairo_array_append (&state->dx, &logical_x, 1);
} else {
state->start_x = logical_x;
}
state->last_x = logical_x;
state->last_y = logical_y;
_cairo_array_append (&state->glyphs, &glyph_index, 1);
}
static void
_finish_glyphs (cairo_glyph_state_t *state,
HDC dc)
{
state->dc = dc;
_flush_glyphs (state);
_cairo_array_fini (&state->glyphs);
_cairo_array_init (&state->dx);
}
static cairo_status_t
_draw_glyphs_on_surface (cairo_win32_surface_t *surface,
HBRUSH brush,
int x_offset,
int y_offset,
const cairo_glyph_t *glyphs,
int num_glyphs)
{
cairo_glyph_state_t state;
cairo_status status;
int prev_mode;
XFORM xform;
XFORM prev_xform;
BRUSH old_brush;
old_brush = SelectObject (tmp_surface->dc, brush);
if (!old_brush)
return _print_gdi_error ();l
prev_mode = GetGraphicsMode (surface->dc);
SetGraphicsMode (surface->dc, GM_ADVANCED);
GetWorldTransform (surface->dc, &prev_xform);
xForm.eM11 = font->logical_to_device->m[0][0];
xForm.eM21 = font->logical_to_device->m[1][0];
xForm.eM12 = font->logical_to_device->m[0][1];
xForm.eM22 = font->logical_to_device->m[1][1];
xForm.eDx = matrix->m[2][0];
xForm.eDy = matrix->m[2][1];
SetWorldTransform (surface->dc, &xform);
_start_glyphs (&glyph_state, tmp_surface->dc);
for (i = 0; i < num_glyphs; i++) {
status = _add_glyph (&glyph_state, glyphs[i].glyph, glyphs[i].x - x, glyphs[i].y - y);
if (!CAIRO_OK (status))
goto FAIL;
}
FAIL:
_finish_glyphs (&glyph_state);
SetWorldTransform (surface>dc, &prev_xform);
SetGraphicsMode (surface->dc, prev_mode);
SelectObject (tmp_surface->dc, old_brush);
}
static cairo_status_t
_cairo_ft_font_show_glyphs (void *abstract_font,
cairo_operator_t operator,
cairo_surface_t *source,
cairo_surface_t *surface,
int source_x,
int source_y,
const cairo_glyph_t *glyphs,
int num_glyphs)
_cairo_win32_font_show_glyphs (void *abstract_font,
cairo_operator_t operator,
cairo_pattern_t *pattern,
cairo_surface_t *surface,
int source_x,
int source_y,
int dest_x,
int dest_y,
unsigned int width,
unsigned int height,
const cairo_glyph_t *glyphs,
int num_glyphs)
{
cairo_win32_font_t *font = abstract_font;
cairo_bbox_t bbox;
cairo_win32_surface_t *win32_surface = (cairo_win32_surface_t *)surface;
cairo_win32_surface_t *tmp_surface;
int i;
RECT r;
if (_cairo_surface_is_win32 (surface) &&
win32_surface->format == CAIRO_FORMAT_RGB24 &&
operator == CAIRO_OPERATOR_OVER &&
pattern->type == CAIRO_PATTERN_SOLID &&
(pattern->color.alpha_short >> 8) == 255) {
/* When compositing OVER on a GDI-understood surface, with a
* solid opaque color, we can just call ExtTextOut directly.
*/
COLORREF new_color;
HBRUSH brush;
new_color = RGB (pattern->color.red_short >> 8,
pattern->color.green_short >> 8,
pattern->color.blue_short >> 8);
brush = CreateSolidBrush (new_color);
if (!brush)
return _cairo_win32_print_gdi_error ("_cairo_win32_font_show_glyphs");
_draw_glyphs_on_surface (win32_surface, brush, glyphs, num_glyphs, 0, 0);
DeleteObject (new_brush);
} else {
/* Otherwise, we need to draw using software fallbacks. We create a mask
/* surface by drawing the the glyphs onto a DIB, white-on-black.
*/
tmp_surface = (cairo_win32_surface_t *)_cairo_win32_surface_create_dib (CAIRO_FORMAT_ARGB32, width, height);
r.left = 0;
r.top = 0;
r.right = width;
r.height = height;
FillRect (hdc, &r, GetStockObject (BLACK_BRUSH));
_draw_glyphs_on_surface (win32_surface, GetStockObject (WHITE_BRUSH),
glyphs, num_glyphs, x, y);
if (font->quality == CLEARTYPE_QUALITY) {
/* For ClearType, we need a 4-channel mask. If we are compositing on
* a surface with alpha, we need to compute the alpha channel of
* the mask as the average of the other channels. But for a destination
* surface without alpha the alpha channel of the mask is ignored
*/
if (win32_surface->format != CAIRO_FORMAT_ARGB24)
_compute_argb32_mask_alpha (tmp_surface);
mask_surface = tmp_surface;
} else {
mask_surface = _compute_a8_mask (tmp_surface);
cairo_suface_destroy (tmp_surface);
}
/* For operator == OVER, no-cleartype, a possible optimization here is to
* draw onto an intermediate ARGB32 surface and alpha-blend that with the
* destination
*/
status = _cairo_surface_composite (operator, pattern,
&(mask_surface->base),
surface,
source_x, source_y,
0, 0,
x, y,
width, height);
cairo_surface_destroy (mask_surface);
}
return CAIRO_STATUS_SUCCESS;
}
@ -365,16 +850,12 @@ cairo_font_t *
cairo_win32_font_create_for_logfont (LOGFONT *logfont,
cairo_matrix_t *scale)
{
cairo_win32_font_t *f;
cairo_font_scale_t sc;
cairo_matrix_get_affine (scale,
&sc.matrix[0][0], &sc.matrix[0][1],
&sc.matrix[1][0], &sc.matrix[1][1],
NULL, NULL);
f = malloc (sizeof(cairo_win32_font_t));
if (f == NULL)
return NULL;
f->logfont = *logfont;
_cairo_font_init ((cairo_font_t *)f, &sc, &cairo_win32_font_backend);
return (cairo_font_t *)f;
return _win32_font_create (logfont, &sc);
}

View file

@ -47,8 +47,17 @@
static const cairo_surface_backend_t cairo_win32_surface_backend;
static void
_print_gdi_error (const char *context)
/**
* _cairo_win32_print_gdi_error:
* @context: context string to display along with the error
*
* Helper function to dump out a human readable form of the
* current error code.
*
* Return value: A Cairo status code for the error code
**/
cairo_status_t
_cairo_win32_print_gdi_error (const char *context)
{
void *lpMsgBuf;
DWORD last_error = GetLastError ();
@ -66,12 +75,8 @@ _print_gdi_error (const char *context)
LocalFree (lpMsgBuf);
}
}
static cairo_status_t
_get_cairo_error (void)
{
/* We should switch off of GetLastError, but we'd either return
/* We should switch off of last_status, but we'd either return
* CAIRO_STATUS_NO_MEMORY or CAIRO_STATUS_UNKNOWN_ERROR and there
* is no CAIRO_STATUS_UNKNOWN_ERROR.
*/
@ -79,6 +84,11 @@ _get_cairo_error (void)
return CAIRO_STATUS_NO_MEMORY;
}
static cairo_status_t
_get_cairo_error (void)
{
}
void
cairo_set_target_win32 (cairo_t *cr,
HDC hdc)
@ -130,6 +140,7 @@ _create_dc_and_bitmap (HDC original_dc,
{
HDC dc = NULL;
HBITMAP bitmap = NULL;
cairo_status_t status;
BITMAPINFO *bitmap_info = NULL;
struct {
@ -257,7 +268,7 @@ _create_dc_and_bitmap (HDC original_dc,
return CAIRO_STATUS_SUCCESS;
FAIL:
_print_gdi_error ("_create_dc_and_bitmap");
status = _cairo_win32_print_gdi_error ("_create_dc_and_bitmap");
if (bitmap_info && num_palette > 2)
free (bitmap_info);
@ -268,7 +279,7 @@ _create_dc_and_bitmap (HDC original_dc,
if (dc)
DeleteDC (dc);
return _get_cairo_error ();
return status;
}
static cairo_surface_t *
@ -360,6 +371,7 @@ _cairo_win32_surface_get_subimage (cairo_win32_surface_t *surface,
cairo_win32_surface_t **local_out)
{
cairo_win32_surface_t *local;
cairo_status_t status;
local =
(cairo_win32_surface_t *) _cairo_win32_surface_create_similar (surface,
@ -382,12 +394,12 @@ _cairo_win32_surface_get_subimage (cairo_win32_surface_t *surface,
return CAIRO_STATUS_SUCCESS;
FAIL:
_print_gdi_error ("_cairo_win32_surface_get_subimage");
status = _cairo_win32_print_gdi_error ("_cairo_win32_surface_get_subimage");
if (local)
cairo_surface_destroy (&local->base);
return _get_cairo_error ();
return status;
}
static cairo_status_t
@ -457,10 +469,8 @@ _cairo_win32_surface_acquire_dest_image (void *abstract_surfa
return CAIRO_STATUS_SUCCESS;
}
if (GetClipBox (surface->dc, &clip_box) == ERROR) {
_print_gdi_error ("_cairo_win3_surface_acquire_dest_image");
return _get_cairo_error ();
}
if (GetClipBox (surface->dc, &clip_box) == ERROR)
return _cairo_win32_print_gdi_error ("_cairo_win3_surface_acquire_dest_image");
x1 = clip_box.left;
x2 = clip_box.right;
@ -517,9 +527,8 @@ _cairo_win32_surface_release_dest_image (void *abstract_surfac
image_rect->width, image_rect->height,
local->dc,
0, 0,
SRCCOPY)) {
_print_gdi_error ("_cairo_win32_surface_release_dest_image");
}
SRCCOPY))
_cairo_win32_print_gdi_error ("_cairo_win32_surface_release_dest_image");
cairo_surface_destroy ((cairo_surface_t *)local);
}
@ -613,10 +622,8 @@ _cairo_win32_surface_composite (cairo_operator_t operator,
width, height,
src->dc,
src_x + itx, src_y + ity,
SRCCOPY)) {
_print_gdi_error ("_cairo_win32_surface_composite");
return _get_cairo_error ();
}
SRCCOPY))
return _cairo_win32_print_gdi_error ("_cairo_win32_surface_composite");
return CAIRO_STATUS_SUCCESS;
@ -641,10 +648,8 @@ _cairo_win32_surface_composite (cairo_operator_t operator,
src->dc,
src_x + itx, src_y + ity,
width, height,
blend_function)) {
_print_gdi_error ("_cairo_win32_surface_composite");
return _get_cairo_error ();
}
blend_function))
return _cairo_win32_print_gdi_error ("_cairo_win32_surface_composite");
return CAIRO_STATUS_SUCCESS;
}
@ -660,6 +665,7 @@ _cairo_win32_surface_fill_rectangles (void *abstract_surface,
int num_rects)
{
cairo_win32_surface_t *surface = abstract_surface;
cairo_status_t status;
COLORREF new_color;
HBRUSH new_brush;
int i;
@ -681,10 +687,8 @@ _cairo_win32_surface_fill_rectangles (void *abstract_surface,
new_color = RGB (color->red_short >> 8, color->green_short >> 8, color->blue_short >> 8);
new_brush = CreateSolidBrush (new_color);
if (!new_brush) {
_print_gdi_error ("_cairo_win32_surface_fill_rectangles");
return _get_cairo_error ();
}
if (!new_brush)
return _cairo_win32_print_gdi_error ("_cairo_win32_surface_fill_rectangles");
for (i = 0; i < num_rects; i++) {
RECT rect;
@ -703,11 +707,11 @@ _cairo_win32_surface_fill_rectangles (void *abstract_surface,
return CAIRO_STATUS_SUCCESS;
FAIL:
_print_gdi_error ("_cairo_win32_surface_fill_rectangles");
status = _cairo_win32_print_gdi_error ("_cairo_win32_surface_fill_rectangles");
DeleteObject (new_brush);
return _get_cairo_error ();
return status;
}
static cairo_int_status_t
@ -744,6 +748,7 @@ _cairo_win32_surface_set_clip_region (void *abstract_surface,
pixman_region16_t *region)
{
cairo_win32_surface_t *surface = abstract_surface;
cairo_status_t status;
/* If we are in-memory, then we set the clip on the image surface
* as well as on the underlying GDI surface.
@ -761,10 +766,8 @@ _cairo_win32_surface_set_clip_region (void *abstract_surface,
/* Clear any clip set by Cairo, return to the original */
if (surface->set_clip) {
if (SelectClipRgn (surface->dc, surface->saved_clip) == ERROR) {
_print_gdi_error ("_cairo_win32_surface_set_clip_region");
return _get_cairo_error ();
}
if (SelectClipRgn (surface->dc, surface->saved_clip) == ERROR)
return _cairo_win32_print_gdi_error ("_cairo_win32_surface_set_clip_region");
if (surface->saved_clip) {
DeleteObject (surface->saved_clip);
@ -851,9 +854,9 @@ _cairo_win32_surface_set_clip_region (void *abstract_surface,
return CAIRO_STATUS_SUCCESS;
FAIL:
_print_gdi_error ("_cairo_win32_surface_set_clip_region");
status = _cairo_win32_print_gdi_error ("_cairo_win32_surface_set_clip_region");
DeleteObject (gdi_region);
return _get_cairo_error ();
return status;
}
}
@ -883,7 +886,7 @@ cairo_win32_surface_create (HDC hdc)
/* Try to figure out the drawing bounds for the Device context
*/
if (GetClipBox (hdc, &rect) == ERROR) {
_print_gdi_error ("cairo_win32_surface_create");
_cairo_win32_print_gdi_error ("cairo_win32_surface_create");
return NULL;
}

View file

@ -111,6 +111,14 @@
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#ifndef FALSE
#define FALSE 0
#endif
#ifndef TRUE
#define TRUE 1
#endif
#include "cairo-wideint.h"
typedef int32_t cairo_fixed_16_16_t;
@ -1136,13 +1144,13 @@ cairo_private cairo_status_t
_cairo_gstate_in_stroke (cairo_gstate_t *gstate,
double x,
double y,
int *inside_ret);
cairo_bool_t *inside_ret);
cairo_private cairo_status_t
_cairo_gstate_in_fill (cairo_gstate_t *gstate,
double x,
double y,
int *inside_ret);
cairo_bool_t *inside_ret);
cairo_private cairo_status_t
_cairo_gstate_init_clip (cairo_gstate_t *gstate);
@ -1731,6 +1739,20 @@ cairo_private void
_cairo_pattern_end_draw (cairo_pattern_t *pattern,
cairo_pattern_info_t *info);
/* cairo_unicode.c */
cairo_private cairo_status_t
_cairo_utf8_to_ucs4 (const char *str,
int len,
uint32_t **result,
int *items_written);
cairo_private cairo_status_t
_cairo_utf8_to_utf16 (const char *str,
int len,
uint16_t **result,
int *items_written);
/* Avoid unnecessary PLT entries. */
slim_hidden_proto(cairo_close_path)