/* XtGState - Implements graphic state drawing for Xt/Xlib

   Copyright (C) 1995 Free Software Foundation, Inc.

   Written by:  Paul Kunz <Paul_Kunz@SLAC.Stanford.edu>,
	Adam Fedor <fedor@boulder.colorado.edu>
   Date: Nov 1995
   
   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 Library 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
   Library General Public License for more details.
   
   You should have received a copy of the GNU Library General Public
   License along with this library; if not, write to the Free
   Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
   */

#include "XtGStateOps.h"
#include "XtDrawContext.h"
#include "XtDrawObject.h"
#include "xttools.h"
#include <objects/Stack.h>
#include <Foundation/NSGeometry.h>
#include <Foundation/NSValue.h>
#include "appkit/View.h"

#define CHECK_GC \
  if (!xgcntxt) \
    [self createGraphicContext]

#define COPY_GC_ON_CHANGE \
  [self _copyGCOnChange]

#define CHECK_WINDOW \
  if (!window.ident) \
    if (window.widget) \
      window.ident = XtWindow((Widget)window.widget)

#define PUSH_PATH_OBJECT(type) \
  [path pushObject: [[XtDrawObject allocWithZone: [self zone]] \
		   initWithDrawType: type]]

static void
gst_currentpoint(NSPoint point)
{
  if (point.x < 0)
    fprintf(stderr, "DPS: No current point\n");
}

@interface XtGState (Private)
- (void) _setGCValues: (XGCValues)values withMask: (int)mask;
- (void) _copyGCOnChange;
- (void) _paintPath;
- (void) setClipMask;
@end

@interface XtDrawContext (Private)
- (Region) viewclipRegion;
- (void) setViewclipRegion: (Region)region;
@end

@implementation XtGState

/* Designated initializer. Note that just calling this methods will not
   fullly initialize the gstate.  One must also call -setWindowDevce:
   or setWindowDevice:andView: so that the gstate knows were and how to
   draw to the screen */
- initWithDrawContext: (XtDrawContext *)context
{
  [super init];

  ctxt = context;
  path = [Stack new];
  point.x = -1;
  return self;
}

- (void) _setViewInfo: (View *)aView
{
  NXRect r;
  window.widget = [aView _widget];
  window.ident  = XtWindow((Widget)window.widget);
  [aView getFrame: &r];
  window.frame = NSMakeRect(NX_X(&r), NX_Y(&r), NX_WIDTH(&r), NX_HEIGHT(&r));
  draw = (window.buffer) ? window.buffer : window.ident;
  /* Flip sets the height of the window, which is what we need to flip
     to X-Window coordinates (origin at top-left) from PS coordinates 
     (origin at bottom-left).  However, if the application is using a
     separate widget set (window.widget != 0) and this is a non-retained
     window (window.buffer == 0), then we want to use the View widget
     height for flip */
  if (window.widget && !window.buffer)
      flip = NSHeight(window.frame);
}

- initWithDrawContext: (XtDrawContext *)context andView: (View *)aView
{
  [self initWithDrawContext: context];
  [self _setViewInfo: aView];
  return self;
}

- (void) dealloc
{
  XWContext context = [ctxt XWContext];

  if ( sharedGC == NO && xgcntxt ) 
    {
      XFreeGC(context->display, xgcntxt);
    }
  if (clipregion)
    XDestroyRegion(clipregion);
  [path release];
  [super dealloc];
}

- deepen
{
  Region new_region;

  /* Share the GC rather than copy it */
  sharedGC = YES;
  path = [path copy];

  /* Copy the clipregion */
  if (clipregion)
    {
      new_region = XCreateRegion();
      XIntersectRegion(clipregion, clipregion, new_region);
      clipregion = new_region;
    }
  update = NO;
  
  if (_view)
    [self _setViewInfo: (View *)_view];
  return self;
}

- copyWithZone: (NSZone *)zone
{
  return [[super copyWithZone: zone] deepen];
}

- copyWithView: (View *)aView
{
  _view = aView;
  return [self copy];
}

- (void) setWindowDevice: (window_device_t)device
{
  window = device;
  draw = (window.buffer) ? window.buffer : window.ident;
  flip = NSHeight(window.frame);
}

