/*********************************************************/
/* This source code copyright (c) 1991-2001, Aaron Giles */
/* See the Read Me file for licensing information.       */
/* Contact email: mac@aarongiles.com                     */
/*********************************************************/

//=====================================================================================
// Generic includes for Macintosh headers
//=====================================================================================

#if THINK_C
#include "THINK.Header"
#include <stddef.h>
#elif applec
#pragma load ":Headers:MPW.Header"
#elif __MWERKS__
//#include "MW.Header"
#else
#include "JPEGView.h"
#endif

//=====================================================================================
// Includes specific to this module
//=====================================================================================

#include "Bottlenecks.h"

//=====================================================================================
// FixedPort: Holds old StdBits procedure information for when we fix up a port's 
// StdBits function to fix the QuickTime 1.5 bug.
//=====================================================================================

typedef struct FixedPort 
{
	struct FixedPort *next;
	CGrafPtr port;
	CQDProcs *oldprocs;
	CQDProcs newprocs;
	QDBitsUPP oldbits;
} FixedPort, *FixedPortPtr, **FixedPortHandle;

//=====================================================================================
// Global variables local to this module
//=====================================================================================

static JVDrawParamsHandle gDrawParamsRoot = nil;
static FixedPortPtr gFixedPortRoot = nil;
static CQDProcs gBottlenecks;
static QDBitsUPP gJVFixedBitsProc;
static DeviceLoopDrawingUPP gDeviceCopy;

//=====================================================================================
// Prototypes for functions local to this module
//=====================================================================================

static OSErr DitherTableInit(void);
static JVDrawParamsHandle FindParams(CGrafPtr thePort);
static pascal void JVFixedBitsProc(PixMap *src, Rect *srcRect, Rect *dstRect, 
			short mode, RgnHandle mask);
static pascal void JVBitsProc(PixMap *src, Rect *srcRect, Rect *dstRect, short mode, 
			RgnHandle mask);
static void DrawOnAndOffscreen(PixMap *src, Rect *srcRect, Rect *dstRect, 
			JVDrawParamsHandle theParams);
static void DrawOnscreen(PixMap *src, Rect *srcRect, Rect *dstRect, 
			JVDrawParamsHandle theParams);
static void DrawOffscreen(PixMap *src, Rect *srcRect, Rect *dstRect, 
			JVDrawParamsHandle theParams);
static pascal void DeviceCopy(short depth, short deviceFlags, GDHandle targetDevice, 
			void *tempParams);
static void CustomCopy(PixMap *src, Rect *srcRect, Rect *dstRect, Boolean dither, 
			RgnHandle mask, short quality);
static Boolean IsGrayDevice(GDHandle theGDevice);
static void DrawVHighQuality(PixMapPtr src, PixMapHandle dst, Rect *srcRect, 
			Rect *dstRect, Boolean dither, RgnHandle mask);
static void DrawHighQuality(PixMapPtr src, PixMapHandle dst, Rect *srcRect, 
			Rect *dstRect, Boolean dither, RgnHandle mask);
static void ShowScaleDither(Boolean scaling, Boolean dither, Boolean state,
			JVDrawParamsHandle theParams);
static void CopyFields(CGrafPtr src, CGrafPtr dst, Rect *srcRect, Rect *dstRect);
static Boolean DiffPixPat(PixPatHandle pp1, PixPatHandle pp2);
static pascal void JVTextProc(short count, Ptr textAddr, Point numer, Point denom);
static pascal void JVLineProc(Point newPt);
static pascal void JVRectProc(GrafVerb verb, Rect *r);
static pascal void JVRRectProc(GrafVerb verb, Rect *r, short ovalWidth, short ovalHeight);
static pascal void JVOvalProc(GrafVerb verb, Rect *r);
static pascal void JVArcProc(GrafVerb verb, Rect *r, short startAngle, short arcAngle);
static pascal void JVPolyProc(GrafVerb verb, PolyHandle poly);
static pascal void JVRgnProc(GrafVerb verb, RgnHandle rgn);

//=====================================================================================
// OSErr DrawingInit(void)
//=====================================================================================
// Initializes the bottlenecks record and the dithering table.
//=====================================================================================

extern OSErr DrawingInit(void) 
{
	KeepSpinning();
	SetStdCProcs(&gBottlenecks);
	gBottlenecks.textProc = NewQDTextProc((ProcPtr)JVTextProc);
	gBottlenecks.lineProc = NewQDLineProc((ProcPtr)JVLineProc);
	gBottlenecks.rectProc = NewQDRectProc((ProcPtr)JVRectProc);
	gBottlenecks.rRectProc = NewQDRRectProc((ProcPtr)JVRRectProc);
	gBottlenecks.ovalProc = NewQDOvalProc((ProcPtr)JVOvalProc);
	gBottlenecks.arcProc = NewQDArcProc((ProcPtr)JVArcProc);
	gBottlenecks.polyProc = NewQDPolyProc((ProcPtr)JVPolyProc);
	gBottlenecks.rgnProc = NewQDRgnProc((ProcPtr)JVRgnProc);
	gBottlenecks.bitsProc = NewQDBitsProc((ProcPtr)JVBitsProc);
	gJVFixedBitsProc = NewQDBitsProc((ProcPtr)JVFixedBitsProc);
	gDeviceCopy = NewDeviceLoopDrawingProc((ProcPtr)DeviceCopy);
	KeepSpinning();
	return DitherTableInit();
}

//=====================================================================================
// OSErr DitherTableInit(void)
//=====================================================================================
// Initializes the dithering and scaling tables.
//=====================================================================================

static OSErr DitherTableInit(void)
{
	Handle tempHandle;
	uchar *theTable;
	short *table;
	short i, j, k;
	
	KeepSpinning();
	if (!(tempHandle = NewHandleClear((3 + 4 + 5 + 6 + 7 + 8) * 256))) 
		FatalError(errNoMemory);
	HLockHi(tempHandle);
	theTable = gScaleTable = (uchar *)StripAddress(*tempHandle);
	for (i = 3; i <= 8; i++) 
		for (j = 0; j < 256; j++)
			for (k = 0; k < i; k++) *theTable++ = j;
	KeepSpinning();
	
	if (!(tempHandle = NewHandleClear(sizeof(short) * 512))) FatalError(errNoMemory);
	HLockHi(tempHandle);
	table = gErrTable = (short *)StripAddress(*tempHandle) + 256;
	for (i = j = 1; i < 0x08; i++, j++) table[i] = j, table[-i] = -j;
	for (i = 0x08; i < 0x18; i++, j += !(i & 1) ? 1 : 0) table[i] = j, table[-i] = -j;
	for (i = 0x18; i < 0x38; i++, j += !(i & 3) ? 1 : 0) table[i] = j, table[-i] = -j;
	for (i = 0x38; i < 0x78; i++, j += !(i & 7) ? 1 : 0) table[i] = j, table[-i] = -j;
	for ( ; i <= 0x100; i++) {
		if (i != 0x100) table[i] = j;
		table[-i] = -j;
	}
	KeepSpinning();
	return noErr;
}

