/*
	File:		Bass_Cache.c

	Contains:	Interfaces between Font Scaler code, QuickDraw and the Font Manager.  Retrieves
				and caches glyphs.  Initializes spline state variables.

	Written by:	Charlton E. Lui
	
	Date:		May 8, 1988
	
	Revision:	1.0

	Copyright:	© 1988-1992 by Apple Computer, Inc., all rights reserved.

	Change History (most recent first):

		<23>	 6/22/92	JH		#1033107 <AMW>: Changed call to GetEncodingTable to
									Font2RealScript.
		<22>	  5/3/92	JH		#1028023 <AMW>: Changing straight jump to fs_NewSfnt to the trap
									version. This enables our Korean subsidiary and potentially
									other non U.S distributors to patch the NewSfnt trap and look
									for a dongle.
		<21>	  1/3/92	JSM		Roll-in changes from Sakura: sb_CheckCache() can return NO_BITS
									from sb_RenderGlyph() (seems to only happen when printing with
									the StyleWriter), check for this and call
									CheckForMaximumDiskCacheSize() in sb_RetrieveGlyph() anyway. We
									need to understand this better. Call
									DumpFontCacheToDiskIfNotTooBig(), not DumpFontCacheToDisk(), in
									sb_DisposeCacheHandle(). Pass squashed to
									LoadFontCacheFromDisk(). If banding in TrueType, don't
									AddGlyphOffset table more than once in sb_RetrieveGlyph.
		<20>	 12/9/91	JH		#1017215,Fixing problem in sb_SetFontMemory... where if
									fs_NewSfnt fails it just bails (calls sb_Debug). The thing about
									this is that we (whose we) have released about 16 international
									fonts that actually have a specificID of Roman for their CMAP
									despite being fonts for scripts other than Roman. These fonts
									work on 7.0, but since we now do the right thing in
									sb_SetFontMemory (figure out which script the font should belong
									to and then use that script for specificID) they won't work for
									7.1 (cubee) so to fix that we try again with the Roman platform
									ID if the first call to sb_SetFontMemory fails.
		<19>	10/23/91	DTY		Flush the FOND candidate cache in sb_KillSomeCaches when
									everything else is being flushed.
		<18>	10/22/91	RB		Add support for sfnt-embedded-bitmaps
		<17>	  9/25/91	jlf		Rolled in modifications from Pacific TrueType project and rolled out
									DOUBLE_BYTE conditional code.
									
									Added support for double-byte bass caches. The glyphArray field of a
									cache is not compatible with double-byte operating systems. Use the
									routines in DoubleByteBassCache.c for international support. Added
									support for disk caching code through the LoadFontCacheFromDisk and
									CheckForMaximumDiskCacheSize routines. The spline directory of a
									TrueType font is now appended to it's global width table for partial
									font support. sb_SetMemPtrs now accepts a widthTable handle instead of
									an sfnt handle in order to initialize the spline sfntDirectory field
									of the Scaler input parameter block. Call GetResInfo to obtain the sfntID
									in FillPrinterWidths instead of hacking it to zero - it would be nice if
									the printer driver passed the sfntID value in, but, that means we would
									have to rev all printer drivers that use this call. Added partial font
									support. Added disposecachehandle routine to support disk caching (routine
									calls DumpFontCacheToDisk before calling disposezonehandle). Call
									sb_DisposeCacheHandle in sb_KillSomeCaches instead of letting the cache
									handles die through a heap reformat. Replaced calls to sb_DisposeZoneHandle
									with cache handle arguments with calls to sb_DisposeCacheHandle. Call
									KillApplicationHeapFragmentTableCaches in flush fonts to flush partial
									font fragments. Removed static qualifier in front of sb_ShrinkCacheToMin.
									Initialize familyID field of a cache in sb_InitCacheHead to the new spline
									key global fLastSwapFontFamilyID since the font manager has the obnoxious
									habit of setting the fID field of a width table and certain low memory
									globals to -1 when the width table is invalidated. This caused major
									problems with cmap lookup when using Asian fonts. Added widthTable parameter
									to SetFontMemory since it calls SetMemPtrs. Initialized specificID field
									of newsfnt input parameter block to the proper script number instead of
									hard-coding it to Roman. Always maintain the cache list in the system heap.
									sb_NewZoneHandle no longer assumes that the current heap is always the
									application heap (this previously caused major heap trashes when the
									system font was an outline font). Rolled back in code for MultiFinder
									memory allocation (this code relies on a bug fix in 6.x MultiFinder
									where the current zone is set to the MultiFinder heap before calling
									TempDisposHandle on a purged handle. 7.x systems shouldn't be affected).
									Rolled in fixes for bugs found during the development of the background
									Tabasco driver (Charlton Lui via Allen Cronce). I friggin' hate this file.
									
		<16>	  3/5/91	CL		(RB)#82681. Needed to make one more change to sb_searchforcache.
									The cache needed to be set to nil to when a cache was
									purged.
		<15>	 2/28/91	CL		(KON)(RB)#82681. Making current cache purgeable.
		<14>	 2/11/91	RB		MR, CL,CC,: Fix dropouts when squashing by trying twice to
									squash rather than once.
		<11>	 1/22/91	CL		(RB) #81198, #81199. Fixing large glyph crash (ptsize 22,000
									pt). Need to pass on error codes.
		<10>	12/11/90	MR		Improve squishing math, use leading from cache for fmLeading.
									Low mem hack. [rb]
		 <9>	11/27/90	MR		Change ByteMax() to return an unsigned char, stop caching
									algo-styles [rb]
		 <8>	11/21/90	CL		(RB)Adding in scan converter runInMinMode operations. Broke
									sb_renderglyph into smaller subroutines.
		 <7>	10/29/90	CL		(RB)if fs_OpenFonts fails we need to get rid of the workhandle
									since it is only partially set up for use. Needed to call
									sb_setmemptrs before settting the clientid.
		 <6>	10/23/90	CL		(MR)Making the preflight call work better.
		 <5>	10/23/90	CL		Somehow this file got corrupt by either BBS, projector or the
									compare file tool??? Fixed it back up!!!
		 <4>	10/22/90	CL		(BKR)Adding runInMinMode code. This will run in a minimal memory
									space when memory is very low. Added in banding of character for
									low memory situations.
		 <3>	10/20/90	MR		Change transform[2][2] from a fix_one to         frac_one
		<2+>	10/20/90	MR,rb	Change transform[2][2] from a fix_one to frac_one
		 <2>	10/11/90	CL		Set ENTRY_ERROR to skip glyphs with zero scan lines.
	    <34>	 10/9/90	CL		Added preflight routine to see if there seems to be enough
	   								room to render the glyphs.
	    <33>	 10/2/90	CL		Fixing up memory error handling.
	    <32>	 9/24/90	CL		Fixing error handling in sb_renderglyph. Needed to check
									the result after sb_renderglyphinfo call.
	    <31>	 9/10/90	CL		Added in a shrinkTest to sb_SizeTheBlock to see whether a block
									should be resized down.  This is good for sizing down the extra
									scan converter space needed for large chars and for large bitmapHands.
	    <30>	 9/10/90	CL		Now checking if system and app heap is full.  If so purge will
	   								be left on.  When both heaps are full it will switch back
									and forth to try to get the memory.  Conditional is in for
									Multi-Finder or system memory.
	    <29>	  9/5/90	CL		Getting rid of call to sb_Debug in sb_newZoneHandle since it
									really is not an error but just a possible temporary failure.
									Bug in sb_FlushFontsÉ needed to zero out the cacheListHand.
	   	<28>	  9/4/90	CL		Fixing up memory allocationsÉ Bug in sb_GrowZoneHandle - Assigned
	   								new zone before DiposeZoneHandle giving this function possibly
									the wrong zone.  Reworked sb_GrowZoneHandle, sb_NewZoneHandle
									logic.  Added in sb_SetCachesNoPurge, sb_SetCachesPurge so caches
									would not unneccessarily get purged.  Took out splineKeyPtr param
									out of sb_DisposeWorkHandle to make code consistent. Took out
									extra call to sb_PrepareWorkHandle from sb_CheckCache.  Bug in
									original sb_GrowZoneHandle code now in sb_SizeTheBlock fix.  When
									a disposeZoneHandle was called the current cache was not cleared
									so it would be used and blamo the heap free list would get
									corrupt.  Bug in sb_SearchForCacheÉ Must make the font non-purgeable
									before calling sb_PrepareWorkHandle and sb_SetNewSFNT.  Font got
									purged when it should not have.  Got rid of the now unneeded
									call to sb_initmemory.  Major bug in the sb_GrowZoneHandle that
									is now in the sb_SizeTheBlock routine.  This routine would
									dispose a handle without being able to update the variables
									from the calling routine.  Therefore you could dispose the
									handle, try to get a new handle and fail, then try to use the
									disposed handle which would of course corrupt the free list
									eventually causing major havoc in the system. Bug when calling
									sb_shrinkbitmap on a cached contour.  Since the scan lines
									could be less than the full height the shrink bitmap call would
									go to far since it used the full scan height that is cached
									in the font cache.  Bug when allocating with the new memory
									routines the bitmapHand needs to be disposed and cleared if
									it is in the quiting apps heap space.  Terrible bug in living
									in the MultiFinder temp memory and being purgeable.  There is
									no way to know the zone and we would die if we dipose the handle
									not knowing the true zone if it is in the Multi_Finder heap.  Fixed
									by living only in the system heap and application heap as we did before
									just like the init code does now.
		<27>	  9/4/90	KSM		Fix Begin/EndSystem mode bug in sb_NewZoneHandle.
		<26>	 8/28/90	MR		Change SetHandleSize calls to set the correct zone by using
									common routines (NewZoneHandle, GrowZoneHandle,
									DisposeZoneHandle).  Changed WorkHandMem to ResizeWorkHandle.
									Added calls to PrepareWorkHandle to pascal routines that use
									fsWorkHand but didn't first check it.  Moved bitmapHand and
									fsWorkHand to use same memory routines as caches.
		<25>	 8/27/90	MR		Fix uninitialized zone in SearchForCache, added call to gestalt
									to NOT use system heap if it is not growable.
		<24>	 8/22/90	MR		Change calls to FillWidthTable to pass sfnt handle and rsrc ID
		<23>	 8/21/90	MR		More consistant checking of fsWorkHand for purginess.  Still not
									completely confident IÕve caught every case.
		<22>	 8/20/90	MR		Restructure memory allocation across heaps.  New routines:
									NewCacheHandle, NewWorkHandle, sb_DisposeZoneHandle.  Conditional
									code for system_7 and init.
		<21>	 8/11/90	MR		Use splineKey as global instead of passing it as a parameter
		<20>	 8/10/90	MR		Removed conditional MIKE code
		<19>	 8/10/90	MR		Remove disk_cache code, Removed call to ReallocHandle in
									SearchForCache (cross-zone bug)
		<18>	  8/1/90	gbm		rid file of vile warnings
		<17>	 7/20/90	MR		change NewHandleSys to NewHandleSys
		<16>	 7/20/90	MR		Remove warnings, cache optimizations, found cacheHand-purge bug
		<15>	 7/18/90	MR		Add Fonts.h to include file list (to define FMOutput since it
									was removed from bass_cache.h
		<14>	 7/16/90	CL		Made Finder compatible for the Goudy init.
		<13>	 7/14/90	MR		changed reference from SQRT2 to FIXEDSQRT2
		<12>	 7/13/90	MR		Changed to use union in FSInput
		<11>	  7/2/90	RB		No change, just get comments synched
		<9+>	  7/2/90	RB		bbs screwup
		 <9>	  7/2/90	CL		Fixed runtime conditional to make sure it clips when needed.
		 <8>	  7/2/90	CL		Reworked sb_renderGlyphÉ Now clips the character if squishing
									was not enough. Took out encryption.
		 <7>	 5/29/90	CL		Took out cache references from the widthtables. Fixed printer
									Font Scaler reset bug.
		 <6>	  5/3/90	CL		Adding shutdown proc for bass clean up. More work on disk
									caching. Removed extra part of transform matrix not needed by
									system. In sb_FlushFonts got rid disposed of Handles that had
									nil pointers. Adding support for new encryption scheme and scan
									converter. Added new memory area
		 <5>	 4/10/90	CL		Added support for double byte codes. Worked on disk caching.
									Fixed squishing routine.
		 <4>	 3/24/90	CL		Font Scaler is returning totally bogus values causing terrible
									stack corruption. Added range checking so we can handle these
									values.
		 <3>	 3/20/90	CL		Adding Disk CacheÉ  Support for the tag format
		 <2>	 2/27/90	CL		Added lots of support for DrTextÕs optimizations.   Added a
									routine to shrink bitmaps after the Font Scaler call and save a
									possible 2x in memory usage.  Re-wrote renderglyph.
	   <2.0>	11/16/89	CEL		Fix in sb_fillprinterwidths. Bad assign from ReallocHandle.
	   <1.9>	11/15/89	CEL		Oops forgot to check memerr in sb_fillprinterwidths.
	   <1.8>	11/14/89	CEL		Added device metrics. Added device capabilities.
	   <1.7>	 9/28/89	CEL		KillSomeCaches now make sure to get rid of purged font handles
									also.
	   <1.6>	 9/25/89	CEL		Was setting numer and denom back to identity for splines since
									splines do the stretch but this would cause bad font manager
									matching. Let the v and h factors to be set back to 1. Added
									back in rounding of widths for width table when fractenable is
									off.
	   <1.5>	 9/15/89	CEL		Checking in just in case something changed that reflects the
									Bass_Cache.h file.
	   <1.4>	 8/28/89	CEL		Put in conditional for debugger state. Only drops into debugger
									if flag is set by hacker.
	   <1.3>	 8/14/89	CEL		Added in new encryption checks. Looks in more places for bitmap
									temp memory.
	   <1.2>	  8/1/89	CEL		Fixed EASEÕs ÒCÓ comment brackets. On check in they were wrong!
	   <1.1>	  8/1/89	CEL		Fixed the include file buffer.h to be Bass_Cache.h
	   <1.0>	  8/1/89	CEL		Adding into Bass build for the first timeÉ
	   <1.9>	  8/1/89	CEL		Fixed over-run array bug. Re-worked data structures.
	   <1.8>	 6/13/89	CEL		Integrated SampoÕs changes to the GlyphInputTypeÉ
	   <1.7>	 6/10/89	CEL		Moved Private.a QuickDraw Equates into proper QuickDraw private
									file (colorequ.a), got rid of QuickDraw nFiles dependencies and
									fixed up necessary filesÉ
	   <1.6>	  6/2/89	CEL		Took out hard coded ascent, descent, leading calculationsÉ
	   <1.5>	 5/26/89	CEL		Integrated the new Font Scaler 1.0 into Spline Fonts
	   <1.4>	 5/15/89	CEL		Bug in sb_SearchForCache - compared purged cache
	   <1.3>	  5/3/89	CEL		Comment brackets were previously messed up from override
	  <¥1.2>	  5/3/89	CEL		All kinks worked out, Blasting in bass filesÉ
	  <¥1.1>	  5/2/89	CEL		Changed glue.h include file to BassGlue.h
	   <1.0>	  5/1/89	cel		Adding Bass for first timeÉ

	To Do:
*/
/*********************/
/** System Includes **/
/*********************/
#include	"BaseIncludes.h"
#include 	<types.h>
#include	<Errors.h>
#include	<memory.h>
#include	<MFPrivate.h>
#include	<QuickDraw.h>
#include	<FixMath.h>
#include 	"ToolUtils.h"
#include 	<resources.h>
#include	<Script.h>
#include	<ShutDown.h>
#include	<Fonts.h>
#include	<GestaltEqu.h>
#include	<SysEqu.h>
#include	<ScriptPriv.h>

/*********************/
/** BASSÕs Includes **/
/*********************/
#include	"FSCdefs.h"
#include	"FontScaler.h"
#include	"MacExtra.h"
#include	"FragmentTable.proto"
#include	"PartialFontExtensions.proto"
#include	"Bass_Cache.h"
#include	"SplineError.h"
#include	"FontMath.h"
#include	"sfnt.h"

#include	"DoubleByteBassCache.h"
#include	"DiskCacheExtensions.proto"

/*  prototypes for DoubleByteBassCache.c routines  */

OSErr									AddLowByteGlyphOffsetTable( uint16 glyphID, sb_SplineKeyHdl splineKey );	
uint32									GetSingleOrDoubleByteGlyphEntryOffset( uint16 glyphID, sb_CacheHeadPtr cachePointer );
extern pascal EncodingTablePointer		GetEncodingTable( short fondID, uint16 *scriptCodePointer );