- (void) setWindowDevice: (window_device_t)device andView: (View *)aView
{
  [self setWindowDevice: device];
  [self _setViewInfo: aView];
}

- (window_device_t) windowDevice
{
  return window;
}

/* Set various characteristics of the graphic context */
- (void) _setGCValues: (XGCValues)values withMask: (int)mask
{
  XWContext context;
  COPY_GC_ON_CHANGE;
  context = [ctxt XWContext];
  XChangeGC(context->display, xgcntxt, mask, &values);
}

/* Set the GC clipmask.  The clipmask needs to be a combination of the
   current clipregion and the viewclipregion (which is part of the 
   DrawContext). */
- (void) setClipMask
{
  XWContext context;
  Region viewclip;
  Region region;

  context = [ctxt XWContext];
  viewclip = [ctxt viewclipRegion];
  COPY_GC_ON_CHANGE;
  if (!clipregion && !viewclip)
    {
      XSetClipMask(context->display, xgcntxt, None);
      return;
    }

  if (clipregion && viewclip)
    {
      region = XCreateRegion();
      XIntersectRegion(clipregion, [ctxt viewclipRegion], region);
    }
  else if (!viewclip)
    region = clipregion;
  else 
    region = viewclip;

  XSetRegion(context->display, xgcntxt, region);
  if (clipregion && viewclip)
    XDestroyRegion(region);
}

- (void) setColor: (device_color_t)acolor;
{
  XWContext context;
  context = [ctxt XWContext];
  color = acolor;
  gcv.foreground = xtColorToPixel(context, color);
  [self _setGCValues: gcv withMask: GCForeground];
}

- (void) setFont: (Font)fid
{
  gcv.font = fid;
  [self _setGCValues: gcv withMask: GCFont];
}

- copyGraphicContext
{
  GC source;
  X11Window ident;
  unsigned long	mask;
  XWContext context = [ctxt XWContext];
  
  CHECK_WINDOW;
  if (!window.ident && !window.root)
    {
      fprintf(stderr, "DPS: Copying a GC on an unrealized Window\n");
      return nil;
    }

  ident = (window.ident) ? : window.root;
  source = xgcntxt;
  mask = 0xffffffff; /* Copy everything (Hopefully) */
  xgcntxt = XCreateGC(context->display, ident, 0, NULL);
  XCopyGC(context->display, source, mask, xgcntxt); 
  sharedGC = NO;
  return self;
}

// Create a default graphics context.
- createGraphicContext
{
  Pixel	black, white;
  X11Window ident;
  XWContext context = [ctxt XWContext];
  
  CHECK_WINDOW;
  if (!window.ident && !window.root)
    {
      fprintf(stderr, "DPS: Creating a GC on an unrealized Window\n");
      return nil;
    }

  ident = (window.ident) ? : window.root;
  gcv.function = GXcopy;
  //    gcv.foreground = xtGrayToPixel(context, 0.0);	/* NX_BLACK */
  //    gcv.background = xtGrayToPixel(context, 0.6666);	/* NX_LTGRAY */
  black = XBlackPixel(context->display, XDefaultScreen(context->display));
  white = XWhitePixel(context->display, XDefaultScreen(context->display));
  gcv.background = white;
  gcv.foreground = black;
  gcv.plane_mask = AllPlanes;
  gcv.fill_style = FillSolid;
  gcv.fill_rule  = WindingRule;
  xgcntxt = XCreateGC(context->display, ident,
		      GCFunction | GCForeground | GCBackground | GCPlaneMask 
		      | GCFillStyle | GCFillRule,
		      &gcv);
  [self setClipMask];
  sharedGC = NO;
  return self;
}

/* Called before access to a X11 Graphic Context (GC). Create
   a private copy of the GC. */
- (void) _copyGCOnChange
{
  CHECK_GC;
  if (sharedGC == YES)
    [self copyGraphicContext];
}

- (NSRect)clipRect
{
  XRectangle r;
  r.width = 0; r.height = 0;
  if (clipregion)
    XClipBox(clipregion, &r);
  return NSMakeRect(r.x, r.y, r.width, r.height);
}

