configure.in src/cairo-features.h.in: Add a check for the Windows platform and --enable-win32. Also add some (currently always off) stubs for native Win32 fonts.

Make building the PDF backend conditional on having FreeType.
src/Makefile.am src/cairo_win32_surface.c src/cairo_win32_font.c src/cairo-win32.h: Add a Win32 backend using GDI and software fallbacks Font code is not yet there yet, but it works with the fontconfig backend.
src/cairo_gdip_font.cpp src/cairo_gdip_surface.cpp: Remove remnants of a GDI+ based backend.
Prefer platform-specific font backends to the fontconfig backend.
This commit is contained in:
Owen Taylor 2005-01-31 16:11:37 +00:00
parent 26148a1d15
commit 86c8755e59
12 changed files with 2827 additions and 37 deletions

View file

@ -1,3 +1,23 @@
2005-01-31 Owen Taylor <otaylor@redhat.com>
* configure.in src/cairo-features.h.in: Add a check for the
Windows platform and --enable-win32. Also add some (currently
always off) stubs for native Win32 fonts.
* configure.in: Make building the PDF backend conditional
on having FreeType.
* src/Makefile.am src/cairo_win32_surface.c src/cairo_win32_font.c
src/cairo-win32.h: Add a Win32 backend using GDI and software
fallbacks Font code is not yet there yet, but it works with the
fontconfig backend.
* src/cairo_gdip_font.cpp src/cairo_gdip_surface.cpp: Remove
remnants of a GDI+ based backend.
* src/cairoint.h: Prefer platform-specific font backends
to the fontconfig backend.
2005-01-31 Owen Taylor <otaylor@redhat.com> 2005-01-31 Owen Taylor <otaylor@redhat.com>
* src/cairoint.h src/cairo_image_surface.c * src/cairoint.h src/cairo_image_surface.c

View file