//=====================================================================================
// JVDrawParamsHandle NewDrawParams(Rect *bounds, short quality, Boolean quantize,
//			NestedProgressPtr progress, Handle privateData)
//=====================================================================================
// Creates and begins initializing a JVDrawParamsHandle in preparation for drawing.
//=====================================================================================

extern JVDrawParamsHandle NewDrawParams(Rect *bounds, short quality, Boolean quantize,
			NestedProgressPtr progress, Handle privateData)
{
	JVDrawParamsHandle theParams;
	
	if (theParams = (JVDrawParamsHandle)NewHandleClear(sizeof(JVDrawParams))) {
		(*theParams)->bounds = *bounds;
		(*theParams)->quality = quality;
		(*theParams)->quantize = quantize;
		if (progress) {
			(*theParams)->progress = *progress;
			(*theParams)->progress.prog.progressRefCon = (long)theParams;
		}
		(*theParams)->privateData = privateData;
	}
	return theParams;
}

//=====================================================================================
// SetUpDrawPort(JVDrawParamsHandle theParams, short whichPort, CGrafPtr thePort,
//			Rect *srcRect, Rect *dstRect, Boolean dither)
//=====================================================================================
// Initialize one of the three drawing ports in the JVDrawParamsHandle.
//=====================================================================================

extern void SetUpDrawPort(JVDrawParamsHandle theParams, short whichPort, CGrafPtr thePort,
			Rect *srcRect, Rect *dstRect, Boolean dither)
{
	JVPortParams port;
	
	port.port = thePort;
	port.outer = (*theParams)->bounds;
	MapRect(&port.outer, srcRect, dstRect);
	port.dither = dither;
	switch (whichPort) {
		case kOnscreenPort:
			(*theParams)->on = port;
			break;
		case kOffscreenPort1:
			(*theParams)->off = port;
			break;
		case kOffscreenPort2:
			(*theParams)->extra = port;
			break;
	}
}

//=====================================================================================
// OSErr PreflightDrawing(JVDrawParamsHandle theParams)
//=====================================================================================
// Inserts theParams into the local linked list of current drawing environments, and
// creates a new destination port with the bottleneck procedures installed.
//=====================================================================================

extern OSErr PreflightDrawing(JVDrawParamsHandle theParams)
{
	Rect bounds = (*theParams)->bounds, dbounds = { 0, 0, 1, 32 }, outer;
	GWorldPtr theGWorld;
	RgnHandle tempRgn;
	Rect theRect;
	
	(*theParams)->next = gDrawParamsRoot;
	(*theParams)->progress.aborted = false;
	gDrawParamsRoot = theParams;
	dbounds.right = Width(&(*theParams)->bounds);
	if (theGWorld = MyNewGWorld(&dbounds, 32, nil, nil, false, false)) {
		(*GetGWorldPixMap(theGWorld))->rowBytes &= 0xc000;
		if (tempRgn = NewRgn()) {
			SetEmptyRgn(theGWorld->visRgn);
			if ((*theParams)->on.port) {
				CopyRgn((*theParams)->on.port->visRgn, tempRgn);
				InsetRgn(tempRgn, -1, -1);
				outer = (*theParams)->on.outer;
				MapRgn(tempRgn, &outer, &bounds);
				UnionRgn(tempRgn, theGWorld->visRgn, theGWorld->visRgn);
			}
			if ((*theParams)->off.port) {
				CopyRgn((*theParams)->off.port->visRgn, tempRgn);
				InsetRgn(tempRgn, -1, -1);
				outer = (*theParams)->off.outer;
				MapRgn(tempRgn, &outer, &bounds);
				UnionRgn(tempRgn, theGWorld->visRgn, theGWorld->visRgn);
				if ((*theParams)->extra.port) {
					CopyRgn((*theParams)->extra.port->visRgn, tempRgn);
					InsetRgn(tempRgn, -1, -1);
					outer = (*theParams)->extra.outer;
					MapRgn(tempRgn, &outer, &bounds);
					UnionRgn(tempRgn, theGWorld->visRgn, theGWorld->visRgn);
				}
			}
			theRect = (*theParams)->bounds;
			RectRgn(theGWorld->clipRgn, &theRect);
			if (!(*theParams)->off.port && !(*theParams)->on.port) 
				CopyRgn(theGWorld->clipRgn, theGWorld->visRgn);
			DisposeRgn(tempRgn);
			theGWorld->grafProcs = &gBottlenecks;
			(*theParams)->dummy = theGWorld;
			return noErr;
		}
		DisposeGWorld(theGWorld);
	}
	return memFullErr;
}

//=====================================================================================
// OSErr PostflightDrawing(JVDrawParamsHandle theParams)
//=====================================================================================
// Removes theParams from the local linked list of current drawing environments,
// disposing of the temporary destination port.
//=====================================================================================

extern OSErr PostflightDrawing(JVDrawParamsHandle theParams)
{
	JVDrawParamsHandle params;
	OSErr theErr = noErr;
	
	if ((*theParams)->progress.aborted) theErr = codecAbortErr;
	if ((*theParams)->dummy) DisposeGWorld((*theParams)->dummy);
	if (theParams == gDrawParamsRoot) gDrawParamsRoot = (*theParams)->next;
	else for (params = gDrawParamsRoot; params; params = (*params)->next)
		if ((*params)->next == theParams) {
			(*params)->next = (*theParams)->next;
			break;
		}
	return theErr;
}

//=====================================================================================
// JVDrawParamsHandle FindParams(CGrafPtr thePort)
//=====================================================================================
// Locates the parameter set associated with the given port.
//=====================================================================================

static JVDrawParamsHandle FindParams(CGrafPtr thePort)
{
	JVDrawParamsHandle theParams;
	
	for (theParams = gDrawParamsRoot; theParams; theParams = (*theParams)->next)
		if ((*theParams)->dummy == thePort) return theParams;
	return nil;
}

//=====================================================================================
// OSErr FixBits(CGrafPtr, Boolean on)
//=====================================================================================
// Turns on/off the QuickTime 1.5 image bug fix for a given port.
//=====================================================================================