- setNeedsDisplay: (BOOL)flag
{
  update = flag;
  return self;
}

- setDidUpdate
{
  update = YES;
  return self;
}

- (BOOL) needsDisplay
{
  return update;
}

- (BOOL) didDraw
{
  return didDraw;
}

- (BOOL) hasGraphicContext
{
  return (xgcntxt) ? YES : NO;
}

- (BOOL) hasDrawable
{
  return (draw ? YES : NO);
}

- (Drawable) drawable
{
  return draw;
}

- (GC) graphicContext
{
  return xgcntxt;
}

- copyDrawable:(Drawable)source fromRect:(NSRect *)aRect
{
  NSPoint p;

  p.x = 0; p.y = 0;
  [self copyDrawable:source fromRect:aRect toPoint:&p];
  return self;
};
    
- copyDrawable:(Drawable)source fromRect:(NSRect *)aRect 
			         toPoint:(NSPoint *)aPoint
{
    XWContext	context = [ctxt XWContext];
    
    CHECK_GC;
    [self convertPointToDrawable:aPoint];
    aPoint->y -= NSHeight(*aRect);
    XCopyArea(context->display, source, draw, xgcntxt,
		aRect->origin.x,   aRect->origin.y,
		aRect->size.width, aRect->size.height,
		aPoint->x, aPoint->y);
    [self setDidUpdate];
    return self;
}

- copyImage:(XImage *)image ofSize:(NSSize *)size
{
    NSPoint	p;
    XWContext	context = [ctxt XWContext];

    CHECK_GC;
    p.x = 0; p.y = 0;
    [self convertPointToDrawable:&p];
    p.y -= size->height;
    XPutImage(context->display, draw, xgcntxt,
			image, 	0, 0,
			p.x, p.y,
			size->width, size->height);
    [self setDidUpdate];
    return self;
}

- convertRectToDrawable:(NSRect *)aRect
{
  NSPoint max;
    
  max.x = NSMaxX(*aRect);
  max.y = NSMaxY(*aRect);
  aRect->origin = applyCGT(aRect->origin, cgt);
  max = applyCGT(max, cgt);
  *aRect = NSMakeRect(NSMinX(*aRect), NSMinY(*aRect),
		      max.x - NSMinX(*aRect), max.y - NSMinY(*aRect));
  
  /* Flip the coordinate system for X-windows */
  NX_Y(aRect) = flip - NSMaxY(*aRect);
  return self;
}

- convertPointToDrawable:(NSPoint *)aPoint
{
  *aPoint = applyCGT(*aPoint, cgt);
  aPoint->y = flip - aPoint->y;
  return self;
}

- (void) flushRect: (NSRect *)frame
{
  XWContext   context;
  NSRect bounds;
  
  /* Are all variables initialized? Are we doing backing store? */
  if (xgcntxt == 0)
    return;
  CHECK_WINDOW;
  if (!window.ident)
    return;
  if (draw == window.ident)
    return;
  
  context = [ctxt XWContext];
  if (!frame)
    frame = &window.frame;
  bounds = NSMakeRect(0, 0, NSWidth(*frame), NSHeight(*frame));
  [self convertRectToDrawable:&bounds];
  XCopyArea(context->display, draw, window.ident, xgcntxt,
	    NSMinX(bounds), NSMinY(bounds),
	    NSWidth(bounds), NSHeight(bounds),
	    NSMinX(bounds), NSMinY(bounds));
  update = NO;
  didDraw = YES;
}

- (void) flushRectIfNeeded: (NSRect *)frame
{
  if ( update ) 
    [self flushRect: frame];
}

/* Paint the current path using Xlib calls. All coordinates should already
   have been transformed to device coordinates (save for the final flip
   needed because the X origin is in the top-left). Filling and clipping
   may not work correctly because we don't really flatten curves (although
   I have code for this - maybe I should add it) - FIXME */