//
//The trap version of this trap is deffed out unless MACINIT is true
//so just define a new constant here, FS_NEWSFNT is defined in FontScaler.h <22>
//
pascal int32 __NewSfntTrap(fs_GlyphInputType *inputPtr, fs_GlyphInfoType *outputPtr)
	= {0x303C,FS_NEWSFNT,0xA854};


#ifndef INITVERSION
#define SYSTEM_7
#endif



#ifdef DEBUG
N2S(unsigned long n, Str255 s)
{
	short i;
	for (i = 10; i > 0; i--)
	{
		char c = n % 10;
		s[i] = '0' + c;
		n /= 10;
	}
	s[0] = 10;
}

HeapCheck()
{
	Str255 s;
	s[0] = 0;
	s[++s[0]] = ';';
	s[++s[0]] = 'h';
	s[++s[0]] = 'c';
	s[++s[0]] = ';';
	s[++s[0]] = 'g';
	s[++s[0]] = ';';
	DebugStr(s);
}
#endif

extern Boolean MultiFinderExist();
extern long PurgeSpaceSysTotal();
long sb_SetUpWorkHand();

/***********************************************************************************************/								
/***********************************************************************************************/								
										/***********/
										/** DEBUG **/
										/***********/
										

static void sb_Debug()
{
	sb_SplineKeyHdl					splineKey		= SPLINE_KEY_HAND;

	if ((*splineKey)->callDebug)		Debugger();
}	/* End sb_Debug */


static char *sb_ReturnDataPointer ( sfntHand, offset, length )
Handle 		sfntHand;
long 		offset, length;
{
	int	i	= length;
	return( *sfntHand + offset );
}

static long LONG_WORD_ALIGN ( long n )
{
	return( (n + 3) & ~3 );
}

static unsigned char ByteMax ( Fixed n )
{
	register short		shortVal = FixRound(n);			/* get rid of low bits */
	
	if (shortVal > 255)		shortVal = 255;
	
	return(shortVal );
}

static char ByteRange ( Fixed n )
{
	register short		shortVal = FixRound(n);			/* get rid of low bits */
	
	if (shortVal > 127)				shortVal = 127;
	else if (shortVal < -127)		shortVal = -127;
	
	return(shortVal);
}

/***********************************************************************************************/								
									/******************/
									/**	MEMORY CALLS **/
									/******************/

/*********************************************************************************************
**									sb_DisposeZoneHandle
**
**	Allocations are made in different zones and a handle may be purged.  When this is the case
**	the memory manager does not have the ptr to figure out what zone it is coming from so it
**	can not hook the memory links up correctly.
**
**	Switch to the correct zone and dipose the handle and then return back to the previous zone.
**
**	<28-CEL> added some comments
**
*/
void sb_DisposeZoneHandle(Handle h, THz zonePtr)
{
	THz		prevZone = GetZone();
	OSErr	error = noErr;
	
	if (zonePtr) {
		SetZone(zonePtr);
		DisposHandle(h);
		SetZone(prevZone);
	} else MFTempDisposHandle(h, &error);
	
}	/* End sb_DisposeZoneHandle */



/*********************************************************************************************
**									sb_SetCachesNoPurge			<28-CEL>
**
**	Run through the caches which have not been purged and make them non-purgeable
**
**	WHEN TO CALL: System heap allocation
**	WHY: System heap only guestimates when to grow which can cause purgeability or caches.
**
*/
void sb_SetCachesNoPurge()
{
	sb_SplineKeyHdl					splineKey		= SPLINE_KEY_HAND;
	register sb_SplineKeyPtr		splineKeyPtr	= *splineKey;

	if (splineKeyPtr->cacheListHandle) {
		register short 				fontCount	= splineKeyPtr->fontCount;
		register CacheReference* 	cacheRef	= *splineKeyPtr->cacheListHandle;

		for (--fontCount; fontCount >= 0; --fontCount) {
			if (cacheRef->cache && *cacheRef->cache)		/* have a ptr??? */
				HNoPurge(cacheRef->cache);
			cacheRef++;
		}
	}

}	/* End sb_SetCachesNoPurge */



/*********************************************************************************************
**									sb_SetCachesPurge			<28-CEL>
**
**	Run through the caches which have not been purged and make them purgeable
**
**	WHEN TO CALL: After system heap memory allocations have been made,
**				  if sb_SetCachesNoPurge was called.
**
*/
void sb_SetCachesPurge()
{
	sb_SplineKeyHdl					splineKey		= SPLINE_KEY_HAND;
	register sb_SplineKeyPtr		splineKeyPtr	= *splineKey;
	register Handle					curCacheHand	= splineKeyPtr->cacheHand;

	if (splineKeyPtr->cacheListHandle) {
		register short 				fontCount	= splineKeyPtr->fontCount;
		register CacheReference* 	cacheRef	= *splineKeyPtr->cacheListHandle;

		for (--fontCount; fontCount >= 0; --fontCount) {
			if (cacheRef->cache && *cacheRef->cache)		/* have a ptr??? */
				HPurge(cacheRef->cache);
			cacheRef++;
		}
	}
	if (curCacheHand && *curCacheHand)		HNoPurge(curCacheHand);	/* Keep current cache non-purgeable */

}	/* End sb_SetCachesPurge */

#ifndef USE_SYSTEM_HEAP
/*********************************************************************************************
**									sb_MultiFinderHandle			<30-CEL>
**
**	Call the Mutlifinder memory manager.
**	Since this is system type memory make sure to turn on BeginSystem mode to make
**	sure Multifinder does not release the memory when the application quits!
**
*/
Handle sb_MultiFinderHandle(long blockSize)
{
	register Handle		h;
	OSErr				resultCode;

	BeginSystemMode();
	h			= MFTempNewHandle((Size)blockSize, &resultCode);
	EndSystemMode();

	if (resultCode)		return nil;
	else				return h;

}	/* End sb_MultiFinderHandle */
#endif

/*********************************************************************************************
**									sb_GetSysHandle			<30-CEL>
**
**
*/
Handle sb_GetSysHandle(long size)
{
	register Handle 			h	= nil;

#ifdef USE_SYSTEM_HEAP
	h 		= NewHandleSys(size);			/* system heap mem */
#else
	h = MultiFinderExist( ) ? sb_MultiFinderHandle( size ) : NewHandleSys( size );
#endif
	
	return h;
}	/* End sb_GetSysHandle */

/*********************************************************************************************
**									sb_GetSysHandleZone			<30-CEL>
**
**
*/
Handle sb_GetSysHandleZone(long size, THz* zone)
{
	register Handle 			h				= nil;

#ifdef USE_SYSTEM_HEAP
	h 		= NewHandleSys(size);			/* system heap mem */
	*zone 	= SystemZone();					/* <30-CEL> */
#else
	if ( MultiFinderExist( ) ) {
	
		h = sb_MultiFinderHandle( size );
		*zone = 0;
	
	} else {
	
		h = NewHandleSys(size);
		*zone = SystemZone( );

	}
	
#endif
	
	return h;
}	/* End sb_GetSysHandleZone */



/*********************************************************************************************
**									sb_GetAppHandleZone			<30-CEL>
**
**
*/
Handle sb_GetAppHandleZone(long size, THz* zone)
{
	register Handle				h;
	register THz				curZone 		= GetZone();
	register GrowZoneProcPtr	growZonePtr		= curZone->gzProc;
	
	curZone->gzProc		= nil;
	h 		= NewHandle(size);				/* <30-CEL> Try the App Heap */
	curZone->gzProc		= growZonePtr;		/* restore the grow zone proc ptr */
	*zone				= curZone;
	
	return h;
	
}	/* End sb_GetAppHandleZone */



/*********************************************************************************************
**									sb_GetAppHandle			<30-CEL>
**
**
*/
Handle sb_GetAppHandle(long size)
{
	register Handle				h;
	register THz				curZone 		= GetZone();
	register GrowZoneProcPtr	growZonePtr		= curZone->gzProc;
	
	curZone->gzProc		= nil;
	h 		= NewHandle(size);				/* <30-CEL> Try the App Heap */
	curZone->gzProc		= growZonePtr;		/* restore the grow zone proc ptr */
	
	return h;
	
}	/* End sb_GetAppHandle */


/*********************************************************************************************
**									sb_GrowAppHandle			<30-CEL>
**
**
*/
long sb_GrowAppHandle(Handle h, long size)
{
	THz					curZone 		= GetZone();
	GrowZoneProcPtr		growZonePtr		= curZone->gzProc;
	
	curZone->gzProc		= nil;
	SetHandleSize(h, size);							/* <30-CEL> took out set and restore zone for sethandlesize */
	curZone->gzProc		= growZonePtr;				/* restore the grow zone proc ptr */
	return MemError();								/* <30-CEL> */
		
}	/* End sb_GrowAppHandle */



/*********************************************************************************************								
**									sb_NewZoneHandle
**
**	BEHAVIOR:										<28-CEL> some logic
**		7.0 - 
**			¥	Make caches non-purgeable
**			¥	Try for Multi-Finder temp memory.
**			¥	Failure: Try for Application memory.
**			¥	Failure: Make caches purgeable and try again from the top.
**					(Better)Selectively choose caches for purgeability.
**		6.0 -
**			Multi-Finder
**				¥	Make caches non-purgeable
**				¥	Try for System Heap
**				¥	Failure: Try for Application memory.
**				¥	Failure: Make caches purgeable and try again from the top.
**						(Better)Selectively choose caches for purgeability.
**			Finder
**				¥	Make caches non-purgeable
**				¥	Try for Application memory.
**				¥	Failure: Make caches purgeable and try again from the top.
**						(Better)Selectively choose caches for purgeability.
**		No luck -
**			¥	Return nil
**
**	Under 7.0 NCH looks in temp mem first, bracketing the call with sysmode
**		What is this bracketing magic???
**
**	Allocate in non app heap with no purge 
**	Allocate in App heap with purge
**	Allocate in Multi heap with purge
**
**	New stuff:
**		¥ Allocate in non-app heap (sys or multi) until full with no purge
**		¥ Allocate in app heap until full with no purge
**		¥ Switch back and forth with purge on
*/
Handle sb_NewZoneHandle(sb_SplineKeyHdl splineKey, long size, THz* zone)
{
	register sb_SplineKeyPtr	splineKeyPtr	= *splineKey;		/* <28-CEL> */
	register Handle 			h				= nil;
	THz							curZone 		= GetZone();
	THz							savedZone;
	Boolean						sameAppZone;

	savedZone = curZone;

	if ( splineKeyPtr->curAppZone == SystemZone( ) )
		splineKeyPtr->curAppZone = nil;
	
	if ( curZone == SystemZone( ) ) {
	
		curZone = splineKeyPtr->curAppZone;
		if ( curZone == nil )
			curZone = ApplicZone( );
	
	}
	
	SetZone( curZone );
	sameAppZone = (splineKeyPtr->curAppZone == curZone);
	if (!sameAppZone){
		splineKeyPtr->curAppZone 	= curZone;			/* log current zone */
		splineKeyPtr->appFull 		= false;			/* Reset for different zone */
	}
	if (!splineKeyPtr->appFull) {						/* <30-CEL> */
		sb_SetCachesNoPurge();
		if (splineKeyPtr->mfExists && !splineKeyPtr->sysFull) {
			h = sb_GetSysHandleZone(size, zone);
			if (!h) {
				splineKeyPtr	= *splineKey;
				splineKeyPtr->sysFull = true;
			}
		}
		if (!h)	{
			h = sb_GetAppHandleZone(size, zone);
			if (!h) {
				splineKeyPtr	= *splineKey;
				splineKeyPtr->appFull 	= true;
			}
		}
		sb_SetCachesPurge();
	}
	if (!h) {							/* Full with no purge on so try without it */
		if (splineKeyPtr->useHeap == useApp) {
			h = sb_GetAppHandleZone(size, zone);
			if (!h)		h = sb_GetSysHandleZone(size, zone);
			splineKeyPtr			= *splineKey;
			splineKeyPtr->useHeap	= useSys;
		} else {
			h = sb_GetSysHandleZone(size, zone);
			if (!h)		h = sb_GetAppHandleZone(size, zone);
			splineKeyPtr			= *splineKey;
			splineKeyPtr->useHeap	= useApp;
		}
	}	

	SetZone( savedZone );
	return h;
	
}	/* End sb_NewZoneHandle */


/*********************************************************************************************								
**									sb_NewSharedHandle		<30-CEL> new routine
**
**	This data will be shared across heaps in Multi-Finder mode so it must be in the system heap.
**	Otherwise under finder just put it in the app heap since it will not be multiply shared.
**		Finder Mode:		Application Heap
**		Multi Finder:		System Heap (Shared)
**
*/
Handle sb_NewSharedHandle(sb_SplineKeyHdl splineKey, long cacheSize)
{
	register sb_SplineKeyPtr	splineKeyPtr	= *splineKey;		/* <28-CEL> */
	register Handle 			h				= nil;

	if (splineKeyPtr->mfExists) {
		if (!splineKeyPtr->appFull && !splineKeyPtr->sysFull) {
			sb_SetCachesNoPurge();							/* <30-CEL> */
			h = sb_GetSysHandle(cacheSize);					/* system heap mem */
			sb_SetCachesPurge();
			if (!h) {
				splineKeyPtr			= *splineKey;
				splineKeyPtr->sysFull 	= true;
			}
		}
		
		if (!h)		h = sb_GetSysHandle(cacheSize);		/* system heap mem */
	} else {
		THz							curZone 		= GetZone();
		Boolean						sameAppZone		= (splineKeyPtr->curAppZone == curZone);

		if (!sameAppZone){
			splineKeyPtr->curAppZone 	= curZone;			/* log current zone */
			splineKeyPtr->appFull 		= false;			/* Reset for different zone */
		}
		if (!splineKeyPtr->appFull) {
			sb_SetCachesNoPurge();							/* <30-CEL> */
			h = sb_GetAppHandle(cacheSize);					/* <28-CEL> Try the App Heap */
			sb_SetCachesPurge();
			if (!h) {
				splineKeyPtr			= *splineKey;
				splineKeyPtr->appFull 	= true;
			}
		}
		
		if (!h)		h = sb_GetAppHandle(cacheSize);			/* app heap mem */
	}	
	
	return h;
}	/* End sb_NewSharedHandle */



/*********************************************************************************************								
**									sb_GrowHandle		<28-CEL> new routine
**
**	Grow the current shared data block handleÉ
**	If this is in the App heap make sure there is enough space before requesting
**	the memory.  Otherwise this could cause the Application purge proc to be called
**	and the App might exit with an out of memory.
**
**	If in the Multi Heap try with no purgeability.
**	Fails:  try with purgeability
**
**	App heap always try with purgeability.
**
*/
long sb_GrowHandle(sb_SplineKeyHdl splineKey, Handle h, long size)
{
	register sb_SplineKeyPtr	splineKeyPtr	= *splineKey;		/* <28-CEL> */
	register long				result 			= NO_ERR;
	THz							curZone 		= GetZone();
	Boolean						sameAppZone		= (splineKeyPtr->curAppZone == curZone);

	if (!sameAppZone) {
		splineKeyPtr->curAppZone 	= curZone;			/* log current zone */
		splineKeyPtr->appFull 		= false;			/* Reset for different zone */
	}
	
	if (HandleZone(h) != curZone) {						/* <30-CEL> sys heap */
		if (!splineKeyPtr->appFull) {					/* <30-CEL> */
			sb_SetCachesNoPurge();						/* <30-CEL> */
			SetHandleSize(h, size);						/* <30-CEL> took out set and restore zone for sethandlesize */
			result = MemError();						/* <30-CEL> */
			sb_SetCachesPurge();						/* <30-CEL> */
			if (result) {
				SetHandleSize(h, size);					/* <30-CEL> took out set and restore zone for sethandlesize */
				result = MemError();					/* <30-CEL> */
			}
		} else {
			SetHandleSize(h, size);						/* <30-CEL> took out set and restore zone for sethandlesize */
			result = MemError();						/* <30-CEL> */
		}
	} else {											/* <30-CEL> app heap */
		if (!splineKeyPtr->appFull) {
			sb_SetCachesNoPurge();						/* <30-CEL> */
			result = sb_GrowAppHandle(h, size);
			sb_SetCachesPurge();
			if (result)	{
				result 					= sb_GrowAppHandle(h, size);
				splineKeyPtr			= *splineKey;
				splineKeyPtr->appFull 	= true;
			}
		} else result = sb_GrowAppHandle(h, size);
	}
	
	return result;
}	/* End sb_GrowHandle */