extern OSErr FixBits(CGrafPtr thePort, Boolean on)
{
	FixedPortPtr theFixedPort;
	
	if (gQTVersion != 0x0150) return noErr;
	if (on) {
		if (theFixedPort = (FixedPortPtr)NewPtrClear(sizeof(FixedPort))) {
			theFixedPort->next = gFixedPortRoot;
			gFixedPortRoot = theFixedPort;
			theFixedPort->port = thePort;
			if (theFixedPort->oldprocs = thePort->grafProcs) 
				theFixedPort->newprocs = *thePort->grafProcs;
			else SetStdCProcs(&theFixedPort->newprocs);
			theFixedPort->oldbits = theFixedPort->newprocs.bitsProc;
			theFixedPort->newprocs.bitsProc = gJVFixedBitsProc;
			thePort->grafProcs = &theFixedPort->newprocs;
		} else return memFullErr;
	} else {
		for (theFixedPort = gFixedPortRoot; theFixedPort; theFixedPort = theFixedPort->next)
			if (theFixedPort->port == thePort) break;
		if (!theFixedPort) return paramErr;
		thePort->grafProcs = theFixedPort->oldprocs;
		if (theFixedPort == gFixedPortRoot) gFixedPortRoot = theFixedPort->next;
		else {
			for (theFixedPort = theFixedPort; theFixedPort->next; 
						theFixedPort = theFixedPort->next)
				if (theFixedPort->next->port == thePort) break;
			if (theFixedPort) theFixedPort->next = theFixedPort->next->next;
			theFixedPort = theFixedPort->next;
		}
		DisposePtr((Ptr)theFixedPort);
	}
	return noErr;
}

//=====================================================================================
// pascal void JVFixedBitsProc(PixMap *src, Rect *srcRect, Rect *dstRect, short mode, 
// 			RgnHandle mask) 
//=====================================================================================
// Bottleneck routine to fix things under QuickTime 1.5 so that drawing cropped
// images works correctly.  Thanks for Mark Krueger for the bugfix!
//=====================================================================================

static pascal void JVFixedBitsProc(PixMap *src, Rect *srcRect, Rect *dstRect,
			short mode, RgnHandle mask) 
{
	long offsetH = srcRect->left, offsetV = srcRect->top, rb = src->rowBytes;
	Rect saveSrcBounds = src->bounds, tmpSrcRect = *srcRect;
	FixedPortPtr theFixedPort;
	Ptr saveBaseAddr = nil;
	
	for (theFixedPort = gFixedPortRoot; theFixedPort; theFixedPort = theFixedPort->next)
		if (theFixedPort->port == (CGrafPtr)qd.thePort) break;
	if (!theFixedPort) return;
	if (offsetH || offsetV) {
		if (rb & 0xc000) {
			rb &= 0x3fff;
			saveBaseAddr = src->baseAddr;
			if (src->pmVersion == 2) LockPixels(&src);
			if (src->pmVersion == 4)
				src->baseAddr += offsetV * rb + ((offsetH * src->pixelSize) >> 3);
			else if (src->pmVersion == 1)
				src->baseAddr = StripAddress(src->baseAddr) + offsetV * rb + 
							((offsetH * src->pixelSize) >> 3);
			OffsetRect(&tmpSrcRect, -offsetH, -offsetV);
		} else {
			BitMap *srcB = (BitMap *)src;
			saveBaseAddr = srcB->baseAddr;
			srcB->baseAddr += offsetH + (offsetV * rb);
			OffsetRect(&tmpSrcRect, -offsetH, -offsetV);
		}
	}
	src->bounds = tmpSrcRect;
	CallQDBitsProc(theFixedPort->oldbits, (BitMap *)src, &tmpSrcRect, dstRect, mode, mask);
	src->bounds = saveSrcBounds;
	if (saveBaseAddr) src->baseAddr = saveBaseAddr;
}

//=====================================================================================
// pascal void JVBitsProc(PixMap *src, Rect *srcRect, Rect *dstRect, short mode, 
// 			RgnHandle mask) 
//=====================================================================================
// Bottleneck routine for CopyBits.
//=====================================================================================

static pascal void JVBitsProc(PixMap *src, Rect *srcRect, Rect *dstRect, short mode, 
			RgnHandle mask) 
{
#if applec
#pragma unused(mode, mask)
#endif
	JVDrawParamsHandle theParams = FindParams((CGrafPtr)qd.thePort);
	PixMapHandle onPixMap = nil, offPixMap = nil;
	Boolean scaling = false;
	char offState;
	
	if (!theParams || (*theParams)->progress.aborted || 
				((*theParams)->progress.aborted = CheckAbort(theParams))) return;
	PushPort();
	(*theParams)->src = src;
	(*theParams)->srcrect = *srcRect;
	(*theParams)->dstrect = *dstRect;
	if ((*theParams)->off.port) {
		offPixMap = GetGWorldPixMap((*theParams)->off.port);
		offState = GetPixelsState(offPixMap);
		LockPixels(offPixMap);
		scaling = !EqualSizeRect(&(*theParams)->bounds, &(*theParams)->off.outer);
	}
	if ((*theParams)->on.port) {
		onPixMap = GetGWorldPixMap((*theParams)->on.port);
		if (!scaling) scaling = !EqualSizeRect(&(*theParams)->bounds, &(*theParams)->on.outer);
	}
	if (Height(dstRect) > 8) 
		ShowScaleDither(scaling, (*theParams)->on.dither, true, theParams);
	if ((*theParams)->quantize) FillHistogram(src);
	if ((*theParams)->on.port && (*theParams)->off.port)
		DrawOnAndOffscreen(src, srcRect, dstRect, theParams);
	else if ((*theParams)->on.port) DrawOnscreen(src, srcRect, dstRect, theParams);
	else if ((*theParams)->off.port) DrawOffscreen(src, srcRect, dstRect, theParams);
	if (Height(dstRect) > 8) 
		ShowScaleDither(scaling, (*theParams)->on.dither, false, theParams);
	if ((*theParams)->off.port) SetPixelsState(offPixMap, offState);
	if (gSlideShow && !(*theParams)->progress.aborted) 
		(*theParams)->progress.aborted = CheckAbort(theParams);
	PopPort();
}

//=====================================================================================
// void DrawOnAndOffscreen(PixMap *src, Rect *srcRect, Rect *dstRect, 
// 			JVDrawParamsHandle theParams)
//=====================================================================================
// Do CopyBits drawing for both onscreen and offscreen.
//=====================================================================================

