2004-08-02 21:50:17 +00:00
|
|
|
/*
|
2007-10-29 23:25:10 +00:00
|
|
|
CairoGState.m
|
2004-08-02 21:50:17 +00:00
|
|
|
|
2007-10-29 23:25:10 +00:00
|
|
|
Copyright (C) 2003 Free Software Foundation, Inc.
|
2004-08-02 21:50:17 +00:00
|
|
|
|
2007-10-29 23:25:10 +00:00
|
|
|
August 31, 2003
|
|
|
|
Written by Banlu Kemiyatorn <object at gmail dot com>
|
|
|
|
Rewrite: Fred Kiefer <fredkiefer@gmx.de>
|
|
|
|
Date: Jan 2006
|
|
|
|
|
|
|
|
This file is part of GNUstep.
|
2004-08-02 21:50:17 +00:00
|
|
|
|
2007-10-29 23:25:10 +00:00
|
|
|
This library is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU Lesser General Public
|
|
|
|
License as published by the Free Software Foundation; either
|
2008-06-10 04:12:46 +00:00
|
|
|
version 2 of the License, or (at your option) any later version.
|
2007-10-29 23:25:10 +00:00
|
|
|
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
Lesser General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
|
|
|
License along with this library; see the file COPYING.LIB.
|
|
|
|
If not, see <http://www.gnu.org/licenses/> or write to the
|
|
|
|
Free Software Foundation, 51 Franklin Street, Fifth Floor,
|
|
|
|
Boston, MA 02110-1301, USA.
|
|
|
|
*/
|
2004-08-02 21:50:17 +00:00
|
|
|
|
2006-10-03 23:29:53 +00:00
|
|
|
#include <AppKit/NSAffineTransform.h>
|
2004-08-02 21:50:17 +00:00
|
|
|
#include <AppKit/NSBezierPath.h>
|
|
|
|
#include <AppKit/NSColor.h>
|
2009-10-23 20:46:41 +00:00
|
|
|
#include <AppKit/NSGradient.h>
|
2004-09-08 22:08:15 +00:00
|
|
|
#include <AppKit/NSGraphics.h>
|
2004-08-02 21:50:17 +00:00
|
|
|
#include "cairo/CairoGState.h"
|
|
|
|
#include "cairo/CairoFontInfo.h"
|
|
|
|
#include "cairo/CairoSurface.h"
|
|
|
|
#include "cairo/CairoContext.h"
|
|
|
|
#include <math.h>
|
|
|
|
|
2007-03-21 13:09:19 +00:00
|
|
|
|
|
|
|
// Macro stolen from base/Header/Additions/GNUstepBase/GSObjRuntime.h
|
|
|
|
#ifndef GS_MAX_OBJECTS_FROM_STACK
|
|
|
|
/**
|
|
|
|
* The number of objects to try to get from varargs into an array on
|
|
|
|
* the stack ... if there are more than this, use the heap.
|
|
|
|
* NB. This MUST be a multiple of 2
|
|
|
|
*/
|
|
|
|
#define GS_MAX_OBJECTS_FROM_STACK 128
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// Macros stolen from base/Source/GSPrivate.h
|
|
|
|
/**
|
|
|
|
* Macro to manage memory for chunks of code that need to work with
|
|
|
|
* arrays of items. Use this to start the block of code using
|
|
|
|
* the array and GS_ENDITEMBUF() to end it. The idea is to ensure that small
|
|
|
|
* arrays are allocated on the stack (for speed), but large arrays are
|
|
|
|
* allocated from the heap (to avoid stack overflow).
|
|
|
|
*/
|
|
|
|
#define GS_BEGINITEMBUF(P, S, T) { \
|
|
|
|
T _ibuf[(S) <= GS_MAX_OBJECTS_FROM_STACK ? (S) : 0]; \
|
|
|
|
T *_base = ((S) <= GS_MAX_OBJECTS_FROM_STACK) ? _ibuf \
|
|
|
|
: (T*)NSZoneMalloc(NSDefaultMallocZone(), (S) * sizeof(T)); \
|
|
|
|
T *(P) = _base;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Macro to manage memory for chunks of code that need to work with
|
|
|
|
* arrays of items. Use GS_BEGINITEMBUF() to start the block of code using
|
|
|
|
* the array and this macro to end it.
|
|
|
|
*/
|
|
|
|
#define GS_ENDITEMBUF() \
|
|
|
|
if (_base != _ibuf) \
|
|
|
|
NSZoneFree(NSDefaultMallocZone(), _base); \
|
|
|
|
}
|
2004-08-02 21:50:17 +00:00
|
|
|
|
2007-11-05 11:01:59 +00:00
|
|
|
static float floatFromUserSpace(NSAffineTransform *ctm, float f)
|
|
|
|
{
|
|
|
|
NSSize s = {f, f};
|
|
|
|
|
|
|
|
if (ctm)
|
|
|
|
{
|
|
|
|
s = [ctm transformSize: s];
|
|
|
|
f = (((s.width > 0.0) ? s.width : -s.width) +
|
|
|
|
((s.height > 0.0) ? s.height : -s.height)) / 2;
|
|
|
|
}
|
|
|
|
return f;
|
|
|
|
}
|
|
|
|
|
|
|
|
static float floatToUserSpace(NSAffineTransform *ctm, float f)
|
|
|
|
{
|
|
|
|
NSAffineTransform *ictm;
|
|
|
|
|
|
|
|
ictm = [ctm copyWithZone: GSObjCZone(ctm)];
|
|
|
|
[ictm invert];
|
|
|
|
f = floatFromUserSpace(ictm, f);
|
|
|
|
RELEASE(ictm);
|
|
|
|
return f;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2004-08-02 21:50:17 +00:00
|
|
|
@implementation CairoGState
|
|
|
|
|
|
|
|
+ (void) initialize
|
|
|
|
{
|
2004-08-23 12:28:16 +00:00
|
|
|
if (self == [CairoGState class])
|
|
|
|
{
|
|
|
|
}
|
2004-08-02 21:50:17 +00:00
|
|
|
}
|
|
|
|
|
2006-10-03 23:29:53 +00:00
|
|
|
- (void) dealloc
|
2004-08-02 21:50:17 +00:00
|
|
|
{
|
2006-10-03 23:29:53 +00:00
|
|
|
if (_ct)
|
|
|
|
{
|
|
|
|
cairo_destroy(_ct);
|
|
|
|
}
|
|
|
|
RELEASE(_surface);
|
|
|
|
|
|
|
|
[super dealloc];
|
2004-08-02 21:50:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (id) copyWithZone: (NSZone *)zone
|
|
|
|
{
|
2006-10-03 23:29:53 +00:00
|
|
|
CairoGState *copy = (CairoGState *)[super copyWithZone: zone];
|
2004-08-02 21:50:17 +00:00
|
|
|
|
2007-09-06 21:32:55 +00:00
|
|
|
RETAIN(_surface);
|
|
|
|
|
2005-07-27 23:25:32 +00:00
|
|
|
if (_ct)
|
|
|
|
{
|
|
|
|
cairo_status_t status;
|
|
|
|
|
|
|
|
// FIXME: Need some way to do a copy
|
2007-09-05 09:59:12 +00:00
|
|
|
// but there isnt anything like copy->_ct = cairo_copy(_ct);
|
2005-07-27 23:25:32 +00:00
|
|
|
copy->_ct = cairo_create(cairo_get_target(_ct));
|
|
|
|
status = cairo_status(copy->_ct);
|
|
|
|
if (status != CAIRO_STATUS_SUCCESS)
|
|
|
|
{
|
2007-10-18 16:51:56 +00:00
|
|
|
NSLog(@"Cairo status '%s' in copy", cairo_status_to_string(status));
|
2008-03-29 13:16:58 +00:00
|
|
|
copy->_ct = NULL;
|
2007-09-05 09:59:12 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
cairo_path_t *cpath;
|
|
|
|
cairo_matrix_t local_matrix;
|
2008-03-06 08:35:20 +00:00
|
|
|
#if CAIRO_VERSION > CAIRO_VERSION_ENCODE(1, 4, 0)
|
2007-09-06 21:32:55 +00:00
|
|
|
cairo_rectangle_list_t *clip_rects;
|
|
|
|
int num_dashes;
|
2008-03-06 08:35:20 +00:00
|
|
|
#endif
|
2007-09-05 09:59:12 +00:00
|
|
|
|
|
|
|
cairo_get_matrix(_ct, &local_matrix);
|
|
|
|
cairo_set_matrix(copy->_ct, &local_matrix);
|
2007-10-01 16:02:16 +00:00
|
|
|
status = cairo_status(copy->_ct);
|
|
|
|
if (status != CAIRO_STATUS_SUCCESS)
|
|
|
|
{
|
2007-10-18 16:51:56 +00:00
|
|
|
NSLog(@"Cairo status '%s' in set matrix", cairo_status_to_string(status));
|
2007-10-01 16:02:16 +00:00
|
|
|
}
|
2007-09-06 21:32:55 +00:00
|
|
|
|
2007-09-05 09:59:12 +00:00
|
|
|
cpath = cairo_copy_path(_ct);
|
2007-09-06 21:32:55 +00:00
|
|
|
status = cpath->status;
|
|
|
|
if (status != CAIRO_STATUS_SUCCESS)
|
|
|
|
{
|
2007-10-01 16:02:16 +00:00
|
|
|
/*
|
|
|
|
Due to an interesting programming concept in cairo this does not
|
|
|
|
mean that an error has occured. It may as well just be that the
|
|
|
|
old path had no elements.
|
|
|
|
At least in cairo 1.4.10 (See file cairo-path.c, line 379).
|
|
|
|
*/
|
2007-10-18 16:51:56 +00:00
|
|
|
// NSLog(@"Cairo status '%s' in copy path", cairo_status_to_string(status));
|
2007-09-06 21:32:55 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
cairo_append_path(copy->_ct, cpath);
|
|
|
|
}
|
2007-09-05 09:59:12 +00:00
|
|
|
cairo_path_destroy(cpath);
|
|
|
|
|
|
|
|
cairo_set_operator(copy->_ct, cairo_get_operator(_ct));
|
|
|
|
cairo_set_source(copy->_ct, cairo_get_source(_ct));
|
|
|
|
cairo_set_tolerance(copy->_ct, cairo_get_tolerance(_ct));
|
|
|
|
cairo_set_antialias(copy->_ct, cairo_get_antialias(_ct));
|
|
|
|
cairo_set_line_width(copy->_ct, cairo_get_line_width(_ct));
|
|
|
|
cairo_set_line_cap(copy->_ct, cairo_get_line_cap(_ct));
|
|
|
|
cairo_set_line_join(copy->_ct, cairo_get_line_join(_ct));
|
|
|
|
cairo_set_miter_limit(copy->_ct, cairo_get_miter_limit(_ct));
|
|
|
|
|
2007-10-05 14:02:31 +00:00
|
|
|
#if CAIRO_VERSION > CAIRO_VERSION_ENCODE(1, 4, 0)
|
2007-09-06 21:32:55 +00:00
|
|
|
// In cairo 1.4 there is a way get the dash.
|
|
|
|
num_dashes = cairo_get_dash_count(_ct);
|
|
|
|
if (num_dashes != 0)
|
|
|
|
{
|
|
|
|
double dash_offset;
|
|
|
|
GS_BEGINITEMBUF(dashes, num_dashes, double);
|
|
|
|
|
|
|
|
cairo_get_dash(_ct, dashes, &dash_offset);
|
|
|
|
cairo_set_dash (copy->_ct, dashes, num_dashes, dash_offset);
|
|
|
|
GS_ENDITEMBUF();
|
|
|
|
}
|
|
|
|
|
|
|
|
// In cairo 1.4 there also is a way to get the current clipping path
|
|
|
|
clip_rects = cairo_copy_clip_rectangle_list(_ct);
|
|
|
|
status = clip_rects->status;
|
2009-02-05 18:44:18 +00:00
|
|
|
if (status == CAIRO_STATUS_SUCCESS)
|
2007-09-06 21:32:55 +00:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
2008-06-25 22:20:18 +00:00
|
|
|
if (cairo_version() >= CAIRO_VERSION_ENCODE(1, 6, 0))
|
2007-09-06 21:32:55 +00:00
|
|
|
{
|
2008-06-25 22:20:18 +00:00
|
|
|
for (i = 0; i < clip_rects->num_rectangles; i++)
|
|
|
|
{
|
|
|
|
cairo_rectangle_t rect = clip_rects->rectangles[i];
|
|
|
|
|
|
|
|
cairo_rectangle(copy->_ct, rect.x, rect.y,
|
|
|
|
rect.width, rect.height);
|
|
|
|
cairo_clip(copy->_ct);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for (i = 0; i < clip_rects->num_rectangles; i++)
|
|
|
|
{
|
|
|
|
cairo_rectangle_t rect = clip_rects->rectangles[i];
|
|
|
|
NSSize size = [_surface size];
|
|
|
|
|
|
|
|
cairo_rectangle(copy->_ct, rect.x,
|
|
|
|
/* This strange computation is due
|
|
|
|
to the device offset missing for
|
|
|
|
clip rects in cairo < 1.6.0. */
|
|
|
|
rect.y + 2*(offset.y - size.height),
|
|
|
|
rect.width, rect.height);
|
|
|
|
cairo_clip(copy->_ct);
|
|
|
|
}
|
2007-09-06 21:32:55 +00:00
|
|
|
}
|
2009-02-05 18:44:18 +00:00
|
|
|
|
|
|
|
cairo_rectangle_list_destroy(clip_rects);
|
|
|
|
}
|
|
|
|
else if (status == CAIRO_STATUS_CLIP_NOT_REPRESENTABLE)
|
|
|
|
{
|
|
|
|
// We cannot get the exact clip, so we do the best we can
|
|
|
|
double x1;
|
|
|
|
double y1;
|
|
|
|
double x2;
|
|
|
|
double y2;
|
|
|
|
|
|
|
|
cairo_clip_extents(_ct, &x1, &y1, &x2, &y2);
|
2009-02-06 10:11:30 +00:00
|
|
|
cairo_rectangle(copy->_ct, x1, y1, x2 - x1, y2 - y1);
|
2009-02-05 18:44:18 +00:00
|
|
|
cairo_clip(copy->_ct);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
NSLog(@"Cairo status '%s' in copy clip", cairo_status_to_string(status));
|
2007-09-06 21:32:55 +00:00
|
|
|
}
|
2007-10-05 14:02:31 +00:00
|
|
|
#endif
|
2008-03-06 08:35:20 +00:00
|
|
|
}
|
2005-07-27 23:25:32 +00:00
|
|
|
}
|
2004-08-02 21:50:17 +00:00
|
|
|
|
|
|
|
return copy;
|
|
|
|
}
|
|
|
|
|
2007-04-27 12:23:28 +00:00
|
|
|
- (void) GSCurrentSurface: (CairoSurface **)surface: (int *)x : (int *)y
|
2004-08-02 21:50:17 +00:00
|
|
|
{
|
|
|
|
if (x)
|
2006-10-03 23:29:53 +00:00
|
|
|
*x = offset.x;
|
2004-08-02 21:50:17 +00:00
|
|
|
if (y)
|
2006-10-03 23:29:53 +00:00
|
|
|
*y = offset.y;
|
2007-04-27 12:23:28 +00:00
|
|
|
if (surface)
|
2004-08-02 21:50:17 +00:00
|
|
|
{
|
2007-04-27 12:23:28 +00:00
|
|
|
*surface = _surface;
|
2004-08-02 21:50:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-04-27 12:23:28 +00:00
|
|
|
- (void) GSSetSurface: (CairoSurface *)surface : (int)x : (int)y
|
2004-08-02 21:50:17 +00:00
|
|
|
{
|
2007-04-27 12:23:28 +00:00
|
|
|
ASSIGN(_surface, surface);
|
2006-10-03 23:29:53 +00:00
|
|
|
[self setOffset: NSMakePoint(x, y)];
|
2005-07-27 23:25:32 +00:00
|
|
|
[self DPSinitgraphics];
|
2004-08-23 12:28:16 +00:00
|
|
|
}
|
2004-08-02 21:50:17 +00:00
|
|
|
|
2006-12-31 17:48:58 +00:00
|
|
|
- (void) setOffset: (NSPoint)theOffset
|
|
|
|
{
|
|
|
|
if (_surface != nil)
|
|
|
|
{
|
2007-04-27 12:23:28 +00:00
|
|
|
NSSize size = [_surface size];
|
|
|
|
|
|
|
|
cairo_surface_set_device_offset([_surface surface], -theOffset.x,
|
|
|
|
theOffset.y - size.height);
|
2006-12-31 17:48:58 +00:00
|
|
|
}
|
|
|
|
[super setOffset: theOffset];
|
|
|
|
}
|
|
|
|
|
2007-06-29 11:31:53 +00:00
|
|
|
- (void) showPage
|
2007-04-27 12:23:28 +00:00
|
|
|
{
|
|
|
|
if (_ct)
|
|
|
|
{
|
|
|
|
cairo_show_page(_ct);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-08-02 21:50:17 +00:00
|
|
|
/*
|
|
|
|
* Color operations
|
|
|
|
*/
|
2006-10-03 23:29:53 +00:00
|
|
|
- (void) setColor: (device_color_t *)color state: (color_state_t)cState
|
2004-08-02 21:50:17 +00:00
|
|
|
{
|
2006-10-03 23:29:53 +00:00
|
|
|
device_color_t c;
|
2006-09-30 12:21:13 +00:00
|
|
|
|
2006-10-03 23:29:53 +00:00
|
|
|
[super setColor: color state: cState];
|
|
|
|
if (_ct == NULL)
|
2006-09-30 12:21:13 +00:00
|
|
|
{
|
2007-03-21 13:09:19 +00:00
|
|
|
// Window device isn't set yet
|
2006-10-03 23:29:53 +00:00
|
|
|
return;
|
2006-09-30 12:21:13 +00:00
|
|
|
}
|
2007-02-28 23:22:34 +00:00
|
|
|
c = fillColor;
|
2006-10-03 23:29:53 +00:00
|
|
|
gsColorToRGB(&c);
|
2007-03-21 13:09:19 +00:00
|
|
|
// The underlying concept does not allow to determine if alpha is set or not.
|
|
|
|
cairo_set_source_rgba(_ct, c.field[0], c.field[1], c.field[2], c.field[AINDEX]);
|
2004-08-02 21:50:17 +00:00
|
|
|
}
|
|
|
|
|
2007-02-10 12:50:48 +00:00
|
|
|
- (void) GSSetPatterColor: (NSImage*)image
|
2004-08-02 21:50:17 +00:00
|
|
|
{
|
2007-02-10 12:50:48 +00:00
|
|
|
// FIXME: Create a cairo surface from the image and set it as source.
|
|
|
|
[super GSSetPatterColor: image];
|
|
|
|
}
|
2005-07-27 23:25:32 +00:00
|
|
|
|
2007-03-18 17:50:58 +00:00
|
|
|
/*
|
|
|
|
* Text operations
|
|
|
|
*/
|
2007-02-10 12:50:48 +00:00
|
|
|
|
2007-03-18 17:50:58 +00:00
|
|
|
- (void) _setPoint
|
2007-02-10 12:50:48 +00:00
|
|
|
{
|
2007-03-18 17:50:58 +00:00
|
|
|
NSPoint p;
|
2007-02-10 12:50:48 +00:00
|
|
|
|
2007-03-18 17:50:58 +00:00
|
|
|
p = [path currentPoint];
|
2007-07-02 23:30:11 +00:00
|
|
|
cairo_move_to(_ct, floorf(p.x), floorf(p.y));
|
2004-08-02 21:50:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void) DPScharpath: (const char *)s : (int)b
|
|
|
|
{
|
2007-02-12 16:21:39 +00:00
|
|
|
if (_ct)
|
|
|
|
{
|
2007-03-21 13:09:19 +00:00
|
|
|
GS_BEGINITEMBUF(c, b + 1, char);
|
2004-08-02 21:50:17 +00:00
|
|
|
|
2007-03-18 17:50:58 +00:00
|
|
|
[self _setPoint];
|
2007-02-12 16:21:39 +00:00
|
|
|
memcpy(c, s, b);
|
|
|
|
c[b] = 0;
|
|
|
|
cairo_text_path(_ct, c);
|
2007-03-21 13:09:19 +00:00
|
|
|
GS_ENDITEMBUF();
|
2008-04-02 22:10:32 +00:00
|
|
|
if (cairo_status(_ct) == CAIRO_STATUS_SUCCESS)
|
|
|
|
{
|
|
|
|
cairo_path_t *cpath;
|
|
|
|
cairo_path_data_t *data;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
cpath = cairo_copy_path(_ct);
|
|
|
|
|
|
|
|
for (i = 0; i < cpath->num_data; i += cpath->data[i].header.length)
|
|
|
|
{
|
|
|
|
data = &cpath->data[i];
|
|
|
|
switch (data->header.type)
|
|
|
|
{
|
|
|
|
case CAIRO_PATH_MOVE_TO:
|
|
|
|
[path moveToPoint: NSMakePoint(data[1].point.x, data[1].point.y)];
|
|
|
|
break;
|
|
|
|
case CAIRO_PATH_LINE_TO:
|
|
|
|
[path lineToPoint: NSMakePoint(data[1].point.x, data[1].point.y)];
|
|
|
|
break;
|
|
|
|
case CAIRO_PATH_CURVE_TO:
|
|
|
|
[path curveToPoint: NSMakePoint(data[3].point.x, data[3].point.y)
|
|
|
|
controlPoint1: NSMakePoint(data[1].point.x, data[1].point.y)
|
|
|
|
controlPoint2: NSMakePoint(data[2].point.x, data[2].point.y)];
|
|
|
|
break;
|
|
|
|
case CAIRO_PATH_CLOSE_PATH:
|
|
|
|
[path closePath];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
cairo_path_destroy(cpath);
|
|
|
|
}
|
2007-02-12 16:21:39 +00:00
|
|
|
}
|
2004-08-02 21:50:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void) DPSshow: (const char *)s
|
|
|
|
{
|
2007-02-12 16:21:39 +00:00
|
|
|
if (_ct)
|
|
|
|
{
|
2007-07-01 22:17:14 +00:00
|
|
|
cairo_matrix_t saved_matrix;
|
|
|
|
cairo_matrix_t local_matrix;
|
|
|
|
NSPoint p = [path currentPoint];
|
|
|
|
|
|
|
|
cairo_get_matrix(_ct, &saved_matrix);
|
|
|
|
|
|
|
|
cairo_matrix_init_scale(&local_matrix, 1, 1);
|
|
|
|
cairo_matrix_translate(&local_matrix, 0, [_surface size].height-(p.y*2));
|
|
|
|
cairo_set_matrix(_ct, &local_matrix);
|
|
|
|
|
|
|
|
cairo_move_to(_ct, p.x, p.y);
|
2007-02-12 16:21:39 +00:00
|
|
|
cairo_show_text(_ct, s);
|
2007-07-01 22:17:14 +00:00
|
|
|
|
|
|
|
cairo_set_matrix(_ct, &saved_matrix);
|
2007-02-12 16:21:39 +00:00
|
|
|
}
|
2004-08-02 21:50:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void) GSSetFont: (GSFontInfo *)fontref
|
|
|
|
{
|
2006-10-03 23:29:53 +00:00
|
|
|
cairo_matrix_t font_matrix;
|
|
|
|
const float *matrix;
|
|
|
|
|
2007-02-10 12:50:48 +00:00
|
|
|
[super GSSetFont: fontref];
|
|
|
|
|
2007-02-12 16:21:39 +00:00
|
|
|
if (_ct)
|
|
|
|
{
|
|
|
|
matrix = [font matrix];
|
|
|
|
cairo_set_font_face(_ct, [((CairoFontInfo *)font)->_faceInfo fontFace]);
|
|
|
|
cairo_matrix_init(&font_matrix, matrix[0], matrix[1], matrix[2],
|
2007-03-18 17:50:58 +00:00
|
|
|
matrix[3], matrix[4], matrix[5]);
|
2007-02-12 16:21:39 +00:00
|
|
|
cairo_set_font_matrix(_ct, &font_matrix);
|
|
|
|
}
|
2004-08-02 21:50:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void) GSSetFontSize: (float)size
|
|
|
|
{
|
2007-02-12 16:21:39 +00:00
|
|
|
if (_ct)
|
|
|
|
{
|
2007-11-05 11:01:59 +00:00
|
|
|
size = floatFromUserSpace(ctm, size);
|
2007-02-12 16:21:39 +00:00
|
|
|
cairo_set_font_size(_ct, size);
|
|
|
|
}
|
2004-08-02 21:50:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void) GSShowText: (const char *)string : (size_t)length
|
|
|
|
{
|
2007-02-12 16:21:39 +00:00
|
|
|
if (_ct)
|
|
|
|
{
|
2007-03-21 13:09:19 +00:00
|
|
|
GS_BEGINITEMBUF(c, length + 1, char);
|
2006-10-03 23:29:53 +00:00
|
|
|
|
2007-03-18 17:50:58 +00:00
|
|
|
[self _setPoint];
|
2007-02-12 16:21:39 +00:00
|
|
|
memcpy(c, string, length);
|
|
|
|
c[length] = 0;
|
|
|
|
cairo_show_text(_ct, c);
|
2007-03-21 13:09:19 +00:00
|
|
|
GS_ENDITEMBUF();
|
2007-02-12 16:21:39 +00:00
|
|
|
}
|
2004-08-02 21:50:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void) GSShowGlyphs: (const NSGlyph *)glyphs : (size_t)length
|
|
|
|
{
|
2007-02-12 16:21:39 +00:00
|
|
|
if (_ct)
|
|
|
|
{
|
2007-06-29 11:31:53 +00:00
|
|
|
cairo_matrix_t local_matrix;
|
|
|
|
NSAffineTransformStruct matrix = [ctm transformStruct];
|
|
|
|
|
2007-03-18 17:50:58 +00:00
|
|
|
[self _setPoint];
|
2007-06-29 11:31:53 +00:00
|
|
|
// FIXME: Hack to get font in rotated view working
|
|
|
|
cairo_save(_ct);
|
|
|
|
cairo_matrix_init(&local_matrix, matrix.m11, matrix.m12, matrix.m21,
|
|
|
|
matrix.m22, 0, 0);
|
|
|
|
cairo_transform(_ct, &local_matrix);
|
|
|
|
// Undo the
|
|
|
|
cairo_matrix_init_scale(&local_matrix, 1, -1);
|
|
|
|
cairo_matrix_translate(&local_matrix, 0, -[_surface size].height);
|
|
|
|
cairo_transform(_ct, &local_matrix);
|
|
|
|
|
2007-02-12 16:21:39 +00:00
|
|
|
[(CairoFontInfo *)font drawGlyphs: glyphs
|
2007-10-18 16:51:56 +00:00
|
|
|
length: length
|
|
|
|
on: _ct];
|
2007-06-29 11:31:53 +00:00
|
|
|
cairo_restore(_ct);
|
2007-02-12 16:21:39 +00:00
|
|
|
}
|
2004-08-02 21:50:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* GState operations
|
|
|
|
*/
|
|
|
|
|
|
|
|
- (void) DPSinitgraphics
|
|
|
|
{
|
2005-07-27 23:25:32 +00:00
|
|
|
cairo_status_t status;
|
2007-03-21 13:09:19 +00:00
|
|
|
cairo_matrix_t local_matrix;
|
2005-07-27 23:25:32 +00:00
|
|
|
|
2006-10-03 23:29:53 +00:00
|
|
|
[super DPSinitgraphics];
|
2004-08-02 21:50:17 +00:00
|
|
|
|
|
|
|
if (_ct)
|
|
|
|
{
|
|
|
|
cairo_destroy(_ct);
|
|
|
|
}
|
2005-07-27 23:25:32 +00:00
|
|
|
if (!_surface)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
_ct = cairo_create([_surface surface]);
|
|
|
|
status = cairo_status(_ct);
|
|
|
|
if (status != CAIRO_STATUS_SUCCESS)
|
|
|
|
{
|
2007-10-18 16:51:56 +00:00
|
|
|
NSLog(@"Cairo status '%s' in DPSinitgraphics", cairo_status_to_string(status));
|
2007-03-21 13:09:19 +00:00
|
|
|
_ct = NULL;
|
2007-03-02 12:24:46 +00:00
|
|
|
return;
|
2005-07-27 23:25:32 +00:00
|
|
|
}
|
2007-03-21 13:09:19 +00:00
|
|
|
|
|
|
|
// cairo draws the other way around.
|
|
|
|
// At this point in time viewIsFlipped has not been set, but it is
|
|
|
|
// OK to ignore this here, as in that case the matrix will later
|
|
|
|
// get flipped by GUI,
|
|
|
|
cairo_matrix_init_scale(&local_matrix, 1, -1);
|
|
|
|
cairo_matrix_translate(&local_matrix, 0, -[_surface size].height);
|
|
|
|
cairo_set_matrix(_ct, &local_matrix);
|
|
|
|
|
|
|
|
// super call did go to the old _ct, so redo it
|
2007-03-01 12:03:06 +00:00
|
|
|
[self setColor: &fillColor state: COLOR_BOTH];
|
2006-10-03 23:29:53 +00:00
|
|
|
|
2007-03-21 13:09:19 +00:00
|
|
|
// Cairo's default line width is 2.0
|
2004-08-02 21:50:17 +00:00
|
|
|
cairo_set_line_width(_ct, 1.0);
|
2006-02-13 00:07:40 +00:00
|
|
|
cairo_set_operator(_ct, CAIRO_OPERATOR_OVER);
|
2007-03-01 12:03:06 +00:00
|
|
|
cairo_new_path(_ct);
|
2007-07-01 23:02:29 +00:00
|
|
|
|
|
|
|
_strokeadjust = 1;
|
2004-08-02 21:50:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void) DPScurrentflat: (float *)flatness
|
|
|
|
{
|
2007-02-27 16:35:31 +00:00
|
|
|
if (_ct)
|
|
|
|
{
|
2007-11-05 11:01:59 +00:00
|
|
|
*flatness = (float)cairo_get_tolerance(_ct);
|
|
|
|
*flatness = floatToUserSpace(ctm, *flatness);
|
2007-02-27 16:35:31 +00:00
|
|
|
}
|
2004-08-02 21:50:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void) DPScurrentlinecap: (int *)linecap
|
|
|
|
{
|
|
|
|
cairo_line_cap_t lc;
|
|
|
|
|
2007-02-27 16:35:31 +00:00
|
|
|
if (_ct)
|
|
|
|
{
|
|
|
|
lc = cairo_get_line_cap(_ct);
|
|
|
|
*linecap = lc;
|
|
|
|
}
|
2004-08-02 21:50:17 +00:00
|
|
|
/*
|
|
|
|
switch (lc)
|
|
|
|
{
|
|
|
|
case CAIRO_LINE_CAP_BUTT:
|
|
|
|
*linecap = 0;
|
|
|
|
break;
|
|
|
|
case CAIRO_LINE_CAP_ROUND:
|
|
|
|
*linecap = 1;
|
|
|
|
break;
|
|
|
|
case CAIRO_LINE_CAP_SQUARE:
|
|
|
|
*linecap = 2;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
NSLog(@"ERROR Line cap unknown");
|
|
|
|
exit(-1);
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) DPScurrentlinejoin: (int *)linejoin
|
|
|
|
{
|
|
|
|
cairo_line_join_t lj;
|
|
|
|
|
2007-02-27 16:35:31 +00:00
|
|
|
if (_ct)
|
|
|
|
{
|
|
|
|
lj = cairo_get_line_join(_ct);
|
|
|
|
*linejoin = lj;
|
|
|
|
}
|
2004-08-02 21:50:17 +00:00
|
|
|
/*
|
|
|
|
switch (lj)
|
|
|
|
{
|
|
|
|
case CAIRO_LINE_JOIN_MITER:
|
|
|
|
*linejoin = 0;
|
|
|
|
break;
|
|
|
|
case CAIRO_LINE_JOIN_ROUND:
|
|
|
|
*linejoin = 1;
|
|
|
|
break;
|
|
|
|
case CAIRO_LINE_JOIN_BEVEL:
|
|
|
|
*linejoin = 2;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
NSLog(@"ERROR Line join unknown");
|
|
|
|
exit(-1);
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) DPScurrentlinewidth: (float *)width
|
|
|
|
{
|
2007-02-27 16:35:31 +00:00
|
|
|
if (_ct)
|
|
|
|
{
|
2007-11-05 11:01:59 +00:00
|
|
|
*width = (float)cairo_get_line_width(_ct);
|
|
|
|
*width = floatToUserSpace(ctm, *width);
|
2007-02-27 16:35:31 +00:00
|
|
|
}
|
2004-08-02 21:50:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void) DPScurrentmiterlimit: (float *)limit
|
|
|
|
{
|
2007-02-27 16:35:31 +00:00
|
|
|
if (_ct)
|
|
|
|
{
|
2007-11-05 11:01:59 +00:00
|
|
|
*limit = (float)cairo_get_miter_limit(_ct);
|
|
|
|
*limit = floatToUserSpace(ctm, *limit);
|
2007-02-27 16:35:31 +00:00
|
|
|
}
|
2004-08-02 21:50:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void) DPScurrentstrokeadjust: (int *)b
|
|
|
|
{
|
2007-03-21 13:09:19 +00:00
|
|
|
// FIXME
|
2004-08-02 21:50:17 +00:00
|
|
|
}
|
|
|
|
|
2007-03-21 13:09:19 +00:00
|
|
|
- (void) DPSsetdash: (const float *)pat : (int)size : (float)foffset
|
2004-08-02 21:50:17 +00:00
|
|
|
{
|
2007-02-27 16:35:31 +00:00
|
|
|
if (_ct)
|
2004-08-02 21:50:17 +00:00
|
|
|
{
|
2007-03-21 13:09:19 +00:00
|
|
|
GS_BEGINITEMBUF(dpat, size, double);
|
2007-11-05 11:01:59 +00:00
|
|
|
double doffset = (double)floatFromUserSpace(ctm, foffset);
|
2007-03-21 13:09:19 +00:00
|
|
|
int i;
|
|
|
|
|
2007-02-27 16:35:31 +00:00
|
|
|
i = size;
|
|
|
|
while (i)
|
|
|
|
{
|
2007-04-04 14:33:10 +00:00
|
|
|
i--;
|
2007-11-05 11:01:59 +00:00
|
|
|
// FIXME: When using the correct values, some dashes look wrong
|
|
|
|
dpat[i] = (double)floatFromUserSpace(ctm, pat[i]) * 1.4;
|
2007-04-04 14:33:10 +00:00
|
|
|
}
|
2007-02-27 16:35:31 +00:00
|
|
|
cairo_set_dash(_ct, dpat, size, doffset);
|
2007-03-21 13:09:19 +00:00
|
|
|
GS_ENDITEMBUF();
|
2004-08-02 21:50:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) DPSsetflat: (float)flatness
|
|
|
|
{
|
2007-03-18 17:50:58 +00:00
|
|
|
[super DPSsetflat: flatness];
|
2007-02-27 16:35:31 +00:00
|
|
|
if (_ct)
|
|
|
|
{
|
2007-11-05 11:01:59 +00:00
|
|
|
cairo_set_tolerance(_ct, floatFromUserSpace(ctm, flatness));
|
2007-02-27 16:35:31 +00:00
|
|
|
}
|
2004-08-02 21:50:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void) DPSsetlinecap: (int)linecap
|
|
|
|
{
|
2007-02-27 16:35:31 +00:00
|
|
|
if (_ct)
|
|
|
|
{
|
|
|
|
cairo_set_line_cap(_ct, (cairo_line_cap_t)linecap);
|
|
|
|
}
|
2004-08-02 21:50:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void) DPSsetlinejoin: (int)linejoin
|
|
|
|
{
|
2007-02-27 16:35:31 +00:00
|
|
|
if (_ct)
|
|
|
|
{
|
|
|
|
cairo_set_line_join(_ct, (cairo_line_join_t)linejoin);
|
|
|
|
}
|
2004-08-02 21:50:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void) DPSsetlinewidth: (float)width
|
|
|
|
{
|
2007-02-27 16:35:31 +00:00
|
|
|
if (_ct)
|
|
|
|
{
|
2007-11-05 11:01:59 +00:00
|
|
|
cairo_set_line_width(_ct, floatFromUserSpace(ctm, width));
|
2007-02-27 16:35:31 +00:00
|
|
|
}
|
2004-08-02 21:50:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void) DPSsetmiterlimit: (float)limit
|
|
|
|
{
|
2007-02-27 16:35:31 +00:00
|
|
|
if (_ct)
|
|
|
|
{
|
2007-11-05 11:01:59 +00:00
|
|
|
cairo_set_miter_limit(_ct, floatFromUserSpace(ctm, limit));
|
2007-02-27 16:35:31 +00:00
|
|
|
}
|
2004-08-02 21:50:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void) DPSsetstrokeadjust: (int)b
|
|
|
|
{
|
2007-07-01 23:02:29 +00:00
|
|
|
_strokeadjust = b;
|
2004-08-02 21:50:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2007-03-21 13:09:19 +00:00
|
|
|
* Path operations
|
2004-08-02 21:50:17 +00:00
|
|
|
*/
|
|
|
|
|
2007-07-01 23:02:29 +00:00
|
|
|
- (void) _adjustPath: (float)offs
|
|
|
|
{
|
|
|
|
unsigned count = [path elementCount];
|
2007-07-02 23:30:11 +00:00
|
|
|
NSBezierPathElement type;
|
|
|
|
NSPoint points[3] = {{0.0, 0.0}, {0.0, 0.0}, {0.0, 0.0}};
|
|
|
|
NSPoint last_points[3] = {{0.0, 0.0}, {0.0, 0.0}, {0.0, 0.0}};
|
2007-07-01 23:02:29 +00:00
|
|
|
unsigned i;
|
2007-07-02 23:30:11 +00:00
|
|
|
int index, last_index;
|
2007-07-01 23:02:29 +00:00
|
|
|
|
|
|
|
for (i = 0; i < count; i++)
|
|
|
|
{
|
|
|
|
type = [path elementAtIndex:i associatedPoints:points];
|
|
|
|
|
|
|
|
if (type == NSCurveToBezierPathElement) break;
|
|
|
|
|
2007-07-02 23:30:11 +00:00
|
|
|
points[0].x = floorf(points[0].x) + offs;
|
|
|
|
points[0].y = floorf(points[0].y) + offs;
|
|
|
|
|
|
|
|
index = i;
|
|
|
|
last_index = i - 1;
|
|
|
|
|
2007-07-01 23:02:29 +00:00
|
|
|
if (type == NSClosePathBezierPathElement)
|
2007-09-06 21:32:55 +00:00
|
|
|
{
|
|
|
|
index = 0;
|
|
|
|
[path elementAtIndex:0 associatedPoints:points];
|
|
|
|
if (fabs(last_points[0].x - points[0].x) < 1.0)
|
|
|
|
{
|
|
|
|
last_points[0].x = floorf(last_points[0].x) + offs;
|
|
|
|
points[0].x = last_points[0].x;
|
|
|
|
}
|
|
|
|
else if (fabs(last_points[0].y - points[0].y) < 1.0)
|
|
|
|
{
|
|
|
|
last_points[0].y = floorf(last_points[0].y) + offs;
|
|
|
|
points[0].y = last_points[0].y;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
index = -1;
|
|
|
|
}
|
|
|
|
}
|
2007-07-01 23:02:29 +00:00
|
|
|
else if (fabs(last_points[0].x - points[0].x) < 1.0)
|
2007-09-06 21:32:55 +00:00
|
|
|
{ // Vertical path
|
|
|
|
points[0].x = floorf(points[0].x) + offs;
|
|
|
|
points[0].y = floorf(points[0].y);
|
|
|
|
if (type == NSLineToBezierPathElement)
|
|
|
|
{
|
|
|
|
last_points[0].x = points[0].x;
|
|
|
|
}
|
|
|
|
}
|
2007-07-01 23:02:29 +00:00
|
|
|
else if (fabs(last_points[0].y - points[0].y) < 1.0)
|
2007-09-06 21:32:55 +00:00
|
|
|
{ // Horizontal path
|
|
|
|
points[0].x = floorf(points[0].x);
|
|
|
|
points[0].y = floorf(points[0].y) + offs;
|
|
|
|
if (type == NSLineToBezierPathElement)
|
|
|
|
{
|
|
|
|
last_points[0].y = points[0].y;
|
|
|
|
}
|
|
|
|
}
|
2007-07-01 23:02:29 +00:00
|
|
|
|
2007-07-02 23:30:11 +00:00
|
|
|
// Save adjusted values into NSBezierPath
|
|
|
|
if (index >= 0)
|
2007-09-06 21:32:55 +00:00
|
|
|
[path setAssociatedPoints:points atIndex:index];
|
2007-07-02 23:30:11 +00:00
|
|
|
if (last_index >= 0)
|
2007-09-06 21:32:55 +00:00
|
|
|
[path setAssociatedPoints:last_points atIndex:last_index];
|
2007-07-02 23:30:11 +00:00
|
|
|
|
2007-07-01 23:02:29 +00:00
|
|
|
last_points[0].x = points[0].x;
|
|
|
|
last_points[0].y = points[0].y;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) _setPath: (BOOL)fillOrClip
|
2004-08-02 21:50:17 +00:00
|
|
|
{
|
2007-03-18 17:50:58 +00:00
|
|
|
unsigned count = [path elementCount];
|
|
|
|
unsigned i;
|
|
|
|
SEL elmsel = @selector(elementAtIndex:associatedPoints:);
|
|
|
|
IMP elmidx = [path methodForSelector: elmsel];
|
2004-08-02 21:50:17 +00:00
|
|
|
|
2007-07-01 23:02:29 +00:00
|
|
|
if (_strokeadjust)
|
|
|
|
{
|
|
|
|
float offs;
|
|
|
|
|
2009-10-19 14:17:45 +00:00
|
|
|
if ((remainderf((float)cairo_get_line_width(_ct), 2.0) == 0.0)
|
2007-09-06 21:32:55 +00:00
|
|
|
|| fillOrClip == YES)
|
|
|
|
offs = 0.0;
|
2007-07-01 23:02:29 +00:00
|
|
|
else
|
2007-09-06 21:32:55 +00:00
|
|
|
offs = 0.5;
|
2007-07-01 23:02:29 +00:00
|
|
|
|
|
|
|
[self _adjustPath:offs];
|
|
|
|
}
|
|
|
|
|
2007-09-06 21:32:55 +00:00
|
|
|
// reset current cairo path
|
|
|
|
cairo_new_path(_ct);
|
2007-03-18 17:50:58 +00:00
|
|
|
for (i = 0; i < count; i++)
|
2007-02-27 16:35:31 +00:00
|
|
|
{
|
2007-03-18 17:50:58 +00:00
|
|
|
NSBezierPathElement type;
|
|
|
|
NSPoint points[3];
|
2004-08-02 21:50:17 +00:00
|
|
|
|
2007-03-18 17:50:58 +00:00
|
|
|
type = (NSBezierPathElement)(*elmidx)(path, elmsel, i, points);
|
|
|
|
switch(type)
|
|
|
|
{
|
2007-04-04 14:33:10 +00:00
|
|
|
case NSMoveToBezierPathElement:
|
|
|
|
cairo_move_to(_ct, points[0].x, points[0].y);
|
|
|
|
break;
|
|
|
|
case NSLineToBezierPathElement:
|
|
|
|
cairo_line_to(_ct, points[0].x, points[0].y);
|
|
|
|
break;
|
|
|
|
case NSCurveToBezierPathElement:
|
|
|
|
cairo_curve_to(_ct, points[0].x, points[0].y,
|
|
|
|
points[1].x, points[1].y,
|
|
|
|
points[2].x, points[2].y);
|
|
|
|
break;
|
|
|
|
case NSClosePathBezierPathElement:
|
|
|
|
cairo_close_path(_ct);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2007-02-27 16:35:31 +00:00
|
|
|
}
|
2004-08-02 21:50:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void) DPSclip
|
|
|
|
{
|
2007-02-27 16:35:31 +00:00
|
|
|
if (_ct)
|
|
|
|
{
|
2007-07-01 23:02:29 +00:00
|
|
|
[self _setPath:YES];
|
2007-02-27 16:35:31 +00:00
|
|
|
cairo_clip(_ct);
|
2007-10-18 16:51:56 +00:00
|
|
|
}
|
2004-08-02 21:50:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void) DPSeoclip
|
|
|
|
{
|
2007-02-27 16:35:31 +00:00
|
|
|
if (_ct)
|
|
|
|
{
|
2007-07-01 23:02:29 +00:00
|
|
|
[self _setPath:YES];
|
2007-02-27 16:35:31 +00:00
|
|
|
cairo_set_fill_rule(_ct, CAIRO_FILL_RULE_EVEN_ODD);
|
|
|
|
cairo_clip(_ct);
|
|
|
|
cairo_set_fill_rule(_ct, CAIRO_FILL_RULE_WINDING);
|
|
|
|
}
|
2004-08-02 21:50:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void) DPSeofill
|
|
|
|
{
|
2007-02-27 16:35:31 +00:00
|
|
|
if (_ct)
|
|
|
|
{
|
2009-10-19 14:17:45 +00:00
|
|
|
if (pattern != nil)
|
|
|
|
{
|
|
|
|
[self eofillPath: path withPattern: pattern];
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2007-07-01 23:02:29 +00:00
|
|
|
[self _setPath:YES];
|
2007-02-27 16:35:31 +00:00
|
|
|
cairo_set_fill_rule(_ct, CAIRO_FILL_RULE_EVEN_ODD);
|
|
|
|
cairo_fill(_ct);
|
|
|
|
cairo_set_fill_rule(_ct, CAIRO_FILL_RULE_WINDING);
|
|
|
|
}
|
2007-09-09 20:34:13 +00:00
|
|
|
[self DPSnewpath];
|
2004-08-02 21:50:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void) DPSfill
|
|
|
|
{
|
2007-02-27 16:35:31 +00:00
|
|
|
if (_ct)
|
|
|
|
{
|
2009-10-19 14:17:45 +00:00
|
|
|
if (pattern != nil)
|
|
|
|
{
|
|
|
|
[self fillPath: path withPattern: pattern];
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2007-07-01 23:02:29 +00:00
|
|
|
[self _setPath:YES];
|
2007-02-27 16:35:31 +00:00
|
|
|
cairo_fill(_ct);
|
|
|
|
}
|
2007-09-09 20:34:13 +00:00
|
|
|
[self DPSnewpath];
|
2004-08-02 21:50:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void) DPSinitclip
|
|
|
|
{
|
2007-02-27 16:35:31 +00:00
|
|
|
if (_ct)
|
|
|
|
{
|
|
|
|
cairo_reset_clip(_ct);
|
|
|
|
}
|
2004-08-02 21:50:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void) DPSstroke
|
|
|
|
{
|
2007-02-27 16:35:31 +00:00
|
|
|
if (_ct)
|
|
|
|
{
|
2007-07-01 23:02:29 +00:00
|
|
|
[self _setPath:NO];
|
2007-02-27 16:35:31 +00:00
|
|
|
cairo_stroke(_ct);
|
|
|
|
}
|
2007-09-09 20:34:13 +00:00
|
|
|
[self DPSnewpath];
|
2004-08-02 21:50:17 +00:00
|
|
|
}
|
|
|
|
|
2007-02-10 12:50:48 +00:00
|
|
|
- (NSDictionary *) GSReadRect: (NSRect)r
|
|
|
|
{
|
|
|
|
NSMutableDictionary *dict;
|
|
|
|
NSSize ssize;
|
|
|
|
NSAffineTransform *matrix;
|
|
|
|
double x, y;
|
2007-02-10 23:21:29 +00:00
|
|
|
int ix, iy;
|
|
|
|
cairo_format_t format = CAIRO_FORMAT_ARGB32;
|
2007-02-10 12:50:48 +00:00
|
|
|
cairo_surface_t *surface;
|
2007-02-10 23:21:29 +00:00
|
|
|
cairo_surface_t *isurface;
|
|
|
|
cairo_t *ct;
|
2007-09-05 09:59:12 +00:00
|
|
|
cairo_status_t status;
|
2007-02-10 23:21:29 +00:00
|
|
|
int size;
|
|
|
|
int i;
|
|
|
|
NSMutableData *data;
|
|
|
|
unsigned char *cdata;
|
2007-02-10 12:50:48 +00:00
|
|
|
|
2007-02-27 16:35:31 +00:00
|
|
|
if (!_ct)
|
|
|
|
{
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
2007-03-18 17:50:58 +00:00
|
|
|
r = [ctm rectInMatrixSpace: r];
|
2007-02-10 12:50:48 +00:00
|
|
|
x = NSWidth(r);
|
|
|
|
y = NSHeight(r);
|
2007-02-12 16:21:39 +00:00
|
|
|
ix = abs(floor(x));
|
|
|
|
iy = abs(floor(y));
|
2007-02-10 23:21:29 +00:00
|
|
|
ssize = NSMakeSize(ix, iy);
|
|
|
|
|
|
|
|
dict = [NSMutableDictionary dictionary];
|
2007-02-10 12:50:48 +00:00
|
|
|
[dict setObject: [NSValue valueWithSize: ssize] forKey: @"Size"];
|
|
|
|
[dict setObject: NSDeviceRGBColorSpace forKey: @"ColorSpace"];
|
2007-02-10 23:21:29 +00:00
|
|
|
|
|
|
|
[dict setObject: [NSNumber numberWithUnsignedInt: 8] forKey: @"BitsPerSample"];
|
|
|
|
[dict setObject: [NSNumber numberWithUnsignedInt: 32]
|
|
|
|
forKey: @"Depth"];
|
|
|
|
[dict setObject: [NSNumber numberWithUnsignedInt: 4]
|
|
|
|
forKey: @"SamplesPerPixel"];
|
|
|
|
[dict setObject: [NSNumber numberWithUnsignedInt: 1]
|
|
|
|
forKey: @"HasAlpha"];
|
|
|
|
|
|
|
|
matrix = [self GSCurrentCTM];
|
|
|
|
[matrix translateXBy: -r.origin.x - offset.x
|
|
|
|
yBy: r.origin.y + NSHeight(r) - offset.y];
|
|
|
|
[dict setObject: matrix forKey: @"Matrix"];
|
|
|
|
|
|
|
|
size = ix*iy*4;
|
|
|
|
data = [NSMutableData dataWithLength: size];
|
|
|
|
if (data == nil)
|
|
|
|
return nil;
|
|
|
|
cdata = [data mutableBytes];
|
2007-02-10 12:50:48 +00:00
|
|
|
|
2007-02-10 23:21:29 +00:00
|
|
|
surface = cairo_get_target(_ct);
|
|
|
|
isurface = cairo_image_surface_create_for_data(cdata, format, ix, iy, 4*ix);
|
2007-09-05 09:59:12 +00:00
|
|
|
status = cairo_surface_status(isurface);
|
|
|
|
if (status != CAIRO_STATUS_SUCCESS)
|
|
|
|
{
|
2007-10-18 16:51:56 +00:00
|
|
|
NSLog(@"Cairo status '%s' in GSReadRect", cairo_status_to_string(status));
|
2007-09-05 09:59:12 +00:00
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
2007-02-10 23:21:29 +00:00
|
|
|
ct = cairo_create(isurface);
|
2007-09-05 09:59:12 +00:00
|
|
|
status = cairo_status(ct);
|
|
|
|
if (status != CAIRO_STATUS_SUCCESS)
|
|
|
|
{
|
2007-10-18 16:51:56 +00:00
|
|
|
NSLog(@"Cairo status '%s' in GSReadRect", cairo_status_to_string(status));
|
2007-09-05 09:59:12 +00:00
|
|
|
cairo_surface_destroy(isurface);
|
|
|
|
return nil;
|
|
|
|
}
|
2007-02-10 23:21:29 +00:00
|
|
|
|
2007-03-20 23:24:04 +00:00
|
|
|
if (_surface != nil)
|
|
|
|
{
|
|
|
|
ssize = [_surface size];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ssize = NSMakeSize(0, 0);
|
|
|
|
}
|
2007-09-05 09:59:12 +00:00
|
|
|
cairo_set_source_surface(ct, surface, -r.origin.x,
|
|
|
|
-ssize.height + r.size.height + r.origin.y);
|
2007-02-10 23:21:29 +00:00
|
|
|
cairo_rectangle(ct, 0, 0, ix, iy);
|
2007-03-20 23:24:04 +00:00
|
|
|
cairo_paint(ct);
|
2007-02-10 23:21:29 +00:00
|
|
|
cairo_destroy(ct);
|
|
|
|
cairo_surface_destroy(isurface);
|
|
|
|
|
2007-03-21 13:09:19 +00:00
|
|
|
for (i = 0; i < 4 * ix * iy; i += 4)
|
2007-02-10 12:50:48 +00:00
|
|
|
{
|
2007-03-21 13:09:19 +00:00
|
|
|
unsigned char d = cdata[i];
|
2007-02-10 23:21:29 +00:00
|
|
|
|
|
|
|
#if GS_WORDS_BIGENDIAN
|
2007-03-21 13:09:19 +00:00
|
|
|
cdata[i] = cdata[i + 1];
|
|
|
|
cdata[i + 1] = cdata[i + 2];
|
|
|
|
cdata[i + 2] = cdata[i + 3];
|
|
|
|
cdata[i + 3] = d;
|
2007-02-10 23:21:29 +00:00
|
|
|
#else
|
2007-03-21 13:09:19 +00:00
|
|
|
cdata[i] = cdata[i + 2];
|
|
|
|
//cdata[i + 1] = cdata[i + 1];
|
|
|
|
cdata[i + 2] = d;
|
|
|
|
//cdata[i + 3] = cdata[i + 3];
|
2007-02-10 23:21:29 +00:00
|
|
|
#endif
|
2007-02-10 12:50:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
[dict setObject: data forKey: @"Data"];
|
|
|
|
|
|
|
|
return dict;
|
|
|
|
}
|
|
|
|
|
2004-08-02 21:50:17 +00:00
|
|
|
static void
|
2007-02-10 23:21:29 +00:00
|
|
|
_set_op(cairo_t *ct, NSCompositingOperation op)
|
2004-08-02 21:50:17 +00:00
|
|
|
{
|
|
|
|
switch (op)
|
|
|
|
{
|
|
|
|
case NSCompositeClear:
|
|
|
|
cairo_set_operator(ct, CAIRO_OPERATOR_CLEAR);
|
|
|
|
break;
|
|
|
|
case NSCompositeCopy:
|
2005-07-27 23:25:32 +00:00
|
|
|
cairo_set_operator(ct, CAIRO_OPERATOR_SOURCE);
|
2004-08-02 21:50:17 +00:00
|
|
|
break;
|
|
|
|
case NSCompositeSourceOver:
|
|
|
|
cairo_set_operator(ct, CAIRO_OPERATOR_OVER);
|
|
|
|
break;
|
|
|
|
case NSCompositeSourceIn:
|
|
|
|
cairo_set_operator(ct, CAIRO_OPERATOR_IN);
|
|
|
|
break;
|
|
|
|
case NSCompositeSourceOut:
|
|
|
|
cairo_set_operator(ct, CAIRO_OPERATOR_OUT);
|
|
|
|
break;
|
|
|
|
case NSCompositeSourceAtop:
|
|
|
|
cairo_set_operator(ct, CAIRO_OPERATOR_ATOP);
|
|
|
|
break;
|
|
|
|
case NSCompositeDestinationOver:
|
2005-07-27 23:25:32 +00:00
|
|
|
cairo_set_operator(ct, CAIRO_OPERATOR_DEST_OVER);
|
2004-08-02 21:50:17 +00:00
|
|
|
break;
|
|
|
|
case NSCompositeDestinationIn:
|
2005-07-27 23:25:32 +00:00
|
|
|
cairo_set_operator(ct, CAIRO_OPERATOR_DEST_IN);
|
2004-08-02 21:50:17 +00:00
|
|
|
break;
|
|
|
|
case NSCompositeDestinationOut:
|
2005-07-27 23:25:32 +00:00
|
|
|
cairo_set_operator(ct, CAIRO_OPERATOR_DEST_OUT);
|
2004-08-02 21:50:17 +00:00
|
|
|
break;
|
|
|
|
case NSCompositeDestinationAtop:
|
2005-07-27 23:25:32 +00:00
|
|
|
cairo_set_operator(ct, CAIRO_OPERATOR_DEST_ATOP);
|
2004-08-02 21:50:17 +00:00
|
|
|
break;
|
|
|
|
case NSCompositeXOR:
|
|
|
|
cairo_set_operator(ct, CAIRO_OPERATOR_XOR);
|
|
|
|
break;
|
|
|
|
case NSCompositePlusDarker:
|
2007-03-21 13:09:19 +00:00
|
|
|
// FIXME: There is no match for this operation in cairo!!!
|
2007-02-18 18:54:08 +00:00
|
|
|
cairo_set_operator(ct, CAIRO_OPERATOR_SATURATE);
|
2004-08-02 21:50:17 +00:00
|
|
|
break;
|
|
|
|
case NSCompositeHighlight:
|
2007-02-18 18:54:08 +00:00
|
|
|
// MacOSX 10.4 documentation maps this value onto NSCompositeSourceOver
|
|
|
|
cairo_set_operator(ct, CAIRO_OPERATOR_OVER);
|
2004-08-02 21:50:17 +00:00
|
|
|
break;
|
|
|
|
case NSCompositePlusLighter:
|
|
|
|
cairo_set_operator(ct, CAIRO_OPERATOR_ADD);
|
|
|
|
break;
|
|
|
|
default:
|
2005-07-27 23:25:32 +00:00
|
|
|
cairo_set_operator(ct, CAIRO_OPERATOR_SOURCE);
|
2004-08-02 21:50:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) DPSimage: (NSAffineTransform *)matrix : (int)pixelsWide
|
|
|
|
: (int)pixelsHigh : (int)bitsPerSample
|
|
|
|
: (int)samplesPerPixel : (int)bitsPerPixel
|
|
|
|
: (int)bytesPerRow : (BOOL)isPlanar
|
|
|
|
: (BOOL)hasAlpha : (NSString *)colorSpaceName
|
|
|
|
: (const unsigned char *const[5])data
|
|
|
|
{
|
|
|
|
cairo_format_t format;
|
|
|
|
NSAffineTransformStruct tstruct;
|
2004-09-08 22:08:15 +00:00
|
|
|
cairo_surface_t *surface;
|
2007-03-21 13:09:19 +00:00
|
|
|
unsigned char *tmp = NULL;
|
2005-08-20 00:10:35 +00:00
|
|
|
int i = 0;
|
2005-08-28 00:48:12 +00:00
|
|
|
int j;
|
2006-02-11 00:32:21 +00:00
|
|
|
int index;
|
2005-08-20 00:10:35 +00:00
|
|
|
unsigned int pixels = pixelsHigh * pixelsWide;
|
2006-02-11 00:32:21 +00:00
|
|
|
unsigned char *rowData;
|
2006-02-12 17:59:30 +00:00
|
|
|
cairo_matrix_t local_matrix;
|
2007-09-05 09:59:12 +00:00
|
|
|
cairo_status_t status;
|
2005-08-20 00:10:35 +00:00
|
|
|
|
2007-02-27 16:35:31 +00:00
|
|
|
if (!_ct)
|
|
|
|
{
|
2007-09-05 09:59:12 +00:00
|
|
|
return;
|
2007-02-27 16:35:31 +00:00
|
|
|
}
|
|
|
|
|
2004-09-08 22:08:15 +00:00
|
|
|
if (isPlanar || !([colorSpaceName isEqualToString: NSDeviceRGBColorSpace] ||
|
|
|
|
[colorSpaceName isEqualToString: NSCalibratedRGBColorSpace]))
|
|
|
|
{
|
2007-03-21 13:09:19 +00:00
|
|
|
// FIXME: Need to conmvert to something that is supported
|
|
|
|
NSLog(@"Image format not support in cairo backend.\n colour space: %@ planar %d", colorSpaceName, isPlanar);
|
2004-09-08 22:08:15 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2006-02-11 00:32:21 +00:00
|
|
|
// default is 8 bit grayscale
|
|
|
|
if (!bitsPerSample)
|
|
|
|
bitsPerSample = 8;
|
|
|
|
if (!samplesPerPixel)
|
|
|
|
samplesPerPixel = 1;
|
|
|
|
|
|
|
|
// FIXME - does this work if we are passed a planar image but no hints ?
|
|
|
|
if (!bitsPerPixel)
|
|
|
|
bitsPerPixel = bitsPerSample * samplesPerPixel;
|
|
|
|
if (!bytesPerRow)
|
|
|
|
bytesPerRow = (bitsPerPixel * pixelsWide) / 8;
|
|
|
|
|
|
|
|
/* make sure its sane - also handles row padding if hint missing */
|
|
|
|
while ((bytesPerRow * 8) < (bitsPerPixel * pixelsWide))
|
|
|
|
bytesPerRow++;
|
|
|
|
|
|
|
|
switch (bitsPerPixel)
|
2004-08-02 21:50:17 +00:00
|
|
|
{
|
|
|
|
case 32:
|
2005-08-20 00:10:35 +00:00
|
|
|
tmp = objc_malloc(pixels * 4);
|
2008-03-29 13:16:58 +00:00
|
|
|
if (!tmp)
|
|
|
|
{
|
|
|
|
NSLog(@"Could not allocate drawing space for image");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
rowData = (unsigned char *)data[0];
|
2006-02-11 00:32:21 +00:00
|
|
|
index = 0;
|
|
|
|
|
|
|
|
for (i = 0; i < pixelsHigh; i++)
|
|
|
|
{
|
2007-04-04 14:33:10 +00:00
|
|
|
unsigned char *d = rowData;
|
2006-02-11 00:32:21 +00:00
|
|
|
|
2007-04-04 14:33:10 +00:00
|
|
|
for (j = 0; j < pixelsWide; j++)
|
|
|
|
{
|
2006-12-26 13:26:40 +00:00
|
|
|
#if GS_WORDS_BIGENDIAN
|
2007-04-04 14:33:10 +00:00
|
|
|
tmp[index++] = d[3];
|
|
|
|
tmp[index++] = d[0];
|
|
|
|
tmp[index++] = d[1];
|
|
|
|
tmp[index++] = d[2];
|
2006-12-26 13:26:40 +00:00
|
|
|
#else
|
2007-04-04 14:33:10 +00:00
|
|
|
tmp[index++] = d[2];
|
|
|
|
tmp[index++] = d[1];
|
|
|
|
tmp[index++] = d[0];
|
|
|
|
tmp[index++] = d[3];
|
2006-12-26 13:26:40 +00:00
|
|
|
#endif
|
2007-04-04 14:33:10 +00:00
|
|
|
d += 4;
|
|
|
|
}
|
|
|
|
rowData += bytesPerRow;
|
|
|
|
}
|
2004-08-02 21:50:17 +00:00
|
|
|
format = CAIRO_FORMAT_ARGB32;
|
|
|
|
break;
|
|
|
|
case 24:
|
2005-08-28 00:48:12 +00:00
|
|
|
tmp = objc_malloc(pixels * 4);
|
2008-03-29 13:16:58 +00:00
|
|
|
if (!tmp)
|
|
|
|
{
|
|
|
|
NSLog(@"Could not allocate drawing space for image");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
rowData = (unsigned char *)data[0];
|
2006-02-11 00:32:21 +00:00
|
|
|
index = 0;
|
|
|
|
|
|
|
|
for (i = 0; i < pixelsHigh; i++)
|
|
|
|
{
|
2007-04-04 14:33:10 +00:00
|
|
|
unsigned char *d = rowData;
|
2006-02-11 00:32:21 +00:00
|
|
|
|
2007-04-04 14:33:10 +00:00
|
|
|
for (j = 0; j < pixelsWide; j++)
|
|
|
|
{
|
2006-12-26 13:26:40 +00:00
|
|
|
#if GS_WORDS_BIGENDIAN
|
2007-04-04 14:33:10 +00:00
|
|
|
tmp[index++] = 0;
|
|
|
|
tmp[index++] = d[0];
|
|
|
|
tmp[index++] = d[1];
|
|
|
|
tmp[index++] = d[2];
|
2006-12-26 13:26:40 +00:00
|
|
|
#else
|
2007-04-04 14:33:10 +00:00
|
|
|
tmp[index++] = d[2];
|
|
|
|
tmp[index++] = d[1];
|
|
|
|
tmp[index++] = d[0];
|
|
|
|
tmp[index++] = 0;
|
2006-12-26 13:26:40 +00:00
|
|
|
#endif
|
2007-04-04 14:33:10 +00:00
|
|
|
d += 3;
|
|
|
|
}
|
|
|
|
rowData += bytesPerRow;
|
|
|
|
}
|
2004-08-02 21:50:17 +00:00
|
|
|
format = CAIRO_FORMAT_RGB24;
|
|
|
|
break;
|
|
|
|
default:
|
2004-09-08 22:08:15 +00:00
|
|
|
NSLog(@"Image format not support");
|
|
|
|
return;
|
2004-08-02 21:50:17 +00:00
|
|
|
}
|
|
|
|
|
2007-03-21 13:09:19 +00:00
|
|
|
surface = cairo_image_surface_create_for_data((void*)tmp,
|
2005-07-27 23:25:32 +00:00
|
|
|
format,
|
|
|
|
pixelsWide,
|
|
|
|
pixelsHigh,
|
2006-02-11 00:32:21 +00:00
|
|
|
pixelsWide * 4);
|
2007-09-05 09:59:12 +00:00
|
|
|
status = cairo_surface_status(surface);
|
|
|
|
if (status != CAIRO_STATUS_SUCCESS)
|
2005-07-27 23:25:32 +00:00
|
|
|
{
|
2007-10-18 16:51:56 +00:00
|
|
|
NSLog(@"Cairo status '%s' in DPSimage", cairo_status_to_string(status));
|
2007-03-21 13:09:19 +00:00
|
|
|
if (tmp)
|
2006-02-11 00:32:21 +00:00
|
|
|
{
|
2007-04-04 14:33:10 +00:00
|
|
|
objc_free(tmp);
|
|
|
|
}
|
2006-02-11 00:32:21 +00:00
|
|
|
|
2005-07-27 23:25:32 +00:00
|
|
|
return;
|
|
|
|
}
|
2004-08-02 21:50:17 +00:00
|
|
|
|
2006-03-07 00:59:30 +00:00
|
|
|
cairo_save(_ct);
|
|
|
|
cairo_set_operator(_ct, CAIRO_OPERATOR_SOURCE);
|
|
|
|
|
2007-03-18 17:50:58 +00:00
|
|
|
// Set the basic transformation
|
|
|
|
tstruct = [ctm transformStruct];
|
|
|
|
cairo_matrix_init(&local_matrix,
|
|
|
|
tstruct.m11, tstruct.m12,
|
|
|
|
tstruct.m21, tstruct.m22,
|
|
|
|
tstruct.tX, tstruct.tY);
|
|
|
|
cairo_transform(_ct, &local_matrix);
|
|
|
|
|
|
|
|
// add the local tranformation
|
|
|
|
tstruct = [matrix transformStruct];
|
2006-03-07 00:59:30 +00:00
|
|
|
cairo_matrix_init(&local_matrix,
|
|
|
|
tstruct.m11, tstruct.m12,
|
|
|
|
tstruct.m21, tstruct.m22,
|
|
|
|
tstruct.tX, tstruct.tY);
|
|
|
|
cairo_transform(_ct, &local_matrix);
|
2007-03-02 12:24:46 +00:00
|
|
|
|
2007-03-21 13:09:19 +00:00
|
|
|
// Make up for flip done in GUI
|
2006-10-03 23:29:53 +00:00
|
|
|
if (viewIsFlipped)
|
2005-11-07 00:11:09 +00:00
|
|
|
{
|
2006-10-03 23:29:53 +00:00
|
|
|
cairo_pattern_t *cpattern;
|
2006-03-07 00:59:30 +00:00
|
|
|
cairo_matrix_t local_matrix;
|
|
|
|
|
2007-03-02 12:24:46 +00:00
|
|
|
cpattern = cairo_pattern_create_for_surface(surface);
|
2006-03-07 00:59:30 +00:00
|
|
|
cairo_matrix_init_scale(&local_matrix, 1, -1);
|
|
|
|
cairo_matrix_translate(&local_matrix, 0, -2*pixelsHigh);
|
2006-10-03 23:29:53 +00:00
|
|
|
cairo_pattern_set_matrix(cpattern, &local_matrix);
|
|
|
|
cairo_set_source(_ct, cpattern);
|
|
|
|
cairo_pattern_destroy(cpattern);
|
2006-03-07 00:59:30 +00:00
|
|
|
|
|
|
|
cairo_rectangle(_ct, 0, pixelsHigh, pixelsWide, pixelsHigh);
|
2005-11-07 00:11:09 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2006-10-03 23:29:53 +00:00
|
|
|
cairo_pattern_t *cpattern;
|
2006-03-07 00:59:30 +00:00
|
|
|
cairo_matrix_t local_matrix;
|
|
|
|
|
2007-03-02 12:24:46 +00:00
|
|
|
cpattern = cairo_pattern_create_for_surface(surface);
|
2006-03-07 00:59:30 +00:00
|
|
|
cairo_matrix_init_scale(&local_matrix, 1, -1);
|
|
|
|
cairo_matrix_translate(&local_matrix, 0, -pixelsHigh);
|
2006-10-03 23:29:53 +00:00
|
|
|
cairo_pattern_set_matrix(cpattern, &local_matrix);
|
|
|
|
cairo_set_source(_ct, cpattern);
|
|
|
|
cairo_pattern_destroy(cpattern);
|
2006-03-07 00:59:30 +00:00
|
|
|
|
2005-11-07 00:11:09 +00:00
|
|
|
cairo_rectangle(_ct, 0, 0, pixelsWide, pixelsHigh);
|
|
|
|
}
|
2007-03-21 13:09:19 +00:00
|
|
|
cairo_clip(_ct);
|
2007-03-20 23:24:04 +00:00
|
|
|
cairo_paint(_ct);
|
2004-09-08 22:08:15 +00:00
|
|
|
cairo_surface_destroy(surface);
|
2005-07-27 23:25:32 +00:00
|
|
|
cairo_restore(_ct);
|
2006-02-11 00:32:21 +00:00
|
|
|
|
2007-03-21 13:09:19 +00:00
|
|
|
if (tmp)
|
2006-02-11 00:32:21 +00:00
|
|
|
{
|
2007-03-21 13:09:19 +00:00
|
|
|
objc_free(tmp);
|
2006-02-11 00:32:21 +00:00
|
|
|
}
|
2004-08-02 21:50:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void) compositerect: (NSRect)aRect op: (NSCompositingOperation)op
|
|
|
|
{
|
2007-02-27 16:35:31 +00:00
|
|
|
if (_ct)
|
|
|
|
{
|
2007-03-18 17:50:58 +00:00
|
|
|
NSBezierPath *oldPath = path;
|
|
|
|
|
2007-02-27 16:35:31 +00:00
|
|
|
cairo_save(_ct);
|
|
|
|
_set_op(_ct, op);
|
2007-03-20 23:24:04 +00:00
|
|
|
|
2007-03-21 13:09:19 +00:00
|
|
|
// This is almost a rectclip::::, but the path stays unchanged.
|
2007-03-18 17:50:58 +00:00
|
|
|
path = [NSBezierPath bezierPathWithRect: aRect];
|
|
|
|
[path transformUsingAffineTransform: ctm];
|
2007-07-01 23:02:29 +00:00
|
|
|
[self _setPath:YES];
|
2007-03-20 23:24:04 +00:00
|
|
|
cairo_clip(_ct);
|
|
|
|
cairo_paint(_ct);
|
2007-02-27 16:35:31 +00:00
|
|
|
cairo_restore(_ct);
|
2007-04-27 12:23:28 +00:00
|
|
|
path = oldPath;
|
2007-02-27 16:35:31 +00:00
|
|
|
}
|
2004-08-02 21:50:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void) compositeGState: (CairoGState *)source
|
2007-04-04 14:33:10 +00:00
|
|
|
fromRect: (NSRect)aRect
|
|
|
|
toPoint: (NSPoint)aPoint
|
|
|
|
op: (NSCompositingOperation)op
|
|
|
|
fraction: (float)delta
|
2004-08-02 21:50:17 +00:00
|
|
|
{
|
|
|
|
cairo_surface_t *src;
|
2005-07-27 23:25:32 +00:00
|
|
|
double minx, miny;
|
|
|
|
double width, height;
|
2007-02-12 16:21:39 +00:00
|
|
|
double x, y;
|
2007-03-21 13:09:19 +00:00
|
|
|
NSSize ssize;
|
|
|
|
cairo_pattern_t *cpattern;
|
|
|
|
cairo_matrix_t local_matrix;
|
2007-09-03 22:26:29 +00:00
|
|
|
BOOL copyOnSelf = NO;
|
2007-02-12 16:21:39 +00:00
|
|
|
|
2007-02-27 16:35:31 +00:00
|
|
|
if (!_ct || !source->_ct)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2007-09-03 22:26:29 +00:00
|
|
|
/*
|
|
|
|
* we check if we copy on ourself, if that's the case
|
|
|
|
* we'll use the groups trick...
|
|
|
|
*/
|
|
|
|
|
2005-07-27 23:25:32 +00:00
|
|
|
src = cairo_get_target(source->_ct);
|
2007-03-21 13:09:19 +00:00
|
|
|
if (src == cairo_get_target(_ct))
|
2007-03-02 12:24:46 +00:00
|
|
|
{
|
2007-03-21 13:09:19 +00:00
|
|
|
NSRect targetRect;
|
|
|
|
|
|
|
|
targetRect.origin = aPoint;
|
|
|
|
targetRect.size = aRect.size;
|
|
|
|
|
|
|
|
if (!NSIsEmptyRect(NSIntersectionRect(aRect, targetRect)))
|
2007-04-04 14:33:10 +00:00
|
|
|
{
|
2007-10-18 16:51:56 +00:00
|
|
|
copyOnSelf = YES;
|
2007-09-02 14:23:03 +00:00
|
|
|
}
|
2006-02-12 17:59:30 +00:00
|
|
|
}
|
2007-03-21 13:09:19 +00:00
|
|
|
|
2007-09-03 22:26:29 +00:00
|
|
|
cairo_save(_ct);
|
2007-09-02 14:23:03 +00:00
|
|
|
|
2007-10-18 16:51:56 +00:00
|
|
|
if (copyOnSelf) cairo_push_group(_ct);
|
2007-09-02 14:23:03 +00:00
|
|
|
|
2007-09-03 22:26:29 +00:00
|
|
|
cairo_new_path(_ct);
|
|
|
|
_set_op(_ct, op);
|
2007-09-04 02:12:30 +00:00
|
|
|
|
|
|
|
if (viewIsFlipped && !copyOnSelf)
|
|
|
|
{
|
|
|
|
aPoint.y -= aRect.size.height;
|
|
|
|
}
|
2007-09-02 14:23:03 +00:00
|
|
|
|
2007-09-03 22:26:29 +00:00
|
|
|
{
|
2007-04-04 14:33:10 +00:00
|
|
|
NSRect newRect;
|
|
|
|
|
|
|
|
newRect.origin = aPoint;
|
|
|
|
newRect.size = aRect.size;
|
|
|
|
[ctm boundingRectFor: newRect result: &newRect];
|
|
|
|
aPoint = newRect.origin;
|
|
|
|
}
|
2007-09-03 22:26:29 +00:00
|
|
|
|
2007-03-22 13:39:26 +00:00
|
|
|
[source->ctm boundingRectFor: aRect result: &aRect];
|
2009-11-03 08:39:15 +00:00
|
|
|
if (cairo_version() >= CAIRO_VERSION_ENCODE(1, 8, 0))
|
2009-07-10 08:11:39 +00:00
|
|
|
{
|
2009-11-03 08:39:15 +00:00
|
|
|
NSSize size = [source->_surface size];
|
2009-07-10 08:11:39 +00:00
|
|
|
|
|
|
|
// For cairo > 1.8 we seem to need this adjustment
|
2009-11-03 08:39:15 +00:00
|
|
|
aRect.origin.y -= 2*(source->offset.y - size.height);
|
2009-07-10 08:11:39 +00:00
|
|
|
}
|
|
|
|
|
2007-07-02 23:30:11 +00:00
|
|
|
x = floorf(aPoint.x);
|
2009-01-29 09:32:32 +00:00
|
|
|
y = floorf(aPoint.y + 0.5);
|
2005-07-27 23:25:32 +00:00
|
|
|
minx = NSMinX(aRect);
|
|
|
|
miny = NSMinY(aRect);
|
|
|
|
width = NSWidth(aRect);
|
|
|
|
height = NSHeight(aRect);
|
2007-03-22 13:39:26 +00:00
|
|
|
|
2007-03-21 13:09:19 +00:00
|
|
|
if (source->_surface != nil)
|
2006-02-12 17:59:30 +00:00
|
|
|
{
|
2007-03-21 13:09:19 +00:00
|
|
|
ssize = [source->_surface size];
|
2006-02-12 17:59:30 +00:00
|
|
|
}
|
|
|
|
else
|
2007-03-21 13:09:19 +00:00
|
|
|
{
|
|
|
|
ssize = NSMakeSize(0, 0);
|
2006-02-12 17:59:30 +00:00
|
|
|
}
|
2005-07-27 23:25:32 +00:00
|
|
|
|
2007-03-21 13:09:19 +00:00
|
|
|
cpattern = cairo_pattern_create_for_surface(src);
|
|
|
|
cairo_matrix_init_scale(&local_matrix, 1, -1);
|
|
|
|
cairo_matrix_translate(&local_matrix, -x + minx, - ssize.height - y + miny);
|
|
|
|
cairo_pattern_set_matrix(cpattern, &local_matrix);
|
|
|
|
cairo_set_source(_ct, cpattern);
|
|
|
|
cairo_pattern_destroy(cpattern);
|
|
|
|
cairo_rectangle(_ct, x, y, width, height);
|
2007-03-02 12:24:46 +00:00
|
|
|
cairo_clip(_ct);
|
2007-03-21 13:09:19 +00:00
|
|
|
|
2005-07-27 23:25:32 +00:00
|
|
|
if (delta < 1.0)
|
2007-03-01 12:03:06 +00:00
|
|
|
{
|
2007-03-02 12:24:46 +00:00
|
|
|
cairo_paint_with_alpha(_ct, delta);
|
2007-03-01 12:03:06 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2007-03-02 12:24:46 +00:00
|
|
|
cairo_paint(_ct);
|
2007-03-01 12:03:06 +00:00
|
|
|
}
|
2007-09-02 14:23:03 +00:00
|
|
|
|
2007-09-03 22:26:29 +00:00
|
|
|
if (copyOnSelf)
|
|
|
|
{
|
2007-10-18 16:51:56 +00:00
|
|
|
cairo_pop_group_to_source(_ct);
|
2007-09-03 22:26:29 +00:00
|
|
|
cairo_paint(_ct);
|
|
|
|
}
|
2007-09-02 14:23:03 +00:00
|
|
|
|
2004-08-02 21:50:17 +00:00
|
|
|
cairo_restore(_ct);
|
|
|
|
}
|
|
|
|
|
|
|
|
@end
|
2009-10-19 14:17:45 +00:00
|
|
|
|
|
|
|
@implementation CairoGState (PatternColor)
|
|
|
|
|
|
|
|
- (void *) saveClip
|
|
|
|
{
|
|
|
|
#if CAIRO_VERSION > CAIRO_VERSION_ENCODE(1, 4, 0)
|
|
|
|
cairo_status_t status;
|
|
|
|
cairo_rectangle_list_t *clip_rects = cairo_copy_clip_rectangle_list(_ct);
|
|
|
|
|
|
|
|
status = cairo_status(_ct);
|
|
|
|
if (status == CAIRO_STATUS_SUCCESS)
|
|
|
|
{
|
|
|
|
return clip_rects;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) restoreClip: (void *)savedClip
|
|
|
|
{
|
|
|
|
#if CAIRO_VERSION > CAIRO_VERSION_ENCODE(1, 4, 0)
|
|
|
|
if (savedClip)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
cairo_rectangle_list_t *clip_rects = (cairo_rectangle_list_t *)savedClip;
|
|
|
|
|
|
|
|
cairo_reset_clip(_ct);
|
|
|
|
if (cairo_version() >= CAIRO_VERSION_ENCODE(1, 6, 0))
|
|
|
|
{
|
|
|
|
for (i = 0; i < clip_rects->num_rectangles; i++)
|
|
|
|
{
|
|
|
|
cairo_rectangle_t rect = clip_rects->rectangles[i];
|
|
|
|
|
|
|
|
cairo_rectangle(_ct, rect.x, rect.y,
|
|
|
|
rect.width, rect.height);
|
|
|
|
cairo_clip(_ct);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for (i = 0; i < clip_rects->num_rectangles; i++)
|
|
|
|
{
|
|
|
|
cairo_rectangle_t rect = clip_rects->rectangles[i];
|
|
|
|
NSSize size = [_surface size];
|
|
|
|
|
|
|
|
cairo_rectangle(_ct, rect.x,
|
|
|
|
/* This strange computation is due
|
|
|
|
to the device offset missing for
|
|
|
|
clip rects in cairo < 1.6.0. */
|
|
|
|
rect.y + 2*(offset.y - size.height),
|
|
|
|
rect.width, rect.height);
|
|
|
|
cairo_clip(_ct);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
cairo_rectangle_list_destroy(clip_rects);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
@end
|
2009-10-23 20:46:41 +00:00
|
|
|
|
|
|
|
@implementation CairoGState (NSGradient)
|
|
|
|
|
|
|
|
- (void) drawGradient: (NSGradient*)gradient
|
|
|
|
fromCenter: (NSPoint)startCenter
|
|
|
|
radius: (CGFloat)startRadius
|
|
|
|
toCenter: (NSPoint)endCenter
|
|
|
|
radius: (CGFloat)endRadius
|
|
|
|
options: (NSUInteger)options
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
int stops = [gradient numberOfColorStops];
|
|
|
|
NSPoint startP = [ctm transformPoint: startCenter];
|
|
|
|
NSPoint endP = [ctm transformPoint: endCenter];
|
|
|
|
cairo_pattern_t *cpattern = cairo_pattern_create_radial(startP.x, startP.y,
|
|
|
|
floatFromUserSpace(ctm, startRadius),
|
|
|
|
endP.x, endP.y,
|
|
|
|
floatFromUserSpace(ctm, endRadius));
|
|
|
|
for (i = 0; i < stops; i++)
|
|
|
|
{
|
|
|
|
NSColor *color;
|
|
|
|
CGFloat location;
|
|
|
|
double red;
|
|
|
|
double green;
|
|
|
|
double blue;
|
|
|
|
double alpha;
|
|
|
|
|
|
|
|
[gradient getColor: &color
|
|
|
|
location: &location
|
|
|
|
atIndex: i];
|
|
|
|
red = [color redComponent];
|
|
|
|
green = [color greenComponent];
|
|
|
|
blue = [color blueComponent];
|
|
|
|
alpha = [color alphaComponent];
|
|
|
|
cairo_pattern_add_color_stop_rgba(cpattern, location,
|
|
|
|
red, green, blue, alpha);
|
|
|
|
}
|
|
|
|
cairo_save(_ct);
|
|
|
|
cairo_set_source(_ct, cpattern);
|
|
|
|
cairo_pattern_destroy(cpattern);
|
|
|
|
cairo_paint(_ct);
|
|
|
|
cairo_restore(_ct);
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) drawGradient: (NSGradient*)gradient
|
|
|
|
fromPoint: (NSPoint)startPoint
|
|
|
|
toPoint: (NSPoint)endPoint
|
|
|
|
options: (NSUInteger)options
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
int stops = [gradient numberOfColorStops];
|
|
|
|
NSPoint startP = [ctm transformPoint: startPoint];
|
|
|
|
NSPoint endP = [ctm transformPoint: endPoint];
|
|
|
|
cairo_pattern_t *cpattern = cairo_pattern_create_linear(startP.x, startP.y,
|
|
|
|
endP.x, endP.y);
|
|
|
|
|
|
|
|
for (i = 0; i < stops; i++)
|
|
|
|
{
|
|
|
|
NSColor *color;
|
|
|
|
CGFloat location;
|
|
|
|
double red;
|
|
|
|
double green;
|
|
|
|
double blue;
|
|
|
|
double alpha;
|
|
|
|
|
|
|
|
[gradient getColor: &color
|
|
|
|
location: &location
|
|
|
|
atIndex: i];
|
|
|
|
red = [color redComponent];
|
|
|
|
green = [color greenComponent];
|
|
|
|
blue = [color blueComponent];
|
|
|
|
alpha = [color alphaComponent];
|
|
|
|
cairo_pattern_add_color_stop_rgba(cpattern, location,
|
|
|
|
red, green, blue, alpha);
|
|
|
|
}
|
|
|
|
cairo_save(_ct);
|
|
|
|
cairo_set_source(_ct, cpattern);
|
|
|
|
cairo_pattern_destroy(cpattern);
|
|
|
|
cairo_paint(_ct);
|
|
|
|
cairo_restore(_ct);
|
|
|
|
}
|
|
|
|
|
|
|
|
@end
|