@ -122,6 +122,50 @@ AC_SUBST(XCB_SURFACE_FEATURE)
dnl =========================================================================== dnl ===========================================================================
AC_MSG_CHECKING([for some Win32 platform])
case "$host" in
*-*-mingw*|*-*-cygwin*)
cairo_platform_win32=yes
;;
*)
cairo_platform_win32=no
;;
esac
AC_MSG_RESULT([$cairo_platform_win32])
AC_ARG_ENABLE(win32,
[ --disable-win32 Disable cairo's Microsoft Windows backend],
[use_win32=$enableval], [use_win32=yes])
if test "x$cairo_platform_win32" != "xyes" ; then
use_win32=no
fi
if test "x$use_win32" = "xyes"; then
CAIRO_LIBS="$CAIRO_LIBS -lgdi32 -lmsimg32"
fi
if test "x$use_win32" != "xyes"; then
WIN32_SURFACE_FEATURE=CAIRO_HAS_NO_WIN32_SURFACE
AM_CONDITIONAL(CAIRO_HAS_WIN32_SURFACE, false)
else
WIN32_SURFACE_FEATURE=CAIRO_HAS_WIN32_SURFACE
AM_CONDITIONAL(CAIRO_HAS_WIN32_SURFACE, true)
fi
if true || test "x$use_win32" != "xyes"; then
WIN32_FONT_FEATURE=CAIRO_HAS_NO_WIN32_FONT
AM_CONDITIONAL(CAIRO_HAS_WIN32_FONT, false)
else
WIN32_FONT_FEATURE=CAIRO_HAS_WIN32_FONT
AM_CONDITIONAL(CAIRO_HAS_WIN32_FONT, true)
fi
AC_SUBST(WIN32_SURFACE_FEATURE)
AC_SUBST(WIN32_FONT_FEATURE)
dnl ===========================================================================
AC_ARG_ENABLE(ps, AC_ARG_ENABLE(ps,
[ --disable-ps Disable cairo's PostScript backend], [ --disable-ps Disable cairo's PostScript backend],
[use_ps=$enableval], [use_ps=yes]) [use_ps=$enableval], [use_ps=yes])
@ -142,37 +186,27 @@ AC_SUBST(PS_LIBS)
dnl =========================================================================== dnl ===========================================================================
AC_ARG_ENABLE(pdf,
[ --disable-pdf Disable cairo's PDF backend],
[use_pdf=$enableval], [use_pdf=yes])
if test "x$use_pdf" != "xyes"; then
PDF_SURFACE_FEATURE=CAIRO_HAS_NO_PDF_SURFACE
AM_CONDITIONAL(CAIRO_HAS_PDF_SURFACE, false)
else
PDF_SURFACE_FEATURE=CAIRO_HAS_PDF_SURFACE
PDF_LIBS=-lz
AM_CONDITIONAL(CAIRO_HAS_PDF_SURFACE, true)
fi
CAIRO_LIBS="$CAIRO_LIBS $PDF_LIBS"
AC_SUBST(PDF_SURFACE_FEATURE)
AC_SUBST(PDF_LIBS)
dnl ===========================================================================
AC_ARG_ENABLE(png, AC_ARG_ENABLE(png,
[ --disable-png Disable cairo's PNG backend], [ --disable-png Disable cairo's PNG backend],
[use_png=$enableval], [use_png=yes]) [use_png=$enableval], [use_png=yes])
if test "x$use_png" = "xyes"; then if test "x$use_png" = "xyes"; then
PKG_CHECK_MODULES(PNG, libpng12, [ use_png=no
PNG_REQUIRES=libpng12 # libpng13 is GnuWin32's libpng-1.2.8 :-(
use_png=yes], [ for l in libpng12 libpng13 libpng10 ; do
PKG_CHECK_MODULES(PNG, libpng10, [ if $PKG_CONFIG --exists $l ; then
PNG_REQUIRES=libpng10 PNG_REQUIRES=$l
use_png=yes], [use_png="no (requires libpng http://www.libpng.org)"])]) use_png=yes
break
fi
done
if test "x$use_png" = "xyes" ; then
# Sets PNG_CFLAGS, PNG_LIBS
PKG_CHECK_MODULES(PNG, $PNG_REQUIRES)
else
AC_MSG_WARN([Could not find libpng in the pkg-config search path])
fi
fi fi
if test "x$use_png" != "xyes"; then if test "x$use_png" != "xyes"; then
@ -306,6 +340,31 @@ AC_SUBST(FT_FONT_FEATURE)
dnl =========================================================================== dnl ===========================================================================
AC_ARG_ENABLE(pdf,
[ --disable-pdf Disable cairo's PDF backend],
[use_pdf=$enableval], [use_pdf=yes])
if test x"$use_freetype" != "xyes" ; then
AC_MSG_WARN([PDF backend requires FreeType, disabling])
use_pdf=no
fi
if test "x$use_pdf" != "xyes"; then
PDF_SURFACE_FEATURE=CAIRO_HAS_NO_PDF_SURFACE
AM_CONDITIONAL(CAIRO_HAS_PDF_SURFACE, false)
else
PDF_SURFACE_FEATURE=CAIRO_HAS_PDF_SURFACE
PDF_LIBS=-lz
AM_CONDITIONAL(CAIRO_HAS_PDF_SURFACE, true)
fi
CAIRO_LIBS="$CAIRO_LIBS $PDF_LIBS"
AC_SUBST(PDF_SURFACE_FEATURE)
AC_SUBST(PDF_LIBS)
dnl ===========================================================================
dnl This check should default to 'yes' once we have code to actually dnl This check should default to 'yes' once we have code to actually
dnl check for the atsui font backend. dnl check for the atsui font backend.
@ -369,13 +428,15 @@ echo "cairo will be compiled with the following surface backends:"
echo " Xlib: $use_xlib" echo " Xlib: $use_xlib"
echo " Quartz: $use_quartz" echo " Quartz: $use_quartz"
echo " XCB: $use_xcb" echo " XCB: $use_xcb"
echo " Win32: $use_win32"
echo " PostScript: $use_ps" echo " PostScript: $use_ps"
echo " PDF: $use_pdf" echo " PDF: $use_pdf"
echo " PNG: $use_png" echo " PNG: $use_png"
echo " glitz: $use_glitz" echo " glitz: $use_glitz"
echo "" echo ""
echo "and the following font backends:" echo "and the following font backends:"
echo " freetype: $use_freetype" echo " FreeType: $use_freetype"
echo " atsui: $use_atsui" echo " Win32: false"
echo " ATSUI: $use_atsui"
echo "" echo ""

View file

@ -29,6 +29,15 @@ libcairo_xcb_headers = cairo-xcb.h
libcairo_xcb_sources = cairo_xcb_surface.c libcairo_xcb_sources = cairo_xcb_surface.c
endif endif
libcairo_win32_sources =
if CAIRO_HAS_WIN32_SURFACE
libcairo_win32_headers = cairo-win32.h
libcairo_win32_sources += cairo_win32_surface.c
endif
if CAIRO_HAS_WIN32_FONT
libcairo_win32_sources += cairo_win32_font.c
endif
if CAIRO_HAS_GLITZ_SURFACE if CAIRO_HAS_GLITZ_SURFACE
libcairo_glitz_headers = cairo-glitz.h libcairo_glitz_headers = cairo-glitz.h
libcairo_glitz_sources = cairo_glitz_surface.c libcairo_glitz_sources = cairo_glitz_surface.c
@ -62,6 +71,7 @@ cairoinclude_HEADERS = \
$(libcairo_png_headers) \ $(libcairo_png_headers) \
$(libcairo_ps_headers) \ $(libcairo_ps_headers) \
$(libcairo_quartz_headers) \ $(libcairo_quartz_headers) \
$(libcairo_win32_headers) \
$(libcairo_xcb_headers) \ $(libcairo_xcb_headers) \
$(libcairo_xlib_headers) $(libcairo_xlib_headers)
@ -101,6 +111,8 @@ libcairo_la_SOURCES = \
$(libcairo_quartz_sources)\ $(libcairo_quartz_sources)\
$(libcairo_xcb_sources) \ $(libcairo_xcb_sources) \
$(libcairo_glitz_sources)\ $(libcairo_glitz_sources)\
$(libcairo_win32_sources)\
$(libcairo_freetype_sources) \
cairoint.h cairoint.h
libcairo_la_LDFLAGS = -version-info @VERSION_INFO@ -no-undefined libcairo_la_LDFLAGS = -version-info @VERSION_INFO@ -no-undefined

View file

@ -49,10 +49,14 @@
#define @XCB_SURFACE_FEATURE@ #define @XCB_SURFACE_FEATURE@
#define @WIN32_SURFACE_FEATURE@
#define @GLITZ_SURFACE_FEATURE@ #define @GLITZ_SURFACE_FEATURE@
#define @FT_FONT_FEATURE@ #define @FT_FONT_FEATURE@
#define @WIN32_FONT_FEATURE@
#define @ATSUI_FONT_FEATURE@ #define @ATSUI_FONT_FEATURE@
#define @SANITY_CHECKING_FEATURE@ #define @SANITY_CHECKING_FEATURE@

View file

@ -394,7 +394,7 @@ static void
_fallback_cleanup (fallback_state_t *state) _fallback_cleanup (fallback_state_t *state)
{ {
_cairo_surface_release_dest_image (state->dst, &state->extents, _cairo_surface_release_dest_image (state->dst, &state->extents,
state->image, &state->image_rect, &state->image_extra); state->image, &state->image_rect, state->image_extra);
} }
static cairo_status_t static cairo_status_t

380
src/cairo-win32-font.c Normal file
View file

@ -0,0 +1,380 @@
/*
* Copyright © 2005 Red Hat Inc.
*
* 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.
*
* 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.
*
* Author: Owen Taylor <otaylor@redhat.com>
*/
#include "cairoint.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
*/
typedef struct {
double x_scale, y_scale;
double shape[2][2];
} ft_font_transform_t;
static void
_compute_transform (ft_font_transform_t *sf,
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.
*/
cairo_matrix_set_affine (&normalized,
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;
_compute_transform (&sf, scale);
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);
}
}
/* implement the font backend interface */
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;
}
static BYTE
_get_system_quality (void)
{
BOOL font_smoothing;
if (!SystemParametersInfo (SPI_GETFONTSMOOTHING, 0, &font_smoothing, 0)) {
_print_gdi_error ();
return FALSE;
}
if (font_smoothing) {
OSVERSIONINFO &version_info;
version_info.size = sizeof (OSVERSIONINFO);
if (!GetVersionEx (&version_info)) {
_print_gdi_error ();
return FALSE;
}
if (version_info.dwMajorVersion > 5 ||
(version_info.dwMajorVersion == 5 &&
version_info.dwMinorVersion >= 1)) { /* XP or newer */
UINT smoothing_type;
if (!SystemParametersInfo (SPI_GETFONTSMOOTHINGTYPE,
0, &smoothing_type, 0)) {
_print_gdi_error ();
return FALSE;
}
if (smoothing_type == FE_FONTSMOTHINGCLEARTYPE)
return CLEARTYPE_QUALITY;
}
return ANTIALIASED_QUALITY;
}
return
}
static cairo_status_t
_cairo_ft_font_create (const char *family,
cairo_font_slant_t slant,
cairo_font_weight_t weight,
cairo_font_scale_t *scale,
cairo_font_t **font_out)
{
LOGFONT logfont;
cairo_font_t *font;
logfont.lfHeight = 0; /* filled in later */
logfont.lfWidth = 0; /* filled in later */
logfont.lfEscapement = 0; /* filled in later */
logfont.lfOrientation = 0; /* filled in later */
logfont.lfOrientation = 0; /* filled in later */
switch (weight) {
case CAIRO_FONT_WEIGHT_NORMAL:
default:
logfont.lfWeight = FW_NORMAL;
break:
case CAIRO_FONT_WEIGHT_BOLD:
logfont.lfWeight = FW_BOLD;
break;
}
switch (slant) {
case CAIRO_FONT_SLANT_NORMAL:
default:
logfont.lfItalic = FALSE;
break;
case CAIRO_FONT_SLANT_ITALIC:
case CAIRO_FONT_SLANT_OBLIQUE:
logfont.lfItalic = TRUE;
break;
}
logfont.lfUnderline = FALSE;
logfont.lfStrikethrough = FALSE;
/* The docs for LOGFONT discourage using this, since the
* interpretation is locale-specific, but it's not clear what
* would be a better alternative.
*/
logfont.lfCharset = DEFAULT_CHARSET;
logfont.lfOutPrecision = OUT_DEFAULT_PRECIS;
logfont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
logfont.lfQuality = DEFAULT_QUALITY;
logfont.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
logfont.lfFaceName = utf8_to_utf16 (family);
if (!logfont.lfFaceName)
return CAIRO_STATUS_NO_MEMORY;
font = cairo_win32_font_create_for_logfont (logfont, scale);
if (!font)
return CAIRO_STATUS_NO_MEMORY;
*font_out = font;
return CAIRO_STATUS_SUCCESS;
}
static void
_cairo_ft_font_destroy_font (void *abstract_font)
{
cairo_win32_font_t *font = abstract_font;
return CAIRO_STATUS_SUCCESS;
}
static void
_cairo_ft_font_get_glyph_cache_key (void *abstract_font,
cairo_glyph_cache_key_t *key)
{
return CAIRO_STATUS_NO_MEMORY;
}
static cairo_status_t
_cairo_ft_font_text_to_glyphs (void *abstract_font,
const unsigned char *utf8,
cairo_glyph_t **glyphs,
int *nglyphs)
{
cairo_win32_font_t *font = abstract_font;
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_ft_font_font_extents (void *abstract_font,
cairo_font_extents_t *extents)
{
cairo_win32_font_t *font = abstract_font;
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_t *font = abstract_font;
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_ft_font_glyph_bbox (void *abstract_font,
const cairo_glyph_t *glyphs,
int num_glyphs,
cairo_box_t *bbox)
{
cairo_win32_font_t *font = abstract_font;
return CAIRO_STATUS_SUCCESS;
}
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_t *font = abstract_font;
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_win32_font_glyph_path (void *abstract_font,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_path_t *path)
{
cairo_win32_font_t *font = abstract_font;
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_win32_font_create_glyph (cairo_image_glyph_cache_entry_t *val)
{
return CAIRO_STATUS_NO_MEMORY;
}
const cairo_font_backend_t cairo_win32_font_backend = {
_cairo_win32_font_create,
_cairo_win32_font_destroy_font,
_cairo_win32_font_destroy_unscaled_font,
_cairo_win32_font_font_extents,
_cairo_win32_font_text_to_glyphs,
_cairo_win32_font_glyph_extents,
_cairo_win32_font_glyph_bbox,
_cairo_win32_font_show_glyphs,
_cairo_win32_font_glyph_path,
_cairo_win32_font_get_glyph_cache_key,
_cairo_win32_font_create_glyph
};
/* implement the platform-specific interface */
cairo_font_t *
cairo_win32_font_create_for_logfont (LOGFONT *logfont,
cairo_matrix_t *scale)
{
cairo_win32_font_t *f;
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;
}

932
src/cairo-win32-surface.c Normal file
View file

@ -0,0 +1,932 @@
/* Cairo - a vector graphics library with display and print output
*
* Copyright © 2005 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Owen Taylor <otaylor@redhat.com>
*/
/* We depend on various features introduced with Win2k and Win98,
* like AlphaBlend. If it turns out to be a problem, we could
* use GetProcAddress() to look them up.
*/
#define WINVER 0x0500
#include <windows.h>
#include <stdio.h>
#include "cairo-win32.h"
#include "cairoint.h"
static const cairo_surface_backend_t cairo_win32_surface_backend;
static void
_print_gdi_error (const char *context)
{
void *lpMsgBuf;
DWORD last_error = GetLastError ();
if (!FormatMessageA (FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
last_error,
MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) &lpMsgBuf,
0, NULL)) {
fprintf (stderr, "%s: Unknown GDI error", context);
} else {
fprintf (stderr, "%s: %s", context, (char *)lpMsgBuf);
LocalFree (lpMsgBuf);
}
}
static cairo_status_t
_get_cairo_error (void)
{
/* We should switch off of GetLastError, but we'd either return
* CAIRO_STATUS_NO_MEMORY or CAIRO_STATUS_UNKNOWN_ERROR and there
* is no CAIRO_STATUS_UNKNOWN_ERROR.
*/
return CAIRO_STATUS_NO_MEMORY;
}
void
cairo_set_target_win32 (cairo_t *cr,
HDC hdc)
{
cairo_surface_t *surface;
if (cr->status && cr->status != CAIRO_STATUS_NO_TARGET_SURFACE)
return;
surface = cairo_win32_surface_create (hdc);
if (surface == NULL) {
cr->status = CAIRO_STATUS_NO_MEMORY;
return;
}
cairo_set_target_surface (cr, surface);
/* cairo_set_target_surface takes a reference, so we must destroy ours */
cairo_surface_destroy (surface);
}
typedef struct _cairo_win32_surface {
cairo_surface_t base;
cairo_format_t format;
HDC dc;
/* We create off-screen surfaces as DIB's */
HBITMAP bitmap;
cairo_surface_t *image;
cairo_rectangle_t clip_rect;
int set_clip;
HRGN saved_clip;
} cairo_win32_surface_t;
static cairo_status_t
_create_dc_and_bitmap (HDC original_dc,
cairo_format_t format,
int width,
int height,
HDC *dc_out,
HBITMAP *bitmap_out,
char **bits_out,
int *rowstride_out)
{
HDC dc = NULL;
HBITMAP bitmap = NULL;
BITMAPINFO *bitmap_info = NULL;
struct {
BITMAPINFOHEADER bmiHeader;
RGBQUAD bmiColors[2];
} bmi_stack;
void *bits;
int num_palette = 0; /* Quiet GCC */
int i;
switch (format) {
case CAIRO_FORMAT_ARGB32:
case CAIRO_FORMAT_RGB24:
num_palette = 0;
break;
case CAIRO_FORMAT_A8:
num_palette = 256;
break;
case CAIRO_FORMAT_A1:
num_palette = 2;
break;
}
if (num_palette > 2) {
bitmap_info = malloc (sizeof (BITMAPINFOHEADER) + num_palette * sizeof (RGBQUAD));
if (!bitmap_info)
return CAIRO_STATUS_NO_MEMORY;
} else {
bitmap_info = (BITMAPINFO *)&bmi_stack;
}
bitmap_info->bmiHeader.biSize = sizeof (BITMAPINFOHEADER);
bitmap_info->bmiHeader.biWidth = width;
bitmap_info->bmiHeader.biHeight = - height; /* top-down */
bitmap_info->bmiHeader.biSizeImage = 0;
bitmap_info->bmiHeader.biXPelsPerMeter = 72. / 0.0254; /* unused here */
bitmap_info->bmiHeader.biYPelsPerMeter = 72. / 0.0254; /* unused here */
bitmap_info->bmiHeader.biPlanes = 1;
switch (format) {
case CAIRO_FORMAT_ARGB32:
case CAIRO_FORMAT_RGB24:
bitmap_info->bmiHeader.biBitCount = 32;
bitmap_info->bmiHeader.biCompression = BI_RGB;
bitmap_info->bmiHeader.biClrUsed = 0; /* unused */
bitmap_info->bmiHeader.biClrImportant = 0;
break;
case CAIRO_FORMAT_A8:
bitmap_info->bmiHeader.biBitCount = 8;
bitmap_info->bmiHeader.biCompression = BI_RGB;
bitmap_info->bmiHeader.biClrUsed = 256;
bitmap_info->bmiHeader.biClrImportant = 0;
for (i = 0; i < 256; i++) {
bitmap_info->bmiColors[i].rgbBlue = i;
bitmap_info->bmiColors[i].rgbGreen = i;
bitmap_info->bmiColors[i].rgbRed = i;
bitmap_info->bmiColors[i].rgbReserved = 0;
}
break;
case CAIRO_FORMAT_A1:
bitmap_info->bmiHeader.biBitCount = 1;
bitmap_info->bmiHeader.biCompression = BI_RGB;
bitmap_info->bmiHeader.biClrUsed = 2;
bitmap_info->bmiHeader.biClrImportant = 0;
for (i = 0; i < 2; i++) {
bitmap_info->bmiColors[i].rgbBlue = i * 255;
bitmap_info->bmiColors[i].rgbGreen = i * 255;
bitmap_info->bmiColors[i].rgbRed = i * 255;
bitmap_info->bmiColors[i].rgbReserved = 0;
break;
}
}
dc = CreateCompatibleDC (original_dc);
if (!dc) {
free (bitmap_info);
goto FAIL;
}
bitmap = CreateDIBSection (dc,
bitmap_info,
DIB_RGB_COLORS,
&bits,
NULL, 0);
if (!bitmap)
goto FAIL;
if (!SelectObject (dc, bitmap))
goto FAIL;
if (num_palette > 2)
free (bitmap_info);
*dc_out = dc;
*bitmap_out = bitmap;
if (bits_out)
*bits_out = bits;
if (rowstride_out) {
/* Windows bitmaps are padded to 16-bit (word) boundaries */
switch (format) {
case CAIRO_FORMAT_ARGB32:
case CAIRO_FORMAT_RGB24:
*rowstride_out = 4 * width;
break;
case CAIRO_FORMAT_A8:
*rowstride_out = (width + 1) & -2;
break;
case CAIRO_FORMAT_A1:
*rowstride_out = ((width + 15) & -16) / 8;
break;
}
}
return CAIRO_STATUS_SUCCESS;
FAIL:
_print_gdi_error ("_create_dc_and_bitmap");
if (bitmap_info && num_palette > 2)
free (bitmap_info);
if (bitmap)
DeleteObject (bitmap);
if (dc)
DeleteDC (dc);
return _get_cairo_error ();
}
static cairo_surface_t *
_cairo_win32_surface_create_similar (void *abstract_src,
cairo_format_t format,
int drawable,
int width,
int height)
{
cairo_win32_surface_t *src = abstract_src;
cairo_win32_surface_t *surface = abstract_src;
HDC dc = NULL;
HBITMAP bitmap = NULL;
char *bits;
int rowstride;
surface = malloc (sizeof (cairo_win32_surface_t));
if (!surface)
return NULL;
if (_create_dc_and_bitmap (src->dc, format,
width, height,
&dc, &bitmap, &bits, &rowstride) != CAIRO_STATUS_SUCCESS)
goto FAIL;
surface->image = cairo_image_surface_create_for_data (bits, format,
width, height, rowstride);
if (!surface->image)
goto FAIL;
surface->format = format;
surface->dc = dc;
surface->bitmap = bitmap;
surface->clip_rect.x = 0;
surface->clip_rect.y = 0;
surface->clip_rect.width = width;
surface->clip_rect.height = height;
surface->set_clip = 0;
surface->saved_clip = NULL;
_cairo_surface_init (&surface->base, &cairo_win32_surface_backend);
return (cairo_surface_t *)surface;
FAIL:
if (bitmap)
DeleteObject (bitmap);
if (dc)
DeleteDC (dc);
if (surface)
free (surface);
return NULL;
}
static void
_cairo_win32_surface_destroy (void *abstract_surface)
{
cairo_win32_surface_t *surface = abstract_surface;
if (surface->image)
cairo_surface_destroy (surface->image);
if (surface->saved_clip)
DeleteObject (surface->saved_clip);
if (surface->bitmap)
DeleteObject (surface->bitmap);
free (surface);
}
static double
_cairo_win32_surface_pixels_per_inch (void *abstract_surface)
{
/* XXX: We should really get this value from somewhere */
return 96.0;
}
static cairo_status_t
_cairo_win32_surface_get_subimage (cairo_win32_surface_t *surface,
int x,
int y,
int width,
int height,
cairo_win32_surface_t **local_out)
{
cairo_win32_surface_t *local;
local =
(cairo_win32_surface_t *) _cairo_win32_surface_create_similar (surface,
surface->format,
0,
width, height);
if (!local)
return CAIRO_STATUS_NO_MEMORY;
if (!BitBlt (local->dc,
0, 0,
width, height,
surface->dc,
x, y,
SRCCOPY))
goto FAIL;
*local_out = local;
return CAIRO_STATUS_SUCCESS;
FAIL:
_print_gdi_error ("_cairo_win32_surface_get_subimage");
if (local)
cairo_surface_destroy (&local->base);
return _get_cairo_error ();
}
static cairo_status_t
_cairo_win32_surface_acquire_source_image (void *abstract_surface,
cairo_image_surface_t **image_out,
void **image_extra)
{
cairo_win32_surface_t *surface = abstract_surface;
cairo_win32_surface_t *local = NULL;
cairo_status_t status;
if (surface->image) {
*image_out = (cairo_image_surface_t *)surface->image;
*image_extra = NULL;
return CAIRO_STATUS_SUCCESS;
}
status = _cairo_win32_surface_get_subimage (abstract_surface, 0, 0,
surface->clip_rect.width,
surface->clip_rect.height, &local);
if (CAIRO_OK (status)) {
cairo_surface_set_filter (&local->base, surface->base.filter);
cairo_surface_set_matrix (&local->base, &surface->base.matrix);
cairo_surface_set_repeat (&local->base, surface->base.repeat);
*image_out = (cairo_image_surface_t *)local->image;
*image_extra = local;
}
return status;
}
static void
_cairo_win32_surface_release_source_image (void *abstract_surface,
cairo_image_surface_t *image,
void *image_extra)
{
cairo_win32_surface_t *local = image_extra;
if (local)
cairo_surface_destroy ((cairo_surface_t *)local);
}
static cairo_status_t
_cairo_win32_surface_acquire_dest_image (void *abstract_surface,
cairo_rectangle_t *interest_rect,
cairo_image_surface_t **image_out,
cairo_rectangle_t *image_rect,
void **image_extra)
{
cairo_win32_surface_t *surface = abstract_surface;
cairo_win32_surface_t *local = NULL;
cairo_status_t status;
RECT clip_box;
int x1, y1, x2, y2;
if (surface->image) {
image_rect->x = 0;
image_rect->y = 0;
image_rect->width = surface->clip_rect.width;
image_rect->height = surface->clip_rect.height;
*image_out = (cairo_image_surface_t *)surface->image;
*image_extra = NULL;
return CAIRO_STATUS_SUCCESS;
}
if (GetClipBox (surface->dc, &clip_box) == ERROR) {
_print_gdi_error ("_cairo_win3_surface_acquire_dest_image");
return _get_cairo_error ();
}
x1 = clip_box.left;
x2 = clip_box.right;
y1 = clip_box.top;
y2 = clip_box.bottom;
if (interest_rect->x > x1)
x1 = interest_rect->x;
if (interest_rect->y > y1)
y1 = interest_rect->y;
if (interest_rect->x + interest_rect->width < x2)
x2 = interest_rect->x + interest_rect->width;
if (interest_rect->y + interest_rect->height < y2)
y2 = interest_rect->y + interest_rect->height;
if (x1 >= x2 || y1 >= y2) {
*image_out = NULL;
*image_extra = NULL;
return CAIRO_STATUS_SUCCESS;
}
status = _cairo_win32_surface_get_subimage (abstract_surface,
x1, y1, x2 - x1, y2 - y1,
&local);
if (CAIRO_OK (status)) {
*image_out = (cairo_image_surface_t *)local->image;
*image_extra = local;
image_rect->x = x1;
image_rect->y = y1;
image_rect->width = x2 - x1;
image_rect->height = y2 - y1;
}
return status;
}
static void
_cairo_win32_surface_release_dest_image (void *abstract_surface,
cairo_rectangle_t *interest_rect,
cairo_image_surface_t *image,
cairo_rectangle_t *image_rect,
void *image_extra)
{
cairo_win32_surface_t *surface = abstract_surface;
cairo_win32_surface_t *local = image_extra;
if (!local)
return;
if (!BitBlt (surface->dc,
image_rect->x, image_rect->y,
image_rect->width, image_rect->height,
local->dc,
0, 0,
SRCCOPY)) {
_print_gdi_error ("_cairo_win32_surface_release_dest_image");
}
cairo_surface_destroy ((cairo_surface_t *)local);
}
static cairo_status_t
_cairo_win32_surface_clone_similar (void *surface,
cairo_surface_t *src,
cairo_surface_t **clone_out)
{
return CAIRO_INT_STATUS_UNSUPPORTED;
}
static cairo_status_t
_cairo_win32_surface_set_matrix (void *abstract_surface,
cairo_matrix_t *matrix)
{
cairo_win32_surface_t *surface = abstract_surface;
if (surface->image)
cairo_surface_set_matrix (surface->image, matrix);
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_win32_surface_set_filter (void *abstract_surface,
cairo_filter_t filter)
{
cairo_win32_surface_t *surface = abstract_surface;
if (surface->image)
cairo_surface_set_filter (surface->image, filter);
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_win32_surface_set_repeat (void *abstract_surface,
int repeat)
{
cairo_win32_surface_t *surface = abstract_surface;
if (surface->image)
cairo_surface_set_repeat (surface->image, repeat);
return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
_cairo_win32_surface_composite (cairo_operator_t operator,
cairo_pattern_t *pattern,
cairo_surface_t *generic_mask,
void *abstract_dst,
int src_x,
int src_y,
int mask_x,
int mask_y,
int dst_x,
int dst_y,
unsigned int width,
unsigned int height)
{
cairo_win32_surface_t *dst = abstract_dst;
cairo_win32_surface_t *src;
cairo_win32_surface_t *mask = (cairo_win32_surface_t *)generic_mask;
int alpha;
int integer_transform;
int itx, ity;
if (pattern->type != CAIRO_PATTERN_SURFACE ||
pattern->extend != CAIRO_EXTEND_NONE ||
pattern->u.surface.surface->backend != dst->base.backend ||
mask)
return CAIRO_INT_STATUS_UNSUPPORTED;
src = (cairo_win32_surface_t *)pattern->u.surface.surface;
integer_transform = _cairo_matrix_is_integer_translation (&pattern->matrix, &itx, &ity);
if (!integer_transform)
return CAIRO_INT_STATUS_UNSUPPORTED;
alpha = (pattern->color.alpha_short) >> 8;
if (alpha == 255 &&
src->format == dst->format &&
(operator == CAIRO_OPERATOR_SRC ||
(src->format == CAIRO_FORMAT_RGB24 && operator == CAIRO_OPERATOR_OVER))) {
if (!BitBlt (dst->dc,
dst_x, dst_y,
width, height,
src->dc,
src_x + itx, src_y + ity,
SRCCOPY)) {
_print_gdi_error ("_cairo_win32_surface_composite");
return _get_cairo_error ();
}
return CAIRO_STATUS_SUCCESS;
} else if (integer_transform &&
(src->format == CAIRO_FORMAT_RGB24 || src->format == CAIRO_FORMAT_ARGB32) &&
dst->format == CAIRO_FORMAT_RGB24 &&
!src->base.repeat &&
operator == CAIRO_OPERATOR_OVER) {
BLENDFUNCTION blend_function;
blend_function.BlendOp = AC_SRC_OVER;
blend_function.BlendFlags = 0;
blend_function.SourceConstantAlpha = alpha;
blend_function.AlphaFormat = src->format == CAIRO_FORMAT_ARGB32 ? AC_SRC_ALPHA : 0;
fprintf (stderr, "AlphaBlend\n");
if (!AlphaBlend (dst->dc,
dst_x, dst_y,
width, height,
src->dc,
src_x + itx, src_y + ity,
width, height,
blend_function)) {
_print_gdi_error ("_cairo_win32_surface_composite");
return _get_cairo_error ();
}
return CAIRO_STATUS_SUCCESS;
}
return CAIRO_INT_STATUS_UNSUPPORTED;
}
static cairo_int_status_t
_cairo_win32_surface_fill_rectangles (void *abstract_surface,
cairo_operator_t operator,
const cairo_color_t *color,
cairo_rectangle_t *rects,
int num_rects)
{
cairo_win32_surface_t *surface = abstract_surface;
COLORREF new_color;
HBRUSH new_brush;
int i;
/* If we have a local image, use the fallback code; it will be as fast
* as calling out to GDI.
*/
if (surface->image)
return CAIRO_INT_STATUS_UNSUPPORTED;
/* We could support possibly support more operators for color->alpha = 0xffff.
* for CAIRO_OPERATOR_SRC, alpha doesn't matter since we know the destination
* image doesn't have alpha. (surface->pixman_image is non-NULL for all
* surfaces with alpha.)
*/
if (operator != CAIRO_OPERATOR_SRC)
return CAIRO_INT_STATUS_UNSUPPORTED;
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 ();
}
for (i = 0; i < num_rects; i++) {
RECT rect;
rect.left = rects[i].x;
rect.top = rects[i].y;
rect.right = rects[i].x + rects[i].width;
rect.bottom = rects[i].y + rects[i].height;
if (!FillRect (surface->dc, &rect, new_brush))
goto FAIL;
}
DeleteObject (new_brush);
return CAIRO_STATUS_SUCCESS;
FAIL:
_print_gdi_error ("_cairo_win32_surface_fill_rectangles");
DeleteObject (new_brush);
return _get_cairo_error ();
}
static cairo_int_status_t
_cairo_win32_surface_composite_trapezoids (cairo_operator_t operator,
cairo_pattern_t *pattern,
void *abstract_dst,
int src_x,
int src_y,
int dst_x,
int dst_y,
unsigned int width,
unsigned int height,
cairo_trapezoid_t *traps,
int num_traps)
{
return CAIRO_INT_STATUS_UNSUPPORTED;
}
static cairo_int_status_t
_cairo_win32_surface_copy_page (void *abstract_surface)
{
return CAIRO_INT_STATUS_UNSUPPORTED;
}
static cairo_int_status_t
_cairo_win32_surface_show_page (void *abstract_surface)
{
return CAIRO_INT_STATUS_UNSUPPORTED;
}
static cairo_int_status_t
_cairo_win32_surface_set_clip_region (void *abstract_surface,
pixman_region16_t *region)
{
cairo_win32_surface_t *surface = abstract_surface;
/* If we are in-memory, then we set the clip on the image surface
* as well as on the underlying GDI surface.
*/
if (surface->image)
_cairo_surface_set_clip_region (surface->image, region);
/* The semantics we want is that any clip set by Cairo combines
* is intersected with the clip on device context that the
* surface was created for. To implement this, we need to
* save the original clip when first setting a clip on surface.
*/
if (region == NULL) {
/* 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 (surface->saved_clip) {
DeleteObject (surface->saved_clip);
surface->saved_clip = NULL;
}
surface->set_clip = 0;
}
return CAIRO_STATUS_SUCCESS;
} else {
pixman_box16_t *boxes = pixman_region_rects (region);
int num_boxes = pixman_region_num_rects (region);
pixman_box16_t *extents = pixman_region_extents (region);
RGNDATA *data;
size_t data_size;
RECT *rects;
int i;
HRGN gdi_region;
/* Create a GDI region for the cairo region */
data_size = sizeof (RGNDATAHEADER) + num_boxes * sizeof (RECT);
data = malloc (data_size);
if (!data)
return CAIRO_STATUS_NO_MEMORY;
rects = (RECT *)data->Buffer;
data->rdh.dwSize = sizeof (RGNDATAHEADER);
data->rdh.iType = RDH_RECTANGLES;
data->rdh.nCount = num_boxes;
data->rdh.nRgnSize = num_boxes * sizeof (RECT);
data->rdh.rcBound.left = extents->x1;
data->rdh.rcBound.top = extents->y1;
data->rdh.rcBound.right = extents->x2;
data->rdh.rcBound.bottom = extents->y2;
for (i = 0; i < num_boxes; i++) {
rects[i].left = boxes[i].x1;
rects[i].top = boxes[i].y1;
rects[i].right = boxes[i].x2;
rects[i].bottom = boxes[i].y2;
}
gdi_region = ExtCreateRegion (NULL, data_size, data);
free (data);
if (!gdi_region)
return CAIRO_STATUS_NO_MEMORY;
if (surface->set_clip) {
/* Combine the new region with the original clip */
if (surface->saved_clip) {
if (CombineRgn (gdi_region, gdi_region, surface->saved_clip, RGN_AND) == ERROR)
goto FAIL;
}
if (SelectClipRgn (surface->dc, gdi_region) == ERROR)
goto FAIL;
} else {
/* Save the the current region */
surface->saved_clip = CreateRectRgn (0, 0, 0, 0);
if (!surface->saved_clip) {
goto FAIL; }
/* This function has no error return! */
if (GetClipRgn (surface->dc, surface->saved_clip) == 0) { /* No clip */
DeleteObject (surface->saved_clip);
surface->saved_clip = NULL;
}
if (ExtSelectClipRgn (surface->dc, gdi_region, RGN_AND) == ERROR)
goto FAIL;
surface->set_clip = 1;
}
DeleteObject (gdi_region);
return CAIRO_STATUS_SUCCESS;
FAIL:
_print_gdi_error ("_cairo_win32_surface_set_clip_region");
DeleteObject (gdi_region);
return _get_cairo_error ();
}
}
static cairo_status_t
_cairo_win32_surface_show_glyphs (cairo_font_t *font,
cairo_operator_t operator,
cairo_pattern_t *pattern,
void *abstract_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)
{
return CAIRO_INT_STATUS_UNSUPPORTED;
}
cairo_surface_t *
cairo_win32_surface_create (HDC hdc)
{
cairo_win32_surface_t *surface;
RECT rect;
/* Try to figure out the drawing bounds for the Device context
*/
if (GetClipBox (hdc, &rect) == ERROR) {
_print_gdi_error ("cairo_win32_surface_create");
return NULL;
}
surface = malloc (sizeof (cairo_win32_surface_t));
if (!surface)
return NULL;
surface->image = NULL;
surface->format = CAIRO_FORMAT_RGB24;
surface->dc = hdc;
surface->bitmap = NULL;
surface->clip_rect.x = rect.left;
surface->clip_rect.y = rect.top;
surface->clip_rect.width = rect.right - rect.left;
surface->clip_rect.height = rect.bottom - rect.top;
surface->set_clip = 0;
surface->saved_clip = NULL;
_cairo_surface_init (&surface->base, &cairo_win32_surface_backend);
return (cairo_surface_t *)surface;
}
static const cairo_surface_backend_t cairo_win32_surface_backend = {
_cairo_win32_surface_create_similar,
_cairo_win32_surface_destroy,
_cairo_win32_surface_pixels_per_inch,
_cairo_win32_surface_acquire_source_image,
_cairo_win32_surface_release_source_image,
_cairo_win32_surface_acquire_dest_image,
_cairo_win32_surface_release_dest_image,
_cairo_win32_surface_clone_similar,
_cairo_win32_surface_set_matrix,
_cairo_win32_surface_set_filter,
_cairo_win32_surface_set_repeat,
_cairo_win32_surface_composite,
_cairo_win32_surface_fill_rectangles,
_cairo_win32_surface_composite_trapezoids,
_cairo_win32_surface_copy_page,
_cairo_win32_surface_show_page,
_cairo_win32_surface_set_clip_region,
_cairo_win32_surface_show_glyphs
};

61
src/cairo-win32.h Normal file
View file

@ -0,0 +1,61 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2005 Red Hat, Inc
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Owen Taylor <otaylor@redhat.com>
*/
#ifndef _CAIRO_WIN32_H_
#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
#include <windows.h>
void
cairo_set_target_win32 (cairo_t *cr,
HDC hdc);
cairo_surface_t *
cairo_win32_surface_create (HDC hdc);
#ifdef __cplusplus
}
#endif
#endif /* _CAIRO_WIN32_H_ */

View file

@ -394,7 +394,7 @@ static void
_fallback_cleanup (fallback_state_t *state) _fallback_cleanup (fallback_state_t *state)
{ {
_cairo_surface_release_dest_image (state->dst, &state->extents, _cairo_surface_release_dest_image (state->dst, &state->extents,
state->image, &state->image_rect, &state->image_extra); state->image, &state->image_rect, state->image_extra);
} }
static cairo_status_t static cairo_status_t

380
src/cairo_win32_font.c Normal file
View file

@ -0,0 +1,380 @@
/*
* Copyright © 2005 Red Hat Inc.
*
* 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.
*
* 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.
*
* Author: Owen Taylor <otaylor@redhat.com>
*/
#include "cairoint.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
*/
typedef struct {
double x_scale, y_scale;
double shape[2][2];
} ft_font_transform_t;
static void
_compute_transform (ft_font_transform_t *sf,
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.
*/
cairo_matrix_set_affine (&normalized,
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;
_compute_transform (&sf, scale);
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);
}
}
/* implement the font backend interface */
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;
}
static BYTE
_get_system_quality (void)
{
BOOL font_smoothing;
if (!SystemParametersInfo (SPI_GETFONTSMOOTHING, 0, &font_smoothing, 0)) {
_print_gdi_error ();
return FALSE;
}
if (font_smoothing) {
OSVERSIONINFO &version_info;
version_info.size = sizeof (OSVERSIONINFO);
if (!GetVersionEx (&version_info)) {
_print_gdi_error ();
return FALSE;
}
if (version_info.dwMajorVersion > 5 ||
(version_info.dwMajorVersion == 5 &&
version_info.dwMinorVersion >= 1)) { /* XP or newer */
UINT smoothing_type;
if (!SystemParametersInfo (SPI_GETFONTSMOOTHINGTYPE,
0, &smoothing_type, 0)) {
_print_gdi_error ();
return FALSE;
}
if (smoothing_type == FE_FONTSMOTHINGCLEARTYPE)
return CLEARTYPE_QUALITY;
}
return ANTIALIASED_QUALITY;
}
return
}
static cairo_status_t
_cairo_ft_font_create (const char *family,
cairo_font_slant_t slant,
cairo_font_weight_t weight,
cairo_font_scale_t *scale,
cairo_font_t **font_out)
{
LOGFONT logfont;
cairo_font_t *font;
logfont.lfHeight = 0; /* filled in later */
logfont.lfWidth = 0; /* filled in later */
logfont.lfEscapement = 0; /* filled in later */
logfont.lfOrientation = 0; /* filled in later */
logfont.lfOrientation = 0; /* filled in later */
switch (weight) {
case CAIRO_FONT_WEIGHT_NORMAL:
default:
logfont.lfWeight = FW_NORMAL;
break:
case CAIRO_FONT_WEIGHT_BOLD:
logfont.lfWeight = FW_BOLD;
break;
}
switch (slant) {
case CAIRO_FONT_SLANT_NORMAL:
default:
logfont.lfItalic = FALSE;
break;
case CAIRO_FONT_SLANT_ITALIC:
case CAIRO_FONT_SLANT_OBLIQUE:
logfont.lfItalic = TRUE;
break;
}
logfont.lfUnderline = FALSE;
logfont.lfStrikethrough = FALSE;
/* The docs for LOGFONT discourage using this, since the
* interpretation is locale-specific, but it's not clear what
* would be a better alternative.
*/
logfont.lfCharset = DEFAULT_CHARSET;
logfont.lfOutPrecision = OUT_DEFAULT_PRECIS;
logfont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
logfont.lfQuality = DEFAULT_QUALITY;
logfont.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
logfont.lfFaceName = utf8_to_utf16 (family);
if (!logfont.lfFaceName)
return CAIRO_STATUS_NO_MEMORY;
font = cairo_win32_font_create_for_logfont (logfont, scale);
if (!font)
return CAIRO_STATUS_NO_MEMORY;
*font_out = font;
return CAIRO_STATUS_SUCCESS;
}
static void
_cairo_ft_font_destroy_font (void *abstract_font)
{
cairo_win32_font_t *font = abstract_font;
return CAIRO_STATUS_SUCCESS;
}
static void
_cairo_ft_font_get_glyph_cache_key (void *abstract_font,
cairo_glyph_cache_key_t *key)
{
return CAIRO_STATUS_NO_MEMORY;
}
static cairo_status_t
_cairo_ft_font_text_to_glyphs (void *abstract_font,
const unsigned char *utf8,
cairo_glyph_t **glyphs,
int *nglyphs)
{
cairo_win32_font_t *font = abstract_font;
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_ft_font_font_extents (void *abstract_font,
cairo_font_extents_t *extents)
{
cairo_win32_font_t *font = abstract_font;
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_t *font = abstract_font;
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_ft_font_glyph_bbox (void *abstract_font,
const cairo_glyph_t *glyphs,
int num_glyphs,
cairo_box_t *bbox)
{
cairo_win32_font_t *font = abstract_font;
return CAIRO_STATUS_SUCCESS;
}
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_t *font = abstract_font;
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_win32_font_glyph_path (void *abstract_font,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_path_t *path)
{
cairo_win32_font_t *font = abstract_font;
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_win32_font_create_glyph (cairo_image_glyph_cache_entry_t *val)
{
return CAIRO_STATUS_NO_MEMORY;
}
const cairo_font_backend_t cairo_win32_font_backend = {
_cairo_win32_font_create,
_cairo_win32_font_destroy_font,
_cairo_win32_font_destroy_unscaled_font,
_cairo_win32_font_font_extents,
_cairo_win32_font_text_to_glyphs,
_cairo_win32_font_glyph_extents,
_cairo_win32_font_glyph_bbox,
_cairo_win32_font_show_glyphs,
_cairo_win32_font_glyph_path,
_cairo_win32_font_get_glyph_cache_key,
_cairo_win32_font_create_glyph
};
/* implement the platform-specific interface */
cairo_font_t *
cairo_win32_font_create_for_logfont (LOGFONT *logfont,
cairo_matrix_t *scale)
{
cairo_win32_font_t *f;
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;
}

932
src/cairo_win32_surface.c Normal file
View file

@ -0,0 +1,932 @@
/* Cairo - a vector graphics library with display and print output
*
* Copyright © 2005 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Owen Taylor <otaylor@redhat.com>
*/
/* We depend on various features introduced with Win2k and Win98,
* like AlphaBlend. If it turns out to be a problem, we could
* use GetProcAddress() to look them up.
*/
#define WINVER 0x0500
#include <windows.h>
#include <stdio.h>
#include "cairo-win32.h"
#include "cairoint.h"
static const cairo_surface_backend_t cairo_win32_surface_backend;
static void
_print_gdi_error (const char *context)
{
void *lpMsgBuf;
DWORD last_error = GetLastError ();
if (!FormatMessageA (FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
last_error,
MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) &lpMsgBuf,
0, NULL)) {
fprintf (stderr, "%s: Unknown GDI error", context);
} else {
fprintf (stderr, "%s: %s", context, (char *)lpMsgBuf);
LocalFree (lpMsgBuf);
}
}
static cairo_status_t
_get_cairo_error (void)
{
/* We should switch off of GetLastError, but we'd either return
* CAIRO_STATUS_NO_MEMORY or CAIRO_STATUS_UNKNOWN_ERROR and there
* is no CAIRO_STATUS_UNKNOWN_ERROR.
*/
return CAIRO_STATUS_NO_MEMORY;
}
void
cairo_set_target_win32 (cairo_t *cr,
HDC hdc)
{
cairo_surface_t *surface;
if (cr->status && cr->status != CAIRO_STATUS_NO_TARGET_SURFACE)
return;
surface = cairo_win32_surface_create (hdc);
if (surface == NULL) {
cr->status = CAIRO_STATUS_NO_MEMORY;
return;
}
cairo_set_target_surface (cr, surface);
/* cairo_set_target_surface takes a reference, so we must destroy ours */
cairo_surface_destroy (surface);
}
typedef struct _cairo_win32_surface {
cairo_surface_t base;
cairo_format_t format;
HDC dc;
/* We create off-screen surfaces as DIB's */
HBITMAP bitmap;
cairo_surface_t *image;
cairo_rectangle_t clip_rect;
int set_clip;
HRGN saved_clip;
} cairo_win32_surface_t;
static cairo_status_t
_create_dc_and_bitmap (HDC original_dc,
cairo_format_t format,
int width,
int height,
HDC *dc_out,
HBITMAP *bitmap_out,
char **bits_out,
int *rowstride_out)
{
HDC dc = NULL;
HBITMAP bitmap = NULL;
BITMAPINFO *bitmap_info = NULL;
struct {
BITMAPINFOHEADER bmiHeader;
RGBQUAD bmiColors[2];
} bmi_stack;
void *bits;
int num_palette = 0; /* Quiet GCC */
int i;
switch (format) {
case CAIRO_FORMAT_ARGB32:
case CAIRO_FORMAT_RGB24:
num_palette = 0;
break;
case CAIRO_FORMAT_A8:
num_palette = 256;
break;
case CAIRO_FORMAT_A1:
num_palette = 2;
break;
}
if (num_palette > 2) {
bitmap_info = malloc (sizeof (BITMAPINFOHEADER) + num_palette * sizeof (RGBQUAD));
if (!bitmap_info)
return CAIRO_STATUS_NO_MEMORY;
} else {
bitmap_info = (BITMAPINFO *)&bmi_stack;
}
bitmap_info->bmiHeader.biSize = sizeof (BITMAPINFOHEADER);
bitmap_info->bmiHeader.biWidth = width;
bitmap_info->bmiHeader.biHeight = - height; /* top-down */
bitmap_info->bmiHeader.biSizeImage = 0;
bitmap_info->bmiHeader.biXPelsPerMeter = 72. / 0.0254; /* unused here */
bitmap_info->bmiHeader.biYPelsPerMeter = 72. / 0.0254; /* unused here */
bitmap_info->bmiHeader.biPlanes = 1;
switch (format) {
case CAIRO_FORMAT_ARGB32:
case CAIRO_FORMAT_RGB24:
bitmap_info->bmiHeader.biBitCount = 32;
bitmap_info->bmiHeader.biCompression = BI_RGB;
bitmap_info->bmiHeader.biClrUsed = 0; /* unused */
bitmap_info->bmiHeader.biClrImportant = 0;
break;
case CAIRO_FORMAT_A8:
bitmap_info->bmiHeader.biBitCount = 8;
bitmap_info->bmiHeader.biCompression = BI_RGB;
bitmap_info->bmiHeader.biClrUsed = 256;
bitmap_info->bmiHeader.biClrImportant = 0;
for (i = 0; i < 256; i++) {
bitmap_info->bmiColors[i].rgbBlue = i;
bitmap_info->bmiColors[i].rgbGreen = i;
bitmap_info->bmiColors[i].rgbRed = i;
bitmap_info->bmiColors[i].rgbReserved = 0;
}
break;
case CAIRO_FORMAT_A1:
bitmap_info->bmiHeader.biBitCount = 1;
bitmap_info->bmiHeader.biCompression = BI_RGB;
bitmap_info->bmiHeader.biClrUsed = 2;
bitmap_info->bmiHeader.biClrImportant = 0;
for (i = 0; i < 2; i++) {
bitmap_info->bmiColors[i].rgbBlue = i * 255;
bitmap_info->bmiColors[i].rgbGreen = i * 255;
bitmap_info->bmiColors[i].rgbRed = i * 255;
bitmap_info->bmiColors[i].rgbReserved = 0;
break;
}
}
dc = CreateCompatibleDC (original_dc);
if (!dc) {
free (bitmap_info);
goto FAIL;
}
bitmap = CreateDIBSection (dc,
bitmap_info,
DIB_RGB_COLORS,
&bits,
NULL, 0);
if (!bitmap)
goto FAIL;
if (!SelectObject (dc, bitmap))
goto FAIL;
if (num_palette > 2)
free (bitmap_info);
*dc_out = dc;
*bitmap_out = bitmap;
if (bits_out)
*bits_out = bits;
if (rowstride_out) {
/* Windows bitmaps are padded to 16-bit (word) boundaries */
switch (format) {
case CAIRO_FORMAT_ARGB32:
case CAIRO_FORMAT_RGB24:
*rowstride_out = 4 * width;
break;
case CAIRO_FORMAT_A8:
*rowstride_out = (width + 1) & -2;
break;
case CAIRO_FORMAT_A1:
*rowstride_out = ((width + 15) & -16) / 8;
break;
}
}
return CAIRO_STATUS_SUCCESS;
FAIL:
_print_gdi_error ("_create_dc_and_bitmap");
if (bitmap_info && num_palette > 2)
free (bitmap_info);
if (bitmap)
DeleteObject (bitmap);
if (dc)
DeleteDC (dc);
return _get_cairo_error ();
}
static cairo_surface_t *
_cairo_win32_surface_create_similar (void *abstract_src,
cairo_format_t format,
int drawable,
int width,
int height)
{
cairo_win32_surface_t *src = abstract_src;
cairo_win32_surface_t *surface = abstract_src;
HDC dc = NULL;
HBITMAP bitmap = NULL;
char *bits;
int rowstride;
surface = malloc (sizeof (cairo_win32_surface_t));
if (!surface)
return NULL;
if (_create_dc_and_bitmap (src->dc, format,
width, height,
&dc, &bitmap, &bits, &rowstride) != CAIRO_STATUS_SUCCESS)
goto FAIL;
surface->image = cairo_image_surface_create_for_data (bits, format,
width, height, rowstride);
if (!surface->image)
goto FAIL;
surface->format = format;
surface->dc = dc;
surface->bitmap = bitmap;
surface->clip_rect.x = 0;
surface->clip_rect.y = 0;
surface->clip_rect.width = width;
surface->clip_rect.height = height;
surface->set_clip = 0;
surface->saved_clip = NULL;
_cairo_surface_init (&surface->base, &cairo_win32_surface_backend);
return (cairo_surface_t *)surface;
FAIL:
if (bitmap)
DeleteObject (bitmap);
if (dc)
DeleteDC (dc);
if (surface)
free (surface);
return NULL;
}
static void
_cairo_win32_surface_destroy (void *abstract_surface)
{
cairo_win32_surface_t *surface = abstract_surface;
if (surface->image)
cairo_surface_destroy (surface->image);
if (surface->saved_clip)
DeleteObject (surface->saved_clip);
if (surface->bitmap)
DeleteObject (surface->bitmap);
free (surface);
}
static double
_cairo_win32_surface_pixels_per_inch (void *abstract_surface)
{
/* XXX: We should really get this value from somewhere */
return 96.0;
}
static cairo_status_t
_cairo_win32_surface_get_subimage (cairo_win32_surface_t *surface,
int x,
int y,
int width,
int height,
cairo_win32_surface_t **local_out)
{
cairo_win32_surface_t *local;
local =
(cairo_win32_surface_t *) _cairo_win32_surface_create_similar (surface,
surface->format,
0,
width, height);
if (!local)
return CAIRO_STATUS_NO_MEMORY;
if (!BitBlt (local->dc,
0, 0,
width, height,
surface->dc,
x, y,
SRCCOPY))
goto FAIL;
*local_out = local;
return CAIRO_STATUS_SUCCESS;
FAIL:
_print_gdi_error ("_cairo_win32_surface_get_subimage");
if (local)
cairo_surface_destroy (&local->base);
return _get_cairo_error ();
}
static cairo_status_t
_cairo_win32_surface_acquire_source_image (void *abstract_surface,
cairo_image_surface_t **image_out,
void **image_extra)
{
cairo_win32_surface_t *surface = abstract_surface;
cairo_win32_surface_t *local = NULL;
cairo_status_t status;
if (surface->image) {
*image_out = (cairo_image_surface_t *)surface->image;
*image_extra = NULL;
return CAIRO_STATUS_SUCCESS;
}
status = _cairo_win32_surface_get_subimage (abstract_surface, 0, 0,
surface->clip_rect.width,
surface->clip_rect.height, &local);
if (CAIRO_OK (status)) {
cairo_surface_set_filter (&local->base, surface->base.filter);
cairo_surface_set_matrix (&local->base, &surface->base.matrix);
cairo_surface_set_repeat (&local->base, surface->base.repeat);
*image_out = (cairo_image_surface_t *)local->image;
*image_extra = local;
}
return status;
}
static void
_cairo_win32_surface_release_source_image (void *abstract_surface,
cairo_image_surface_t *image,
void *image_extra)
{
cairo_win32_surface_t *local = image_extra;
if (local)
cairo_surface_destroy ((cairo_surface_t *)local);
}
static cairo_status_t
_cairo_win32_surface_acquire_dest_image (void *abstract_surface,
cairo_rectangle_t *interest_rect,
cairo_image_surface_t **image_out,
cairo_rectangle_t *image_rect,
void **image_extra)
{
cairo_win32_surface_t *surface = abstract_surface;
cairo_win32_surface_t *local = NULL;
cairo_status_t status;
RECT clip_box;
int x1, y1, x2, y2;
if (surface->image) {
image_rect->x = 0;
image_rect->y = 0;
image_rect->width = surface->clip_rect.width;
image_rect->height = surface->clip_rect.height;
*image_out = (cairo_image_surface_t *)surface->image;
*image_extra = NULL;
return CAIRO_STATUS_SUCCESS;
}
if (GetClipBox (surface->dc, &clip_box) == ERROR) {
_print_gdi_error ("_cairo_win3_surface_acquire_dest_image");
return _get_cairo_error ();
}
x1 = clip_box.left;
x2 = clip_box.right;
y1 = clip_box.top;
y2 = clip_box.bottom;
if (interest_rect->x > x1)
x1 = interest_rect->x;
if (interest_rect->y > y1)
y1 = interest_rect->y;
if (interest_rect->x + interest_rect->width < x2)
x2 = interest_rect->x + interest_rect->width;
if (interest_rect->y + interest_rect->height < y2)
y2 = interest_rect->y + interest_rect->height;
if (x1 >= x2 || y1 >= y2) {
*image_out = NULL;
*image_extra = NULL;
return CAIRO_STATUS_SUCCESS;
}
status = _cairo_win32_surface_get_subimage (abstract_surface,
x1, y1, x2 - x1, y2 - y1,
&local);
if (CAIRO_OK (status)) {
*image_out = (cairo_image_surface_t *)local->image;
*image_extra = local;
image_rect->x = x1;
image_rect->y = y1;
image_rect->width = x2 - x1;
image_rect->height = y2 - y1;
}
return status;
}
static void
_cairo_win32_surface_release_dest_image (void *abstract_surface,
cairo_rectangle_t *interest_rect,
cairo_image_surface_t *image,
cairo_rectangle_t *image_rect,
void *image_extra)
{
cairo_win32_surface_t *surface = abstract_surface;
cairo_win32_surface_t *local = image_extra;
if (!local)
return;
if (!BitBlt (surface->dc,
image_rect->x, image_rect->y,
image_rect->width, image_rect->height,
local->dc,
0, 0,
SRCCOPY)) {
_print_gdi_error ("_cairo_win32_surface_release_dest_image");
}
cairo_surface_destroy ((cairo_surface_t *)local);
}
static cairo_status_t
_cairo_win32_surface_clone_similar (void *surface,
cairo_surface_t *src,
cairo_surface_t **clone_out)
{
return CAIRO_INT_STATUS_UNSUPPORTED;
}
static cairo_status_t
_cairo_win32_surface_set_matrix (void *abstract_surface,
cairo_matrix_t *matrix)
{
cairo_win32_surface_t *surface = abstract_surface;
if (surface->image)
cairo_surface_set_matrix (surface->image, matrix);
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_win32_surface_set_filter (void *abstract_surface,
cairo_filter_t filter)
{
cairo_win32_surface_t *surface = abstract_surface;
if (surface->image)
cairo_surface_set_filter (surface->image, filter);
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_win32_surface_set_repeat (void *abstract_surface,
int repeat)
{
cairo_win32_surface_t *surface = abstract_surface;
if (surface->image)
cairo_surface_set_repeat (surface->image, repeat);
return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
_cairo_win32_surface_composite (cairo_operator_t operator,
cairo_pattern_t *pattern,
cairo_surface_t *generic_mask,
void *abstract_dst,
int src_x,
int src_y,
int mask_x,
int mask_y,
int dst_x,
int dst_y,
unsigned int width,
unsigned int height)
{
cairo_win32_surface_t *dst = abstract_dst;
cairo_win32_surface_t *src;
cairo_win32_surface_t *mask = (cairo_win32_surface_t *)generic_mask;
int alpha;
int integer_transform;
int itx, ity;
if (pattern->type != CAIRO_PATTERN_SURFACE ||
pattern->extend != CAIRO_EXTEND_NONE ||
pattern->u.surface.surface->backend != dst->base.backend ||
mask)
return CAIRO_INT_STATUS_UNSUPPORTED;
src = (cairo_win32_surface_t *)pattern->u.surface.surface;
integer_transform = _cairo_matrix_is_integer_translation (&pattern->matrix, &itx, &ity);
if (!integer_transform)
return CAIRO_INT_STATUS_UNSUPPORTED;
alpha = (pattern->color.alpha_short) >> 8;
if (alpha == 255 &&
src->format == dst->format &&
(operator == CAIRO_OPERATOR_SRC ||
(src->format == CAIRO_FORMAT_RGB24 && operator == CAIRO_OPERATOR_OVER))) {
if (!BitBlt (dst->dc,
dst_x, dst_y,
width, height,
src->dc,
src_x + itx, src_y + ity,
SRCCOPY)) {
_print_gdi_error ("_cairo_win32_surface_composite");
return _get_cairo_error ();
}
return CAIRO_STATUS_SUCCESS;
} else if (integer_transform &&
(src->format == CAIRO_FORMAT_RGB24 || src->format == CAIRO_FORMAT_ARGB32) &&
dst->format == CAIRO_FORMAT_RGB24 &&
!src->base.repeat &&
operator == CAIRO_OPERATOR_OVER) {
BLENDFUNCTION blend_function;
blend_function.BlendOp = AC_SRC_OVER;
blend_function.BlendFlags = 0;
blend_function.SourceConstantAlpha = alpha;
blend_function.AlphaFormat = src->format == CAIRO_FORMAT_ARGB32 ? AC_SRC_ALPHA : 0;
fprintf (stderr, "AlphaBlend\n");
if (!AlphaBlend (dst->dc,
dst_x, dst_y,
width, height,
src->dc,
src_x + itx, src_y + ity,
width, height,
blend_function)) {
_print_gdi_error ("_cairo_win32_surface_composite");
return _get_cairo_error ();
}
return CAIRO_STATUS_SUCCESS;
}
return CAIRO_INT_STATUS_UNSUPPORTED;
}
static cairo_int_status_t
_cairo_win32_surface_fill_rectangles (void *abstract_surface,
cairo_operator_t operator,
const cairo_color_t *color,
cairo_rectangle_t *rects,
int num_rects)
{
cairo_win32_surface_t *surface = abstract_surface;
COLORREF new_color;
HBRUSH new_brush;
int i;
/* If we have a local image, use the fallback code; it will be as fast
* as calling out to GDI.
*/
if (surface->image)
return CAIRO_INT_STATUS_UNSUPPORTED;
/* We could support possibly support more operators for color->alpha = 0xffff.
* for CAIRO_OPERATOR_SRC, alpha doesn't matter since we know the destination
* image doesn't have alpha. (surface->pixman_image is non-NULL for all
* surfaces with alpha.)
*/
if (operator != CAIRO_OPERATOR_SRC)
return CAIRO_INT_STATUS_UNSUPPORTED;
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 ();
}
for (i = 0; i < num_rects; i++) {
RECT rect;
rect.left = rects[i].x;
rect.top = rects[i].y;
rect.right = rects[i].x + rects[i].width;
rect.bottom = rects[i].y + rects[i].height;
if (!FillRect (surface->dc, &rect, new_brush))
goto FAIL;
}
DeleteObject (new_brush);
return CAIRO_STATUS_SUCCESS;
FAIL:
_print_gdi_error ("_cairo_win32_surface_fill_rectangles");
DeleteObject (new_brush);
return _get_cairo_error ();
}
static cairo_int_status_t
_cairo_win32_surface_composite_trapezoids (cairo_operator_t operator,
cairo_pattern_t *pattern,
void *abstract_dst,
int src_x,
int src_y,
int dst_x,
int dst_y,
unsigned int width,
unsigned int height,
cairo_trapezoid_t *traps,
int num_traps)
{
return CAIRO_INT_STATUS_UNSUPPORTED;
}
static cairo_int_status_t
_cairo_win32_surface_copy_page (void *abstract_surface)
{
return CAIRO_INT_STATUS_UNSUPPORTED;
}
static cairo_int_status_t
_cairo_win32_surface_show_page (void *abstract_surface)
{
return CAIRO_INT_STATUS_UNSUPPORTED;
}
static cairo_int_status_t
_cairo_win32_surface_set_clip_region (void *abstract_surface,
pixman_region16_t *region)
{
cairo_win32_surface_t *surface = abstract_surface;
/* If we are in-memory, then we set the clip on the image surface
* as well as on the underlying GDI surface.
*/
if (surface->image)
_cairo_surface_set_clip_region (surface->image, region);
/* The semantics we want is that any clip set by Cairo combines
* is intersected with the clip on device context that the
* surface was created for. To implement this, we need to
* save the original clip when first setting a clip on surface.
*/
if (region == NULL) {
/* 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 (surface->saved_clip) {
DeleteObject (surface->saved_clip);
surface->saved_clip = NULL;
}
surface->set_clip = 0;
}
return CAIRO_STATUS_SUCCESS;
} else {
pixman_box16_t *boxes = pixman_region_rects (region);
int num_boxes = pixman_region_num_rects (region);
pixman_box16_t *extents = pixman_region_extents (region);
RGNDATA *data;
size_t data_size;
RECT *rects;
int i;
HRGN gdi_region;
/* Create a GDI region for the cairo region */
data_size = sizeof (RGNDATAHEADER) + num_boxes * sizeof (RECT);
data = malloc (data_size);
if (!data)
return CAIRO_STATUS_NO_MEMORY;
rects = (RECT *)data->Buffer;
data->rdh.dwSize = sizeof (RGNDATAHEADER);
data->rdh.iType = RDH_RECTANGLES;
data->rdh.nCount = num_boxes;
data->rdh.nRgnSize = num_boxes * sizeof (RECT);
data->rdh.rcBound.left = extents->x1;
data->rdh.rcBound.top = extents->y1;
data->rdh.rcBound.right = extents->x2;
data->rdh.rcBound.bottom = extents->y2;
for (i = 0; i < num_boxes; i++) {
rects[i].left = boxes[i].x1;
rects[i].top = boxes[i].y1;
rects[i].right = boxes[i].x2;
rects[i].bottom = boxes[i].y2;
}
gdi_region = ExtCreateRegion (NULL, data_size, data);
free (data);
if (!gdi_region)
return CAIRO_STATUS_NO_MEMORY;
if (surface->set_clip) {
/* Combine the new region with the original clip */
if (surface->saved_clip) {
if (CombineRgn (gdi_region, gdi_region, surface->saved_clip, RGN_AND) == ERROR)
goto FAIL;
}
if (SelectClipRgn (surface->dc, gdi_region) == ERROR)
goto FAIL;
} else {
/* Save the the current region */
surface->saved_clip = CreateRectRgn (0, 0, 0, 0);
if (!surface->saved_clip) {
goto FAIL; }
/* This function has no error return! */
if (GetClipRgn (surface->dc, surface->saved_clip) == 0) { /* No clip */
DeleteObject (surface->saved_clip);
surface->saved_clip = NULL;
}
if (ExtSelectClipRgn (surface->dc, gdi_region, RGN_AND) == ERROR)
goto FAIL;
surface->set_clip = 1;
}
DeleteObject (gdi_region);
return CAIRO_STATUS_SUCCESS;
FAIL:
_print_gdi_error ("_cairo_win32_surface_set_clip_region");
DeleteObject (gdi_region);
return _get_cairo_error ();
}
}
static cairo_status_t
_cairo_win32_surface_show_glyphs (cairo_font_t *font,
cairo_operator_t operator,
cairo_pattern_t *pattern,
void *abstract_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)
{
return CAIRO_INT_STATUS_UNSUPPORTED;
}
cairo_surface_t *
cairo_win32_surface_create (HDC hdc)
{
cairo_win32_surface_t *surface;
RECT rect;
/* Try to figure out the drawing bounds for the Device context
*/
if (GetClipBox (hdc, &rect) == ERROR) {
_print_gdi_error ("cairo_win32_surface_create");
return NULL;
}
surface = malloc (sizeof (cairo_win32_surface_t));
if (!surface)
return NULL;
surface->image = NULL;
surface->format = CAIRO_FORMAT_RGB24;
surface->dc = hdc;
surface->bitmap = NULL;
surface->clip_rect.x = rect.left;
surface->clip_rect.y = rect.top;
surface->clip_rect.width = rect.right - rect.left;
surface->clip_rect.height = rect.bottom - rect.top;
surface->set_clip = 0;
surface->saved_clip = NULL;
_cairo_surface_init (&surface->base, &cairo_win32_surface_backend);
return (cairo_surface_t *)surface;
}
static const cairo_surface_backend_t cairo_win32_surface_backend = {
_cairo_win32_surface_create_similar,
_cairo_win32_surface_destroy,
_cairo_win32_surface_pixels_per_inch,
_cairo_win32_surface_acquire_source_image,
_cairo_win32_surface_release_source_image,
_cairo_win32_surface_acquire_dest_image,
_cairo_win32_surface_release_dest_image,
_cairo_win32_surface_clone_similar,
_cairo_win32_surface_set_matrix,
_cairo_win32_surface_set_filter,
_cairo_win32_surface_set_repeat,
_cairo_win32_surface_composite,
_cairo_win32_surface_fill_rectangles,
_cairo_win32_surface_composite_trapezoids,
_cairo_win32_surface_copy_page,
_cairo_win32_surface_show_page,
_cairo_win32_surface_set_clip_region,
_cairo_win32_surface_show_glyphs
};

View file

@ -522,6 +522,12 @@ extern const cairo_private struct _cairo_font_backend cairo_ft_font_backend;
#endif #endif
#ifdef CAIRO_HAS_WIN32_FONT
extern const cairo_private struct _cairo_font_backend cairo_win32_font_backend;
#endif
#ifdef CAIRO_HAS_ATSUI_FONT #ifdef CAIRO_HAS_ATSUI_FONT
extern const cairo_private struct _cairo_font_backend cairo_atsui_font_backend; extern const cairo_private struct _cairo_font_backend cairo_atsui_font_backend;
@ -787,19 +793,21 @@ typedef struct _cairo_traps {
#define CAIRO_FONT_SLANT_DEFAULT CAIRO_FONT_SLANT_NORMAL #define CAIRO_FONT_SLANT_DEFAULT CAIRO_FONT_SLANT_NORMAL
#define CAIRO_FONT_WEIGHT_DEFAULT CAIRO_FONT_WEIGHT_NORMAL #define CAIRO_FONT_WEIGHT_DEFAULT CAIRO_FONT_WEIGHT_NORMAL
#ifdef CAIRO_HAS_FT_FONT #if defined (CAIRO_HAS_WIN32_FONT)
#define CAIRO_FONT_FAMILY_DEFAULT "serif" #define CAIRO_FONT_FAMILY_DEFAULT "Arial"
#define CAIRO_FONT_BACKEND_DEFAULT &cairo_win32_font_backend
/* XXX: Platform-specific. Other platforms may want a different default */ #elif defined (CAIRO_HAS_ATSUI_FONT)
#define CAIRO_FONT_BACKEND_DEFAULT &cairo_ft_font_backend
#elif defined(CAIRO_HAS_ATSUI_FONT)
#define CAIRO_FONT_FAMILY_DEFAULT "Monaco" #define CAIRO_FONT_FAMILY_DEFAULT "Monaco"
#define CAIRO_FONT_BACKEND_DEFAULT &cairo_atsui_font_backend #define CAIRO_FONT_BACKEND_DEFAULT &cairo_atsui_font_backend
#elif defined (CAIRO_HAS_FT_FONT)
#define CAIRO_FONT_FAMILY_DEFAULT "serif"
#define CAIRO_FONT_BACKEND_DEFAULT &cairo_ft_font_backend
#endif #endif
#define CAIRO_GSTATE_OPERATOR_DEFAULT CAIRO_OPERATOR_OVER #define CAIRO_GSTATE_OPERATOR_DEFAULT CAIRO_OPERATOR_OVER