static void DrawOnAndOffscreen(PixMap *src, Rect *srcRect, Rect *dstRect, 
			JVDrawParamsHandle theParams)
{
	PixMapHandle offPixMap = GetGWorldPixMap((*theParams)->off.port);
	Rect onDstRect = *dstRect, offDstRect = *dstRect;
	char hState = HGetState((Handle)offPixMap);
	RgnHandle tempRgn;

	PushPort();
	MapRect(&onDstRect, &(*theParams)->bounds, &(*theParams)->on.outer);
	MapRect(&offDstRect, &(*theParams)->bounds, &(*theParams)->off.outer);
	MySetPort((*theParams)->off.port);
	(*theParams)->dstrect = offDstRect;
	CustomCopy(src, srcRect, &offDstRect, (*theParams)->off.dither, nil,
				(*theParams)->quality);
	if ((*theParams)->extra.port) {
		Rect extraDstRect = *dstRect;
		MapRect(&extraDstRect, &(*theParams)->bounds, &(*theParams)->extra.outer);
		MySetPort((*theParams)->extra.port);
		(*theParams)->dstrect = extraDstRect;
		CustomCopy(src, srcRect, &extraDstRect, (*theParams)->extra.dither, nil, 
					(*theParams)->quality);
	}
	HLock((Handle)offPixMap);
	(*theParams)->src = *offPixMap;
	(*theParams)->srcrect = offDstRect;
	(*theParams)->dstrect = onDstRect;
	MySetPort((*theParams)->on.port);
	DeviceLoop((*theParams)->on.port->visRgn, gDeviceCopy, (long)theParams, singleDevices);
	if ((*theParams)->newupdates && (tempRgn = NewRgn())) {
		RectRgn(tempRgn, &onDstRect);
		DiffRgn((*theParams)->newupdates, tempRgn, (*theParams)->newupdates);
		DisposeRgn(tempRgn);
	}
	HSetState((Handle)offPixMap, hState);
	PopPort();
	if (onDstRect.bottom >= (*theParams)->endprogress) (*theParams)->endprogress = 0;
}

//=====================================================================================
// void DrawOnscreen(PixMap *src, Rect *srcRect, Rect *dstRect, 
// 			JVDrawParamsHandle theParams)
//=====================================================================================
// Do CopyBits drawing for onscreen.
//=====================================================================================

static void DrawOnscreen(PixMap *src, Rect *srcRect, Rect *dstRect, 
			JVDrawParamsHandle theParams)
{
#if applec
#pragma unused(src, srcRect)
#endif
	Rect onDstRect = *dstRect;
	RgnHandle tempRgn;

	PushPort();
	MapRect(&onDstRect, &(*theParams)->bounds, &(*theParams)->on.outer);
	(*theParams)->dstrect = onDstRect;
	MySetPort((*theParams)->on.port);
	DeviceLoop((*theParams)->on.port->visRgn, gDeviceCopy, (long)theParams, singleDevices);
	if ((*theParams)->newupdates && (tempRgn = NewRgn())) {
		RectRgn(tempRgn, &onDstRect);
		DiffRgn((*theParams)->newupdates, tempRgn, (*theParams)->newupdates);
		DisposeRgn(tempRgn);
	}
	PopPort();
	if (onDstRect.bottom >= (*theParams)->endprogress) (*theParams)->endprogress = 0;
}

//=====================================================================================
// void DrawOffscreen(PixMap *src, Rect *srcRect, Rect *dstRect, 
// 			JVDrawParamsHandle theParams)
//=====================================================================================
// Do CopyBits drawing for offscreen.
//=====================================================================================

static void DrawOffscreen(PixMap *src, Rect *srcRect, Rect *dstRect, 
			JVDrawParamsHandle theParams)
{
	Rect offDstRect = *dstRect;

	PushPort();
	MapRect(&offDstRect, &(*theParams)->bounds, &(*theParams)->off.outer);
	(*theParams)->dstrect = offDstRect;
	MySetPort((*theParams)->off.port);
	CustomCopy(src, srcRect, &offDstRect, (*theParams)->off.dither, nil, 
				(*theParams)->quality);
	if ((*theParams)->extra.port) {
		Rect extraDstRect = *dstRect;
		MapRect(&extraDstRect, &(*theParams)->bounds, &(*theParams)->extra.outer);
		(*theParams)->dstrect = extraDstRect;
		MySetPort((*theParams)->extra.port);
		CustomCopy(src, srcRect, &extraDstRect, (*theParams)->extra.dither, nil, 
					(*theParams)->quality);
	}
	PopPort();
}

//=====================================================================================
// pascal void DeviceCopy(short depth, short deviceFlags, GDHandle targetDevice, 
// 			void *tempParams)
//=====================================================================================
// Stub for calling CustomCopy for each device in the device list.
//=====================================================================================

static pascal void DeviceCopy(short depth, short deviceFlags, GDHandle targetDevice, 
			void *tempParams)
{
#if applec
#pragma unused(depth, deviceFlags)
#endif
	JVDrawParamsHandle theParams = (JVDrawParamsHandle)tempParams;
	Rect srcRect = (*theParams)->srcrect, dstRect = (*theParams)->dstrect;
	GDHandle oldDevice = GetGDevice();
	
	SetGDevice(targetDevice);
	CustomCopy((*theParams)->src, &srcRect, &dstRect, (*theParams)->on.dither, 
				(*theParams)->on.port->visRgn, (*theParams)->quality);
	SetGDevice(oldDevice);
}

//=====================================================================================
// Boolean IsGrayDevice(GDHandle theGDevice)
//=====================================================================================
// Checks an 8-bit device's color table and returns true if it's all grayscales.
//=====================================================================================

static Boolean IsGrayDevice(GDHandle theGDevice)
{
	PixMapHandle thePixMap = (*theGDevice)->gdPMap;
	ColorSpec *theSpec;
	short i;
	
	if ((*thePixMap)->pmTable && (*(*thePixMap)->pmTable)->ctSize == 255) {
		theSpec = (*(*thePixMap)->pmTable)->ctTable;
		for (i = 0; i < 256; i++) {
			if (theSpec->rgb.red != theSpec->rgb.green ||
						theSpec->rgb.red != theSpec->rgb.blue) return false;
			theSpec++;
		}
		return true;
	}
	return false;
}

//=====================================================================================
// void CustomCopy(PixMap *src, Rect *srcRect, Rect *dstRect, Boolean dither, 
// 			RgnHandle mask, short quality)
//=====================================================================================
// Do our custom copying.
//=====================================================================================

static void CustomCopy(PixMap *src, Rect *srcRect, Rect *dstRect, Boolean dither, 
			RgnHandle mask, short quality)
{
	PixMapHandle dst = (*GetGDevice())->gdPMap;
	Boolean oldState;
	
	if ((*dst)->pixelType != RGBDirect) {
		ITabHandle theITab = (*GetGDevice())->gdITable;
		CTabHandle theCTab = (*dst)->pmTable;
		if (theCTab && ((*dst)->pixelSize == 8))
			if (!theITab || ((*theITab)->iTabRes != 5) || 
						((*theITab)->iTabSeed != (*theCTab)->ctSeed))
				MakeITable(nil, nil, 5);
	}
	ClipRect(dstRect);
	RGBForeColor(&gBlack); 
	RGBBackColor(&gWhite);
	SpinIndef();
	switch (quality) {
		case iqVHigh:
			DrawVHighQuality(src, dst, srcRect, dstRect, dither, mask);
			break;
		case iqHigh:
			DrawHighQuality(src, dst, srcRect, dstRect, dither, mask);
			break;
		case iqMedium:
			oldState = GetQDxDispatchPatchState();
			if (oldState) RemoveQDxDispatchPatch();
			CallProperBitsProc((BitMap *)src, srcRect, dstRect, 
						dither ? srcCopy + ditherCopy : srcCopy, mask);
			if (oldState) InstallQDxDispatchPatch(true);
			break;
	}
	KeepSpinning();
	return;
}
			
//=====================================================================================
// void DrawVHighQuality(PixMapPtr src, PixMapHandle dst, Rect *srcRect, Rect *dstRect,
//			Boolean dither, RgnHandle mask)
//=====================================================================================
// Do very high-quality custom drawing.
//=====================================================================================

static void DrawVHighQuality(PixMapPtr src, PixMapHandle dst, Rect *srcRect, 
			Rect *dstRect, Boolean dither, RgnHandle mask)
{
	short srcDepth = (src->rowBytes & 0x8000) ? src->pixelSize : 1;
	
	if (srcDepth == 32 && (dither || (*dst)->pixelSize == 32)) {
		switch ((*dst)->pixelSize) {
			case 8:
				if (IsGrayDevice(GetGDevice())) break;
			case 16:
			case 32:
				DoCustomCopy(src, *dst, srcRect, dstRect, false, (*dst)->pixelSize);
				return;
		}
	}
	CallProperBitsProc((BitMap *)src, srcRect, dstRect, 
				dither ? srcCopy + ditherCopy : srcCopy, mask);
}

//=====================================================================================
// void DrawHighQuality(PixMapPtr src, PixMapHandle dst, Rect *srcRect, Rect *dstRect,
//			Boolean dither, RgnHandle mask)
//=====================================================================================
// Do high-quality custom drawing.
//=====================================================================================

static void DrawHighQuality(PixMapPtr src, PixMapHandle dst, Rect *srcRect, 
			Rect *dstRect, Boolean dither, RgnHandle mask)
{
	short srcDepth = (src->rowBytes & 0x8000) ? src->pixelSize : 1;
	
	if ((srcDepth == 32) && (dither || (*dst)->pixelSize == 32)) {
		switch ((*dst)->pixelSize) {
			case 32:
				break; 
			case 8:
				if (IsGrayDevice(GetGDevice())) break;
			case 16:
				DoCustomCopy(src, *dst, srcRect, dstRect, true, (*dst)->pixelSize);
				return;
		}
	}
	CallProperBitsProc((BitMap *)src, srcRect, dstRect, 
				dither ? srcCopy + ditherCopy : srcCopy, mask);
}

//=====================================================================================
// void ShowScaleDither(Boolean scaling, Boolean dither, Boolean state,
// 			JVDrawParamsHandle theParams)
//=====================================================================================
// Do high-quality custom drawing.
//=====================================================================================

static void ShowScaleDither(Boolean scaling, Boolean dither, Boolean state,
			JVDrawParamsHandle theParams)
{
	if ((*theParams)->progress.prog.progressProc) {
		if (scaling) CallICMProgressProc((*theParams)->progress.prog.progressProc, 
					codecProgressUpdateScaling, state, 
					(*theParams)->progress.prog.progressRefCon);
		else if (dither) CallICMProgressProc((*theParams)->progress.prog.progressProc, 
					codecProgressUpdateDithering, state, 
					(*theParams)->progress.prog.progressRefCon);
	}
}

//=====================================================================================
// void CopyFields(CGrafPtr src, CGrafPtr dst, Rect *srcRect, Rect *dstRect)
//=====================================================================================
// Sets the drawing parameters of the dst port to be indentical to those in the src
// port.
//=====================================================================================

static void CopyFields(CGrafPtr src, CGrafPtr dst, Rect *srcRect, Rect *dstRect)
{
	Point thePoint;
	long x, y;
	
	MySetPort(dst);
	CopyRgn(src->clipRgn, dst->clipRgn);
	MapRgn(dst->clipRgn, srcRect, dstRect);
	thePoint = src->pnLoc;
	MapPt(&thePoint, srcRect, dstRect);
	MoveTo(thePoint.h, thePoint.v);
	x = (long)src->pnSize.h * (long)Width(dstRect) / (long)Width(srcRect);
	y = (long)src->pnSize.v * (long)Height(dstRect) / (long)Height(srcRect);
	PenSize(x ? x : 1, y ? y : 1);
	PenMode(src->pnMode);
	TextFont(src->txFont);
	TextFace(src->txFace);
	TextMode(src->txMode);
	x = (long)src->txSize * (long)Height(dstRect) / (long)Height(srcRect);
	TextSize(x ? x : 1);
	y = (long)src->spExtra * (long)Width(dstRect) / (long)Width(srcRect);
	SpaceExtra(y ? y : 1);
	if (src->portVersion & 0x8000) {
		PixPatHandle thePixPat;
		if (DiffPixPat(src->pnPixPat, dst->pnPixPat) && (thePixPat = NewPixPat())) {
			CopyPixPat(src->pnPixPat, thePixPat);
			PenPixPat(thePixPat);
		}
		if (DiffPixPat(src->bkPixPat, dst->bkPixPat) && (thePixPat = NewPixPat())) {
			CopyPixPat(src->bkPixPat, thePixPat);
			BackPixPat(thePixPat);
		}
		RGBForeColor(&src->rgbFgColor);
		RGBBackColor(&src->rgbBkColor);
	} else {
		PenPat(&((GrafPtr)src)->pnPat);
		BackPat(&((GrafPtr)src)->bkPat);
		ForeColor(src->fgColor);
		BackColor(src->bkColor);
	}
}

//=====================================================================================
// Boolean DiffPixPat(PixPatHandle pp1, PixPatHandle pp2) 
//=====================================================================================
// Compares two PixPatHandles; returns true if they're different.
//=====================================================================================

static Boolean DiffPixPat(PixPatHandle pp1, PixPatHandle pp2)
{
	Size size1, size2;
	ulong *p1, *p2;
	
	if (!pp1) return false;
	if (!pp2) return true;
	if ((*pp1)->patType != (*pp2)->patType) return true;
	if (!(*pp1)->patData) return false;
	if (!(*pp2)->patData) return true;
	size1 = GetHandleSize((*pp1)->patData);
	size2 = GetHandleSize((*pp2)->patData);
	if (size1 != size2) return true;
	p1 = (ulong *)*(*pp1)->patData;
	p2 = (ulong *)*(*pp2)->patData;
	size1 >>= 2;
	while (size1--) if (*p1++ != *p2++) return true;
	return false;
}

