libs-back/Source/gsc/GSGState.m
Adam Fedor 250ebdfad0 Revert library license version to 2 until applications can be converted
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/back/trunk@26620 72102866-910b-0410-8b05-ffd578937521
2008-06-10 04:12:46 +00:00

1222 lines
28 KiB
Objective-C

/* GSGState - Generic graphic state
Copyright (C) 1998 Free Software Foundation, Inc.
Written by: Adam Fedor <fedor@gnu.org>
Date: Mar 2002
This file is part of the GNU Objective C User Interface Library.
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
version 2 of the License, or (at your option) any later version.
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.
*/
#include "config.h"
#include <Foundation/NSObjCRuntime.h>
#include <AppKit/NSAffineTransform.h>
#include <AppKit/NSBezierPath.h>
#include <AppKit/NSColor.h>
#include <AppKit/NSColorSpace.h>
#include <AppKit/NSImage.h>
#include <GNUstepGUI/GSFontInfo.h>
#include <AppKit/NSGraphics.h>
#include "gsc/GSContext.h"
#include "gsc/GSGState.h"
#include "gsc/GSFunction.h"
#include "math.h"
#include <GNUstepBase/Unicode.h>
#define CHECK_PATH \
if (!path) \
{ \
path = [NSBezierPath new]; \
}
@implementation GSGState
/* Designated initializer. */
- initWithDrawContext: (GSContext *)drawContext
{
self = [super init];
if (!self)
return nil;
drawcontext = drawContext;
offset = NSMakePoint(0, 0);
path = nil;
font = nil;
fillColorS = nil;
strokeColorS = nil;
[self DPSinitgraphics];
return self;
}
- (void) dealloc
{
TEST_RELEASE(font);
TEST_RELEASE(path);
RELEASE(ctm);
RELEASE(textCtm);
RELEASE(fillColorS);
RELEASE(strokeColorS);
TEST_RELEASE(pattern);
[super dealloc];
}
- (id) deepen
{
NSZone *zone = GSObjCZone(self);
if (path)
self->path = [path copyWithZone: zone];
self->ctm = [ctm copyWithZone: zone];
self->textCtm = [textCtm copyWithZone: zone];
// Just retain the other objects
if (font != nil)
RETAIN(font);
if (fillColorS != nil)
RETAIN(fillColorS);
if (strokeColorS != nil)
RETAIN(strokeColorS);
if (pattern != nil)
RETAIN(pattern);
return self;
}
- copyWithZone: (NSZone *)zone
{
GSGState *new = (GSGState *)NSCopyObject(self, 0, zone);
/* Do a deep copy since gstates are isolated from each other */
return [new deepen];
}
- (void) setOffset: (NSPoint)theOffset
{
offset = theOffset;
}
- (NSPoint) offset
{
return offset;
}
/** Subclasses should override this method to be notified of changes
in the current color */
- (void) setColor: (device_color_t *)color state: (color_state_t)cState
{
float alpha;
alpha = fillColor.field[AINDEX];
if (cState & COLOR_FILL)
fillColor = *color;
fillColor.field[AINDEX] = alpha;
alpha = strokeColor.field[AINDEX];
if (cState & COLOR_STROKE)
strokeColor = *color;
strokeColor.field[AINDEX] = alpha;
cstate = cState;
DESTROY(pattern);
}
- (void) GSSetPatterColor: (NSImage*)image
{
ASSIGN(pattern, image);
}
- (void) compositeGState: (GSGState *)source
fromRect: (NSRect)aRect
toPoint: (NSPoint)aPoint
op: (NSCompositingOperation)op
{
[self subclassResponsibility: _cmd];
}
- (void) dissolveGState: (GSGState *)source
fromRect: (NSRect)aRect
toPoint: (NSPoint)aPoint
delta: (float)delta
{
[self subclassResponsibility: _cmd];
}
- (void) compositeGState: (GSGState *)source
fromRect: (NSRect)aRect
toPoint: (NSPoint)aPoint
op: (NSCompositingOperation)op
fraction: (float)delta
{
if (op == NSCompositeSourceOver)
{
[self dissolveGState: source
fromRect: aRect
toPoint: aPoint
delta: delta];
}
else
{
[self compositeGState: source
fromRect: aRect
toPoint: aPoint
op: op];
}
}
- (void) compositerect: (NSRect)aRect
op: (NSCompositingOperation)op
{
[self subclassResponsibility: _cmd];
}
- (NSPoint) pointInMatrixSpace: (NSPoint)aPoint
{
return [ctm transformPoint: aPoint];
}
- (NSPoint) deltaPointInMatrixSpace: (NSPoint)aPoint
{
return [ctm deltaPointInMatrixSpace: aPoint];
}
- (NSRect) rectInMatrixSpace: (NSRect)rect
{
return [ctm rectInMatrixSpace: rect];
}
@end
@implementation GSGState (Ops)
/* ----------------------------------------------------------------------- */
/* Color operations */
/* ----------------------------------------------------------------------- */
- (void) DPScurrentalpha: (float*)a
{
*a = fillColor.field[AINDEX];
}
- (void) DPScurrentcmykcolor: (float*)c : (float*)m : (float*)y : (float*)k
{
device_color_t new = fillColor;
gsColorToCMYK(&new);
*c = new.field[0];
*m = new.field[1];
*y = new.field[2];
*k = new.field[3];
}
- (void) DPScurrentgray: (float*)gray
{
device_color_t gcolor = fillColor;
gsColorToGray(&gcolor);
*gray = gcolor.field[0];
}
- (void) DPScurrenthsbcolor: (float*)h : (float*)s : (float*)b
{
device_color_t gcolor = fillColor;
gsColorToHSB(&gcolor);
*h = gcolor.field[0]; *s = gcolor.field[1]; *b = gcolor.field[2];
}
- (void) DPScurrentrgbcolor: (float*)r : (float*)g : (float*)b
{
device_color_t gcolor = fillColor;
gsColorToRGB(&gcolor);
*r = gcolor.field[0]; *g = gcolor.field[1]; *b = gcolor.field[2];
}
#define CLAMP(x) \
if (x < 0.0) x = 0.0; \
if (x > 1.0) x = 1.0;
- (void) DPSsetalpha: (float)a
{
CLAMP(a)
fillColor.field[AINDEX] = strokeColor.field[AINDEX] = a;
[self setColor: &fillColor state: COLOR_FILL];
[self setColor: &strokeColor state: COLOR_STROKE];
}
- (void) DPSsetcmykcolor: (float)c : (float)m : (float)y : (float)k
{
device_color_t col;
CLAMP(c)
CLAMP(m)
CLAMP(y)
CLAMP(k)
gsMakeColor(&col, cmyk_colorspace, c, m, y, k);
[self setColor: &col state: COLOR_BOTH];
}
- (void) DPSsetgray: (float)gray
{
device_color_t col;
CLAMP(gray)
gsMakeColor(&col, gray_colorspace, gray, 0, 0, 0);
[self setColor: &col state: COLOR_BOTH];
}
- (void) DPSsethsbcolor: (float)h : (float)s : (float)b
{
device_color_t col;
CLAMP(h)
CLAMP(s)
CLAMP(b)
gsMakeColor(&col, hsb_colorspace, h, s, b, 0);
[self setColor: &col state: COLOR_BOTH];
}
- (void) DPSsetrgbcolor: (float)r : (float)g : (float)b
{
device_color_t col;
CLAMP(r)
CLAMP(g)
CLAMP(b)
gsMakeColor(&col, rgb_colorspace, r, g, b, 0);
[self setColor: &col state: COLOR_BOTH];
}
- (void) GSSetFillColorspace: (void *)spaceref
{
device_color_t col;
ASSIGN(fillColorS, spaceref);
gsMakeColor(&col, rgb_colorspace, 0, 0, 0, 0);
[self setColor: &col state: COLOR_FILL];
}
- (void) GSSetStrokeColorspace: (void *)spaceref
{
device_color_t col;
ASSIGN(strokeColorS, spaceref);
gsMakeColor(&col, rgb_colorspace, 0, 0, 0, 0);
[self setColor: &col state: COLOR_STROKE];
}
- (void) GSSetFillColor: (const float *)values
{
device_color_t dcolor;
NSColor *color;
if ((fillColorS == nil)
|| ((color = [NSColor colorWithColorSpace: fillColorS
components: values
count: [fillColorS numberOfColorComponents] + 1]) == nil)
|| ((color = [color colorUsingColorSpaceName: NSDeviceRGBColorSpace]) == nil))
{
DPS_ERROR(DPSundefined, @"No fill colorspace defined, assume DeviceRGB");
gsMakeColor(&dcolor, rgb_colorspace, values[0], values[1],
values[2], values[3]);
}
else
{
[color getRed: &dcolor.field[0]
green: &dcolor.field[1]
blue: &dcolor.field[2]
alpha: &dcolor.field[AINDEX]];
}
[self setColor: &dcolor state: COLOR_FILL];
}
- (void) GSSetStrokeColor: (const float *)values
{
device_color_t dcolor;
NSColor *color;
if ((strokeColorS == nil)
|| ((color = [NSColor colorWithColorSpace: strokeColorS
components: values
count: [strokeColorS numberOfColorComponents] + 1]) == nil)
|| ((color = [color colorUsingColorSpaceName: NSDeviceRGBColorSpace]) == nil))
{
DPS_ERROR(DPSundefined, @"No stroke colorspace defined, assume DeviceRGB");
gsMakeColor(&dcolor, rgb_colorspace, values[0], values[1],
values[2], values[3]);
}
else
{
[color getRed: &dcolor.field[0]
green: &dcolor.field[1]
blue: &dcolor.field[2]
alpha: &dcolor.field[AINDEX]];
}
[self setColor: &dcolor state: COLOR_STROKE];
}
/* ----------------------------------------------------------------------- */
/* Text operations */
/* ----------------------------------------------------------------------- */
typedef enum {
show_delta, show_array_x, show_array_y, show_array_xy
} show_array_t;
/* Omnibus show string routine that combines that characteristics of
ashow, awidthshow, widthshow, xshow, xyshow, and yshow */
- (void) _showString: (const char *)s
xCharAdj: (float)cx
yCharAdj: (float)cy
char: (char)c
adjArray: (const float *)arr
arrType: (show_array_t)type
isRelative: (BOOL)relative;
{
NSPoint point = [path currentPoint];
unichar *uch;
unsigned int ulen;
int i;
/*
FIXME: We should use proper glyph generation here.
*/
uch = NULL;
ulen = 0;
GSToUnicode(&uch, &ulen, (const unsigned char*)s, strlen(s),
[font mostCompatibleStringEncoding], NSDefaultMallocZone(), 0);
for (i = 0; i < ulen; i++)
{
NSPoint delta;
NSGlyph glyph;
glyph = (NSGlyph)uch[i];
[self GSShowGlyphs: &glyph : 1];
/* Note we update the current point according to the current
transformation scaling, although the text isn't currently
scaled (FIXME). */
if (type == show_array_xy)
{
delta.x = arr[2*i]; delta.y = arr[2*i+1];
}
else if (type == show_array_x)
{
delta.x = arr[i]; delta.y = 0;
}
else if (type == show_array_y)
{
delta.x = 0; delta.y = arr[i];
}
else
{
delta.x = arr[0]; delta.y = arr[1];
}
delta = [ctm deltaPointInMatrixSpace: delta];
if (relative == YES)
{
NSSize advancement;
advancement = [font advancementForGlyph: glyph];
/* Use only delta transformations (no offset). Is this conversion needed?*/
advancement = [ctm transformSize: NSMakeSize(advancement.width,
[font ascender])];
delta.x += advancement.width;
delta.y += advancement.height;
}
if (c && *(s+i) == c)
{
NSPoint cdelta;
cdelta.x = cx; cdelta.y = cy;
cdelta = [ctm deltaPointInMatrixSpace: cdelta];
delta.x += cdelta.x; delta.y += cdelta.y;
}
point.x += delta.x;
if (type != show_delta)
{
point.y += delta.y;
}
[path moveToPoint: point];
}
free(uch);
}
- (void) DPSashow: (float)x : (float)y : (const char*)s
{
float arr[2];
arr[0] = x; arr[1] = y;
[self _showString: s
xCharAdj: 0 yCharAdj: 0 char: 0 adjArray: arr arrType: show_delta
isRelative: YES];
}
- (void) DPSawidthshow: (float)cx : (float)cy : (int)c : (float)ax : (float)ay
: (const char*)s
{
float arr[2];
arr[0] = ax; arr[1] = ay;
[self _showString: s
xCharAdj: cx yCharAdj: cy char: c adjArray: arr arrType: show_delta
isRelative: YES];
}
- (void) DPScharpath: (const char*)s : (int)count
{
NSGlyph glBuf[count];
int i;
if (!font)
return;
// FIXME
for (i = 0; i < count; i++)
{
glBuf[i] = [font glyphForCharacter: s[i]];
}
CHECK_PATH;
[font appendBezierPathWithGlyphs: glBuf
count: count
toBezierPath: path];
}
- (void) appendBezierPathWithPackedGlyphs: (const char *)packedGlyphs
path: (NSBezierPath*)aPath
{
unsigned int count = packedGlyphs[0];
NSMultibyteGlyphPacking packing;
NSGlyph glBuf[count];
int i;
int j;
unsigned char a, b, c, d;
if (!font)
return;
packing = [font glyphPacking];
j = 1;
for (i = 0; i < count; i++)
{
switch (packing)
{
case NSOneByteGlyphPacking:
glBuf[i] = (NSGlyph)packedGlyphs[j++];
break;
case NSTwoByteGlyphPacking:
a= packedGlyphs[j++];
glBuf[i] = (NSGlyph)((a << 8) | packedGlyphs[j++]);
break;
case NSFourByteGlyphPacking:
a = packedGlyphs[j++];
b = packedGlyphs[j++];
c = packedGlyphs[j++];
d = packedGlyphs[j++];
glBuf[i] = (NSGlyph)((a << 24) | (b << 16)
| (c << 8) | d);
break;
case NSJapaneseEUCGlyphPacking:
case NSAsciiWithDoubleByteEUCGlyphPacking:
default:
// FIXME
break;
}
}
[font appendBezierPathWithGlyphs: glBuf
count: count
toBezierPath: aPath];
}
- (void) DPSshow: (const char*)s
{
[self subclassResponsibility: _cmd];
}
- (void) DPSwidthshow: (float)x : (float)y : (int)c : (const char*)s
{
float arr[2];
arr[0] = 0; arr[1] = 0;
[self _showString: s
xCharAdj: x yCharAdj: y char: c adjArray: arr arrType: show_delta
isRelative: YES];
}
- (void) DPSxshow: (const char*)s : (const float*)numarray : (int)size
{
[self _showString: s
xCharAdj: 0 yCharAdj: 0 char: 0 adjArray: numarray arrType: show_array_x
isRelative: NO];
}
- (void) DPSxyshow: (const char*)s : (const float*)numarray : (int)size
{
[self _showString: s
xCharAdj: 0 yCharAdj: 0 char: 0 adjArray: numarray arrType: show_array_xy
isRelative: NO];
}
- (void) DPSyshow: (const char*)s : (const float*)numarray : (int)size
{
[self _showString: s
xCharAdj: 0 yCharAdj: 0 char: 0 adjArray: numarray arrType: show_array_y
isRelative: NO];
}
- (void) GSSetCharacterSpacing: (float)extra
{
charSpacing = extra;
}
- (void) GSSetFont: (GSFontInfo *)fontref
{
if (font == fontref)
return;
ASSIGN(font, fontref);
}
- (void) GSSetFontSize: (float)size
{
}
- (NSAffineTransform *) GSGetTextCTM
{
return textCtm;
}
- (NSPoint) GSGetTextPosition
{
return [textCtm transformPoint: NSMakePoint(0,0)];
}
- (void) GSSetTextCTM: (NSAffineTransform *)newCtm
{
ASSIGN(textCtm, newCtm);
}
- (void) GSSetTextDrawingMode: (GSTextDrawingMode)mode
{
textMode = mode;
}
- (void) GSSetTextPosition: (NSPoint)loc
{
[textCtm translateToPoint: loc];
}
- (void) GSShowText: (const char *)string : (size_t) length
{
[self subclassResponsibility: _cmd];
}
- (void) GSShowGlyphs: (const NSGlyph *)glyphs : (size_t) length
{
[self subclassResponsibility: _cmd];
}
/* ----------------------------------------------------------------------- */
/* Gstate operations */
/* ----------------------------------------------------------------------- */
- (void) DPSinitgraphics
{
DESTROY(path);
DESTROY(font);
DESTROY(fillColorS);
DESTROY(strokeColorS);
if (ctm)
[ctm makeIdentityMatrix];
else
ctm = [[NSAffineTransform allocWithZone: GSObjCZone(self)] init];
/* Initialize colors. By default the same color is used for filling and
stroking unless fill and/or stroke color is set explicitly */
gsMakeColor(&fillColor, gray_colorspace, 0, 0, 0, 0);
fillColor.field[AINDEX] = 1.0;
strokeColor.field[AINDEX] = 1.0;
[self setColor: &fillColor state: COLOR_BOTH];
charSpacing = 0;
textMode = GSTextFill;
if (textCtm)
[textCtm makeIdentityMatrix];
else
textCtm = [[NSAffineTransform allocWithZone: GSObjCZone(self)] init];
}
- (void)DPScurrentflat: (float *)flatness
{
if (path)
*flatness = [path flatness];
else
*flatness = 1.0;
}
- (void) DPScurrentlinecap: (int*)linecap
{
[self subclassResponsibility: _cmd];
}
- (void) DPScurrentlinejoin: (int*)linejoin
{
[self subclassResponsibility: _cmd];
}
- (void) DPScurrentlinewidth: (float*)width
{
[self subclassResponsibility: _cmd];
}
- (void) DPScurrentmiterlimit: (float*)limit
{
[self subclassResponsibility: _cmd];
}
- (NSPoint) currentPoint
{
NSAffineTransform *ictm;
NSPoint user;
if (path == nil)
{
return NSMakePoint(0, 0);
}
// This is rather slow, but it is not used very often
ictm = [ctm copyWithZone: GSObjCZone(self)];
[ictm invert];
user = [ictm transformPoint: [path currentPoint]];
RELEASE(ictm);
return user;
}
- (void)DPScurrentpoint: (float *)x : (float *)y
{
NSPoint user;
user = [self currentPoint];
*x = user.x;
*y = user.y;
}
- (void) DPScurrentstrokeadjust: (int*)b
{
[self subclassResponsibility: _cmd];
}
- (void) DPSsetdash: (const float*)pat : (int)size : (float)offset
{
[self subclassResponsibility: _cmd];
}
- (void)DPSsetflat: (float)flatness
{
if (path)
[path setFlatness: flatness];
}
- (void) DPSsetlinecap: (int)linecap
{
[self subclassResponsibility: _cmd];
}
- (void) DPSsetlinejoin: (int)linejoin
{
[self subclassResponsibility: _cmd];
}
- (void) DPSsetlinewidth: (float)width
{
[self subclassResponsibility: _cmd];
}
- (void) DPSsetmiterlimit: (float)limit
{
[self subclassResponsibility: _cmd];
}
- (void) DPSsetstrokeadjust: (int)b
{
[self subclassResponsibility: _cmd];
}
/* ----------------------------------------------------------------------- */
/* Matrix operations */
/* ----------------------------------------------------------------------- */
- (void)DPSconcat: (const float *)m
{
NSAffineTransformStruct matrix;
NSAffineTransform *new_ctm = [NSAffineTransform new];
matrix.m11 = m[0];
matrix.m12 = m[1];
matrix.m21 = m[2];
matrix.m22 = m[3];
matrix.tX = m[4];
matrix.tY = m[5];
[new_ctm setTransformStruct: matrix];
[ctm prependTransform: new_ctm];
RELEASE(new_ctm);
}
- (void)DPSinitmatrix
{
[ctm makeIdentityMatrix];
}
- (void)DPSrotate: (float)angle
{
[ctm rotateByDegrees: angle];
}
- (void)DPSscale: (float)x : (float)y
{
[ctm scaleXBy: x yBy: y];
}
- (void)DPStranslate: (float)x : (float)y
{
[ctm translateToPoint: NSMakePoint(x, y)];
}
- (NSAffineTransform *) GSCurrentCTM
{
return AUTORELEASE([ctm copy]);
}
- (void) GSSetCTM: (NSAffineTransform *)newctm
{
ASSIGN(ctm, newctm);
}
- (void) GSConcatCTM: (NSAffineTransform *)newctm
{
[ctm prependTransform: newctm];
}
/* ----------------------------------------------------------------------- */
/* Paint operations */
/* ----------------------------------------------------------------------- */
- (void) DPSarc: (float)x : (float)y : (float)r : (float)angle1 : (float)angle2
{
NSBezierPath *newPath;
newPath = [[NSBezierPath alloc] init];
if ((path != nil) && ([path elementCount] != 0))
{
[newPath lineToPoint: [self currentPoint]];
}
[newPath appendBezierPathWithArcWithCenter: NSMakePoint(x, y)
radius: r
startAngle: angle1
endAngle: angle2
clockwise: NO];
[newPath transformUsingAffineTransform: ctm];
CHECK_PATH;
[path appendBezierPath: newPath];
RELEASE(newPath);
}
- (void) DPSarcn: (float)x : (float)y : (float)r : (float)angle1 : (float)angle2
{
NSBezierPath *newPath;
newPath = [[NSBezierPath alloc] init];
if ((path != nil) && ([path elementCount] != 0))
{
[newPath lineToPoint: [self currentPoint]];
}
[newPath appendBezierPathWithArcWithCenter: NSMakePoint(x, y)
radius: r
startAngle: angle1
endAngle: angle2
clockwise: YES];
[newPath transformUsingAffineTransform: ctm];
CHECK_PATH;
[path appendBezierPath: newPath];
RELEASE(newPath);
}
- (void)DPSarct: (float)x1 : (float)y1 : (float)x2 : (float)y2 : (float)r
{
NSBezierPath *newPath;
newPath = [[NSBezierPath alloc] init];
if ((path != nil) && ([path elementCount] != 0))
{
[newPath lineToPoint: [self currentPoint]];
}
[newPath appendBezierPathWithArcFromPoint: NSMakePoint(x1, y1)
toPoint: NSMakePoint(x2, y2)
radius: r];
[newPath transformUsingAffineTransform: ctm];
CHECK_PATH;
[path appendBezierPath: newPath];
RELEASE(newPath);
}
- (void) DPSclip
{
[self subclassResponsibility: _cmd];
}
- (void)DPSclosepath
{
CHECK_PATH;
[path closePath];
}
- (void)DPScurveto: (float)x1 : (float)y1 : (float)x2 : (float)y2 : (float)x3
: (float)y3
{
NSPoint p1 = [ctm transformPoint: NSMakePoint(x1, y1)];
NSPoint p2 = [ctm transformPoint: NSMakePoint(x2, y2)];
NSPoint p3 = [ctm transformPoint: NSMakePoint(x3, y3)];
CHECK_PATH;
[path curveToPoint: p3 controlPoint1: p1 controlPoint2: p2];
}
- (void) DPSeoclip
{
[self subclassResponsibility: _cmd];
}
- (void) DPSeofill
{
[self subclassResponsibility: _cmd];
}
- (void) DPSfill
{
[self subclassResponsibility: _cmd];
}
- (void)DPSflattenpath
{
if (path)
ASSIGN(path, [path bezierPathByFlatteningPath]);
}
- (void) DPSinitclip;
{
[self subclassResponsibility: _cmd];
}
- (void)DPSlineto: (float)x : (float)y
{
NSPoint p = [ctm transformPoint: NSMakePoint(x, y)];
CHECK_PATH;
[path lineToPoint: p];
}
- (void)DPSmoveto: (float)x : (float)y
{
NSPoint p = [ctm transformPoint: NSMakePoint(x, y)];
CHECK_PATH;
[path moveToPoint: p];
}
- (void)DPSnewpath
{
if (path)
[path removeAllPoints];
}
- (NSBezierPath *) bezierPath
{
// This is rather slow, but it is not used very often
NSBezierPath *newPath = [path copy];
NSAffineTransform *ictm = [ctm copyWithZone: GSObjCZone(self)];
[ictm invert];
[newPath transformUsingAffineTransform: ictm];
RELEASE(ictm);
return AUTORELEASE(newPath);
}
- (void)DPSpathbbox: (float *)llx : (float *)lly : (float *)urx : (float *)ury
{
NSBezierPath *bpath = [self bezierPath];
NSRect rect = [bpath controlPointBounds];
if (llx)
*llx = NSMinX(rect);
if (lly)
*lly = NSMinY(rect);
if (urx)
*urx = NSMaxX(rect);
if (ury)
*ury = NSMaxY(rect);
}
- (void)DPSrcurveto: (float)x1 : (float)y1 : (float)x2 : (float)y2 : (float)x3
: (float)y3
{
NSPoint p1 = [ctm deltaPointInMatrixSpace: NSMakePoint(x1, y1)];
NSPoint p2 = [ctm deltaPointInMatrixSpace: NSMakePoint(x2, y2)];
NSPoint p3 = [ctm deltaPointInMatrixSpace: NSMakePoint(x3, y3)];
CHECK_PATH;
[path relativeCurveToPoint: p3
controlPoint1: p1
controlPoint2: p2];
}
- (void) DPSrectclip: (float)x : (float)y : (float)w : (float)h
{
NSBezierPath *oldPath = path;
path = [[NSBezierPath alloc] init];
[path appendBezierPathWithRect: NSMakeRect(x, y, w, h)];
[path transformUsingAffineTransform: ctm];
[self DPSclip];
RELEASE(path);
path = oldPath;
if (path)
[path removeAllPoints];
}
- (void) DPSrectfill: (float)x : (float)y : (float)w : (float)h
{
NSBezierPath *oldPath = path;
path = [[NSBezierPath alloc] init];
[path appendBezierPathWithRect: NSMakeRect(x, y, w, h)];
[path transformUsingAffineTransform: ctm];
[self DPSfill];
RELEASE(path);
path = oldPath;
}
- (void) DPSrectstroke: (float)x : (float)y : (float)w : (float)h
{
NSBezierPath *oldPath = path;
path = [[NSBezierPath alloc] init];
[path appendBezierPathWithRect: NSMakeRect(x, y, w, h)];
[path transformUsingAffineTransform: ctm];
[self DPSstroke];
RELEASE(path);
path = oldPath;
}
- (void)DPSreversepath
{
if (path)
ASSIGN(path, [path bezierPathByReversingPath]);
}
- (void)DPSrlineto: (float)x : (float)y
{
NSPoint p = [ctm deltaPointInMatrixSpace: NSMakePoint(x, y)];
CHECK_PATH;
[path relativeLineToPoint: p];
}
- (void)DPSrmoveto: (float)x : (float)y
{
NSPoint p = [ctm deltaPointInMatrixSpace: NSMakePoint(x, y)];
CHECK_PATH;
[path relativeMoveToPoint: p];
}
- (void) DPSstroke;
{
[self subclassResponsibility: _cmd];
}
- (void) GSSendBezierPath: (NSBezierPath *)newpath
{
int count = 10;
float dash_pattern[10];
float phase;
// Appending to the current path is a lot faster than copying!
//ASSIGNCOPY(path, newpath);
CHECK_PATH;
[path removeAllPoints];
[path appendBezierPath: newpath];
[path transformUsingAffineTransform: ctm];
// The following should be moved down into the specific subclasses
[self DPSsetlinewidth: [newpath lineWidth]];
[self DPSsetlinejoin: [newpath lineJoinStyle]];
[self DPSsetlinecap: [newpath lineCapStyle]];
[self DPSsetmiterlimit: [newpath miterLimit]];
[self DPSsetflat: [newpath flatness]];
[newpath getLineDash: dash_pattern count: &count phase: &phase];
[self DPSsetdash: dash_pattern : count : phase];
}
- (void) GSRectClipList: (const NSRect *)rects : (int) count
{
int i;
NSRect union_rect;
if (count == 0)
return;
/*
The specification is not clear if the union of the rects
should produce the new clip rect or if the outline of all rects
should be used as clip path.
*/
union_rect = rects[0];
for (i = 1; i < count; i++)
union_rect = NSUnionRect(union_rect, rects[i]);
[self DPSrectclip: NSMinX(union_rect) : NSMinY(union_rect)
: NSWidth(union_rect) : NSHeight(union_rect)];
}
- (void) GSRectFillList: (const NSRect *)rects : (int) count
{
int i;
for (i=0; i < count; i++)
[self DPSrectfill: NSMinX(rects[i]) : NSMinY(rects[i])
: NSWidth(rects[i]) : NSHeight(rects[i])];
}
- (NSDictionary *) GSReadRect: (NSRect)r
{
return nil;
}
- (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
{
[self subclassResponsibility: _cmd];
}
- (void) DPSshfill: (NSDictionary *)shader
{
NSNumber *v;
NSDictionary *function_dict;
GSFunction2in3out *function;
NSAffineTransform *matrix, *inverse;
NSAffineTransformStruct ts;
NSRect rect;
int iwidth, iheight;
double x, y;
int i;
unsigned char *data;
v = [shader objectForKey: @"ShadingType"];
/* only type 1 shaders */
if ([v intValue] != 1)
{
NSLog(@"ShadingType != 1 not supported.");
return;
}
/* in device rgb space */
if ([shader objectForKey: @"ColorSpace"])
if (![[shader objectForKey: @"ColorSpace"] isEqual: NSDeviceRGBColorSpace])
{
NSLog(@"Only device RGB ColorSpace supported for shading.");
return;
}
function_dict = [shader objectForKey: @"Function"];
if (!function_dict)
{
NSLog(@"Shading function not set.");
return;
}
function = [[GSFunction2in3out alloc] initWith: function_dict];
if (!function)
return;
matrix = [ctm copy];
if ([shader objectForKey: @"Matrix"])
{
[matrix prependTransform: [shader objectForKey: @"Matrix"]];
}
inverse = [matrix copy];
[inverse invert];
rect = [function affectedRect];
iwidth = rect.size.width;
iheight = rect.size.height;
data = objc_malloc(sizeof(char) * iwidth * iheight * 4);
i = 0;
for (y = NSMinY(rect); y < NSMaxY(rect); y++)
{
double in[2], out[3];
NSPoint p;
p = [inverse transformPoint: NSMakePoint(NSMinX(rect), y)];
in[0] = p.x;
in[1] = p.y;
out[0] = out[1] = out[2] = 0.0;
for (x = NSMinX(rect); x < NSMaxX(rect); x++)
{
char r, g, b, a;
[function eval: in : out];
// Set data at x - NSMinX(rect), y - NSMinY(rect) to out
r = out[0] * 255;
g = out[1] * 255;
b = out[2] * 255;
a = 255;
data[i++] = r;
data[i++] = g;
data[i++] = b;
data[i++] = a;
// This gives the same result as:
// p = [inverse transformPoint: NSMakePoint(x, y)];
in[0] += ts.m11;
in[1] += ts.m12;
}
}
// Copy data to device
DESTROY(matrix);
matrix = [NSAffineTransform new];
[matrix translateXBy: NSMinX(rect) yBy: NSMinY(rect)];
[self DPSimage: matrix
: iwidth : iheight
: 8 : 4
: 32 : 4 * iwidth : NO
: YES : NSDeviceRGBColorSpace
: (const unsigned char **)&data];
objc_free(data);
DESTROY(matrix);
DESTROY(inverse);
DESTROY(function);
}
@end