- (void) _doPath: (XPoint *)pts : (int)count draw: (ctxt_object_t)type
{
  int fill_rule;
  XWContext   context;
  
  context = [ctxt XWContext];
  COPY_GC_ON_CHANGE;
  fill_rule = WindingRule;
  switch (type)
    {
    case path_stroke:
      XDrawLines(context->display, draw, xgcntxt, pts, count, CoordModeOrigin);
      break;
    case path_eofill:
      gcv.fill_rule = EvenOddRule;
      [self _setGCValues: gcv withMask: GCFillRule];
      /* NO BREAK */
    case path_fill:
      XFillPolygon(context->display, draw, xgcntxt, pts, count, Complex, 
		   CoordModeOrigin);
      
      if (gcv.fill_rule == EvenOddRule)
	{
	  gcv.fill_rule = WindingRule;
	  [self _setGCValues: gcv withMask: GCFillRule];
	}
      break;
    case path_eoclip:
      fill_rule = EvenOddRule;
      /* NO BREAK */
    case path_clip:
      {
	Region region, new_region;
	region = XPolygonRegion(pts, count, fill_rule);
	if (clipregion)
	  {
	    XIntersectRegion(clipregion, region, new_region);
	    XDestroyRegion(region);
	    XDestroyRegion(clipregion);
	  } else
	    new_region = region;
	clipregion = new_region;
	[self setClipMask];
      }
      break;
    case path_eoviewclip:
      fill_rule = EvenOddRule;
      /* NO BREAK */
    case path_viewclip:
      {
	Region region;
	region = XPolygonRegion(pts, count, fill_rule);
	[ctxt setViewclipRegion: region];
	[self setClipMask];
      }
      break;
    default:
      break;
    }
}

- (void) _paintPath
{
  int i, count;
  id drawobj;
  id obj;
  XPoint *pts;
  Stack *savepath;

  drawobj = [path popObject];
  /* clip does not delete the current path, so we have to save it here
     and reset it after processing. */
  if (([drawobj drawType] == path_clip) || ([drawobj drawType] == path_eoclip))
    savepath = [path copy];

  count = [path count];
  OBJC_MALLOC(pts, XPoint, count/2);
  i = 0;
  while ([path count])
    {
      NSPoint p, new;
      BOOL doit;
      
      doit = NO;
      obj = [path removeFirstObject];
      switch ([obj drawType])
	{
	case path_moveto:
	  new = [[path removeFirstObject] pointValue];
	  point  = new;
	  doit = YES;
	  break;
	case path_rmoveto:
	  gst_currentpoint(point);
	  p = [[path removeFirstObject] pointValue];
	  new.x  += p.x; new.y += p.y;
	  doit = YES;
	  break;
	case path_lineto:
	  gst_currentpoint(point);
	  new = [[path removeFirstObject] pointValue];
	  break;
	case path_rlineto:
	  gst_currentpoint(point);
	  p = [[path removeFirstObject] pointValue];
	  new.x  += p.x; new.y += p.y;
	  break;
	case path_arc:
	  break;
	case path_curveto:
	  break;
	case path_charpath:
	  break;
	case path_closepath:
	  new = point;
	  doit = YES;
	  break;
	default:
	  break;
	}
      point = new;
      pts[i].x = new.x; pts[i].y = flip - new.y;
      i++;
      if (doit && i > 1) 
	{
	  [self _doPath: pts : i draw: [drawobj drawType]];
	  i = 0;
	}
    } /* while */
  if (i > 1) 
    {
      [self _doPath: pts : i draw: [drawobj drawType]];
    }
  OBJC_FREE(pts);

  if (([drawobj drawType] == path_clip) || ([drawobj drawType] == path_eoclip))
    {
      [path release];
      path = savepath;
    }

  [self setDidUpdate];
}

@end

@implementation XtGState (ColorOps)

- (void)DPScolorimage 
{
}

- (void)DPScurrentblackgeneration 
{
}

- (void)DPScurrentcmykcolor: (float *)c : (float *)m : (float *)y : (float *)k 
{
  device_color_t new = color;
  if (new.space != cmyk_colorspace)
    new = xtConvertToCMYK(new);
  *c = new.field[0];
  *m = new.field[1];
  *y = new.field[2];
  *k = new.field[3];
}

- (void)DPScurrentcolorscreen 
{
}

- (void)DPScurrentcolortransfer 
{
}

- (void)DPScurrentundercolorremoval 
{
}