/*********************************************************************************************								
**									sb_SizeTheBlock			<28-CEL> some logic
**
**	Block exist: Resize handleÉ if this fails, get new one, copy over data if needed, and dipose old one. 
**	Empty or purged Handle: Dipose if handle is purged but exists and then get brand new one.
**
**	Upfront we will try to keep existing caches.  If memory allocations fail try again with purgeable
**	caches.
**
**	If it is the App heap, make sure there is enough contiguous space to make the request.
**	If this is not done, it could cause the applicaton purge proc to be called and it could
**	cause a out of memory error.
**
**	MERGE comments from sb_GrowZoneHandleÉ
**	Block exist: Resize handleÉ if this fails, get new one, copy over data if needed, and dipose old one. 
**	Empty or purged Handle: Dispose if handle is purged but exists and then get brand new one.
**
**	Upfront we will try to keep existing caches.  If memory allocations fail try again with purgeable
**	caches.
**
**	CachePlace:
**		¥ When a cacheHandle is moved via a newHandle of somekind the cacheHandle inside the
**		  cacheList must be updated.  Use CachePlace to find the correct cache info inside the
**		  the cache list.
**		¥ if cachePlace == -1, ignore the update.  This means it is not a cacheChunk.
**
*/
Handle sb_SizeTheBlock(sb_SplineKeyHdl splineKey, Handle inputH, THz* inputZone, long inputSize, 
					   ZoneHandleOptions options, short cachePlace, ShrinkOptions shrinkTest)
{
	register Handle		h			= inputH;			/* <28-CEL> */
	register THz		*zone		= inputZone;		/* <28-CEL> */
	register long		size		= inputSize;		/* <28-CEL> */
	Boolean				room		= true;

	if (h) {											/* <28-CEL> */
		if (*h) {										/* <28-CEL> */
			if (shrinkTest == noShrink && size <= GetHandleSize(h))		return h;	/* <30-CEL> Right sizeÉ leave it alone */
			if (!sb_GrowHandle(splineKey, h, size))		return h;	/* <30-CEL> */

			/* THIS SHOULD BE A RARE CASE!!! */
			/* If we get this far, growing the existing handle failed, so allocate a new one */
			if (options & kKeepContents) {
				register long 	origSize = GetHandleSize(h);	/* <28-CEL> */
				THz 			newZ;
				Handle 			newH;
				short			handState	= HGetState(h);
				
				if (newH = sb_NewZoneHandle(splineKey, size, &newZ)) {
				
					BlockMove( *h, *newH, origSize );
					sb_DisposeZoneHandle( h, *zone );			/* <28-CEL> assigned zone before disposing caused problems */

					if (cachePlace != -1) {		/* <28-CEL> Need to update cache info in cacheList */
						register sb_SplineKeyPtr	splineKeyPtr	= *splineKey;		/* <28-CEL> */
						register CacheReference		*cacheR			= *splineKeyPtr->cacheListHandle + splineKeyPtr->cachePlace; /* <28-CEL> */

						cacheR->cache		= newH;				/* <28-CEL> */
						cacheR->zone		= newZ;				/* <28-CEL> */
					}
					*zone 	= newZ;								/* <28-CEL> */
					HSetState(newH,handState);					/* <31-CEL> set to original state */
					return	 newH;
				} else		return nil;
			}
		} else {		/* ERROR!!!: This routine should never be called with a purged handle!!! */
			sb_Debug();			/* <27-CEL> */
			return nil;			/* <27-CEL> */
		}
	}
	return(sb_NewZoneHandle( splineKey, size, zone ));
	
}	/* End sb_SizeTheBlock */



/*********************************************************************************************								
**									sb_ModCacheList
**
**	sb_ModCacheList increases the number of nil cache_head entries in the cacheListHandle.
**		either it grows cacheListHandle by GROW_CACHE_NUM
**		or if cacheListHandle is nil, it allocates INITIAL_CACHES entries
**
**	Finder Mode:
**		CacheListHand lives in the App Heap
**	Multi Mode:
**		CacheListHand lives in the Sys Heap
**
*/
static long sb_ModCacheList(sb_SplineKeyHdl splineKey)
{
	register sb_SplineKeyPtr	splineKeyPtr	= *splineKey;
	register short				newFontCount;
	register long				cacheSize;
	register short				initCount;
	long						result			= NO_ERR;
	register Handle				tempHand		= nil;
	
	if (splineKeyPtr->cacheListHandle) {
		register Handle		h			= splineKeyPtr->cacheListHandle;
		THz					zone		= HandleZone(h);
		
		newFontCount	= splineKeyPtr->fontCount + GROW_CACHE_NUM;
		initCount		= GROW_CACHE_NUM;
		cacheSize		= GetHandleSize(h) + GROW_CACHE_NUM * sizeof(CacheReference);

		result = sb_GrowHandle(splineKey, h, cacheSize);					/* <30-CEL> */
 	} else {
		splineKeyPtr->fontCount		= 0;
		newFontCount = initCount	= INITIAL_CACHES;
		cacheSize					= INITIAL_CACHES * sizeof(CacheReference);
		
		tempHand = NewHandleSys( cacheSize );
		if (tempHand) {														/* <30-CEL> */
			splineKeyPtr	= *splineKey;
			splineKeyPtr->cacheListHandle = (CacheReference**)tempHand;		/* <30-CEL> */
		} else	
			result = NEWCACHELIST_HANDLE_ERR;								/* <30-CEL> */
	}	/* End If */

	if (!result) {
		register CacheReference*		cacheR; /* <28-CEL> */
		register Handle 				zero = 0;
		
		splineKeyPtr	= *splineKey;
		cacheR = *splineKeyPtr->cacheListHandle + splineKeyPtr->fontCount;
		
		for (--initCount; initCount >= 0; --initCount) {	/* begin new caches as nil */
			cacheR->cache = zero;
			cacheR++;
		}
		splineKeyPtr->fontCount	= newFontCount;
	}

	return result;											/* <27-CEL */
	
}	/* End sb_ModCacheList */



/*******************************/
/** WRAPPERS For memory calls **/
/*******************************/

void sb_DisposeCacheHandle( Handle cacheHandle, THz cacheZone )

{

	DumpFontCacheToDiskIfNotTooBig( (sb_CacheHeadHdl) cacheHandle );
	sb_DisposeZoneHandle( cacheHandle, cacheZone );

}


/*********************************************************************************************								
**									sb_DisposeWorkHandle				<28-CEL> a little comment
**
**	If a handle is purged and the zone from which the handle came from is not the current zone,
**	the memory manager does not know where to link the free handle.  This is bad news unless
**	we switch to the correct zone and then dispose of the handle!
**
*/
void sb_DisposeWorkHandle()		/* <28-CEL> took out splineKeyPtr param to make code consistent */
{
	sb_SplineKeyHdl				splineKey 		= SPLINE_KEY_HAND;
	register sb_SplineKeyPtr	splineKeyPtr	= *splineKey;

	if (splineKeyPtr->fsWorkHand) {				/* <28-CEL> */
		sb_DisposeZoneHandle(splineKeyPtr->fsWorkHand, splineKeyPtr->fsWorkZone);
		splineKeyPtr->fsWorkHand = 0;
		splineKeyPtr->fsWorkZone = 0;			/* <28-CEL> */
	}
}

/*********************************************************************************************								
**									sb_SizeWorkHandle				<28-CEL>
**
**	Size the Font Scaler work space.  If it does not exist it will
**	create one.
**
**	ZoneHandleOptions: Sets state if the memory needs to be preserved.
**	letShrink: Set if memory should be shrunk.
**
*/
long sb_SizeWorkHandle( long size, ZoneHandleOptions zOptions, ShrinkOptions shrinkTest )
{
	sb_SplineKeyHdl				splineKey 		= SPLINE_KEY_HAND;
	register sb_SplineKeyPtr	splineKeyPtr	= *splineKey;					/* <28-CEL> */
	register Handle 			h				= splineKeyPtr->fsWorkHand; 	/* <28-CEL> */
	THz 						z; 												/* <28-CEL> */
	register long				result			= NO_ERR;		/* <28-CEL> */

	if (h && !*h) 	sb_DisposeWorkHandle();						/* <31-CEL> */
		
	z 				= splineKeyPtr->fsWorkZone;					/* <28-CEL> */
	h 				= splineKeyPtr->fsWorkHand;					/* <28-CEL> */
	
	if (h = sb_SizeTheBlock( splineKey, h, &z, size, zOptions, -1, shrinkTest )) {
		splineKeyPtr				= *splineKey;				/* <28-CEL> */
		splineKeyPtr->fsWorkHand	= h;						/* <28-CEL> */
		splineKeyPtr->fsWorkZone	= z;						/* <28-CEL> */
	} else {
		result = MEM_ERR;
	}
	
	return result;
}	/* End sb_SizeWorkHandle */




/*********************************************************************************************								
**									sb_GetBitMapSpace		<28-CEL> rewrote
**
**	This is a temporary bitmap to blit in when the glyph is not cached.
**
*/
static Handle sb_GetBitMapSpace(register long bmSize)
{
	sb_SplineKeyHdl				splineKey 		= SPLINE_KEY_HAND;
	register sb_SplineKeyPtr	splineKeyPtr	= *splineKey;				/* <28-CEL> */
	register Handle				h				= splineKeyPtr->bitmapHand; /* <28-CEL> */
	THz							z;
	register long				result			= NO_ERR;

	if (h && !*h) {		/* purged so get rid of it and start over */	/* <28-CEL> */
		sb_DisposeZoneHandle(h, splineKeyPtr->bitmapZone);				/* <28-CEL> */
		splineKeyPtr->bitmapHand	= 0;								/* <28-CEL> */
		splineKeyPtr->bitmapZone	= 0;								/* <28-CEL> */
	}
	z	= splineKeyPtr->bitmapZone;										/* <28-CEL> */
	if (h = sb_SizeTheBlock( splineKey, splineKeyPtr->bitmapHand, &z, bmSize, kNoOptions, -1, doShrink )) {	/* <28-CEL> */
		splineKeyPtr				= *splineKey;						/* <28-CEL> */
		splineKeyPtr->bitmapZone 	= z;								/* <28-CEL> */
		splineKeyPtr->bitmapHand	= h;
	}
	
	return h;															/* <28-CEL> */

}	/* End sb_GetBitMapSpace */


/*********************************************************************************************								
**									sb_BandChar
**
**
*/
Handle sb_BandChar(sb_SplineKeyHdl splineKey, short *scan, short byteWidth, long memForScanLine)
{
	register sb_SplineKeyPtr	splineKeyPtr	= *splineKey;
	register Handle				tempHand;
	long						sizeOfMem6;
	
	for ((*scan) >>= 1;*scan >= 1;(*scan) >>= 1) {
		sizeOfMem6		= (long)LONG_WORD_ALIGN((*scan * memForScanLine));			/* divide by 2 */
		
		if (!sb_SizeWorkHandle((*splineKey)->rowArrayOffset6+sizeOfMem6, kKeepContents, doShrink)) {
			if (tempHand = sb_GetBitMapSpace(*scan * byteWidth))
				return tempHand;
		}
	}
			
	return 0;
	
}	/* End sb_BandChar */
									/**********************/
									/**	END MEMORY CALLS **/
									/**********************/
/***********************************************************************************************/								


/***********************************************************************************************/								
/***********************************************************************************************/								
										/********************/
										/* SET UP AND CACHE */
										/********************/

/*********************************************************************************************						
**									sb_ResetFSWorkState
**
**	Reset the SplineKey Font Scaler state.
**
**
*/
sb_ResetFSWorkState(sb_SplineKeyPtr	splineKeyPtr)
{
	register sb_SplineKeyPtr	skPtr	= splineKeyPtr;
	
	skPtr->StrikeID		= -1;		
	skPtr->ptSize		= 0;		
	skPtr->device		= 0;		
	skPtr->face			= 0;			
	skPtr->trans00		= -1;	
	skPtr->trans11		= -1;	
	skPtr->trans10		= -1;
	
}	/* End sb_ResetFSWorkState */



/*********************************************************************************************								
**									sb_SetMemPtrs
**
**	sb_SetMemPtrs
**
**	Usage:			Called once to set up spline package vectors and init the workspace.
**
**	Notes: memory [5] points to bitmap hand
*
*	Assumes that fsWorkHand is NOT purged or empty
**
*/

static void sb_SetMemPtrs( widthTableHdl widthTableHandle )
{
	
	register sb_SplineKeyPtr	splineKeyPtr	= *(SPLINE_KEY_HAND);
	char						*memoryPtr		= *splineKeyPtr->fsWorkHand;
	register char**				memBase;	/*<16> increment ptr instead of array */

	splineKeyPtr->inPtr							= (fs_GlyphInputType *)(memoryPtr + splineKeyPtr->inputOffset);
	splineKeyPtr->outPtr						= (fs_GlyphInfoType *)(memoryPtr + splineKeyPtr->infoOffset);
	memBase = (*splineKeyPtr->inPtr).memoryBases;
	*memBase++		= memoryPtr + splineKeyPtr->globalOffset0;		/* memoryBases[0] */
	*memBase++		= memoryPtr + splineKeyPtr->globalOffset1;		/* memoryBases[1] */
	*memBase++		= memoryPtr + splineKeyPtr->globalOffset2;		/* memoryBases[2] */
	*memBase++		= memoryPtr + splineKeyPtr->sfntDataOffset3;	/* memoryBases[3] */
	*memBase++		= memoryPtr + splineKeyPtr->sfntDataOffset4;	/* memoryBases[4] */
	memBase++;														/* memoryBases[5] */
	*memBase++		= memoryPtr + splineKeyPtr->rowArrayOffset6;	/* memoryBases[6] */
	*memBase		= memoryPtr + splineKeyPtr->columnArrayOffset7;	/* memoryBases[7] */
	(*splineKeyPtr->inPtr).sfntDirectory = (widthTableHandle == nil) ? nil : (int32*) (*widthTableHandle)->fSplineDirectory;

}	/* End sb_SetMemPtrs */



/*********************************************************************************************								
**									sb_CheckWorkHandle				<28-CEL> new routine
**
**	Check to see if the workhandle exists.  If it does then just return, otherwise re-establish.
**
*/
long sb_CheckWorkHandle()
{
	sb_SplineKeyHdl				splineKey 		= SPLINE_KEY_HAND;
	register sb_SplineKeyPtr	splineKeyPtr	= *splineKey;
	register Handle 			h 				= splineKeyPtr->fsWorkHand;
	register long				result			= NO_ERR;

	if (!h || !*h) {
		long 						position		= 0;
		short						splineKeyState	= HGetState((Handle)splineKey);
		register char				*memoryPtr;

		HLock((Handle)splineKey);
		
		splineKeyPtr->inputOffset		= position;
		position						+= LONG_WORD_ALIGN(sizeof(fs_GlyphInputType));
		splineKeyPtr->infoOffset		= position; 
		position						+= LONG_WORD_ALIGN( sizeof(fs_GlyphInfoType));
	
		if (!(result = sb_SizeWorkHandle(position, kNoOptions, noShrink))) {
			memoryPtr 				= *splineKeyPtr->fsWorkHand;
			splineKeyPtr->inPtr		= (fs_GlyphInputType *)(memoryPtr + splineKeyPtr->inputOffset);
			splineKeyPtr->outPtr	= (fs_GlyphInfoType *)(memoryPtr + splineKeyPtr->infoOffset);
			(*splineKeyPtr->inPtr).GetSfntFragmentPtr	= (GetSFNTFunc)QDGetFontFrag;
			(*splineKeyPtr->inPtr).ReleaseSfntFrag		= (ReleaseSFNTFunc)QDUngetFontFrag;
			
			/* reinitialize the state to make sure the FS gets ran through */
			sb_ResetFSWorkState(splineKeyPtr);
			
			if (!(result = fs_OpenFonts( splineKeyPtr->inPtr, splineKeyPtr->outPtr ))) {
				/*******************/
				/* SETTING OFFSETS */
				/*******************/
				splineKeyPtr->globalOffset0		= position;
				position += LONG_WORD_ALIGN((*splineKeyPtr->outPtr).memorySizes[0]);
		
				splineKeyPtr->globalOffset1		= position;
				position += LONG_WORD_ALIGN((*splineKeyPtr->outPtr).memorySizes[1]);
		
				splineKeyPtr->globalOffset2		= position;
				position += LONG_WORD_ALIGN((*splineKeyPtr->outPtr).memorySizes[2]);
				splineKeyPtr->sfntDataOffset3	= position;
				/*******************/
			
				/***********************/
				/** FSWorkHand HANDLE **/
				/***********************/
				if (!(result = sb_SizeWorkHandle( position, kKeepContents, noShrink ))) {
					sb_SetMemPtrs(0);
					if (result = fs_Initialize( splineKeyPtr->inPtr, splineKeyPtr->outPtr ))
						sb_Debug();
				}
			} else sb_Debug();
			if (result)		sb_DisposeWorkHandle();		/* failed so get rid of state */
		}
		HSetState((Handle)splineKey, splineKeyState);
	}
	return result;
}	/* End sb_CheckWorkHandle */


/*********************************************************************************************						
**									sb_ShrinkBitmap
**
**	The scan converted bitmap can have extra space at the end of it so shrink down to get  rid
**	of the excess.
**
**
*/
static void sb_ShrinkBitmap( sb_GlyphData *glyphDataPtr, long *bitMapPtr, short inputScan )
{
	register short		bitWidth		= glyphDataPtr->bitWidth;
	register short		scan			= inputScan - 1;
	short 				scanByteWidth	= glyphDataPtr->scanByteWidth;

	/*************************/
	/* Shrinking down the bitmap
	** 16-bit or less	-> word 
	** 32-bit or less	-> long
	** > 32-bit			-> multiple of longs
	*/
	if (bitWidth <= 16) {		/*<16> fast scan-loop */
		register short		*src, *dest;
		
		src = dest = (short *)bitMapPtr;
		for (; scan >= 0; --scan) {
			*dest++ = *src++;
			src++;				/* next src row */
		}
		glyphDataPtr->byteWidth		= 2;
	} else {	/*<16> fast scan-loops, set src and dest once */
		register long		*src, *dest;

		src = dest = (long *)bitMapPtr;
		if (bitWidth <= 32) {
			if (scanByteWidth > 4) {					/* Sampo uses two longs even though bitwidth is only 32 */
				for (; scan >= 0; --scan) {
					*dest++ = *src++;
					src++;						/* next src row */
				}
				glyphDataPtr->byteWidth		= 4;
			}
		} else {	/*<16> fast j-loop */
			register short	numOfLongs = ((bitWidth + 31) >> 5);	/* number of longs truely needed */
			
			if (numOfLongs > (scanByteWidth >> 2)) {		/* Sampo uses an extra long if last whole long is used */
				register short j;
				--numOfLongs;			/* save decrement in j-loop */
				for (; scan >= 0; --scan) {
					for (j = numOfLongs; j >= 0; --j)
						*dest++ = *src++;
					src++;						/* next src row */
				}
				numOfLongs++;			/* restore to orig value */
				glyphDataPtr->byteWidth 	= numOfLongs << 2;			/* turn to bytes */
			}
		}
	}
}	/* End sb_ShrinkBitmap */

/*********************************************************************************************								
**									sb_SetFontMemory
**
** Note on 6/19/92 change.  This routine formerly called GetEncodingTable to get the script.
**	the funny thing about that is that GetEncodingTable's primary raison d'etre is to return
**	a table of booleans used to distinguish high and low bytes in a CJK font.  It also
**	happened to return the script of the encoding table returned.  Well, until now if
**	the FOND ID being passed in wasn't an ID for a CJK font then GetEncodingTable returned
**	roman.  This tended to make international fonts with correctly coded cmap tables not
**  work at all.  The first thing I did was change GetEncodingTable to return the correct value
**	However, I've rethought the wisdom of calling a routine primarily designed for CJK and have
**	changed this routine (which never really cared about encoding tables) to call the more generic
**	script manager trap Font2RealScript.  The change to GetEncodingTable was left in though.
*/
static long sb_SetFontMemory(sb_SplineKeyHdl splineKey, widthTableHdl widthTableHandle )
{
	register sb_SplineKeyPtr	splineKeyPtr		= *splineKey;
	register long				result				= NO_ERR;
	register long				position;
	uint16						scriptID;
	
	sb_SetMemPtrs(widthTableHandle);
	//GetEncodingTable( splineKeyPtr->fLastSwapFontFamilyID, &scriptID );
	scriptID = Font2RealScript( splineKeyPtr->fLastSwapFontFamilyID );
	(*splineKeyPtr->inPtr).param.newsfnt.platformID = 1;
	(*splineKeyPtr->inPtr).param.newsfnt.specificID = scriptID;
	result = __NewSfntTrap(splineKeyPtr->inPtr, splineKeyPtr->outPtr);		//<22>
	if ( result ) {
	
		if ( scriptID != smRoman ) {	//we tried for a script this might be an old font so let's try Roman
		
			(*splineKeyPtr->inPtr).param.newsfnt.platformID = 1;
			(*splineKeyPtr->inPtr).param.newsfnt.specificID = smRoman;
			result = __NewSfntTrap(splineKeyPtr->inPtr, splineKeyPtr->outPtr);		//<22> 
	 		
		}
		
		//
		//test result again, if still non-zero that is it for us, if it is 0 we fall throught and set up
		//memory.
		//
		if ( result ) {
			sb_Debug();
			return	result;
		}
	}

	position							= splineKeyPtr->sfntDataOffset3;
	position 							+= LONG_WORD_ALIGN( (*splineKeyPtr->outPtr).memorySizes[3]);
	splineKeyPtr->sfntDataOffset4		= position;
	position 							+= LONG_WORD_ALIGN((*splineKeyPtr->outPtr).memorySizes[4]);
	splineKeyPtr->rowArrayOffset6		= position;
	splineKeyPtr->columnArrayOffset7	= position;
	
	if (result = sb_SizeWorkHandle( position, kKeepContents, noShrink ))		return MEM_ERR;

	return result;

}


/*********************************************************************************************								
**									sb_SetNewSFNT
**
**	If the sfnt has changed, reset the FontScaler environment.
**
**	Logic:
**		¥ Font change: run fs_NewSfnt and fs_NewTransformation
**		¥ ptSize or transformation changed : run fs_NewTransformation
**	
**
*/
static long sb_SetNewSFNT( widthTableHdl widTabHand )
{
	sb_SplineKeyHdl				splineKey			= SPLINE_KEY_HAND;
	register sb_SplineKeyPtr	splineKeyPtr		= *splineKey;
	register widthTablePtr		widTabPtr			= *widTabHand;
	register long				result				= NO_ERR;
	short						doNewTrans			= false;

	sb_SetMemPtrs(widTabHand);
	(*splineKeyPtr->inPtr).clientID 		= widTabPtr->tabFont;		/* Always reset because the memory environment may have changed */

	if ( splineKeyPtr->StrikeID != widTabPtr->StrikeID  ) {
		if (result = sb_SetFontMemory(splineKey, widTabHand))		return MEM_ERR;
		splineKeyPtr			= *splineKey;
		widTabPtr				= *widTabHand;
		doNewTrans				= true;
		splineKeyPtr->StrikeID 	= widTabPtr->StrikeID;
	}
	
	if ( doNewTrans	||
		 splineKeyPtr->ptSize 				  	!= widTabPtr->fSize		||
		 splineKeyPtr->trans00 					!= widTabPtr->trans00	||
		 splineKeyPtr->trans11				 	!= widTabPtr->trans11	||
		 splineKeyPtr->trans10				 	!= widTabPtr->trans10
		 ) {
		register fs_GlyphInputType* 	fsInput;
		transMatrix 					matrix;			/* this could be a global matrix */
		
		matrix.transform[2][0] = 0;
		matrix.transform[0][1] = 0;
		matrix.transform[2][1] = 0;
		matrix.transform[0][2] = 0;
		matrix.transform[1][2] = 0;
		matrix.transform[2][2] = (1L << 30);

		matrix.transform[0][0] = widTabPtr->trans00;
		matrix.transform[1][1] = widTabPtr->trans11;
		matrix.transform[1][0] = widTabPtr->trans10;

		sb_SetMemPtrs(widTabHand);
		fsInput = splineKeyPtr->inPtr;
		fsInput->param.newtrans.transformMatrix = &matrix;
		fsInput->param.newtrans.pointSize 		= (Fixed)widTabPtr->fSize << 16;
		fsInput->param.newtrans.xResolution 	= POINTSPERINCH;
		fsInput->param.newtrans.yResolution 	= POINTSPERINCH;
		fsInput->param.newtrans.pixelDiameter	= FIXEDSQRT2;
		fsInput->param.newtrans.traceFunc 		= 0;
#if TheFuture /* <18 > EBITMAP */
		fsInput->param.newtrans.bitmapMethodPreferences 		= 1;
		fsInput->param.newtrans.scalingPreference 		= 0;
#endif		
		if ( result = fs_NewTransformation( splineKeyPtr->inPtr, splineKeyPtr->outPtr ) ) {
			splineKeyPtr->ptSize	 	= 0;
			splineKeyPtr->trans00		= 0;
			splineKeyPtr->trans11 		= 0;
			splineKeyPtr->trans10		= 0;
			sb_Debug();
			return	result;
		}
		splineKeyPtr->ptSize	 	= widTabPtr->fSize;
		splineKeyPtr->trans00		= widTabPtr->trans00;
		splineKeyPtr->trans11		= widTabPtr->trans11;
		splineKeyPtr->trans10 		= widTabPtr->trans10;
	 
	}	/* End If */
	
	return NO_ERR;
	
}	/* End sb_SetNewSFNT */

/*
 *	Returns the font's real style, ignoring any algorithmic effects
 */
short IntrinsicStyle(widthTablePtr w)
{
	return (w->face >> 8) & ~w->aFace;
}

/*********************************************************************************************								
**									sb_InitCacheHead
**
**	Initialize the cacheHead with the widthTable information.
**
**
**
*/
static long sb_InitCacheHead(widthTableHdl widthTabHand, sb_CacheHeadHdl cacheHand )
{
	sb_SplineKeyHdl				splineKey			= SPLINE_KEY_HAND;
	register widthTablePtr		widTabPtr 			= *widthTabHand;
	sb_SplineKeyPtr				splineKeyPtr		= *splineKey;	/*<16> removed register */
	register sb_CacheHeadPtr	cachePtr			= *cacheHand;
	char						*hiliteModePtr		= HILITEMODE;
	long						result				= NO_ERR;

	cachePtr->familyID					= (*splineKey)->fLastSwapFontFamilyID;
	cachePtr->StrikeID					= widTabPtr->StrikeID;
	cachePtr->ptSize					= widTabPtr->fSize;
	cachePtr->face						= IntrinsicStyle(widTabPtr);
	cachePtr->squashed					= !(*hiliteModePtr & PRESERVE_GLYPH);
	cachePtr->trans00 					= widTabPtr->trans00;
	cachePtr->trans11 					= widTabPtr->trans11;
	cachePtr->trans10 					= widTabPtr->trans10;
	cachePtr->bitsCached				= widTabPtr->aSize <= MAX_PPEM_CACHED;
	cachePtr->addEntryOffset			= (GLYPH_COUNT * sizeof(long)) + sizeof(sb_CacheHead);
	cachePtr->fEncodingTablePointer		= (Ptr) GetEncodingTable( (*splineKey)->fLastSwapFontFamilyID, &cachePtr->fScriptNumber );
	
	sb_SetMemPtrs(widthTabHand);
	
	result = fs_FillLayoutInfo( splineKeyPtr->inPtr, splineKeyPtr->outPtr, (fs_LayoutInfo *)&cachePtr->ascent );
	if (!result) {
		if (cachePtr->trans10 /*OBLIQUE*/) {		/* If oblique changes change this slop adjust */
			if (widTabPtr->aSize <= 8) {
				cachePtr->rightItalicSlop	=  (cachePtr->ascent / 2);		
				cachePtr->leftItalicSlop	=  (cachePtr->descent / 2);	
			} else if (widTabPtr->aSize <= 16) {
				cachePtr->rightItalicSlop	=  (cachePtr->ascent / 3);
				cachePtr->leftItalicSlop	=  (cachePtr->descent / 3);	
			} else if (widTabPtr->aSize <= 22) {
				cachePtr->rightItalicSlop	=  (cachePtr->ascent / 4);
				cachePtr->leftItalicSlop	=  (cachePtr->descent / 4);	
			} else {
				cachePtr->rightItalicSlop	=  (cachePtr->ascent / 5);
				cachePtr->leftItalicSlop	=  (cachePtr->descent / 5);	
			}
		} else {
			cachePtr->rightItalicSlop	=  0;	
			cachePtr->leftItalicSlop	=  0;		
		}
		/********************/
		/* Round to ceiling */
		/********************/
		/*<16> put masks into registers */
		{
			Fixed lowordmask = 0x0000FFFF;
			Fixed hiwordmask = 0xFFFF0000;
			cachePtr->ascent			= (cachePtr->ascent + lowordmask) & hiwordmask;
			cachePtr->descent			= (-cachePtr->descent + lowordmask) & hiwordmask;
			if ( (*hiliteModePtr & PRESERVE_GLYPH) ) {
				cachePtr->yMax				= (cachePtr->yMax + lowordmask) & hiwordmask;
				cachePtr->yMin				= (cachePtr->yMin - lowordmask) & hiwordmask;
			} else {
				cachePtr->yMax				= cachePtr->ascent;
				cachePtr->yMin				= -cachePtr->descent;
			}
			cachePtr->height			= (short)((cachePtr->yMax - cachePtr->yMin) >> 16);
			cachePtr->widMax			= (cachePtr->widMax + lowordmask) & hiwordmask;
			cachePtr->leading			= (cachePtr->leading + lowordmask) & hiwordmask;
			cachePtr->lOverHMax			= (cachePtr->lOverHMax + lowordmask) & hiwordmask;
			cachePtr->rOverHMax			= (cachePtr->rOverHMax + lowordmask) & hiwordmask;
			cachePtr->leftItalicSlop	= -((cachePtr->leftItalicSlop + lowordmask) & hiwordmask);
			cachePtr->rightItalicSlop	= (cachePtr->rightItalicSlop + lowordmask) & hiwordmask;
			
			
			cachePtr->fmAscent			= ByteMax(cachePtr->ascent);
			cachePtr->fmDescent			= ByteMax(cachePtr->descent);
			cachePtr->fmWidMax			= ByteMax(cachePtr->widMax);
			cachePtr->fmLeading			= ByteRange(cachePtr->leading);
			
		}
		/********************/
	}

	/*<16> fast loop, local i, initArrayPtr */
	{
		register long* initArrayPtr	= (long*)cachePtr->glyphArray;
		register short i = GLYPH_COUNT - 1;
		for (; i >= 0; --i)
			*initArrayPtr++ 		= EMPTY;
	}
		
	return result;

}	/* End sb_InitCacheHead */


/*********************************************************************************************								
**									sb_ShrinkCacheToMin			<3-CEL>
**
**	Low on memory so shrink the cache to a minimum and initialize new state.
**
**
**	AddEntryOffset = 0:	Do not copy glyph entry.
**
*/
long sb_ShrinkCacheToMin(sb_CacheHeadHdl cacheHand, long addEntryOffset)
{
	sb_SplineKeyHdl				splineKey			= SPLINE_KEY_HAND;
	sb_SplineKeyPtr				splineKeyPtr		= *splineKey;
	sb_CacheHeadPtr				cachePtr			= *cacheHand;
	register long				entryArraySize		= (GLYPH_COUNT * sizeof(long));
	register long* 				initArrayPtr		= cachePtr->glyphArray;
	long						result				= NO_ERR;
	register short 				i;
	register long				*oldGDataPtr;
	register long				*newGDataPtr;
	
	/* new start for add entry */
	cachePtr->addEntryOffset			= entryArraySize + sizeof(sb_CacheHead);
	if (addEntryOffset) {
		oldGDataPtr		= (long *)((char *)cachePtr + addEntryOffset);
		newGDataPtr		= (long *)((char *)cachePtr + cachePtr->addEntryOffset);
		i	= (GLYPH_HEAD_BYTES>>2);		/* longs to copy */
		for (--i; i >= 0; --i)	
			*newGDataPtr++ = *oldGDataPtr++;
	}
	
	for (i=GLYPH_COUNT-1; i >= 0; --i)
		*initArrayPtr++ = EMPTY;

	SetHandleSize((Handle)cacheHand, sizeof(sb_CacheHead) + entryArraySize + GLYPH_HEAD_BYTES);
	if (!(result = MemError()))
		result = sb_SizeWorkHandle((*splineKey)->rowArrayOffset6, kKeepContents, doShrink);		/* <8-CEL,RB> */

	return result;

}	/* End sb_ShrinkCacheToMin */



/*********************************************************************************************						
**									sb_FigureCacheSize
**
**	Takes the current WidthTable and calculates the initial cache size needed.
**
**	Make it the minimum of the cache header and enough room for one entry header.
**
*/
static long sb_FigureCacheSize(widthTableHdl widthTabHand)
{
	register widthTablePtr	widTabPtr 			= *widthTabHand;
	register long			entryArraySize		= (GLYPH_COUNT * sizeof(long));
	register long			cacheSize			= 0;
	Boolean					bitsCached			= widTabPtr->aSize < MAX_PPEM_CACHED;

	cacheSize			= sizeof(sb_CacheHead) + GLYPH_HEAD_BYTES;		/* <34-CEL> */
	
#ifdef LEAVE_OUT				/* <33-CEL> forget about room for characters for now */
	if ( bitsCached )
			cacheSize	+= (widTabPtr->aSize / 8) * widTabPtr->aSize * INITIAL_CHAR_COUNT;
	else	cacheSize	+= AVG_CONTOUR_SIZE * INITIAL_CHAR_COUNT;
#endif

	cacheSize	+= entryArraySize;				/* Add glyph array */
	cacheSize	+= 3;	cacheSize	&= ~3;		/* Start Long word aligned */

	return cacheSize;

}	/* End sb_FigureCacheSize */


/*********************************************************************************************							
**									sb_ResetHeapState
**
**
**
*/
void sb_ResetHeapState( sb_SplineKeyPtr splineKeyPtr )
{
	register sb_SplineKeyPtr	sPtr = splineKeyPtr;
	
	sPtr->curAppZone 	= 0;				/* <30-CEL> */			
	sPtr->appFull 		= false;			/* <30-CEL> */	
	sPtr->sysFull 		= false;			/* <30-CEL> */
	sPtr->useHeap 		= useApp;			/* <30-CEL> */
	
}	/* End sb_ResetHeapState */


/*********************************************************************************************							
**									sb_FlushFonts
**
**	sb_FlushFonts
**
**
*/
pascal OSErr sb_FlushFonts()
{
	sb_SplineKeyHdl		splineKey		= SPLINE_KEY_HAND;
	sb_SplineKeyPtr		splineKeyPtr	= *splineKey;
	long* 				lastSpExtrPtr	= LASTSPEXTRA;
		
	*lastSpExtrPtr		= 0xFFFFFFFF;

	if (splineKeyPtr->cacheListHandle) {
		register short fontCount = splineKeyPtr->fontCount;
		register CacheReference* cacheRef = *splineKeyPtr->cacheListHandle;
		register Handle zero = 0;
		for (--fontCount; fontCount >= 0; --fontCount) {
			if (cacheRef->cache) {
				sb_DisposeCacheHandle(cacheRef->cache, cacheRef->zone);
				cacheRef->cache	= zero;
			}
			cacheRef++;
		}
		splineKeyPtr->cacheHand = 0;		/* <28-CEL> */
		splineKeyPtr->cacheZone = 0;		/* <28-CEL> */
		splineKeyPtr->cachePlace = 0;		/* <28-CEL> */
		
		sb_DisposeZoneHandle((Handle)splineKeyPtr->cacheListHandle,		/* <28-CEL> start over */
							 HandleZone((Handle)splineKeyPtr->cacheListHandle));
		splineKeyPtr->cacheListHandle	= 0;
	}
	
	sb_DisposeWorkHandle();					/* <28-CEL> */
	
	/* Dispose of all fragment table caches */
	KillApplicationHeapFragmentTableCaches( (Handle) 0, (Handle) 0x7fffffff );
	
	/* Reset since the heaps have changed */
	sb_ResetHeapState(splineKeyPtr);

	return NO_ERR;
}	/* End sb_FlushFonts */


/*********************************************************************************************							
**									sb_KillSomeCaches
**
**	Clean up caches in the current heap that is going away.  If the cachelisthandle is going
**	away, throw away the caches and get rid of the cachelisthandle.  Make sure to get rid of
**	any blocks that are in this heap also like the fsWorkHand. 
**
**
*/
pascal long sb_KillSomeCaches( Handle inputStartAddr, Handle inputEndAddr )
{
	register sb_SplineKeyPtr	splineKeyPtr	= *(SPLINE_KEY_HAND);		/* <28-CEL> register */
	register CacheReference* 	cacheR;										/* <28-CEL> */
	register short 				fontCount		= splineKeyPtr->fontCount;
	register Handle				startAddr		= inputStartAddr;			/* <28-CEL> */
	register Handle				endAddr			= inputEndAddr;				/* <28-CEL> */
	register Handle 			h;											/* <28-CEL> */

	if (splineKeyPtr->cacheListHandle) {					/* <28-CEL> make sure it even exists */
		cacheR			= *splineKeyPtr->cacheListHandle;					/* <28-CEL> */
		h				= (Handle)splineKeyPtr->cacheListHandle;			/* <28-CEL> */
		if (h >= startAddr && h < endAddr) {				/* <28-CEL> cacheListHand in this heap clean all caches */
			for (--fontCount; fontCount >= 0; --fontCount) {							/* <28-CEL> */
				if (cacheR->cache)	sb_DisposeCacheHandle(cacheR->cache, cacheR->zone);	/* <28-CEL> */
				cacheR++;																/* <28-CEL> */
			}
			sb_DisposeZoneHandle(h, HandleZone(h));
			splineKeyPtr->cacheListHandle	= 0;		/* <28-CEL> */
			splineKeyPtr->cacheHand			= 0;		/* <28-CEL> */
			splineKeyPtr->cacheZone			= 0;		/* <28-CEL> */
			splineKeyPtr->cachePlace		= 0;		/* <28-CEL> */
			sb_ResetFSWorkState(splineKeyPtr);
		} else {
			for (--fontCount; fontCount >= 0; --fontCount) {
				h 		= cacheR->cache;						/* <28-CEL> */
				
				if (h >= startAddr && h < endAddr) {			/* <28-CEL> */
					if (splineKeyPtr->cacheHand == h) {			/* <28-CEL> */
						splineKeyPtr->cacheHand 	= 0;		/* <28-CEL> */
						splineKeyPtr->cacheZone		= 0;		/* <28-CEL> */
						splineKeyPtr->cachePlace	= 0;		/* <28-CEL> */
					}
					
					sb_DisposeCacheHandle( cacheR->cache, cacheR->zone );
					cacheR->cache		= 0;
					cacheR->zone		= 0;					/* <28-CEL> */
				}
				cacheR++;
			}
		}
	}
		
	KillApplicationHeapFragmentTableCaches( startAddr, endAddr );

	if ((h = splineKeyPtr->bitmapHand) && (h >= startAddr && h < endAddr)) {	/* <28-CEL> */
		sb_DisposeZoneHandle(h, splineKeyPtr->bitmapZone);						/* <28-CEL> */
		splineKeyPtr->bitmapHand		= 0;									/* <28-CEL> */
		splineKeyPtr->bitmapZone		= 0;									/* <28-CEL> */
	}
	
	if ((h = splineKeyPtr->fsWorkHand) && (h >= startAddr && h < endAddr))		/* <28-CEL> */											/* <28-CEL> */
		sb_DisposeWorkHandle();													/* <28-CEL> */

	// <19> If FOND candidate lists are cached, flush them out too.

	h = splineKeyPtr->fondCache[0];												// <19>
	if (h) {																	// <19>
		DisposeHandle(h);														// <19>
		splineKeyPtr->fondCache[0] = nil;										// <19>
	}
	h = splineKeyPtr->fondCache[1];												// <19>
	if (h) {																	// <19>
		DisposeHandle(h);														// <19>
		splineKeyPtr->fondCache[1] = nil;										// <19>
	}
		
	/* Reset since the heaps have changed */
	sb_ResetHeapState(splineKeyPtr);
	
	return NO_ERR;
}	/* End sb_KillSomeCaches */



/*********************************************************************************************						
**									sb_CacheSFNTMatch
**
**	Simply checks to see if the current widthtable request matches the cache found.
**
**
*/
Boolean sb_CacheSFNTMatch( sb_CacheHeadPtr cachePtr, widthTablePtr widTabPtr )
{
	register sb_CacheHeadPtr		cPtr	= cachePtr;		/* registers */
	register widthTablePtr 			wtPtr	= widTabPtr;

	return(cPtr->StrikeID 	== wtPtr->StrikeID 			&&
		   cPtr->ptSize		== wtPtr->fSize 			&&
		   cPtr->face 		== IntrinsicStyle(wtPtr)	&&
		   cPtr->trans00 	== wtPtr->trans00  			&&
		   cPtr->trans11 	== wtPtr->trans11  			&&
		   cPtr->trans10	== wtPtr->trans10);
}	/* End sb_CacheSFNTMatch */


/*********************************************************************************************						
**									sb_LoadNewCache
**
**	On entry
**		splineKeyPtr is locked
**		
**
*/
long sb_LoadNewCache( sb_SplineKeyHdl splineKey, widthTableHdl widthTabHand, Boolean squashed )
{
	register sb_SplineKeyPtr	splineKeyPtr	= *splineKey;			/* <28-CEL> */
	register CacheReference* 	cacheR			= *splineKeyPtr->cacheListHandle;
	register short 				i, fontCount	= splineKeyPtr->fontCount;
	register short 				cachePlace 		= -1;
	long						result			= NO_ERR;

	/* Search through the list of caches to see if we have a match */
	for (i = 0; i < fontCount; i++) {
		if (cacheR->cache && *cacheR->cache) {
			sb_CacheHeadPtr cachePtr	= (sb_CacheHeadPtr)*cacheR->cache;
			if (sb_CacheSFNTMatch(cachePtr, *widthTabHand) && cachePtr->squashed == squashed) {
				splineKeyPtr->cacheHand 	= (sb_CacheHeadHdl)cacheR->cache;	/* <28-CEL> */
				splineKeyPtr->cacheZone		= cacheR->zone;						/* <28-CEL> */
				splineKeyPtr->cachePlace	= i;								/* <28-CEL> */
				HNoPurge((Handle)splineKeyPtr->cacheHand);	/* Current one is non-purgable */
				break;
			}	/* End If */ 
		} else if (cachePlace == -1)
			cachePlace		= i;	/* remember first available (purged or gone) */
		cacheR++;
	}	/* End For */

	if (!splineKeyPtr->cacheHand) {					/* no match, use cachePlace if valid */
		THz 		zone;							/* <28-CEL> just moved this above */
		Handle		cache;							/* <28-CEL> just moved this above */

		if (cachePlace == -1) {						/* -1 means grow the cache */
			cachePlace	= splineKeyPtr->fontCount;	/* first available of new caches */
			if ( sb_ModCacheList(splineKey) ) {		/* add more cache heads if needed */
				cachePlace	= 1;
			}
		}	/* End If */

		cacheR			= *splineKeyPtr->cacheListHandle + cachePlace;			/* <28-CEL> */
		zone			= cacheR->zone;

		if (cacheR->cache && !*cacheR->cache) {	/* <28-CEL> been purged so get rid of it and start over */
			sb_DisposeZoneHandle( cacheR->cache, zone );
			cacheR->cache = 0;
			cacheR->zone = 0;
		}
		
		result = LoadFontCacheFromDisk( (sb_CacheHeadHdl*) &cache, &zone, widthTabHand, squashed );
		cacheR = *splineKeyPtr->cacheListHandle + cachePlace;		
		if ( (result == noErr) && (cache != nil) ) {
		
			cacheR->cache = cache;
			cacheR->zone = zone;
			splineKeyPtr->cacheHand = (sb_CacheHeadHdl) cache;
			splineKeyPtr->cacheZone = zone;
			splineKeyPtr->cachePlace = cachePlace;
			HNoPurge( cache );
		
		} else {

			if (cache = sb_SizeTheBlock( splineKey, cacheR->cache, &zone, sb_FigureCacheSize(widthTabHand), 
										   kKeepContents, cachePlace, doShrink )) {
				if (!(result = sb_SetNewSFNT(widthTabHand))) {
					if (!(result = sb_InitCacheHead(widthTabHand, (sb_CacheHeadHdl)cache))) {
						cacheR			= *splineKeyPtr->cacheListHandle + cachePlace;	/* <34> */
						cacheR->cache	= cache;										/* <34> */
						cacheR->zone	= zone;											/* <34> */
						splineKeyPtr->cacheHand		= (sb_CacheHeadHdl)cacheR->cache;	/* <34> */
						splineKeyPtr->cacheZone		= cacheR->zone;						/* <34> */
						splineKeyPtr->cachePlace	= cachePlace;						/* <34> */	
						HNoPurge(cache);
					}
				}
				if (result) {															/* <34> */
					cacheR			= *splineKeyPtr->cacheListHandle + cachePlace;		/* <34> */
					cacheR->cache	= 0;
					cacheR->zone	= 0;
					DisposHandle(cache);		/* Get rid of cachehandle */
					sb_Debug();
				}
			} else	result = GROWZONE_HANDLE_ERR;
			
		}
		
	}	/* End If */
	
	return result;
	
}	/* End sb_LoadNewCache */


/*********************************************************************************************						
**									sb_SearchForCache
**
**	Find the cache that matches the width table requestÉ
**		¥ Check if the current one is okay - FAST CASE
**		¥ NOT FOUND: Check through the list of caches to see if one exists
**		¥ÊNOT FOUND: Get a brand new one
**		¥ NOT FOUND: re-use a cache
**
*/
pascal long sb_SearchForCache( widthTableHdl widthTabHand )
{
	sb_SplineKeyHdl				splineKey		= SPLINE_KEY_HAND;		/* <28-CEL> */
	register sb_SplineKeyPtr	splineKeyPtr	= *splineKey;			/* <28-CEL> */
	register widthTablePtr		widTabPtr		= *widthTabHand;		/* <27-CEL> */
	long						result			= NO_ERR;
	char* 						hiliteModePtr	= HILITEMODE;
	register Boolean			squashed		= !(*hiliteModePtr & PRESERVE_GLYPH); 
	short						splineKeyState, fontState, workHandState;
	register Handle				aCacheHand		= splineKeyPtr->cacheHand;

	if (aCacheHand && *aCacheHand) {			/* Current cache okay??? Fast case */
		sb_CacheHeadPtr cachePtr	= (sb_CacheHeadPtr)*aCacheHand;
		if ( sb_CacheSFNTMatch(cachePtr, widTabPtr) && cachePtr->squashed == squashed)
				return NO_ERR;
		else	HPurge((Handle)aCacheHand);		/* <16-CEL> */
	}
	splineKeyPtr->cacheHand 	= 0;			/* we need a new current cache */
	splineKeyPtr->cacheZone		= 0;			/* <16-CEL> */
	splineKeyPtr->cachePlace	= 0;			/* <16-CEL> */
	
	widTabPtr		= *widthTabHand;
	splineKeyPtr	= *splineKey;
	splineKeyState	= HGetState ((Handle)splineKey);
	fontState		= HGetState ((Handle)widTabPtr->tabFont);
	HLock((Handle)splineKey);											/* <32-CEL> */
	HNoPurge(widTabPtr->tabFont);

	if (!(result = sb_CheckWorkHandle())) {								/* <32-CEL> */
		workHandState		= HGetState ((Handle)splineKeyPtr->fsWorkHand);
		HNoPurge(splineKeyPtr->fsWorkHand);								/* <32-CEL> */
		if (splineKeyPtr->cacheListHandle || !(result = sb_ModCacheList(splineKey)))
			result = sb_LoadNewCache(splineKey, widthTabHand, squashed);
		HSetState((Handle)splineKeyPtr->fsWorkHand, workHandState);
	}

	HPurge((Handle)(*splineKey)->cacheHand);							/* 15-CEL */
	HSetState((Handle)splineKey, splineKeyState);
	HSetState((*widthTabHand)->tabFont, fontState);
	return result;

}	/* End sb_SearchForCache */




/***************************************************************************************************/
/***************************************************************************************************/
								/**********************************/
								/* ROUTINES THAT CALL FONT SCALER */
								/**********************************/

/*********************************************************************************************								
**									sb_SetUpWorkHand
**
**	sb_SetUpWorkHand
**
**
*/
static long sb_SetUpWorkHand()
{
	sb_SplineKeyHdl				splineKey		= SPLINE_KEY_HAND;
	long 						position		= 0;
	register sb_SplineKeyPtr	splineKeyPtr	= *splineKey;
	short						splineKeyState	= HGetState ((Handle)splineKey);
	long						result;
	register char				*memoryPtr;

	HLock((Handle)splineKey);
	
	splineKeyPtr->inputOffset		= position;
	position						+= LONG_WORD_ALIGN(sizeof(fs_GlyphInputType));
	splineKeyPtr->infoOffset		= position; 
	position						+= LONG_WORD_ALIGN( sizeof(fs_GlyphInfoType));

	if (result = sb_SizeWorkHandle(position, kNoOptions, noShrink))		goto EXIT;			/* Error so can not continue */

	memoryPtr 				= *splineKeyPtr->fsWorkHand;
	splineKeyPtr->inPtr		= (fs_GlyphInputType *)(memoryPtr + splineKeyPtr->inputOffset);
	splineKeyPtr->outPtr	= (fs_GlyphInfoType *)(memoryPtr + splineKeyPtr->infoOffset);
	(*splineKeyPtr->inPtr).GetSfntFragmentPtr				= (GetSFNTFunc)QDGetFontFrag;
	(*splineKeyPtr->inPtr).ReleaseSfntFrag					= (ReleaseSFNTFunc)QDUngetFontFrag;;
	
	/* reinitialize the state to make sure the FS gets ran through */
	sb_ResetFSWorkState(splineKeyPtr);
	
	if (!(result = fs_OpenFonts( splineKeyPtr->inPtr, splineKeyPtr->outPtr ))) {
		/*******************/
		/* SETTING OFFSETS */
		/*******************/
		splineKeyPtr->globalOffset0		= position;
		position += LONG_WORD_ALIGN((*splineKeyPtr->outPtr).memorySizes[0]);

		splineKeyPtr->globalOffset1		= position;
		position += LONG_WORD_ALIGN((*splineKeyPtr->outPtr).memorySizes[1]);

		splineKeyPtr->globalOffset2		= position;
		position += LONG_WORD_ALIGN((*splineKeyPtr->outPtr).memorySizes[2]);
		splineKeyPtr->sfntDataOffset3	= position;
		/*******************/
	
		/***********************/
		/** FSWorkHand HANDLE **/
		/***********************/
		if (!(result = sb_SizeWorkHandle( position, kKeepContents, noShrink ))) {
			sb_SetMemPtrs(0);
			if (result = fs_Initialize( splineKeyPtr->inPtr, splineKeyPtr->outPtr ))
				sb_Debug();
		}
	}	/* End if */

EXIT:
	HSetState((Handle)splineKey, splineKeyState);
	return result;
}	/* End sb_SetUpWorkHand */

/*********************************************************************************************								
**									sb_SFNTMatchSize
**
**	sb_SFNTMatchSize
**
**
*/
pascal Boolean sb_SFNTMatchSize(Handle /*sfntHand*/, short /*matchSize*/)
{
	return true;

}	/* End sb_SFNTMatchSize */





/*********************************************************************************************								
**								AppendSplineDirectoryToWidthTable
**
**	AppendSplineDirectoryToWidthTable
**
**	This routine appends the spline directory for the sfnt specified by the widthTableHandle's
**	tabFont field to the end of the widthTableHandle by resizing the widthTableHandle and
**	blockmoving the directory data.
**
*/


long AppendSplineDirectoryToWidthTable( Handle splineHandle, widthTableHdl widthTableHandle )

{

	// Locals
	
		long									error;
		Size									splineDirectorySize;
		sfnt_OffsetTable*						splineDirectoryPointer;
	
	error = memFullErr;
	splineDirectoryPointer = (sfnt_OffsetTable*) QDGetFontFrag( splineHandle, 0, OFFSETTABLESIZE );
	if ( splineDirectoryPointer != nil ) {
	
		splineDirectorySize = OFFSETTABLESIZE + (splineDirectoryPointer->numOffsets * sizeof(sfnt_DirectoryEntry));
		QDUngetFontFrag( splineHandle, splineDirectoryPointer );
		
		splineDirectoryPointer = (sfnt_OffsetTable*) QDGetFontFrag( splineHandle, 0, splineDirectorySize );
		if ( splineDirectoryPointer != nil ) {
		
			SetHandleSize( (Handle) widthTableHandle, sizeof( widthTable ) + splineDirectorySize );
			if ( (error = MemError( )) == noErr ) {
			
				BlockMove( (Ptr) splineDirectoryPointer, (Ptr) (*widthTableHandle)->fSplineDirectory, splineDirectorySize );
				
			}
		
		}
		
		QDUngetFontFrag( splineHandle, splineDirectoryPointer );
	
	}

	return( error );
	
}


/*********************************************************************************************								
**									sb_FillWidthTab
**
**	sb_FillWidthTab
**
**	This routine is called by the Font Manager when a new font width table needs to be filled
**	out with the proper metrics for spline fonts.
**
*/
pascal long sb_FillWidthTab(widthTableHdl widthTabHand, Boolean fractEnable)
{
	register sb_SplineKeyHdl		splineKey		= SPLINE_KEY_HAND;
	register sb_SplineKeyPtr		splineKeyPtr	= *splineKey;
	register widthTablePtr			widTabPtr 		= *widthTabHand;
	short							FontHandState	= HGetState (widTabPtr->tabFont);
	FMOutput						*fmRecPtr		= &FMOUTPUT_PTR;
	register long					result			= NO_ERR;
	Boolean							runInMinMode	= false;

#ifndef SYSTEM_7
	if (!splineKeyPtr->mfExists)			/* If it's not already running, check */
		splineKeyPtr->mfExists = MultiFinderExist();
#endif

	HNoPurge(widTabPtr->tabFont);

	widTabPtr->vOutput		= 1 << 8;			/* reset to no factor */
	widTabPtr->hOutput		= 1 << 8;
	widTabPtr->vFactor		= 1 << 8;
	widTabPtr->hFactor		= 1 << 8;	
	widTabPtr->notFast 		= (fmRecPtr->boldPixels || fmRecPtr->ulThick || fmRecPtr->shadowPixels);
	widTabPtr->trans00 		= FixDiv(widTabPtr->inNumer.h, widTabPtr->inDenom.h);
	widTabPtr->trans11 		= FixDiv(widTabPtr->inNumer.v, widTabPtr->inDenom.v);

	if (widTabPtr->aFace & OBLIQUE_BIT) {
		if (widTabPtr->aSize <= 8) {
			widTabPtr->trans10 = (widTabPtr->trans00) / 2;
		} else if (widTabPtr->aSize <= 16) {
			widTabPtr->trans10 = (widTabPtr->trans00) / 3;
		} else if (widTabPtr->aSize <= 22) {
			widTabPtr->trans10 = (widTabPtr->trans00) / 4;
		} else {
			widTabPtr->trans10 = (widTabPtr->trans00) / 5;
		}
	} else 		widTabPtr->trans10 = 0L;

	result = AppendSplineDirectoryToWidthTable( widTabPtr->tabFont, widthTabHand );
	if ( result == noErr ) {
	
		widTabPtr = *widthTabHand;

		if ((result = sb_CheckWorkHandle()) == MEM_ERR) {
			splineKeyPtr = *splineKey;
			if (!(result = sb_ShrinkCacheToMin(splineKeyPtr->cacheHand, 0))) {
				runInMinMode	= true;
				result 			= sb_CheckWorkHandle();
			}
		}
		if (!result) {
			splineKeyPtr	= *splineKey;
			HNoPurge(splineKeyPtr->fsWorkHand);								/* <30-CEL> */
			if (((result = sb_SetNewSFNT(widthTabHand)) == MEM_ERR) && !runInMinMode) {
				splineKeyPtr	= *splineKey;
				if (!(result = sb_ShrinkCacheToMin(splineKeyPtr->cacheHand, 0)))
					result 			= sb_SetNewSFNT(widthTabHand);
			}
			splineKeyPtr	= *splineKey;
			if (!result) {
				widTabPtr 		= *widthTabHand;
				sb_SetMemPtrs(widthTabHand);
	
				result = fs_FillWidthTable(splineKeyPtr->inPtr, (Fixed*)widTabPtr, widTabPtr->tabFont, widTabPtr->style, widTabPtr->fID, !fractEnable);
				if (result)
					sb_Debug();
			}
			HPurge(splineKeyPtr->fsWorkHand);								/* <30-CEL> */
		}
		
	}
	
	HSetState((**widthTabHand).tabFont, FontHandState);
	return (**widthTabHand).badFontFlag	= result;

}	/* End sb_FillWidthTab */


/*********************************************************************************************								
**									sb_FillPrinterWidths
**
**	sb_FillPrinterWidths
**
**	This routine is called by the Font Manager when a new font width table needs to be filled
**	out with the proper metrics for spline fonts.
**
*/
pascal long sb_FillPrinterWidths(Fixed *widthsArrayPtr, Handle sfntHand)
{
	sb_SplineKeyHdl					splineKey		= SPLINE_KEY_HAND;	/*<16> removed register */
	register sb_SplineKeyPtr		splineKeyPtr	= *splineKey;
	register long					result			= NO_ERR;
	register widthTablePtr 			widTabPtr;

#ifndef SYSTEM_7
	if (!splineKeyPtr->mfExists)			/* If it's not already running, check */
		splineKeyPtr->mfExists = MultiFinderExist();
#endif

	HLock( (Handle)splineKey );
	
	if (result = sb_CheckWorkHandle())		goto CLEANUP;
	HNoPurge(splineKeyPtr->fsWorkHand);									/* <28-CEL> */

	if (!splineKeyPtr->tempWidthTabHand) {
		splineKeyPtr->tempWidthTabHand		= (widthTableHdl)NewHandleSys(sizeof(widthTable));
		result = MemError();
	} else if (!*splineKeyPtr->tempWidthTabHand) {
		THz prevZone = GetZone();
		
		SetZone(SystemZone());
		ReallocHandle((Handle)splineKeyPtr->tempWidthTabHand, sizeof(widthTable));
		result = MemError();
		SetZone(prevZone);
	}
	
	if (!result) {
		widTabPtr				= *splineKeyPtr->tempWidthTabHand;
		widTabPtr->tabFont		= sfntHand;
		widTabPtr->fSize		= 1;
		widTabPtr->inNumer.h	= 1;
		widTabPtr->inNumer.v	= 1;
		widTabPtr->inDenom.h	= 1;
		widTabPtr->inDenom.v	= 1;
		widTabPtr->face			= 0;
		widTabPtr->aFace		= 0;
		widTabPtr->aSize		= 1;
		widTabPtr->trans00		= 1L << 16;
		widTabPtr->trans11		= 1L << 16;
		widTabPtr->trans10		= 0;
		
		result = AppendSplineDirectoryToWidthTable( sfntHand, splineKeyPtr->tempWidthTabHand );
		if ( result == noErr ) {
		
			if (result = sb_SetNewSFNT ( splineKeyPtr->tempWidthTabHand ))	
				sb_Debug();
			else {
				short	sfntID;			/* hack, should be id of this sfnt (passed in by caller) */
				ResType	sfntType;
				Str255	sfntName;
				
				GetResInfo( sfntHand, &sfntID, &sfntType, &sfntName[0] );
				sb_SetMemPtrs(splineKeyPtr->tempWidthTabHand);
				if (result = fs_FillWidthTable(splineKeyPtr->inPtr, widthsArrayPtr, sfntHand, 0, sfntID, 0))
					sb_Debug();
			}
		}
	} else sb_Debug();
	
	HPurge(splineKeyPtr->fsWorkHand);									/* <28-CEL> */
CLEANUP:
	HPurge((Handle)(splineKeyPtr->tempWidthTabHand));		/* Do not need if memory is needed */
	HUnlock((Handle)splineKey);
	return result;

}	/* End sb_FillPrinterWidths */


/*********************************************************************************************			
**									sb_PreFlightFontMem
**
**	sb_PreFlightFontMem
**
**	LONG_WORD_ALIGN((ppem+8) >> 3) == scan bytes long aligned.
**
**	Called by:		DrText, FMSwapFont
**
**	This preflighting will get better!!!
*/
#define CACHE_ARRAY_SIZE		1024
pascal long sb_PreFlightFontMem ( widthTableHdl widTabHand, Handle fontHandle, short scanLines, short ppem )
{
	sb_SplineKeyHdl				splineKey		= SPLINE_KEY_HAND;
	register sb_SplineKeyPtr	splineKeyPtr	= *splineKey;
	register long				result			= NO_ERR;
	Handle						tempHand;
	register long				bitAndSlopSpace;
	register widthTablePtr		widTabPtr		= *widTabHand;
	short						fontHandState;

#ifndef SYSTEM_7
	if (!splineKeyPtr->mfExists)			/* If it's not already running, check */
		splineKeyPtr->mfExists = MultiFinderExist();
#endif

	fontHandState	= HGetState(fontHandle);
	HNoPurge(fontHandle);
	
	result = AppendSplineDirectoryToWidthTable( fontHandle, widTabHand );
	if ( result == noErr ) {
	
		if (!(result = sb_CheckWorkHandle())) {
			splineKeyPtr		= *splineKey;
			sb_ResetFSWorkState(splineKeyPtr);
			HNoPurge(splineKeyPtr->fsWorkHand);
			
			sb_SetMemPtrs(widTabHand);
			(*splineKeyPtr->inPtr).clientID 		= fontHandle;
			if (!(result = sb_SetFontMemory(splineKey, widTabHand))) {
				register short		calcRowBytes = (LONG_WORD_ALIGN((ppem+8) >> 3));
	
				scanLines			= 4;		/* Hard code minumum band */
				bitAndSlopSpace		= scanLines * calcRowBytes;
				bitAndSlopSpace		+= (sizeof(sb_CacheHead) + CACHE_ARRAY_SIZE);
				/* bitAndSlopSpace		+= (ppem * calcRowBytes); */	/* for scan converter extra */
	
				if (!(tempHand = sb_GetBitMapSpace(bitAndSlopSpace))) {
					result	= PRE_FLIGHT_ERR;
				} else 		HPurge(tempHand);
			}
			HPurge((*splineKey)->fsWorkHand);
		}
	}
	HSetState(fontHandle, fontHandState);
	return result;

}	/* End sb_PreFlightFontMem */


/*********************************************************************************************						
**									sb_RenderGlyphInfo
**
**	sb_RenderGlyphInfo
**
*/
static long sb_RenderGlyphInfo ( sb_SplineKeyHdl splineKey, widthTableHdl widTabHand, long addEntryOffset )
{
	register sb_SplineKeyPtr	splineKeyPtr;
	register widthTablePtr		widTabPtr;
	register sb_CacheHeadPtr	cachePtr;
	register fs_GlyphInfoType	*infoPtr;
	register sb_GlyphData		*glyphDataPtr;
	char						*hiliteModePtr	= HILITEMODE;
	long						result;
	BitMap						*bitMapPtr;
	int16						ascent, descent, yMax, yMin;
	Fixed						newTrans11		= (*widTabHand)->trans11;
	unsigned char				resetTrans	= 0;						/* <14> */

SQUASH:
	if (result = sb_SetNewSFNT ( widTabHand )) 		return result;

	/* re-estab ptrs */
	splineKeyPtr	= *splineKey;
	widTabPtr		= *widTabHand;
	cachePtr		= *splineKeyPtr->cacheHand;
	glyphDataPtr	= (sb_GlyphData *)((char *)cachePtr + addEntryOffset);
	
	sb_SetMemPtrs(widTabHand);
#if TheFuture /* <18 > EBITMAP */
		(*splineKeyPtr->inPtr).param.newglyph.bitmapMethodPreferences 		= 1;
		(*splineKeyPtr->inPtr).param.newglyph.scalingPreference 		= 0;
#endif		
	(*splineKeyPtr->inPtr).param.newglyph.characterCode 	= glyphDataPtr->glyphID;
	if (result = fs_NewGlyph( splineKeyPtr->inPtr, splineKeyPtr->outPtr )) {
		sb_Debug();
		return	result;
	}

	(*splineKeyPtr->inPtr).param.gridfit.styleFunc = 0;
	(*splineKeyPtr->inPtr).param.gridfit.traceFunc = 0;

#if TheFuture /* <18 > EBITMAP */
	if (result = fs_GetGlyphInfo( splineKeyPtr->inPtr, splineKeyPtr->outPtr )) {
		sb_Debug();
		return	result;
	}
	if (!(*splineKeyPtr->outPtr).outlinesExist) {
		return SKIP_CHAR;	/* really means char is ok, but has no contours */
	}
#endif
#if !TheFuture /* <18 > EBITMAP */
	if (result = fs_ContourGridFit( splineKeyPtr->inPtr, splineKeyPtr->outPtr )) {
		sb_Debug();
		return	result;
	}
	if (!(*splineKeyPtr->outPtr).outlinesExist) {
		return SKIP_CHAR;	/* really means char is ok, but has no contours */
	}
	if (result = fs_FindBitMapSize( splineKeyPtr->inPtr, splineKeyPtr->outPtr )) {
		sb_Debug();
		return	result;
	}
#endif

	ascent						= (cachePtr->ascent >> 16);
	descent						= -(cachePtr->descent >> 16);			/* turn back into itÕs true sign */

	infoPtr						= (fs_GlyphInfoType	*)splineKeyPtr->outPtr;
	bitMapPtr					= &(infoPtr->bitMapInfo);
	glyphDataPtr->yMin = yMin	= bitMapPtr->bounds.top;
	glyphDataPtr->yMax = yMax 	= bitMapPtr->bounds.bottom;

	/* Squashing */
	if ( !(*hiliteModePtr & PRESERVE_GLYPH) && (resetTrans<2) && (yMax > ascent || yMin < descent)) /* <14> */
	{
		Fixed				maxTrans11, minTrans11;								/* <14> */
		++resetTrans;															/* <14> */

		if (yMax > ascent && ascent > 0)										/* <14> */
				maxTrans11 = ShortMulDiv(widTabPtr->trans11, ascent, yMax);		/* <14> */
		else	maxTrans11 = widTabPtr->trans11;								/* <14> */		
		if (yMin < descent && descent < 0)										/* <14> */
				minTrans11 = ShortMulDiv(widTabPtr->trans11, descent, yMin);	/* <14> */
		else	minTrans11 = widTabPtr->trans11;								/* <14> */
		
		widTabPtr->trans11	= (maxTrans11 < minTrans11) ? maxTrans11 : minTrans11;/* <14> */
			
		goto SQUASH;
	}	/* End Testing no line height */

	glyphDataPtr->lsb 			= infoPtr->metricInfo.leftSideBearing.x;
	glyphDataPtr->devLSB 		= infoPtr->metricInfo.devLeftSideBearing.x >> 16;
	glyphDataPtr->xMin			= infoPtr->bitMapInfo.bounds.left;
	glyphDataPtr->bitWidth 		= bitMapPtr->bounds.right - bitMapPtr->bounds.left;
	glyphDataPtr->scan 			= yMax - yMin;
	glyphDataPtr->byteWidth 	= glyphDataPtr->scanByteWidth = (uint32)bitMapPtr->rowBytes;

	widTabPtr->trans11 			= newTrans11;									/* <14> */

	return	NO_ERR;
}	/* End sb_RenderGlyphInfo */


/*********************************************************************************************						
**									sb_RenderMemShrink
**
**	
**
*/
long sb_RenderMemShrink(sb_SplineKeyHdl splineKey, long *addEntryOffset, Boolean *runInMinMode)
{
	register sb_SplineKeyPtr	splineKeyPtr		= *splineKey;	
	register sb_CacheHeadPtr	cachePtr;
	long						result;
	
	if (result = sb_ShrinkCacheToMin(splineKeyPtr->cacheHand, *addEntryOffset)) {
		sb_Debug();
		return result;
	} else {
		*runInMinMode 			= true;
		cachePtr				= *splineKeyPtr->cacheHand;
		*addEntryOffset			= cachePtr->addEntryOffset;
	}
	return NO_ERR;
}	/* End sb_RenderMemShrink */


/*********************************************************************************************						
**									sb_RoomForHead
**	Make room for the header
**
**	MOVES MEMORY
**
*/
long sb_RoomForHead(sb_SplineKeyHdl splineKey, long *addEntryOffset, Boolean *runInMinMode)
{
	register sb_SplineKeyPtr	splineKeyPtr		= *splineKey;	
	long						cacheSize;
	register Handle				tempHand;

	/**************************
	** Make room for the header
	**
	** MOVES MEMORY
	*/
	cacheSize		= GetHandleSize((Handle)splineKeyPtr->cacheHand);
	if (GLYPH_HEAD_BYTES > ( cacheSize - *addEntryOffset )) {
		THz		zone = splineKeyPtr->cacheZone;
		
		if (tempHand = sb_SizeTheBlock(splineKey, (Handle)splineKeyPtr->cacheHand, &zone, 
										 *addEntryOffset + GLYPH_HEAD_BYTES, kKeepContents,
										 splineKeyPtr->cachePlace, noShrink)) {
			splineKeyPtr			= *splineKey;
			splineKeyPtr->cacheHand = (sb_CacheHeadHdl)tempHand;
			splineKeyPtr->cacheZone = zone;
		} else	return(sb_RenderMemShrink(splineKey, addEntryOffset, runInMinMode));
	}
	return NO_ERR;
}	/* End 	sb_RoomForHead */




/*********************************************************************************************						
**									sb_RangeCheck
**
**	
**
*/
long sb_RangeCheck(sb_CacheHeadPtr cachePtr, sb_GlyphData *glyphDataPtr, 
				   short yMin16, short yMax16, long addEntryOffset, long glyphEntryOffset)
{
	/****** Font Scaler may return completely bogus values because of a bad font *******/
	/***** is the font bad????  do some range checking ******/
	if (!glyphDataPtr->scan			||
		glyphDataPtr->yMax < yMin16 ||
		glyphDataPtr->yMin > yMax16 ||
		glyphDataPtr->bitWidth == 0 || 
		glyphDataPtr->bitWidth > ((short)(cachePtr->widMax >> 16) * 2) ||
		(glyphDataPtr->yMax - glyphDataPtr->yMin) > ((yMax16 << 1) - yMin16)) {
		*(uint32*) ((Ptr) cachePtr + glyphEntryOffset) = (addEntryOffset | ERROR_ENTRY_BIT);
		sb_Debug( );		
		return ENTRY_ERROR;
	}
	return NO_ERR;
}	/* End sb_RangeCheck */

/*********************************************************************************************						
**									sb_SquishFailAdjust
**
** 	Squish Failure Adjustment
**
** 	If squishing was not enough, then clip away to
** 	keep in range
**
**	
**
*/
sb_SquishFailAdjust(sb_GlyphData *glyphDataPtr, sb_Glyph *glyphPtr, 
					short yMin16, short yMax16, Boolean *doBits, Boolean bitsCached)
{
	if (glyphDataPtr->yMax > yMax16)	glyphDataPtr->yMax = yMax16;
	if (glyphDataPtr->yMin < yMin16)	glyphDataPtr->yMin = yMin16;	
	glyphDataPtr->scan 			= glyphDataPtr->yMax - glyphDataPtr->yMin;
	glyphDataPtr->adjustTop 	= yMax16 - glyphDataPtr->yMax;
	glyphPtr->yMin				= glyphDataPtr->yMin;
	glyphPtr->yMax				= glyphDataPtr->yMax;
	glyphPtr->scan				= glyphDataPtr->scan;
	
	if (!bitsCached || glyphPtr->clipVert) {
		if (glyphPtr->topClip < glyphDataPtr->yMax)		glyphPtr->yMax = glyphPtr->topClip;
		if (glyphPtr->botClip > glyphDataPtr->yMin)		glyphPtr->yMin = glyphPtr->botClip;
		glyphPtr->scan	= glyphPtr->yMax - glyphPtr->yMin;
	
		if (glyphPtr->scan <= 0)	*doBits	= false;
	}
	return;

}	/* End sb_SquishFailAdjust */


/*********************************************************************************************						
**									sb_GrowForGlyphData
**
**	
**
*/
long sb_GrowForGlyphData(sb_SplineKeyHdl splineKey, widthTableHdl widTabHand, sb_GlyphData *glyphDataPtr,
						 long *addEntryOffset, Boolean *runInMinMode, Boolean bitsCached,
						 long *dataByteSize)
{
	register sb_SplineKeyPtr	splineKeyPtr		= *splineKey;	
	widthTablePtr				widTabPtr			= *widTabHand;
	register Handle				tempHand;
	long						result;
	long						cacheSize;

	/***********************
	** CALC THE DATA SIZE
	*/
	if (bitsCached) {
		*dataByteSize = ((glyphDataPtr->scanByteWidth * glyphDataPtr->scan) + 3) & ~3;
	} else {
		sb_SetMemPtrs(widTabHand);
		fs_SizeOfOutlines( splineKeyPtr->inPtr, splineKeyPtr->outPtr );
		*dataByteSize = ((*splineKeyPtr->outPtr).outlineCacheSize + 3) & ~3;
	}

	/************************************
	** Check CACHE size - MOVES MEMORY
	*/
	cacheSize		= GetHandleSize((Handle)splineKeyPtr->cacheHand);
	if (*dataByteSize + GLYPH_HEAD_BYTES > cacheSize - *addEntryOffset) {
		THz		zone = splineKeyPtr->cacheZone;

		if (!(tempHand = sb_SizeTheBlock( splineKey, (Handle)splineKeyPtr->cacheHand, &zone, 
								*addEntryOffset + *dataByteSize + GLYPH_HEAD_BYTES + INCREASE_CACHE,
								kKeepContents, splineKeyPtr->cachePlace, noShrink))) {
			splineKeyPtr	= *splineKey;	/* Try for minimum chunk */
			tempHand = sb_SizeTheBlock( splineKey, (Handle)splineKeyPtr->cacheHand, &zone, 
												*addEntryOffset + GLYPH_HEAD_BYTES + *dataByteSize, 
												kKeepContents, splineKeyPtr->cachePlace, noShrink);
		}
		if (tempHand) {
			splineKeyPtr				= *splineKey;
			splineKeyPtr->cacheHand 	= (sb_CacheHeadHdl)tempHand;
			splineKeyPtr->cacheZone 	= zone;
		} else if (!*runInMinMode) {
			if (result = sb_RenderMemShrink(splineKey, addEntryOffset, runInMinMode))
				return result;
		} else return GROWZONE_HANDLE_ERR;
	}
	return NO_ERR;

}	/* End sb_GrowForGlyphData */


/*********************************************************************************************						
**									sb_GrowWork6and7
**
**	
**
*/
long sb_GrowWork6and7(sb_SplineKeyHdl splineKey, widthTableHdl widTabHand, 
				 	  long *addEntryOffset, Boolean *runInMinMode)
{
	register sb_SplineKeyPtr	splineKeyPtr		= *splineKey;	
	widthTablePtr				widTabPtr			= *widTabHand;
	long						result, position;

	/*********************************************
	** Do the clipping dance - CAN MOVE MEMORY
	**
	** <6> new memory for the scan converter
	*/
	sb_SetMemPtrs(widTabHand);
	position	= splineKeyPtr->rowArrayOffset6 + LONG_WORD_ALIGN(splineKeyPtr->outPtr->memorySizes[6]);
	
	if (!*runInMinMode) {
		splineKeyPtr->columnArrayOffset7 = position;
		position 	+= LONG_WORD_ALIGN(splineKeyPtr->outPtr->memorySizes[7]);
	}
	
	if ((result = sb_SizeWorkHandle( position, kKeepContents, doShrink )) && !*runInMinMode)
		if (!(result = sb_RenderMemShrink(splineKey, addEntryOffset, runInMinMode)))
			result = sb_SizeWorkHandle( position, kKeepContents, doShrink );

	return result;


}	/* End sb_GrowWork6and7 */

/*********************************************************************************************						
**									sb_GetMemForBits
**
**	
**
*/
long sb_GetMemForBits(sb_SplineKeyHdl splineKey, widthTableHdl widTabHand, 
					  sb_Glyph *glyphPtr, Boolean *runInMinMode, long *addEntryOffset, 
					  short yMax16, long memForScanLine)
{
	register sb_SplineKeyPtr	splineKeyPtr		= *splineKey;	
	register widthTablePtr		widTabPtr			= *widTabHand;
	register sb_CacheHeadPtr	cachePtr			= *splineKeyPtr->cacheHand;
	register sb_GlyphData		*glyphDataPtr		= (char *)cachePtr + *addEntryOffset;
	short						scanBytes			= glyphDataPtr->scanByteWidth;
	Handle						tempHand;
	long						bmSize;
	long						result, position;
	Boolean						bandGlyph			= false;

	if (glyphPtr->nextBand) {
		glyphDataPtr->yMax = glyphPtr->yMax	= glyphPtr->nextTopBand;
		if (glyphPtr->nextTopBand - glyphPtr->nextBotBand <= glyphPtr->bandScan) {
			glyphDataPtr->yMin = glyphPtr->yMin	= glyphPtr->nextBotBand;
		} else {
			glyphDataPtr->yMin = glyphPtr->yMin	= glyphPtr->yMax - glyphPtr->scan;
			glyphPtr->nextTopBand	= glyphPtr->yMin;
		}
		glyphDataPtr->scan = glyphPtr->scan	= glyphPtr->yMax - glyphPtr->yMin;
		glyphDataPtr->adjustTop = yMax16 - glyphDataPtr->yMax;
	}
	
	bmSize		= glyphPtr->scan * scanBytes;
	if (*runInMinMode && !glyphPtr->nextBand) {
		sb_SetMemPtrs(widTabHand);
		position	= splineKeyPtr->rowArrayOffset6 + LONG_WORD_ALIGN(memForScanLine*glyphPtr->scan);
		if (result = sb_SizeWorkHandle( position, kKeepContents, doShrink ))
			bandGlyph	= true;
	}
	
	tempHand		= nil;		/* init to nil */
	if (!bandGlyph || glyphPtr->nextBand) {
		if (!(tempHand = sb_GetBitMapSpace(bmSize))) {
			if (!glyphPtr->nextBand) {
				if (!*runInMinMode) {
					if (result = sb_RenderMemShrink(splineKey, addEntryOffset, runInMinMode))
						return result;
				}
				bandGlyph			= true;
			} else {
				glyphPtr->nextBand		= false;			/* second time so we are in trouble */
				sb_Debug();
				return MEM_ERR;
			}
		} else if (glyphPtr->yMin == glyphPtr->nextBotBand)
			glyphPtr->nextBand		= false;			/* finished char loop */
	}

	if (bandGlyph) {		/* could still not get the bitmap */
		if (tempHand = sb_BandChar(splineKey, &glyphPtr->scan, scanBytes, memForScanLine)) {
			splineKeyPtr			= *splineKey;
			cachePtr				= (sb_CacheHead *)*splineKeyPtr->cacheHand;
			glyphDataPtr			= (sb_GlyphData *)((char *)cachePtr + *addEntryOffset);
			
			glyphPtr->nextBand		= true;
			glyphPtr->nextBotBand	= glyphPtr->yMin;
			glyphDataPtr->yMin 		= glyphPtr->yMin = glyphPtr->yMax - glyphPtr->scan;
			glyphPtr->nextTopBand	= glyphPtr->yMin;
			glyphDataPtr->scan 		= glyphPtr->bandScan = glyphPtr->scan;
			glyphDataPtr->yMax 		= glyphPtr->yMax;
		} else {
			sb_Debug();
			return MEM_ERR;
		}
	}

	/* This is a temporary hack!!! This fixes the problem with low memory banding */
	if (glyphPtr->topClip - glyphPtr->botClip == 0 && glyphPtr->nextBand)
		glyphPtr->nextBand	= false;
	
	glyphPtr->bitMapPtr		= (uint32 *)*tempHand;
	HPurge(tempHand);
	return NO_ERR;

}	/* End sb_GetMemForBits */


/*********************************************************************************************						
**									sb_DoTheBits
**
**	
**
*/
long sb_DoTheBits(sb_SplineKeyHdl splineKey, widthTableHdl widTabHand, register sb_Glyph *glyphPtr,
				  short topClip, short bottomClip, Boolean bitsCached, Boolean  runInMinMode, 
				  long addEntryOffset, long glyphEntryOffset)									
{
	register sb_SplineKeyPtr	splineKeyPtr		= *splineKey;	
	register widthTablePtr		widTabPtr			= *widTabHand;
	register sb_CacheHeadPtr	cachePtr			= *splineKeyPtr->cacheHand;
	register sb_GlyphData		*glyphDataPtr		= (char *)cachePtr + addEntryOffset;
	long						result;

	sb_SetMemPtrs(widTabHand);
	(*splineKeyPtr->inPtr).memoryBases[5]			= (char *)glyphPtr->bitMapPtr; 				/* bitmap space */
	(*splineKeyPtr->inPtr).param.scan.topClip		= topClip;
	(*splineKeyPtr->inPtr).param.scan.bottomClip	= bottomClip;
	if (runInMinMode)		(*splineKeyPtr->inPtr).memoryBases[7]		= 0;
#if TheFuture /* <18 > EBITMAP */
	if (result = fs_GetGlyphData( splineKeyPtr->inPtr, splineKeyPtr->outPtr )) {
		*(uint32*) ((Ptr) cachePtr + glyphEntryOffset) |= ERROR_ENTRY_BIT;						
		sb_Debug();
		return result;
	}
#endif
#if !TheFuture /* <18 > EBITMAP */
	if (result = fs_ContourScan( splineKeyPtr->inPtr, splineKeyPtr->outPtr )) {
		*(uint32*) ((Ptr) cachePtr + glyphEntryOffset) |= ERROR_ENTRY_BIT;						
		sb_Debug();
		return result;
	}
#endif
	if ((bitsCached && !runInMinMode) || !glyphPtr->clipVert) {			/* <3-CEL> */
		sb_ShrinkBitmap( glyphDataPtr, (long *)glyphPtr->bitMapPtr, topClip-bottomClip);
	}
	
	glyphPtr->byteWidth = glyphDataPtr->byteWidth;

	if (bitsCached && !runInMinMode) {									/* <3-CEL> */
		int16		sourceYMaxAdjust = glyphDataPtr->yMax - glyphPtr->topClip;

		cachePtr->addEntryOffset 	+= (((glyphDataPtr->byteWidth * glyphDataPtr->scan) + 3) & ~3);
		if (sourceYMaxAdjust > 0)
			glyphPtr->bitMapPtr = (uint32 *)((char *)glyphPtr->bitMapPtr + (sourceYMaxAdjust * glyphDataPtr->byteWidth));
	}
	return NO_ERR;

}	/* End sb_DoTheBits */

/*********************************************************************************************						
**									sb_RenderGlyph
**
**	
**
*/
static long sb_RenderGlyph( sb_SplineKeyHdl splineKey, widthTableHdl widTabHand, register sb_Glyph *glyphPtr )
{
	register sb_SplineKeyPtr	splineKeyPtr		= *splineKey;	
	register widthTablePtr		widTabPtr			= *widTabHand;
	register sb_CacheHeadPtr	cachePtr			= *splineKeyPtr->cacheHand;
	Boolean						bitsCached			= cachePtr->bitsCached;
	long						addEntryOffset		= cachePtr->addEntryOffset;
	register sb_GlyphData		*glyphDataPtr		= (char *)cachePtr + addEntryOffset;
	uint16						yMinAdjust			= 0;			/* adjust for scan lines out of bounds */
	Boolean						doBits				= true;
	short						yMax16				= (cachePtr->yMax >> 16);
	short						yMin16				= (cachePtr->yMin >> 16);
	Boolean						runInMinMode		= false;			/* <3-CEL> */
	long						dataByteSize;
	long						glyphEntryOffset;															
	long						result;
	int16 						topClip, bottomClip;
	long						memForScanLine;


	glyphPtr->entryOffset				= 0;
	if (glyphPtr->nextBand) {
		glyphEntryOffset = GetSingleOrDoubleByteGlyphEntryOffset( glyphPtr->glyphID, cachePtr );		
		runInMinMode	= true;
		goto DO_NEXT_BAND;
	} else if (result = sb_RoomForHead(splineKey, &addEntryOffset, &runInMinMode))
		return result;
		
	/************************************
	** Re-Establish pointers
	*/
	splineKeyPtr	= *splineKey;
	cachePtr		= *splineKeyPtr->cacheHand;
	glyphDataPtr	= (sb_GlyphData *)((char *)cachePtr + addEntryOffset);
	glyphDataPtr->glyphID			= glyphPtr->glyphID;
	
	if (!runInMinMode) {							/* <3-CEL> */
		cachePtr->addEntryOffset 		+= GLYPH_HEAD_BYTES;			/* For next entry */
	}

	if ((result = sb_RenderGlyphInfo(splineKey, widTabHand, addEntryOffset)) == MEM_ERR) {
		if (!runInMinMode) {
			if (result = sb_RenderMemShrink(splineKey, &addEntryOffset, &runInMinMode))
				return result;
			if (result = sb_RenderGlyphInfo(splineKey, widTabHand, addEntryOffset))
				return result;
		}
	}
	
	/***********************
	** Re-establish pointers
	*/
	splineKeyPtr		= *splineKey;
	widTabPtr			= *widTabHand;
	cachePtr			= *splineKeyPtr->cacheHand;
	glyphDataPtr		= (sb_GlyphData *)((char *)cachePtr + addEntryOffset);

	/************************************
	** Determine glyph position in array
	*/

	glyphEntryOffset = GetSingleOrDoubleByteGlyphEntryOffset( glyphDataPtr->glyphID, cachePtr );		

	if (result) {
		*(uint32*) ((Ptr) cachePtr + glyphEntryOffset) = ERROR_ENTRY_BIT;								
		return ENTRY_ERROR;
	}
	if (glyphDataPtr->scan)
		memForScanLine = LONG_WORD_ALIGN(splineKeyPtr->outPtr->memorySizes[6])/glyphDataPtr->scan;

	if (result = sb_RangeCheck(cachePtr, glyphDataPtr, yMin16, yMax16, addEntryOffset, glyphEntryOffset))	
		return result;
	
	/**********************************************
	** Figure out the bottom and top scan lines
	*/
	if (!runInMinMode) {						/* <3-CEL> */
		if (bitsCached)
			*(uint32*) ((Ptr) cachePtr + glyphEntryOffset) = addEntryOffset;						
		else
			*(uint32*) ((Ptr) cachePtr + glyphEntryOffset) = (addEntryOffset | CONTOUR_ENTRY_BIT);	
	}
	
	sb_SquishFailAdjust(glyphDataPtr, glyphPtr, yMin16, yMax16, &doBits, bitsCached);

	if (!glyphDataPtr->scan) {						/* <2-CEL> if no scan lines, skip char */
		*(uint32*) ((Ptr) cachePtr + glyphEntryOffset) = ERROR_ENTRY_BIT;								
		return ENTRY_ERROR;
	}
	
	if (!runInMinMode) {
		if (result = sb_GrowForGlyphData(splineKey, widTabHand, glyphDataPtr, &addEntryOffset, 
					 					 &runInMinMode, bitsCached, &dataByteSize)) {
			sb_Debug();
			return result;
		}
	}

	if (result = sb_GrowWork6and7(splineKey, widTabHand, &addEntryOffset, &runInMinMode)) {
		sb_Debug();
		return result;
	}

	/************************************
	** Re-Establish pointers
	*/
	splineKeyPtr					= *splineKey;	
	widTabPtr						= *widTabHand;
	cachePtr						= (sb_CacheHead *)*splineKeyPtr->cacheHand;
	glyphDataPtr					= (sb_GlyphData *)((char *)cachePtr + addEntryOffset);
	sb_SetMemPtrs(widTabHand);

	/************************************
	** Make space at tail and init pointers 
	*/
	if (bitsCached) {
		glyphPtr->bitMapPtr					= (uint32 *)&glyphDataPtr->cacheData[0];
		topClip 	= glyphDataPtr->yMax;
		bottomClip 	= glyphDataPtr->yMin;
	} else if (!runInMinMode) {
		(*splineKeyPtr->inPtr).param.scan.outlineCache		= (long *)&glyphDataPtr->cacheData[0];
		if (result = fs_SaveOutlines( splineKeyPtr->inPtr, splineKeyPtr->outPtr )) {
			*(uint32*) ((Ptr) cachePtr + glyphEntryOffset) |= ERROR_ENTRY_BIT;							
			sb_Debug();
			return result;
		}
		cachePtr->addEntryOffset		+= dataByteSize;
	}
DO_NEXT_BAND:	
	if (doBits && (runInMinMode || !bitsCached)) {			/* <3-CEL> */
		if (result = sb_GetMemForBits(splineKey, widTabHand, glyphPtr, &runInMinMode, 
									  &addEntryOffset, yMax16, memForScanLine))
			return result;
		bottomClip 				= glyphPtr->yMin;
		topClip 				= glyphPtr->yMax;
	}
	
	if (doBits || (bitsCached && !runInMinMode)) {
		if (result = sb_DoTheBits(splineKey, widTabHand, glyphPtr, topClip, bottomClip, bitsCached, 
						 runInMinMode, addEntryOffset, glyphEntryOffset))	/* 11-CEL assign result */
			return result;
	}
	glyphPtr->entryOffset	= addEntryOffset;
	if (!doBits) 	return NO_BITS;

	return NO_ERR;
}	/* sb_RenderGlyph */


/*********************************************************************************************						
**									sb_CheckCache
**
**	sb_CheckCache
**
**
*/
pascal long sb_CheckCache( sb_SplineKeyHdl splineKey, widthTableHdl widthTabHand, register sb_Glyph *glyphPtr )
{
	register sb_SplineKeyPtr	splineKeyPtr;
	register widthTablePtr		widTabPtr 			= *widthTabHand;
	register sb_CacheHead		*cachePtr;
	register sb_GlyphData		*glyphDataPtr;
	long						glyphEntryOffset;														
	register long				cacheDataOffset;
	Handle						tempHand;
	long						result;
	Boolean						runInMinMode		= false;
	
	if (glyphPtr->nextBand) 		goto MIN_MODE;
	
	widTabPtr		= *widthTabHand;
	splineKeyPtr 	= *splineKey;
	cachePtr 		= *splineKeyPtr->cacheHand;
	glyphPtr->entryOffset				= 0;

	/*********************************************/
	/** FIND THE POSITION, OFFSET, AND DATA PTR **/
	/*********************************************/

	glyphEntryOffset = GetSingleOrDoubleByteGlyphEntryOffset( glyphPtr->glyphID, cachePtr );		
	cacheDataOffset = (*(uint32*) ((Ptr) cachePtr + glyphEntryOffset)) & ENTRY_MASK;									
	
	/********************/
	/** FIND THE ENTRY **/
	/********************/
	if (cacheDataOffset) {
		long		bmSize;
		long		position;
		
		glyphDataPtr		= (sb_GlyphData *)((char *)cachePtr + cacheDataOffset);
		glyphPtr->yMin 		= glyphDataPtr->yMin;
		glyphPtr->yMax 		= glyphDataPtr->yMax;
		glyphPtr->scan		= glyphDataPtr->scan;
		glyphPtr->byteWidth = glyphDataPtr->scanByteWidth;
		if (glyphPtr->clipVert) {
			if (glyphPtr->topClip < glyphDataPtr->yMax)	 	glyphPtr->yMax = glyphPtr->topClip;
			if (glyphPtr->botClip > glyphDataPtr->yMin)	 	glyphPtr->yMin = glyphPtr->botClip;

			glyphPtr->scan	= glyphPtr->yMax - glyphPtr->yMin;
			if (glyphPtr->scan <= 0)	return CLIPPED_OUT;
		}

		sb_SetMemPtrs(widthTabHand);
		(*splineKeyPtr->inPtr).param.scan.outlineCache = (long *)&glyphDataPtr->cacheData[0];
		if (result = fs_RestoreOutlines( splineKeyPtr->inPtr, splineKeyPtr->outPtr )) {	
			sb_Debug();
			return result;
		}

		/* <6> new memory for the scan converter */
		position	= splineKeyPtr->rowArrayOffset6 + LONG_WORD_ALIGN((*splineKeyPtr->outPtr).memorySizes[6]);
		splineKeyPtr->columnArrayOffset7 = position;
		position 	+= LONG_WORD_ALIGN((*splineKeyPtr->outPtr).memorySizes[7]);

		bmSize 		= glyphPtr->scan * glyphDataPtr->scanByteWidth;

		/****************/
		/* MOVES MEMORY */
		/****************/
		if (result = sb_SizeWorkHandle( position, kKeepContents, doShrink )) {
			splineKeyPtr = *splineKey;
			if (result = sb_ShrinkCacheToMin(splineKeyPtr->cacheHand, cacheDataOffset)) {
				sb_Debug();
				return result;
			} else {
				goto MIN_MODE;			/* must rerun since data is lost */
			}
		}

		/****************/
		/* MOVES MEMORY */
		/****************/
		if (!(tempHand = sb_GetBitMapSpace(bmSize))) {
			splineKeyPtr = *splineKey;
			if (result = sb_ShrinkCacheToMin(splineKeyPtr->cacheHand, cacheDataOffset)) {
				sb_Debug();
				return result;
			} else {
				goto MIN_MODE;			/* must rerun since data is lost */
			}
		}
		HPurge(tempHand);
		/****************/

		/*************************************************/
		/* Re-establish pointers after memory allocation */
		splineKeyPtr			= *splineKey;
		widTabPtr 				= *widthTabHand;
		cachePtr 				= (sb_CacheHead *)*splineKeyPtr->cacheHand;
		glyphDataPtr			= (sb_GlyphData *)((char *)cachePtr + cacheDataOffset);
		glyphPtr->bitMapPtr		= (uint32 *)*tempHand;

		sb_SetMemPtrs(widthTabHand);
		(*splineKeyPtr->inPtr).memoryBases[5] 			= (char *)glyphPtr->bitMapPtr;
		(*splineKeyPtr->inPtr).param.scan.outlineCache	= (long *)&glyphDataPtr->cacheData[0];
		(*splineKeyPtr->inPtr).param.scan.bottomClip	= glyphPtr->yMin;
		(*splineKeyPtr->inPtr).param.scan.topClip		= glyphPtr->yMax;
#if TheFuture /* <18 > EBITMAP */
		if (result = fs_GetGlyphData( splineKeyPtr->inPtr, splineKeyPtr->outPtr )) {
			sb_Debug();
			*(uint32*) ((Ptr) cachePtr + glyphEntryOffset) |= ERROR_ENTRY_BIT;						
			return result;
		}
#endif
#if !TheFuture /* <18 > EBITMAP */
		if (result = fs_ContourScan( splineKeyPtr->inPtr, splineKeyPtr->outPtr )) {
			sb_Debug();
			*(uint32*) ((Ptr) cachePtr + glyphEntryOffset) |= ERROR_ENTRY_BIT;						
			return result;
		}
#endif

		if (!glyphPtr->clipVert) {
			sb_ShrinkBitmap( glyphDataPtr, (long *)glyphPtr->bitMapPtr, glyphPtr->yMax-glyphPtr->yMin);
			glyphPtr->byteWidth = glyphDataPtr->byteWidth;
		}
		glyphPtr->entryOffset	= cacheDataOffset;
		return NO_ERR;
		
	} 	/* End If */
		
MIN_MODE:
	return( sb_RenderGlyph(splineKey, widthTabHand, glyphPtr) );

}	/* End sb_CheckCache */

/*********************************************************************************************						
**									sb_RetrieveGlyph
**
**	sb_RetrieveGlyph
**
**
*/
pascal long sb_RetrieveGlyph( widthTableHdl widthTabHand, sb_Glyph *glyphPtr )
{
	sb_SplineKeyHdl				splineKey			= SPLINE_KEY_HAND;
	register sb_SplineKeyPtr	splineKeyPtr		= *splineKey;
	register widthTablePtr		widTabPtr 			= *widthTabHand;
	short						fontHandState		= HGetState (widTabPtr->tabFont);
	short						cacheHandState		= HGetState ((Handle)splineKeyPtr->cacheHand);	/* 15-CEL */
	long						result;
 
#ifndef SYSTEM_7
	if (!splineKeyPtr->mfExists)			/* If it's not already running, check */
		splineKeyPtr->mfExists = MultiFinderExist();
#endif
	splineKeyPtr->glyphID	= glyphPtr->glyphID;		/* keep track in key which glyphid */
	
	HNoPurge(widTabPtr->tabFont);
	HNoPurge((Handle)splineKeyPtr->cacheHand);							/* 15-CEL */

	if ((result = sb_CheckWorkHandle()) == MEM_ERR) {
		splineKeyPtr = *splineKey;
		if (!(result = sb_ShrinkCacheToMin(splineKeyPtr->cacheHand, 0)))
			result 			= sb_CheckWorkHandle();
	}
	if (!result) {
		HNoPurge(splineKeyPtr->fsWorkHand);
		
		/* If banding in TrueType, don't AddGlyphOffset table more than once <KON Sakura2>*/
		if (!glyphPtr->nextBand)
			result = AddLowByteGlyphOffsetTable( glyphPtr->glyphID, splineKey );
			
		if ( result == noErr ) {
		
			result	= sb_CheckCache( splineKey, widthTabHand, glyphPtr );
			if ((result == noErr) ||
				(result == NO_BITS))		// can be returned by sb_RenderGlyph for some reason
											// seems to only happen printing with the StyleWriter
			{

				CheckForMaximumDiskCacheSize( (*splineKey)->cacheHand );
				
			}
			
		}
		
		HPurge((*splineKey)->fsWorkHand);
	}

	HSetState((Handle)(*splineKey)->cacheHand, cacheHandState);         /* 15-CEL */
	HSetState((*widthTabHand)->tabFont, fontHandState);
	return result;


}	/* End sb_RetrieveGlyph */

									/****************************/
									/* END CALLS TO FONT SCALER */
									/****************************/
/***************************************************************************************************/
/***************************************************************************************************/