//=====================================================================================
// pascal void JVTextProc(short count, void *textAddr, Point numer, Point denom)
//=====================================================================================
// Bottleneck to handle text drawing.
//=====================================================================================

static pascal void JVTextProc(short count, Ptr textAddr, Point numer, Point denom) 
{
	JVDrawParamsHandle theParams = FindParams((CGrafPtr)qd.thePort);
	Rect bounds, outer;

	if (!theParams) return;
	bounds = (*theParams)->bounds;
	KeepSpinning();
	if ((*theParams)->off.port) {
		PushPort();
		outer = (*theParams)->off.outer;
		CopyFields((CGrafPtr)qd.thePort, (*theParams)->off.port, &bounds, &outer);
		CallProperTextProc(count, textAddr, numer, denom);
		PopPort();
		if ((*theParams)->extra.port) {
			PushPort();
			outer = (*theParams)->extra.outer;
			CopyFields((CGrafPtr)qd.thePort, (*theParams)->extra.port, &bounds, &outer);
			CallProperTextProc(count, textAddr, numer, denom);
			PopPort();
		}
	}
	KeepSpinning();
	if ((*theParams)->on.port) {
		PushPort();
		outer = (*theParams)->on.outer;
		CopyFields((CGrafPtr)qd.thePort, (*theParams)->on.port, &bounds, &outer);
		CallProperTextProc(count, textAddr, numer, denom);
		PopPort();
	}
	KeepSpinning();
}

//=====================================================================================
// pascal void JVLineProc(Point newPt) 
//=====================================================================================
// Bottleneck to handle line drawing.
//=====================================================================================

static pascal void JVLineProc(Point newPt) 
{
	JVDrawParamsHandle theParams = FindParams((CGrafPtr)qd.thePort);
	Rect bounds, outer;
	Point thePoint;

	if (!theParams) return;
	bounds = (*theParams)->bounds;
	KeepSpinning();
	if ((*theParams)->off.port) {
		PushPort();
		outer = (*theParams)->off.outer;
		CopyFields((CGrafPtr)qd.thePort, (*theParams)->off.port, &bounds, &outer);
		thePoint = newPt;
		MapPt(&thePoint, &bounds, &outer);
		CallProperLineProc(thePoint);
		PopPort();
		if ((*theParams)->extra.port) {
			PushPort();
			outer = (*theParams)->extra.outer;
			CopyFields((CGrafPtr)qd.thePort, (*theParams)->extra.port, &bounds, &outer);
			thePoint = newPt;
			MapPt(&thePoint, &bounds, &outer);
			CallProperLineProc(thePoint);
			PopPort();
		}
	}
	KeepSpinning();
	if ((*theParams)->on.port) {
		PushPort();
		outer = (*theParams)->on.outer;
		CopyFields((CGrafPtr)qd.thePort, (*theParams)->on.port, &bounds, &outer);
		thePoint = newPt;
		MapPt(&thePoint, &bounds, &outer);
		CallProperLineProc(thePoint);
		PopPort();
	}
	KeepSpinning();
}

//=====================================================================================
// pascal void JVRectProc(GrafVerb verb, Rect *r) 
//=====================================================================================
// Bottleneck to handle rectangle drawing.
//=====================================================================================

static pascal void JVRectProc(GrafVerb verb, Rect *r) 
{
	JVDrawParamsHandle theParams = FindParams((CGrafPtr)qd.thePort);
	Rect theRect, bounds, outer;

	if (!theParams) return;
	bounds = (*theParams)->bounds;
	KeepSpinning();
	if ((*theParams)->off.port) {
		PushPort();
		outer = (*theParams)->off.outer;
		CopyFields((CGrafPtr)qd.thePort, (*theParams)->off.port, &bounds, &outer);
		theRect = *r;
		MapRect(&theRect, &bounds, &outer);
		CallProperRectProc(verb, &theRect);
		PopPort();
		if ((*theParams)->extra.port) {
			PushPort();
			outer = (*theParams)->extra.outer;
			CopyFields((CGrafPtr)qd.thePort, (*theParams)->extra.port, &bounds, &outer);
			theRect = *r;
			MapRect(&theRect, &bounds, &outer);
			CallProperRectProc(verb, &theRect);
			PopPort();
		}
	}
	KeepSpinning();
	if ((*theParams)->on.port) {
		PushPort();
		outer = (*theParams)->on.outer;
		CopyFields((CGrafPtr)qd.thePort, (*theParams)->on.port, &bounds, &outer);
		theRect = *r;
		MapRect(&theRect, &bounds, &outer);
		CallProperRectProc(verb, &theRect);
		PopPort();
	}
	KeepSpinning();
}

//=====================================================================================
// pascal void JVRRectProc(GrafVerb verb, Rect *r, short ovalWidth, short ovalHeight) 
//=====================================================================================
// Bottleneck to handle rounded rectangle drawing.
//=====================================================================================

static pascal void JVRRectProc(GrafVerb verb, Rect *r, short ovalWidth, short ovalHeight) 
{
	JVDrawParamsHandle theParams = FindParams((CGrafPtr)qd.thePort);
	Rect theRect, bounds, outer;

	if (!theParams) return;
	bounds = (*theParams)->bounds;
	KeepSpinning();
	if ((*theParams)->off.port) {
		PushPort();
		outer = (*theParams)->off.outer;
		CopyFields((CGrafPtr)qd.thePort, (*theParams)->off.port, &bounds, &outer);
		theRect = *r;
		MapRect(&theRect, &bounds, &outer);
		CallProperRRectProc(verb, &theRect, ovalWidth, ovalHeight);
		PopPort();
		if ((*theParams)->extra.port) {
			PushPort();
			outer = (*theParams)->extra.outer;
			CopyFields((CGrafPtr)qd.thePort, (*theParams)->extra.port, &bounds, &outer);
			theRect = *r;
			MapRect(&theRect, &bounds, &outer);
			CallProperRRectProc(verb, &theRect, ovalWidth, ovalHeight);
			PopPort();
		}
	}
	KeepSpinning();
	if ((*theParams)->on.port) {
		PushPort();
		outer = (*theParams)->on.outer;
		CopyFields((CGrafPtr)qd.thePort, (*theParams)->on.port, &bounds, &outer);
		theRect = *r;
		MapRect(&theRect, &bounds, &outer);
		CallProperRRectProc(verb, &theRect, ovalWidth, ovalHeight);
		PopPort();
	}
	KeepSpinning();
}

//=====================================================================================
// pascal void JVOvalProc(GrafVerb verb, Rect *r) 
//=====================================================================================
// Bottleneck to handle oval drawing.
//=====================================================================================

static pascal void JVOvalProc(GrafVerb verb, Rect *r) 
{
	JVDrawParamsHandle theParams = FindParams((CGrafPtr)qd.thePort);
	Rect theRect, bounds, outer;

	if (!theParams) return;
	bounds = (*theParams)->bounds;
	KeepSpinning();
	if ((*theParams)->off.port) {
		PushPort();
		outer = (*theParams)->off.outer;
		CopyFields((CGrafPtr)qd.thePort, (*theParams)->off.port, &bounds, &outer);
		theRect = *r;
		MapRect(&theRect, &bounds, &outer);
		CallProperOvalProc(verb, &theRect);
		PopPort();
		if ((*theParams)->extra.port) {
			PushPort();
			outer = (*theParams)->extra.outer;
			CopyFields((CGrafPtr)qd.thePort, (*theParams)->extra.port, &bounds, &outer);
			theRect = *r;
			MapRect(&theRect, &bounds, &outer);
			CallProperOvalProc(verb, &theRect);
			PopPort();
		}
	}
	KeepSpinning();
	if ((*theParams)->on.port) {
		PushPort();
		outer = (*theParams)->on.outer;
		CopyFields((CGrafPtr)qd.thePort, (*theParams)->on.port, &bounds, &outer);
		theRect = *r;
		MapRect(&theRect, &bounds, &outer);
		CallProperOvalProc(verb, &theRect);
		PopPort();
	}
	KeepSpinning();
}

//=====================================================================================
// pascal void JVArcProc(GrafVerb verb, Rect *r, short startAngle, short arcAngle) 
//=====================================================================================
// Bottleneck to handle arc drawing.
//=====================================================================================

static pascal void JVArcProc(GrafVerb verb, Rect *r, short startAngle, short arcAngle) 
{
	JVDrawParamsHandle theParams = FindParams((CGrafPtr)qd.thePort);
	Rect theRect, bounds, outer;

	if (!theParams) return;
	bounds = (*theParams)->bounds;
	KeepSpinning();
	if ((*theParams)->off.port) {
		PushPort();
		outer = (*theParams)->off.outer;
		CopyFields((CGrafPtr)qd.thePort, (*theParams)->off.port, &bounds, &outer);
		theRect = *r;
		MapRect(&theRect, &bounds, &outer);
		CallProperArcProc(verb, &theRect, startAngle, arcAngle);
		PopPort();
		if ((*theParams)->extra.port) {
			PushPort();
			outer = (*theParams)->extra.outer;
			CopyFields((CGrafPtr)qd.thePort, (*theParams)->extra.port, &bounds, &outer);
			theRect = *r;
			MapRect(&theRect, &bounds, &outer);
			CallProperArcProc(verb, &theRect, startAngle, arcAngle);
			PopPort();
		}
	}
	KeepSpinning();
	if ((*theParams)->on.port) {
		PushPort();
		outer = (*theParams)->on.outer;
		CopyFields((CGrafPtr)qd.thePort, (*theParams)->on.port, &bounds, &outer);
		theRect = *r;
		MapRect(&theRect, &bounds, &outer);
		CallProperArcProc(verb, &theRect, startAngle, arcAngle);
		PopPort();
	}
	KeepSpinning();
}

//=====================================================================================
// pascal void JVPolyProc(GrafVerb verb, PolyHandle poly) 
//=====================================================================================
// Bottleneck to handle polygon drawing.
//=====================================================================================

static pascal void JVPolyProc(GrafVerb verb, PolyHandle poly) 
{
	JVDrawParamsHandle theParams = FindParams((CGrafPtr)qd.thePort);
	Rect bounds, outer;
	PolyHandle thePoly;

	if (!theParams) return;
	bounds = (*theParams)->bounds;
	KeepSpinning();
	if ((*theParams)->off.port) {
		PushPort();
		outer = (*theParams)->off.outer;
		CopyFields((CGrafPtr)qd.thePort, (*theParams)->off.port, &bounds, &outer);
		thePoly = poly;
		if (HandToHand((Handle *)&thePoly) == noErr) {
			MapPoly(thePoly, &bounds, &outer);
			CallProperPolyProc(verb, thePoly);
			DisposeHandle((Handle)thePoly);
		}
		PopPort();
		if ((*theParams)->extra.port) {
			PushPort();
			outer = (*theParams)->extra.outer;
			CopyFields((CGrafPtr)qd.thePort, (*theParams)->extra.port, &bounds, &outer);
			thePoly = poly;
			if (HandToHand((Handle *)&thePoly) == noErr) {
				MapPoly(thePoly, &bounds, &outer);
				CallProperPolyProc(verb, thePoly);
				DisposeHandle((Handle)thePoly);
			}
			PopPort();
		}
	}
	KeepSpinning();
	if ((*theParams)->on.port) {
		PushPort();
		outer = (*theParams)->on.outer;
		CopyFields((CGrafPtr)qd.thePort, (*theParams)->on.port, &bounds, &outer);
		thePoly = poly;
		if (HandToHand((Handle *)&thePoly) == noErr) {
			MapPoly(thePoly, &bounds, &outer);
			CallProperPolyProc(verb, thePoly);
			DisposeHandle((Handle)thePoly);
		}
		PopPort();
	}
	KeepSpinning();
}

//=====================================================================================
// pascal void JVRgnProc(GrafVerb verb, RgnHandle rgn) 
//=====================================================================================
// Bottleneck to handle polygon drawing.
//=====================================================================================

static pascal void JVRgnProc(GrafVerb verb, RgnHandle rgn) 
{
	JVDrawParamsHandle theParams = FindParams((CGrafPtr)qd.thePort);
	Rect bounds, outer;
	RgnHandle theRgn;

	if (!theParams) return;
	bounds = (*theParams)->bounds;
	KeepSpinning();
	if ((*theParams)->off.port) {
		PushPort();
		outer = (*theParams)->off.outer;
		CopyFields((CGrafPtr)qd.thePort, (*theParams)->off.port, &bounds, &outer);
		if (theRgn = NewRgn()) {
			CopyRgn(rgn, theRgn);
			MapRgn(theRgn, &bounds, &outer);
			CallProperRgnProc(verb, theRgn);
			DisposeHandle((Handle)theRgn);
		}
		PopPort();
		if ((*theParams)->extra.port) {
			PushPort();
			outer = (*theParams)->extra.outer;
			CopyFields((CGrafPtr)qd.thePort, (*theParams)->extra.port, &bounds, &outer);
			if (theRgn = NewRgn()) {
				CopyRgn(rgn, theRgn);
				MapRgn(theRgn, &bounds, &outer);
				CallProperRgnProc(verb, theRgn);
				DisposeHandle((Handle)theRgn);
			}
			PopPort();
		}
	}
	KeepSpinning();
	if ((*theParams)->on.port) {
		PushPort();
		outer = (*theParams)->on.outer;
		CopyFields((CGrafPtr)qd.thePort, (*theParams)->on.port, &bounds, &outer);
		if (theRgn = NewRgn()) {
			CopyRgn(rgn, theRgn);
			MapRgn(theRgn, &bounds, &outer);
			CallProperRgnProc(verb, theRgn);
			DisposeHandle((Handle)theRgn);
		}
		PopPort();
	}
	KeepSpinning();
}

//=====================================================================================
// void CallProperBitsProc(BitMap *src, Rect *srcRect, Rect *dstRect, short mode, 
//			RgnHandle mask) 
//=====================================================================================
// Call StdBits, or a bottleneck function, as appropriate for the current port.
//=====================================================================================

extern void CallProperBitsProc(BitMap *src, Rect *srcRect, Rect *dstRect, short mode, 
			RgnHandle mask)
{
	if (qd.thePort->grafProcs && ((CGrafPtr)qd.thePort)->grafProcs->bitsProc)
		CallQDBitsProc(((CGrafPtr)qd.thePort)->grafProcs->bitsProc, (BitMap *)src, 
					srcRect, dstRect, mode, mask);
	else StdBits((BitMap *)src, srcRect, dstRect, mode, mask);
}

//=====================================================================================
// void CallProperTextProc(short count, const void *textAddr, Point numer, Point denom) 
//=====================================================================================
// Call StdText, or a bottleneck function, as appropriate for the current port.
//=====================================================================================

extern void CallProperTextProc(short count, Ptr textAddr, Point numer, Point denom)
{
	if (qd.thePort->grafProcs && ((CGrafPtr)qd.thePort)->grafProcs->textProc)
		CallQDTextProc(((CGrafPtr)qd.thePort)->grafProcs->textProc, count, textAddr,
					numer, denom);
	else StdText(count, textAddr, numer, denom);
}

//=====================================================================================
// void CallProperLineProc(Point newPt) 
//=====================================================================================
// Call StdLine, or a bottleneck function, as appropriate for the current port.
//=====================================================================================

extern void CallProperLineProc(Point newPt)
{
	if (qd.thePort->grafProcs && ((CGrafPtr)qd.thePort)->grafProcs->lineProc)
		CallQDLineProc(((CGrafPtr)qd.thePort)->grafProcs->lineProc, newPt);
	else StdLine(newPt);
}

//=====================================================================================
// void CallProperRectProc(GrafVerb verb, Rect *r) 
//=====================================================================================
// Call StdRect, or a bottleneck function, as appropriate for the current port.
//=====================================================================================

extern void CallProperRectProc(GrafVerb verb, Rect *r)
{
	if (qd.thePort->grafProcs && ((CGrafPtr)qd.thePort)->grafProcs->rectProc)
		CallQDRectProc(((CGrafPtr)qd.thePort)->grafProcs->rectProc, verb, r);
	else StdRect(verb, r);
}

//=====================================================================================
// void CallProperRRectProc(GrafVerb verb, Rect *r, short ovalWidth, short ovalHeight) 
//=====================================================================================
// Call StdRRect, or a bottleneck function, as appropriate for the current port.
//=====================================================================================

extern void CallProperRRectProc(GrafVerb verb, Rect *r, short ovalWidth, short ovalHeight)
{
	if (qd.thePort->grafProcs && ((CGrafPtr)qd.thePort)->grafProcs->rRectProc)
		CallQDRRectProc(((CGrafPtr)qd.thePort)->grafProcs->rRectProc, verb, r, ovalWidth, 
					ovalHeight);
	else StdRRect(verb, r, ovalWidth, ovalHeight);
}

//=====================================================================================
// void CallProperOvalProc(GrafVerb verb, Rect *r) 
//=====================================================================================
// Call StdOval, or a bottleneck function, as appropriate for the current port.
//=====================================================================================

extern void CallProperOvalProc(GrafVerb verb, Rect *r)
{
	if (qd.thePort->grafProcs && ((CGrafPtr)qd.thePort)->grafProcs->ovalProc)
		CallQDOvalProc(((CGrafPtr)qd.thePort)->grafProcs->ovalProc, verb, r);
	else StdOval(verb, r);
}

//=====================================================================================
// void CallProperArcProc(GrafVerb verb, Rect *r, short startAngle, short arcAngle) 
//=====================================================================================
// Call StdArc, or a bottleneck function, as appropriate for the current port.
//=====================================================================================

extern void CallProperArcProc(GrafVerb verb, Rect *r, short startAngle, short arcAngle)
{
	if (qd.thePort->grafProcs && ((CGrafPtr)qd.thePort)->grafProcs->arcProc)
		CallQDArcProc(((CGrafPtr)qd.thePort)->grafProcs->arcProc, verb, r, startAngle,
					arcAngle);
	else StdArc(verb, r, startAngle, arcAngle);
}

//=====================================================================================
// void CallProperPolyProc(GrafVerb verb, PolyHandle poly) 
//=====================================================================================
// Call StdPoly, or a bottleneck function, as appropriate for the current port.
//=====================================================================================

extern void CallProperPolyProc(GrafVerb verb, PolyHandle poly)
{
	if (qd.thePort->grafProcs && ((CGrafPtr)qd.thePort)->grafProcs->polyProc)
		CallQDPolyProc(((CGrafPtr)qd.thePort)->grafProcs->polyProc, verb, poly);
	else StdPoly(verb, poly);
}

//=====================================================================================
// void CallProperRgnProc(GrafVerb verb, RgnHandle rgn) 
//=====================================================================================
// Call StdRgn, or a bottleneck function, as appropriate for the current port.
//=====================================================================================

extern void CallProperRgnProc(GrafVerb verb, RgnHandle rgn)
{
	if (qd.thePort->grafProcs && ((CGrafPtr)qd.thePort)->grafProcs->rgnProc)
		CallQDRgnProc(((CGrafPtr)qd.thePort)->grafProcs->rgnProc, verb, rgn);
	else StdRgn(verb, rgn);
}

//=====================================================================================
// void CallProperPixProc(PixMap *src, Rect *srcRect, MatrixRecord *matrix, short mode,
//			RgnHandle mask, PixMap *matte, Rect *matteRect, short flags) 
//=====================================================================================
// Call StdRgn, or a bottleneck function, as appropriate for the current port.
//=====================================================================================

extern void CallProperPixProc(PixMap *src, Rect *srcRect, MatrixRecord *matrix, short mode,
			RgnHandle mask, PixMap *matte, Rect *matteRect, short flags)
{
	if (qd.thePort->grafProcs && ((CGrafPtr)qd.thePort)->grafProcs->newProc1)
		CallStdPixProc((StdPixUPP)((CGrafPtr)qd.thePort)->grafProcs->newProc1, src, 
					srcRect, matrix, mode, mask, matte, matteRect, flags);
	else StdPix(src, srcRect, matrix, mode, mask, matte, matteRect, flags);
}