- (void)DPSsetblackgeneration 
{
}

- (void)DPSsetcmykcolor: (float)c : (float)m : (float)y : (float)k 
{
  color.space = cmyk_colorspace;
  color.field[0] = c;
  color.field[1] = m;
  color.field[2] = y;
  color.field[3] = k;
  [self setColor:color];
}

- (void)DPSsetcolorscreen 
{
}

- (void)DPSsetcolortransfer 
{
}

- (void)DPSsetundercolorremoval 
{
}

@end

@implementation XtGState (GStateOps)

- (void)DPSconcat: (const float *)m
{
  cgt_t acgt;
  acgt.a = m[0]; acgt.b = m[1]; acgt.c = m[2]; acgt.d = m[3];
  acgt.tx = m[4]; acgt.ty = m[5];
  cgt = concatCGT(cgt, acgt);
}

- (void)DPScurrentdash 
{
}

- (void)DPScurrentflat: (float *)flatness 
{
}

- (void)DPScurrentgray: (float *)gray 
{
  device_color_t gcolor;
  gcolor = xtConvertToGray(color);
  *gray = gcolor.field[0];
}

- (void)DPScurrenthalftone 
{
}

- (void)DPScurrenthalftonephase: (float *)x : (float *)y 
{
}

- (void)DPScurrenthsbcolor: (float *)h : (float *)s : (float *)b 
{
  device_color_t gcolor;
  gcolor = xtConvertToHSB(color);
  *h = gcolor.field[0]; *s = gcolor.field[1]; *b = gcolor.field[2];
}

- (void)DPScurrentlinecap: (int *)linecap 
{
  *linecap = gcv.cap_style - CapButt;
}

- (void)DPScurrentlinejoin: (int *)linejoin 
{
  *linejoin = gcv.join_style - JoinMiter;
}

- (void)DPScurrentlinewidth: (float *)width 
{
  *width = gcv.line_width;
}

- (void)DPScurrentmatrix: (float *)m
{
  m[0] = cgt.a; m[1] = cgt.b; m[2] = cgt.c; m[3] = cgt.d;
  m[4] = cgt.tx; m[5] = cgt.ty;
}

- (void)DPScurrentmiterlimit: (float *)limit 
{
}

- (void)DPScurrentpoint: (float *)x : (float *)y 
{
  NSPoint user;

  user = applyCGT(point, invertCGT(cgt));
  *x = user.x;
  *y = user.y;
}

- (void)DPScurrentrgbcolor: (float *)r : (float *)g : (float *)b 
{
  device_color_t gcolor;
  gcolor = xtConvertToRGB(color);
  *r = gcolor.field[0]; *g = gcolor.field[1]; *b = gcolor.field[2];
}

- (void)DPScurrentscreen 
{
}

- (void)DPScurrentstrokeadjust: (int *)b 
{
}

- (void)DPScurrenttransfer 
{
}

- (void)DPSinitgraphics 
{
  cgt = composeCGT(NULL, 0, NULL);

  point.x = -1;
  if (clipregion)
    XDestroyRegion(clipregion);
  clipregion = 0;
  /* FIXME: reset the GC */
  color.space = gray_colorspace; color.field[0] = 0.0;
  [self setColor: color];
}

- (void)DPSinitmatrix 
{
  cgt = composeCGT(NULL, 0, NULL);
}

- (void)DPSrotate: (float)angle 
{
  cgt = concatCGT(cgt, composeCGT(NULL, angle, NULL));
}

- (void)DPSscale: (float)x : (float)y 
{
  NSSize scale;
  scale.width = x;
  scale.height = y;
  cgt = concatCGT(cgt, composeCGT(&scale, 0, NULL));
}

- (void)DPSsetdash: (const float *)pat : (int)size : (float)offset 
{
}

- (void)DPSsetflat: (float)flatness 
{
}

- (void)DPSsetgray: (float)gray 
{
  color.space = gray_colorspace;
  color.field[0] = gray;
  [self setColor: color];
}

- (void)DPSsethalftone 
{
}

- (void)DPSsethalftonephase: (float)x : (float)y 
{
}

- (void)DPSsethsbcolor: (float)h : (float)s : (float)b 
{
  color.space = hsb_colorspace;
  color.field[0] = h; color.field[1] = s; color.field[2] = b;
  [self setColor: color];
}

- (void)DPSsetlinecap: (int)linecap 
{
  gcv.cap_style = linecap + CapButt;
  [self _setGCValues: gcv withMask: GCCapStyle];
}

- (void)DPSsetlinejoin: (int)linejoin 
{
  gcv.join_style = linejoin + JoinMiter;
  [self _setGCValues: gcv withMask: GCJoinStyle];
}

- (void)DPSsetlinewidth: (float)width 
{
  gcv.line_width = width;
  [self _setGCValues: gcv withMask: GCLineWidth];
}

- (void)DPSsetmatrix: (const float *)m;
{
  cgt.a = m[0]; cgt.b = m[1]; cgt.c = m[2]; cgt.d = m[3];
  cgt.tx = m[4]; cgt.ty = m[5];
}

- (void)DPSsetmiterlimit: (float)limit 
{
}

- (void)DPSsetrgbcolor: (float)r : (float)g : (float)b 
{
  color.space = rgb_colorspace;
  color.field[0] = r; color.field[1] = g; color.field[2] = b;
  [self setColor: color];
}

- (void)DPSsetscreen 
{
}

- (void)DPSsetstrokeadjust: (int)b 
{
}

- (void)DPSsettransfer 
{
}

- (void)DPStranslate: (float)x : (float)y 
{
  NSPoint p;
  p.x = x;
  p.y = y;
  cgt = concatCGT(cgt, composeCGT(NULL, 0, &p));
}

@end

@implementation XtGState (PaintOps)

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;
{
  int i;
  int len;
  int width;
  cgt_t trans;
  NSSize scale;
  XFontStruct *fontinfo;
  XWContext context;

  /* Transformation should only be delta transformations (no offset) */
  trans = cgt;
  trans.tx = 0; trans.ty = 0;

  len = strlen(s);
  context = [ctxt XWContext];
  scale = scaleFromCGT(cgt);
  fontinfo = XQueryFont(context->display, gcv.font);
  COPY_GC_ON_CHANGE; 
  for (i=0; i < len; i++)
    {
      NSPoint delta;
      width = XTextWidth(fontinfo, s+i, 1);
      XDrawString(context->display, draw, xgcntxt, point.x, flip-point.y,
	      s, 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 = applyCGT(delta, trans);
      if (relative == YES)
	{
	  delta.x += width * scale.width;
	  delta.y += fontinfo->max_bounds.ascent * scale.height;
	}
      if (c && *(s+i) == c)
	{
	  NSPoint cdelta;
	  cdelta.x = cx; cdelta.y = cy;
	  cdelta = applyCGT(cdelta, trans);
	  delta.x += cdelta.x; delta.y += cdelta.y;
	}
      point.x += delta.x;
      if (type != show_delta)
	point.y += delta.y;
    }
  [self setDidUpdate];
  
}

- (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)DPScopypage 
{
}

- (void)DPSeofill 
{
  PUSH_PATH_OBJECT(path_eofill);
  [self _paintPath];
}

- (void)DPSerasepage 
{
}

- (void)DPSfill 
{
  PUSH_PATH_OBJECT(path_fill);
  [self _paintPath];
}

- (void)DPSimage 
{
}

- (void)DPSimagemask 
{
}

- (void)DPSkshow: (const char *)s 
{
}

- (void)DPSrectfill: (float)x : (float)y : (float)w : (float)h 
{
  XWContext	context = [ctxt XWContext];
  NSRect	bounds;
  
  COPY_GC_ON_CHANGE;
  bounds = NSMakeRect(x, y, w, h);
  [self convertRectToDrawable:&bounds];
  XFillRectangle(context->display, draw, xgcntxt,
		 NSMinX(bounds), NSMinY(bounds),
		 NSWidth(bounds), NSHeight(bounds));
  [self setDidUpdate];
}

- (void)DPSrectstroke: (float)x : (float)y : (float)w : (float)h 
{
  XWContext	context = [ctxt XWContext];
  NSRect	bounds;
  
  COPY_GC_ON_CHANGE; 
  bounds = NSMakeRect(x, y, w, h);
  [self convertRectToDrawable:&bounds];
  XDrawRectangle(context->display, draw, xgcntxt,
		 NSMinX(bounds), NSMinY(bounds),
		 NSWidth(bounds), NSHeight(bounds));
  [self setDidUpdate];
}

- (void)DPSshow: (const char *)s 
{
  int len;
  int width;
  NSSize scale;
  XFontStruct *fontinfo;
  XWContext context;

  len = strlen(s);
  context = [ctxt XWContext];
  fontinfo = XQueryFont(context->display, gcv.font);
  width = XTextWidth(fontinfo, s, len);
  COPY_GC_ON_CHANGE; 

  XDrawString(context->display, draw, xgcntxt, point.x, flip-point.y,
	      s, len);

  /* Note we update the current point according to the current 
     transformation scaling, although the text isn't currently
     scaled (FIXME). */
  scale = scaleFromCGT(cgt);
  point.x += width * scale.width;
  [self setDidUpdate];
}

- (void)DPSshowpage 
{
}

- (void)DPSstroke 
{
  PUSH_PATH_OBJECT(path_stroke);
  [self _paintPath];
}

- (void)DPSstrokepath 
{
}

- (void)DPSueofill: (const char *)nums : (int)n : (const char *)ops : (int)l 
{
}

- (void)DPSufill: (const char *)nums : (int)n : (const char *)ops : (int)l 
{
}

- (void)DPSustroke: (const char *)nums : (int)n : (const char *)ops : (int)l 
{
}

- (void)DPSustrokepath: (const char *)nums : (int)n : (const char *)ops : (int)l 
{
}

- (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];
}

@end

@implementation XtGState (PathOps)

- (void)DPSarc: (float)x : (float)y : (float)r : (float)angle1 : (float)angle2 
{
}

- (void)DPSarcn: (float)x : (float)y : (float)r : (float)angle1 : (float)angle2 
{
}

- (void)DPSarct: (float)x1 : (float)y1 : (float)x2 : (float)y2 : (float)r 
{
}

- (void)DPSarcto: (float)x1 : (float)y1 : (float)x2 : (float)y2 : (float)r : (float *)xt1 : (float *)yt1 : (float *)xt2 : (float *)yt2 
{
}

- (void)DPScharpath: (const char *)s : (int)b 
{
}

- (void)DPSclip 
{
  PUSH_PATH_OBJECT(path_clip);
  [self _paintPath];
}

- (void)DPSclippath 
{
}

- (void)DPSclosepath 
{
  PUSH_PATH_OBJECT(path_closepath);
}

- (void)DPScurveto: (float)x1 : (float)y1 : (float)x2 : (float)y2 : (float)x3 : (float)y3 
{
}

- (void)DPSeoclip 
{
  PUSH_PATH_OBJECT(path_eoclip);
  [self _paintPath];
}

- (void)DPSeoviewclip 
{
  PUSH_PATH_OBJECT(path_eoviewclip);
  [self _paintPath];
}

- (void)DPSflattenpath 
{
}

- (void)DPSinitclip 
{
  if (clipregion)
    XDestroyRegion(clipregion);
  clipregion = 0;
  [self setClipMask];
}

- (void)DPSinitviewclip 
{
  [ctxt setViewclipRegion: 0];
}

- (void)DPSlineto: (float)x : (float)y 
{
  NSPoint p;
  p.x = x; p.y = y;
  p = applyCGT(p, cgt);
  PUSH_PATH_OBJECT(path_lineto);
  [path pushObject: [NSValue valueWithPoint: p]];
}

- (void)DPSmoveto: (float)x : (float)y 
{
  NSPoint p;
  p.x = x; p.y = y;
  p = applyCGT(p, cgt);
  PUSH_PATH_OBJECT(path_moveto);
  [path pushObject: [NSValue valueWithPoint: p]];
  point = p;
}

- (void)DPSnewpath 
{
  int count;
  count = [path count];
  while (count--)
    [path popObject];
  point.x = 0 ; point.y = 0;
}

- (void)DPSpathbbox: (float *)llx : (float *)lly : (float *)urx : (float *)ury 
{
}

- (void)DPSpathforall 
{
}

- (void)DPSrcurveto: (float)x1 : (float)y1 : (float)x2 : (float)y2 : (float)x3 : (float)y3 
{
}

- (void)DPSrectclip: (float)x : (float)y : (float)w : (float)h 
{
  NSRect	bounds;
  Region        new_region;
  XRectangle    xrect;

  COPY_GC_ON_CHANGE; 
  bounds = NSMakeRect(x, y, w, h);
  [self convertRectToDrawable:&bounds];
  xrect.x = NSMinX(bounds); xrect.y = NSMinY(bounds);
  xrect.width = NSWidth(bounds); xrect.height = NSHeight(bounds);
  new_region = XCreateRegion();
  if (!clipregion)
    clipregion = XCreateRegion();
  XUnionRectWithRegion(&xrect, clipregion, new_region);
  XDestroyRegion(clipregion);
  clipregion = new_region;
  [self setClipMask];
}

- (void)DPSrectviewclip: (float)x : (float)y : (float)w : (float)h 
{
  NSRect	bounds;
  Region        region, new_region;
  XRectangle    xrect;

  bounds = NSMakeRect(x, y, w, h);
  [self convertRectToDrawable:&bounds];
  xrect.x = NSMinX(bounds); xrect.y = NSMinY(bounds);
  xrect.width = NSWidth(bounds); xrect.height = NSHeight(bounds);
  region = XCreateRegion();
  new_region = XCreateRegion();
  XUnionRectWithRegion(&xrect, region, new_region);
  XDestroyRegion(region);
  [ctxt setViewclipRegion: new_region];
}

- (void)DPSreversepath 
{
}

- (void)DPSrlineto: (float)x : (float)y 
{
  NSPoint p;
  p.x = x; p.y = y;
  p = applyCGT(p, cgt);
  PUSH_PATH_OBJECT(path_rlineto);
  [path pushObject: [NSValue valueWithPoint: p]];
}

- (void)DPSrmoveto: (float)x : (float)y 
{
  NSPoint p;
  p.x = x; p.y = y;
  p = applyCGT(p, cgt);
  PUSH_PATH_OBJECT(path_rmoveto);
  [path pushObject: [NSValue valueWithPoint: p]];
  point.x += p.x;
  point.y += p.y;
}

- (void)DPSsetbbox: (float)llx : (float)lly : (float)urx : (float)ury 
{
}

- (void)DPSsetucacheparams 
{
}

- (void)DPSuappend: (const char *)nums : (int)n : (const char *)ops : (int)l 
{
}

- (void)DPSucache 
{
}

- (void)DPSucachestatus 
{
}

- (void)DPSupath: (int)b 
{
}

- (void)DPSviewclip 
{
  PUSH_PATH_OBJECT(path_viewclip);
  [self _paintPath];
}

- (void)DPSviewclippath 
{
}

@end

@implementation XtGState (WinOps)

- (void)DPSineofill: (float)x : (float)y : (int *)b 
{
}

- (void)DPSinfill: (float)x : (float)y : (int *)b 
{
}

- (void)DPSinstroke: (float)x : (float)y : (int *)b 
{
}

- (void)DPSinueofill: (float)x : (float)y : (const char *)nums : (int)n : (const char *)ops : (int)l : (int *)b 
{
}

- (void)DPSinufill: (float)x : (float)y : (const char *)nums : (int)n : (const char *)ops : (int)l : (int *)b 
{
}

- (void)DPSinustroke: (float)x : (float)y : (const char *)nums : (int)n  : (const char *)ops : (int)l : (int *)b 
{
}

- (void)DPSwtranslation: (float *)x : (float *)y 
{
}

@end

@implementation XtGState (L2Ops)

- (void)DPScshow: (const char *)s 
{
}

- (void)DPScurrentcolor 
{
}

- (void)DPScurrentcolorrendering 
{
}

- (void)DPScurrentcolorspace 
{
}

- (void)DPSsetcolor 
{
}

- (void)DPSsetcolorrendering 
{
}

- (void)DPSsetcolorspace 
{
}

- (void)DPSsetpattern: (int)patternDict 
{
}

@end
