mirror of
https://gitlab.freedesktop.org/cairo/cairo.git
synced 2026-05-05 06:28:01 +02:00
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:
parent
f4ccbb4615
commit
711d7965c8
19 changed files with 1471 additions and 518 deletions
17
ChangeLog
17
ChangeLog
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
*~
|
||||
|
||||
|
|
@ -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)\
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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_ */
|
||||
|
|
|
|||
|
|
@ -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>";
|
||||
|
|
|
|||
23
src/cairo.h
23
src/cairo.h
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue