supermario/base/SuperMarioProj.1994-02-09/Toolbox/FontMgr/FontMgrPatch.a
2019-06-29 23:17:50 +08:00

2923 lines
109 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

;EASE$$$ READ ONLY COPY of file “FontMgrPatch.a”
; 1.3 CCH 04/17/1989 Unconditionalized fixes from 6.0.3.
; 1.2 CCH 01/31/1989 Merged changes from 6.0.3.
; 1.1 CCH 01/16/1989 Merged 6.0.3 final sources into 7.0.
; 1.0 CCH 11/16/1988 Added to EASE.
; END EASE MODIFICATION HISTORY
; File: FontMgrPatch.a
;
;________________________________________________________________________________
; NOTICE: When entering patches use the format that is described below...
;
; Please read the following description for
; the Patch Collator. Patch Collator will
; aid us in finding out where system
; patches are located. Therefore, making
; it a little easier to track down rodents!
;
;
; Patch Collator for the Macintosh System Disk
; ============================================
;
; File: patch.c
; Language: "C"
;
; Date: April 16, 1987
; Revision: 1.0
; Author: Charlton E. Lui
;
; Patch collator is a simple program that scans through files looking for Apple System Patches.
; It finds a patch comment by finding a header that looks like this...
;
; *** One to one mapping of a fix ***
; Fix File Date Patch# Fix Routine(s) Routine(s) Fixed
;*AppleSystemPatch FontMgrPatch.a 08Jul85 #0 (InstallRDrivers) (InstallRDrivers)
;
; *** One to many mapping of a fix ***
; Fix File Date Patch# Fix Routine(s) Routine(s) Fixed
;*AppleSystemPatch FontMgrPatch.a 09Dec85 #13 (SoundVBLAddress) (RecoverHandle,ROMBMap)
;
; *** Many to one mapping of a fix ***
; Fix File Date Patch# Fix Routine(s) Routine(s) Fixed
;*AppleSystemPatch FontMgrPatch.a 17May86 #47 (FontMgr,DialogMgr) (GetRsrc)
;
; *** One to many mapping of a fix ***
; Fix File Date Patch# Fix Routine(s) Routine(s) Fixed
;*AppleSystemPatch FontMgrPatch.a 23Apr86 #43 (BTFlush,BTClose) (BTFlush,BTClose)
;
;
;
; The examples show the many mappings a fix may have. Each file should have the appropiate ROM
; version already inserted atop the file so it does not need be entered.
;
; WARNING: To make sure the scan works properly, use parenthesis around the routine field(s).
;
; This header will be inserted atop of each patch file. Whenever a new patch is entered the person
; who is entering the patch will copy the header down to the place where they are making the fix
; and enter the pertinent information.
;
; IMPORTANT! Make sure to take out the asterix before the AppleSystemPatch symbol.
; The "*" was added so that Patch Collator would not mistake the comments above as
; an actual patch. So delete the "*" before. Also, make sure that there is no
; space between the ";"(semicolon) and the "AppleSystemPatch" symbol. It should look like this
; ";AppleSystemPatch".
;
; A file will contain a list of names of the main patch files. Patch collator will use
; MPW's funnel facility to feed the names into the patch collator.
;
; PatchCollator < PatchFiles
;
; The files will also be scanned for other patch file includes. The included patch files will
; be added to the list of patch files.
;
; Each file will be scanned for patch information and then entered into a binary tree.
; The binary tree is used to sort the patch list alpabetically. After it finishes,
; it disposes of all of the nodes of the tree.
;
; Patch Collator uses simple parsing techniques. It does not check whether or not the information
; is correct or not. Patch Collator will leave that for the AI group.
;
; Output will contain the information something like this...
;
; Files working on...
; ===================
; #1) Reading file PatchPlusROM.a
; Includes patch files for PatchPlusROM.a are as follows...
; #3) DrawPicturePatch.a
; #4) TEPatch.a
; #5) FontMgrPatch.a
; #6) MenuMgr.a
; #7) HMenuPatch.Install
; #2) Reading file PatchSEROM.a
; Includes patch files for PatchSEROM.a are as follows...
; #3) DrawPicturePatch.a
; #6) MenuMgr.a
; #7) HMenuPatch.Install
; #3) **Warning - could not open DrawPicturePatch.a
; #4) **Warning - could not open TEPatch.a
; #5) **Warning - could not open FontMgrPatch.a
; #6) **Warning - could not open MenuMgr.a
; #7) **Warning - could not open HMenuPatch.Install
; ====================================================================================================
; *****PATCH COLLATOR*****
; ====================================================================================================
;
; ** Column Condition:
; ** X means this trap is patched to fix another trap.
; Y means that this trap is being fixed by a trap ( possibly itself ).
;
; Patch List Condition Patch# Fix File Line# Date
; ====================================================================================================
;
; AsynchDrvrs Y #3 PatchPlusROM.a 2348 14Oct85
; AsynchDrvrs Y #42 PatchPlusROM.a 2302 14Oct85
; atalk:lap.a X #P019 PatchSEROM.a 2273 23Dec86
; atalk:nonres.a X #PA073 PatchSEROM.a 2276 2Mar87
; AutoInt1 X #21 PatchPlusROM.a 1700 01Jan1904
; BasicIO X #50 PatchPlusROM.a 2540 11Sep86
; BasicIO Y #50 PatchPlusROM.a 2540 11Sep86
; BTClose X #43 PatchPlusROM.a 2404 23Apr86
; BTClose Y #43 PatchPlusROM.a 2404 23Apr86
;
; Notice: The files that couldn't be opened will give a warning. This could have resulted in
; a typo or perhaps the file was not found in the directory.
;
;
;
;
;_______________________________________________________________________________________
FontManager PROC EXPORT
EXPORT InitFonts
EXPORT SetFontLock
EXPORT GetFontName
EXPORT FMSwapFont
EXPORT RealFont
EXPORT FontMetrics
EXPORT SetFScaleDisable
EXPORT SetFractEnable
EXPORT FMgrEnd
EXPORT FPointOne ; (so that first reference wil be seen.)
bugFix EQU 1
patch EQU 1
FoutCurStyle EQU FOutUnused ;post the current style used here.
NumTables EQU 12
WidListSize EQU NumTables*4
FMSwapTrap EQU $101 ;the FMSwapFont trap number for _GetTrapAddr
; format of a width table:
WidTabData EQU 0 ;256 fixed point widths
WidTabFont EQU 1024 ;(long) font handle used to generate this width table
WidthSExtra EQU WidTabFont+4 ;(long) fixed point space extra used for this table
WidthStyle EQU WidthSExtra+4 ;(long) fixed point extra due to style, used for this table
WidthFID EQU WidthStyle+4 ;(word) font family ID for this table
WidthFSize EQU WidthFID+2 ;(word) font size request that generated this table
WidthFace EQU WidthFSize+2 ;(word) face request that generated this table
WidthDevice EQU WidthFace+2 ;(word) device requested
WidthScales EQU WidthDevice+2 ;(8 bytes) scale factors requested on input
WidthAFID EQU WidthScales+8 ;(word) actual font family ID for this table
WidthFHand EQU WidthAFID+2 ;(long) font family handle for this table
WidthUsedFam EQU WidthFHand+4 ;(boolean) whether we used fixed point family widths
WidthAFace EQU WidthUsedFam+1 ;(byte) actual face produced (may differ for styled fonts)
WidthVOutput EQU WidthAFace+1 ;(word) vertical scale output value
WidthHOutput EQU WidthVOutput+2 ;(word) horizontal scale output value
WidthVFactor EQU WidthHOutput+2 ;(word) vertical scale output value
WidthHFactor EQU WidthVFactor+2 ;(word) horizontal scale output value
WidthASize EQU WidthHFactor+2 ;(word) actual size of font strike used
WidTabSize EQU WidthASize+2 ;total size of a width table.
; FOND format definition
FONDFlags EQU 0 ; 0 (word) Flags word for family
FONDFamID EQU FONDFlags+2 ; 2 (word) Family ID number
FONDFirst EQU FONDFamID+2 ; 4 (word) first character in font
FONDLast EQU FONDFirst+2 ; 6 (word) last character in font
FONDAscent EQU FONDLast+2 ; 8 (word) maximum Ascent expressed for 1 pt.
FONDDescent EQU FONDAscent+2 ; A (word) maximum Descent expressed for 1 pt.
FONDLeading EQU FONDDescent+2 ; C (word) maximum Leading expressed for 1 pt.
FONDWidMax EQU FONDLeading+2 ; E (word) maximum MaxWidth expressed for 1 pt.
FONDWTabOff EQU FONDWidMax+2 ;10 (long) Offset to width table
FONDKernOff EQU FONDWTabOff+4 ;14 (long) Offset to kerning table
FONDStylOff EQU FONDKernOff+4 ;18 (long) Offset to Style Mapping Table
FONDProperty EQU FONDStylOff+4 ;1C (12 words) contains style property info
FONDAssoc EQU FONDProperty+24 ;34 (variable length) Font Association Table.
FAssocSiz EQU 6 ;size of a font association table entry.
;————————————————————————————————————————————————————————————————————
; PROCEDURE InitFonts -- initialize the font manager data structures
; Fix File Date Patch# Fix Routine(s) Routine(s) Fixed
;AppleSystemPatch FontMgrPatch.a 01Jan1904 #??? (InitFonts) (InitFonts)
;
InitFonts
IF bugFix THEN
MOVEQ #-1,D2 ;get some ones
CLR.W FOutError ;clear once at init time
ELSE
CLR.W FOutError ;clear once at init time
CLR.L FOutFontHandle ;may point to non-existent font, so clear
MOVEQ #-1,D2 ;get some ones
MOVE.W D2,FONDID ;init FOND cache
CLR.L LastFOND
ENDIF
BSR SetScreenDevice ;make the screen the default device
CLR.W CurFMDevice ;make the device 0
CLR.B FScaleDisable ;enable font scaling
CLR.B FractEnable ;for now, turn off fractWidths
ST FontFlag ;set to note that a call is not re-entrant
MOVE.W SPFont,ApFontID ;set up default font ID
ADDQ.W #1,ApFontID ;bump it by 1
MOVE.B #12,FMDefaultSize ;set up FMDefault Size
; allocate and initialize the width table in the system heap, if we haven't already
MOVE.L WidthTabHandle,D0 ;already got it?
BNE.S @4 ;if we have it, skip
MOVE.L #WidTabSize,D0 ;size of table
_NewHandle ,SYS ;new handle in sysHeap
BNE.S CantAllocWTab ;if an error, skip
MOVE.L A0,WidthTabHandle ;remember it
; allocate a width table list if there is room for them.
IF bugFix THEN
ELSE
CLR.L WidthListHand ;assume not enough memory for other tables.
CMP.W #2,MemTop ;are we in a small memory system?
BLS.S @4 ;yes, then forget the second width table handle.
ENDIF
MOVE.L #WidListSize,D0 ;size of table
_NewHandle ,SYS,CLEAR ;new handle in sysHeap, cleared
BNE.S @4 ;if an error, skip
MOVE.L A0,WidthListHand ;remember it
; Invalidate all of the extra width tables, if they exist.
@4
; set up swapFont jump table entry
IF patch THEN
MOVE #$101,D0
_GetTrapAddress
MOVE.L A0,JSwapFont
ELSE
MOVE.L $1204,JSwapFont ;set up the jump vector
ENDIF
BSR.S InValWidths ;invalidate all of the width tables.
; new system font logic to handle non-12 point, or non-Chicago system font.
MOVE.L OneOne,-(SP) ;scale factor denominator
MOVE.L OneOne,-(SP) ;scale factor numerator
CLR.L -(SP) ;clear face, need bits, device
CLR.L -(SP) ;pass system family, size
SUBQ #4,SP ;room for function result
PEA 4(SP) ;pass the address of the input record
_FMSwapFont
ADD #20,SP ;toss function result & input record
MOVE.L FOutFontHandle,RomFont0 ;salt away system font for backwards compat.
@skipRest
RTS
; we couldn't allocate the width table so issue the out-of-memory deepShit alert
; >> note that since there is no system font yet, this will flash the box repeatedly until the stack
; >> runs into something important. There must be a better way!
CantAllocWTab
MOVEQ #25,D0 ;out of mem code
_SysError ;self-destruct...
; Invalidate all of the extra width tables, if they exist.
InValWidths
; * restore purge state of old FOND first
MOVE.L LastFOND,A0
MOVE.B FONDstate,D0
CMP.B #$FF,D0
BEQ.S @skipUnintialized
_HSetState
@skipUnintialized
MOVEQ #-1,D2 ;get some ones
MOVE.L D2,LastSPExtra ;flag that we can't get a match next time <DLD 24-Oct-85>
IF bugFix THEN
MOVE.W D2,FONDID ;init FOND cache (bug fix: not specific to color)
ENDIF
MOVE.L WidthListHand,D0
BEQ.S InvalWidthTab
MOVE.L D0,A1
MOVE.L (A1),A1 ;handle->pointer
MOVEQ #NumTables-1,D1
@5
MOVE.L (A1)+,D0 ;get a handle from the table
BEQ.S InvalWidthTab ;end of table.
MOVE.L D0,A0
MOVE.L (A0),D0 ;was this handle purged?
BEQ.S @55
MOVE.L (A0),A0
MOVE.L D2,WidTabFont(A0) ;invalidate it
MOVE.W D2,WidthFID(A0) ;and invalidate requested font ID.
@55
DBRA D1,@5 ;until end of table.
; Invalidate the width table.
InvalWidthTab
MOVEQ #-1,D2 ;set up invalid value
BSR.S DerefWidthTab
MOVE.L D2,WidTabFont(A0) ;invalidate it
MOVE.W D2,WidthFID(A0) ;and invalidate requested font ID.
MOVE D2,CurFMFamily ;and avoid simple match
RTS
;common dereference
DerefWidthTab
MOVE.L WidthTabHandle,A0
MOVE.L (A0),A0 ;handle->pointer
RTS
;————————————————————————————————————————————————————————————————————
; FamSizeInD0 returns both the family and the high word and the size in the low word.
FamSizeInD0
MOVEQ #0,D1 ;zero high byte of size
MOVE (A3),D0 ;get the family
BNE.S @notSystem ;only system if it is zero
MOVE SysFontFam,D0 ;set up system family (could be zero, OK)
MOVE SysFontSize,D1 ;set up system size (less OK if zero)
BNE.S @sysSizeOK ;if nonzero, keep it
@notSystem
MOVE.B FMDefaultSize,D1 ;get default font size
BNE.S @sizeNonZero
MOVEQ #12,D1 ;if low memory is no help, hard code to 12
@sizeNonZero
CMP #1,D0 ;is the font the application font?
BNE.S @sysSizeOK ;if not, dont change it
MOVE ApFontID,D0 ;change family to application family
@sysSizeOK
SWAP D0 ;save the family
MOVE fmInSize(A3),D0 ;get current size
BNE.S @notSizeZero ;if nonzero, leave alone
MOVE D1,D0 ;else use either SysFontSize or FMDefaultSize
@notSizeZero
RTS
;———————————————————————————————————————————————————————————————————
; A6 offsets for SwapFont
copyInput EQU -16 ;place to hold copy of CurFMInput
styleID EQU copyInput-4 ;saved style and ID from FOND (set up in GoLoadStrike)
paramBlk EQU styleID-ioQElSize
saveMap EQU paramBlk-2 ;the applications resource map in the system sub case
fwidStyle EQU saveMap-2 ;the style of the best width table found in the FOND
stackFrame EQU fwidStyle ;size of stack frame
;
; FUNCTION FMSwapFont(inRec:FontInputRecord):^FontOutputRecord
;
; Fix File Date Patch# Fix Routine(s) Routine(s) Fixed
;AppleSystemPatch FontMgrPatch.a 01Jan1904 #??? (FMSwapFont) (FMSwapFont)
;AppleSystemPatch PatchIIROM.a 27Aug87 #PABM253 (GetHandleSize) (RealFont)
;
; FMSwapFont is the heart of the font manager. It receives an input record
; from QuickDraw specifying the font, face, device and scale of the requested
; font and figures out the best set of bits to load and return in the output
; record. It is optimized so that if the request is the same as the previous
; one, it returns as fast as it can.
; Some init conditions are rolled in from patches...
;
; To (try to) understand FontFlag, see the comments at SubFont, far, far below.
;
FMSwapFont
; Check FontFlag to see if we got here through SysError first.
LEA FMgrOutRec,A0 ;get pointer to our output record
MOVE.L A0,8(SP) ;return it as the result
MOVEQ #-1,D2 ;common constant to invalidate globals
CMP.L LastSpExtra,D2
BEQ GoDifFont
ADDQ.B #1,FontFlag ;if not a re-entrant call, this sets to zero
BEQ.S @notReentrant
BSR.S InvalWidthTab ;dont use the current cache; may be incomplete
; Here we know that the call to LoadResource failed, the disk switch hook is trying to go up, or a real
; SysError occured.
CMP.B #9,FontFlag ;are all substitutions exhausted ?
BEQ GoTryChicago ;if so, go straight for the ROM font
BGT FMSwapDone ;if that didnt work, this just return the last record
MOVE.B #8,FontFlag ;set to next re-entrant range.
@notReentrant
; the most important thing to do is to see if the input record is the same
; as it was last time, as fast as we can
MOVE.L 4(SP),A0 ;keep input record pointer in A3
LEA CurFMInput,A1 ;point at last request
CMPM.L (A0)+,(A1)+ ;the same?
BEQ.S @okFamSize ;if so, skip
MOVE.L A3,-(SP) ;maybe just substitution
MOVE.L 8(SP),A3 ;set up input record for utility
BSR.S FamSizeInD0 ;returns family, size
MOVE.L D0,D2 ;save input record, substituted
LEA CurFMInput,A3 ;maybe actuals need subbing as well
BSR.S FamSizeInD0 ;get last family, size
MOVE.L (SP)+,A3 ;restore
CMP.L D2,D0 ;the same?
BNE.S GoDifFont
MOVE.L -4(A0),-4(A1) ;jam original so next time is fast
@okFamSize
CMPM.L (A0)+,(A1)+ ;face, needbits, device the same?
BEQ.S @okFaceBitsDev ;if so, fine, continue fast case
; ! assume for now that I can get away without matching needBits
MOVE.L -(A0),D0 ;get the request face, needBits, device
MOVE.L -(A1),D1 ;check that against the last accessed face, bits, dev.
EOR.L D0,D1 ;set the bits that are different
AND.L #$FF00FFFF,D1 ;clear the needBits part
BNE.S GoDifFont ;if more is different, go handle it
MOVE.L (A0)+,(A1)+ ;make fast for next time, continue fast case
@okFaceBitsDev
CMPM.L (A0)+,(A1)+ ;numer the same?
BNE.S GoDifFont ;if not, skip
CMPM.L (A0)+,(A1)+ ;denom the same?
BNE.S GoDifFont ;if so, we're cool!
; ugh -- now we have to pull SpExtra out of the port to see if
; that changed. If not, we're cool.
; Believe it or not, it is possible that QuickDraw is not around at all, so test first.
TST.B QDExist ;is QuickDraw around
BMI.S StraightLineCP
MOVE.L grafGlobals(A5),A0 ;get grafGlobals
MOVE.L thePort(A0),D0 ;get thePort
BEQ.S StraightLineCP ;if no port, dont check space extra
MOVE.L D0,A0
@checkLastSp
MOVE.L LastSpExtra,D0 ;get spaceExtra <DLD 24-Oct-85>
CMP.L SpExtra(A0),D0 ;did it change? <DLD 24-Oct-85>
BEQ.S StraightLineCP ;if not, skip
; spaceExtra changing is not such a big deal; we don't have to recalculate
; everything. Dive in at the right spot...
LINK A6,#stackFrame
CLR saveMap(A6) ;in case substitution must switch res. maps
CLR fwidStyle(A6) ;just in case, remember no styled widths have been found
MOVEM.L D3-D7/A2-A4,-(SP) ;save work registers
MOVE.L 8(A6),A3 ;get input pointer
SUBQ.B #2,FontFlag ;set up substitution position to try again.
BRA AdjustSpace ;dive in...
; the request is different from the last one, so do things the slow way
GoDifFont
BRA.S DifFont ;go handle it
;————————————————————————————————————————————————————————————————————
; Hurray! the font was the same as last time so we can return right away. The
; only thing left to do is to make sure the font wasn't purged. The master pointer can only contain
; a real live font or NIL. No need to check to see if the resource bits are set or if the master pointer
; is part of the free chain or if the handle has been reused since any calls to OpenResFile, CloseResFile
; and ReleaseResource have invalidated any cached handle state.
; A large scale change made here is to branch to DifFont if the font can not be loaded. This allows the
; same substitution to be used by all. Before, the system font was loaded instead, using the CurFMInput
; record. The new code is possibly disasterous since CheckPurged is called at the tail end of DifFont, so
; the space extra only special case can use the same code as the long way around. I need to make sure
; that DifFont only gets this far if the font has been successfully loaded, and no further purging sort of
; operations have occurred.
StraightLineCP
SUBQ.B #2,FontFlag ;set up substitution position to try again.
CheckPurged
MOVE.L FOutFontHandle,A0 ;get the font handle.
TST.L (A0)
BNE.S FMSwapDone
MOVE.L A0,-(SP) ;push it
MOVE.W #MapTrue,ROMMapInsert ;get it from ROM if possible <10 Jul 85>
_LoadResource ;make sure its loaded
CMP.B #-1,FontFlag ;hit disk-switch?
BEQ.S GoDifFont ;other data is inconsistent so start over.
TST.L (A0) ;still NIL?
BEQ.S GoDifFont ;if so, in trouble
BSR BuildCharTable ;need to rebuild character table
; all done with FMSwapFont so restore registers and return to our caller
FMSwapDone
; we must re-establish widthPtr each time we are called, as the heap might
; have been compacted. Note that this is for backwards compatability only.
MOVE.L WidthTabHandle,A0
MOVE.L (A0),WidthPtr ;assume color QD needs this no more.
ST FontFlag ;no more worry about re-entrancy
; If returning to previous font manager call (via LoadResource, GetResource, etc.), will need to check
; FontFlag to see if it is -1; if so, start substitution all over since state is no good.
MOVE.L (SP)+,A0 ;get return address
ADDQ #4,SP ;strip parameter
JMP (A0) ;return to caller
;————————————————————————————————————————————————————————————————————
; Utility called by DoMapFont when the correct widths were found in the width cache. It is called twice
; to set up FOutNumer h & v, FScaleVFact & FScaleHFact. A1 first points to widthVOutput in the FOND.
; D1 is either 0 (for v) or 2 (for h).
;————————————————————————————————————————————————————————————————————
SetUpScale
IF patch THEN
IF onMac THEN
JMP $40EA96
ELSEIF onMacPP THEN
JMP $41931C ; *NB Patch* need addresses for both SE and Plus.
ENDIF
ELSE
LEA fmOutNumer+FOutRec,A0 ;set up the scale factor in the output record.
MOVE.W (A1)+,0(A0,D1) ;save @ FOutNumer. (FOutDenom is always 256.)
LEA FScaleVFact,A0 ;also set up scale factor in low memory.
MOVEQ #0,D0 ;clear high word (unsigned?)
MOVE.W 2(A1),D0 ;widthVFactor or widthHFactor
ASL.L #8,D0 ;adjust 8.8 number to 16.16
ADD D1,D1 ;double to 0 or 4.
NEG.W D1 ;make 0 or -4. (Low memory is h, v; table is v, h)
MOVE.L D0,0(A0,D1) ;save @ FScaleVFact, then FScaleHFact
RTS
ENDIF
;————————————————————————————————————————————————————————————————————
; Given a handle to a FONT, NFNT or FOND in A0, DeRefResource loads it if it has been purged (skipping
; the trap call if it is already in memory.) A0 is set on output to point to the resource, or equals NIL
; if the call to LoadResource fails. The Z flag is set if the call to load resource failed.
;————————————————————————————————————————————————————————————————————
DeRefResource
TST.L (A0) ;see if it is already loaded.
BNE.S alreadyLoaded ;if so, do nothing.
MOVE.L A0,-(SP) ;push it
MOVE.W #MapTrue,ROMMapInsert ;get it from ROM if possible <10 Jul 85>
_LoadResource ;make sure its loaded
CMP.B #-1,FontFlag ;hit disk-switch?
BEQ.S badLoad ;other data is inconsistent so start over.
TST.L (A0) ;still NIL?
BEQ.S badLoad ;if so, in trouble
alreadyLoaded
MOVE.L (A0),A0 ;handle -> pointer
RTS
badLoad
BRA Pop4SubFont ;start substituting (throw away return address)
;———————————————————————————————————————————————————————————————————
; DifFont - handle a font or style change.
;
; We reach this point when the family, size, scale or device has been changed, which usually means that
; we have to load in some new bits. The first thing to do is see if the device changed and, if it has, ask it
; for a new style table and dots/inch values.
;
;———————————————————————————————————————————————————————————————————
DifFont
LINK A6,#stackFrame ;might as well use locals as locals.
CLR saveMap(A6) ;in case substitution must switch res. maps.
CLR fwidStyle(A6) ;just in case, remember no styled widths have been found
MOVEM.L D3-D7/A2-A4,-(SP) ;save work registers
MoreDifFont
MOVE.L 8(A6),A0 ;pick up request pointer
LEA copyInput(A6),A1
MOVEQ #$10,D0
_BlockMove ;make copy of request
MOVE.L A1,A3
MOVE.B fmInFace(A3),FOutCurStyle ;set up desired style
MOVE.W fmInDevice(A3),D0 ;get device in request
CMP.W CurFMDevice,D0 ;did it change?
BEQ.S @sameDevice ;if not, we're cool
BSR SetNewDevice ;otherwise, read in the new stuff
@sameDevice
;———————————————————————————————————————————————————————————————————
;
; The TryAgain entry point is used if no size/style variant of the requested font was found. SubFont has
; changed the family field and restored the size field from the original input record before entering here.
;
;———————————————————————————————————————————————————————————————————
TryAgain
BSR FamSizeInD0
MOVE.L D0,(A3) ;save the size, family
; remember that copy has needBits cleared, but spline code (??) should check A6 input record !!!
CLR.B fmInNeedBits(A3)
LEA FontFlag,A4 ;we save a word here.
CMP.B #6,(A4) ;did we just substitute the ROM font?
BLT.S @skipROMFamily ;if not, all is well
CLR (A3) ;zero family, but leave substituted size
@skipROMFamily
; if we got here from the shortcut exact match or space extra only change, and LoadResource of
; the font failed, then FontFlag is set to -2.
TST.B (A4) ;test FontFlag for -2
BPL.S DoMapFont ;if 0 or greater, no problem
BSR InvalWidthTab ;invalidate WidthTabHandle
CLR.B (A4) ;advance to real substitution
; Use the info from the old width table if it applies.
;———————————————————————————————————————————————————————————————————
; DoMapFont searches handles pointed to by the width list for a table of widths matching the font
; requested by the input pointer.
;
; Fix File Date Patch# Fix Routine(s) Routine(s) Fixed
;AppleSystemPatch FontMgrPatch.a 01Jan1904 #??? (DoMapFont) (DoMapFont)
;
; Registers used:
; D0 = size of width table, scratch D1 = scratch D2 = last purged handle entry offset
; D3 = last invalidated entry offset D4 = table full flag D5 = offset into entry list
; D6 = call MapFont flag D7 = last nonpurged offset A0 = scratch
; A1 = scratch A2 = A3 = input pointer
; A4 = width list handle, pointer
;
; Significant changes made since the Macintosh + ROM:
;
; 12-Aug-86 CRC Details, details…
; The algorithm for determining which entry to use was:
; Check list until match, or entry = 0, or entry has been purged, or the end of the list is reached.
; If an entry was purged, reallocate it and use it.
; If entry = 0, allocate it and use it.
;
; The algorithm is now:
; Check list until match or entry = 0 or the end of the list is reached.
; if no match, use the last invalidated entry in the list.
; if memory is not full:
; if no invalidated entry, reallocate the last purged entry in the list.
; if no purged entry, and the last entry = 0, allocate a new entry at the end of the list.
; if memory is full or the list is full:
; reuse the last nonpurged entry in the list.
; if there isnt a nonpurged entry then were out of luck; dont use cache.
; if a memory allocation call fails, then the system heap is in bad shape; dont use cache.
;
; The actual size and font are stored in the width table instead of 0 or applFont.
;
; NewHandle, ReallocHandle recover if an error is returned.
;
; Entries in queue are rotated so that list is ordered most recently accessed to least recently
; accessed. If the system heap has room for all twelve elements, the least recently accessed is
; reused first. Otherwise, the Memory Manager roving purge pointer spins the wheel of fortune to
; decide who is purged (but only if some other process allocates heap space, or if the system heap
; is sufficiently fragmented.)
;
; Just for grins, all local branches are forward except for branches to the tops of loops.
;
; Any newly allocated or reused width table has the font handle and family ID fields invalidated to
; allow optimization of the remainder of the table fill-in code.
;
;———————————————————————————————————————————————————————————————————
DoMapFont
MOVE.L WidthListHand,D0 ;do we have any spare width tables?
BEQ.S @shortSkip ;if not, then skip this nonsense.
; Check if the width-table cache is still valid. <18-Oct-85>
MOVEQ #-1,D2 ;handy invalidation constant
CMP.L LastSpExtra,D2 ;invalidated through normal means or switcher?
BEQ.S @invalAll
CMP CurFMFamily,D2 ;just reuse WidthTabHandle?
BNE.S @notInvalid
BRA.S @shortSkip
@invalAll
BSR InvalWidths ;invalidate all of the width tables.
@shortSkip
BRA @skipCache ;
; We know that there has been some change. Search the list of width tables for a match.
@notInvalid
MOVE.L D0,A4 ;get the width list handle.
MOVE.L (A4),A4
MOVEQ #-1,D2 ;no purged handles found so far.
MOVEQ #-1,D3 ;no invalidated entries found so far.
SF D4 ;assume that table is not full.
MOVEQ #-4,D5 ;list entry counter is incremented at the top of loop.
SF D6 ;do call MapFont
MOVEQ #-1,D7 ;no nonpurged handles found so far.
; Check each list entry to see if it has been allocated, or if the table has purged.
@loopTop
ADDQ #4,D5 ;advance to next entry in width table handle
MOVE.L (A4),D1 ;get a possible width table handle.
BEQ @outOfLoop ;if none, create a new entry.
MOVE.L D1,A0
MOVE.L (A0),D0 ;get the master pointer.
BEQ @rememberPurge ;skip if it has been purged.
MOVE D5,D7 ;remember that this one was not purged.
MOVE.L D0,A1 ;we are pointing at the table now.
; We know that the device and scales match. But does the old table match the requested style?
MOVEQ #3,D1 ;number of longs to check - 1
MOVE.L A3,A0 ;copy the input pointer
LEA WidthFID(A1),A1 ;point to old width's info.
CMP #-1,(A1) ;check to see if it is valid.
BNE.S @valid ;skip if valid.
MOVE D5,D3 ;remember offset to invalid entry
@valid
CMPM.L (A0)+,(A1)+ ;does family, size; face, needbits, device;
DBNE D1,@valid ; numer; denom match?
BNE.S @loopBottom ;
; We already have the font handle (from the old width table), so skip most of MapFont.
ST D6 ;dont call MapFont
MOVE (A1),D0 ;get new font family ID
CMP FONDID,D0 ;different from old one?
BEQ.S @sameFOND ;if not, fond globals are already set up
MOVE.B FONDState,D0 ;get old FOND state
MOVE.L LastFOND,A0 ;maybe zero; if so, HSetState will reject
_HSetState ;restore purge state
MOVE.L (A4), A0 ; Get the Width Table handle <PMAB528>
_HNoPurge ; Make the Width Table non-purgeable <PMAB528>
MOVE (A1)+,D0 ;get new FOND ID
MOVE D0,FONDID ;save it
MOVE.L (A1)+,A0 ;get new FOND handle
MOVE.L A0,LastFOND ;save it
BEQ.S @noFOND
BSR DerefResource ;load it if it has purged
MOVE.B (A0),SaveFondFlags ;save the high byte of the FOND flags.
MOVE.L LastFOND,A0
_HGetState ;get the purge state
MOVE.B D0,FONDState ;preserve it until the next change
_HNoPurge ;and make the font nonpurgable
MOVE.L WidthListHand, A4 ; Get the list handle of Width Tables <PMAB528>
MOVE.L (A4), A4 ; Pointer to Width Table Handles <PMAB528>
ADD D5, A4 ; Add Offset of current Width Table <PMAB528>
MOVE.L (A4), A1 ; Handle to Width Table <PMAB528>
MOVE.L (A1), A1 ; Width Table ptr <PMAB528>
LEA WidthUsedFam(A1), A1 ; Load the address of the WidthUsedFam <PMAB528>
BRA.S @noFOND ;skip skip
@sameFOND
ADDQ #6,A1 ;skip over FOND ID, handle
@noFOND
MOVE.B (A1)+,UsedFWidths ;remember if we used family widths.
; We are changing back to an old style, so set up FOutFontHandle from our width.
MOVE.B (A1)+,FOutCurStyle ;set up real style (computed along with width table).
MOVEQ #0,D1
BSR SetUpScale ;set up the vertical scale factor and output.
MOVEQ #2,D1
BSR SetUpScale ;set up the horizontal scale factor and output.
; If we really want an expanded version, see if it already exists.
MOVE.L (A4),A0 ;get width handle.
MOVE.L (A0),A1 ;pointer to width table.
MOVE.L WidTabFont(A1),A1 ;corresponding font handle.
MOVE.L A1,FOutFontHandle ;get the font handle.
BRA.S @toSkipNew ;insert width handle in list.
; This entry did not match the request, so go on to the next one.
@rememberPurge
MOVE D5,D2 ;remember that this one was purged.
@loopBottom ;
ADDQ #4,A4 ;bump the list pointer.
CMP.W #(NumTables-1)*4,D5 ;done with the table yet?
BLO @loopTop ;try for a match on the next one in the list.
; end of loop
ST D4 ;remember that the table was full.
SUBQ #4,A4 ;point back at the one we want to use.
@outOfLoop
; if no exact match was found, check the existing WidthTabHandle to see if it is already invalid.
MOVE.L WidthTabHandle,A1 ;get address of handle
MOVE.L (A1),A1 ;get master pointer
CMP.W #-1,WidthFID(A1) ;has it been marked invalid?
BEQ.S @skipCache ;it is all ready to use.
EXG D3,D5 ;set up invalid position, preserve end of table.
TST D5 ;was an invalid table found?
BPL.S @reuseIt ;if so, skip purge check.
MOVE.L #WidTabSize,D1 ;get size of a table, in case we must allocate it.
IF bugFix THEN
_MaxBlock ,SYS ;better than FreeMem; unfortunately, didnt know for Aladdin ROM
ELSE
MOVE.L TheZone,A1
MOVE.L SysZone,TheZone
_FreeMem ;get the total free space in the system heap.
MOVE.L A1,TheZone
ENDIF
CMP.L D1,D0 ;is there enough room?
BLE.S @useNonpurged ;if not, use the last nonpurged entry in the list.
MOVE.L D1,D0 ;set up size to allocate.
MOVE D2,D5 ;was a purged handle found (to be missing)?
BPL.S @reuseIt ;if so, since we have enough memory, reuse it.
TST.B D4 ;is the table full?
BNE.S @useNonpurged ;if so, re-use nonpurged entry.
; We are beyond all list entries, so create a new one.
MOVE D3,D5 ;restore end of table position.
_NewHandle ,SYS ;_NewHandle in system heap.
BNE.S @skipCache ;use it only if allocation successful.
BRA.S @reuseIt ;reset width list pointer since it may have moved.
@useNonpurged
MOVE D7,D5 ;last nonpurged entry.
BMI.S @skipCache ;if not one, all out of options.
@reuseIt
MOVE.L WidthListHand,A4 ;get the width list handle again.
MOVE.L (A4),A4 ;since it may have moved.
LEA 0(A4,D5),A4 ;determine list entry address.
MOVE.L (A4),D1 ;get the master pointer.
BEQ.S @newWidthTable ;if zero, just created; skip purge test.
MOVE.L D1,A0 ;get the master pointer.
TST.L (A0) ;has it been purged?
BNE.S @newWidthTable ;if non-purged, mark as invalid.
; We found a purged list entry, so let's re-allocate it.
_ReAllocHandle
BNE.S @skipCache ;it failed, so nothing can be cached.
BRA.S @reuseIt ;reset width list pointer since it may have moved.
; If ReallocHandle or NewHandle fail, then there is no room to cache anything (since all other cache
; members would have purged to allow ReallocHandle or NewHandle to succeed).
; At this point and at the entry point skipNew, A0 is the handle to be
; installed at the front of the table, A4 points to the entry position being reused, and D5 is the offset
; from the front of the table to the reused position.
@newWidthTable
@toSkipNew
BRA.S @skipNew ;dive in.
@skipNext
MOVE.L -(A4),4(A4) ;move previous entry to this one.
@skipNew
SUBQ #4,D5 ;see if this is the first entry.
BPL.S @skipNext ;if so, nothing to do.
@swapHandles
MOVE.L WidthTabHandle,D1 ;save current handle - it's old now.
MOVE.L A0,WidthTabHandle ;save it in widthTabHandle.
_HNoPurge ;the current handle can't purge.
MOVE.L D1,(A4) ;save old handle in the front of the list.
MOVE.L D1,A0
_HPurge ;now it can purge if it wants.
; check to see if font is already figured out and installed
TST.B D6 ;call MapFont?
BNE.S GotFontHandle ;dont bother if the widths were found
; call MapFont to do all the hard work, installing a font in the output record
@skipCache
; Invalidate the new table entry.
BSR InvalWidthTab
BSR MapFont ;figure out font and install it
;——————————————————————————————————————————————————————————
GotFontHandle
MOVE.L FOutFontHandle,A0 ;get the current font handle
BSR DeRefResource ;load resource who's handle is in A0.
; set up ascent, descent, etc...
TST.B FScaleDisable ; if scaling disabled, do new way
BNE.S newSetupHeight
LEA FOutAscent,A1 ;point to the info section
MOVE.B FAscent+1(A0),(A1)+ ;copy ascent
MOVE.B FDescent+1(A0),(A1)+ ;copy descent
MOVE.B FWidMax+1(A0),(A1)+ ;copy max width
MOVE.B FLeading+1(A0),(A1) ;copy leading
BRA.S DoStyle
;————————————————————————————————————————————————————————————————————
; ByteScale, ByteHScale are utility routines used to figure the font metrics for this font.
; FScaleVFact contains the nice factor to allow scaling to be disabled so that QD can do no or easy bitmap
; scaling. The value to be scaled is passed in D0, and scaled by the value in D1.
;————————————————————————————————————————————————————————————————————
ByteScale
MOVE.L FScaleVFact,D1
ByteHScale
EXT D0 ;fix-ize the byte in D0
SWAP D0
CLR D0 ;clear fract
MOVEM.L D0-D3/A0-A1,-(SP) ;D0, D1are operands; D2, D3 make room for results,
;preserves A0, A1.
_FixMul ;
_FixRound
MOVE (SP)+,D0 ;get result in low byte
ADDQ #2,SP ;throw away the other half of D3
MOVEM.L (SP)+,A0-A1 ;restore registers
MOVE.B D0,(A1)+ ;save it in FMgrOutRec
RTS
newSetupHeight
LEA FOutAscent,A1 ;point to the info section
MOVE.B FAscent+1(A0),D0
BSR.S ByteScale ;copy integer ascent
MOVE.B FDescent+1(A0),D0
BSR.S ByteScale ;copy descent
MOVE.B FWidMax+1(A0),D0 ;maxwidth needs a horizontal factor adjustment.
MOVE.L FScaleHFact,D1
BSR.S ByteHScale ;copy max width
MOVE.B FLeading+1(A0),D0
BSR.S ByteScale ;copy leading
;———————————————————————————————————————————————————————————————————
; At this point, we have the proper bits but the style parameters are wrong.
; Fill out the style record using a table supplied by the current device
DoStyle
MOVE.B FOutCurStyle,D1 ;get style byte
LEA FOutBold,A0 ;point at style part of output record
CLR.L (A0)+ ;set everything to 0
CLR.W (A0)+ ;clear some more
CLR.B (A0)+ ;clear seven bytes total
; special case the most common case -- plain text (ie, style byte is 0)
TST.B D1 ;plain?
BEQ.S CheckWTable ;if so, skip the loop
; we must fill out the style record the hard way, by looping through the
; driver-supplied style definition table
MOVEQ #0,D2 ;clear high part for indexing
LEA FMStyleTab,A1 ;point to the style table
MOVEQ #6,D0 ;consider 7 bits worth
LEA FOutBold,A0 ;point to style params
@fmStyloop
MOVE.B (A1)+,D2 ;get index
MOVE.B (A1)+,D3 ;get field increment
MOVE.B (A1)+,D4 ;get extra increment
LSR #1,D1 ;examine next style bit
BCC.S @nextSBit ;if its off, don't bother
ADD.B D3,0(A0,D2) ;increment proper style param
ADD.B D4,FOutExtra ;also increment extra
@nextSBit
DBRA D0,@fmStyloop ;loop till done
; special case underlining since it doesn't fit into our model
BTST #ULineBit,FOutCurStyle ;underlining on?
BEQ.S CheckWTable ;if not, skip
LEA FOutULOffset,A0 ;point to underline parameters
MOVE.B (A1)+,(A0)+ ;copy the three underline parameters
MOVE.B (A1)+,(A0)+ ;copy second byte
MOVE.B (A1)+,(A0)+ ;copy third byte
;————————————————————————————————————————————————————————————————————
; Now the style is all set up so its time to make sure the width table is cool. First check to see if the
; widths were already cached, so we can skip the most time-consuming part of the work.
CheckWTable
; These tests decide to use either the integral style extra provided by the Font Manager, or the
; fractional style extra in the FOND.
MOVE.L LastFond,D0 ;check if there is a last FOND.
BEQ MakeITab ;if not, style extra cant be fractional.
TST.B FDevDisable ;set if the device would prefer the FOND style extra.
BNE.S @skipDevice
TST.B fmInDevice(A3) ;if the device is not the screen, it can supply its
BNE MakeITab ; own style widths, so skip looking at the FOND widths.
@skipDevice
BTST #5,saveFondFlags ;set if fractional style extra is never from FOND.
BNE.S MakeITab
BTST #4,saveFondFlags ;set if fractional style extra is always from FOND.
BNE.S @computeFractExtra ; <06Nov85>
TST.B FractEnable ;set if application allows fractional spacing
BEQ.S MakeITab ;if not, dont figure fractional style extra from FOND. <06Nov85>
@computeFractExtra ;
; We can only get this far if the FOND has valid style extra entries (part of the FOND flags)?
; Next, compute the fixed point extra into D6 when we do have a family definition record present.
MOVE.L D0,A0 ;get the last fond.
BSR DeRefResource ;load resource who's handle is in A0.
; But wait, maybe this FOND is an empty FOND created by Font/DA Mover. If so, the FONDLast field
; will contain a zero.
TST FONDLast(A0) ;see if last character is zero.
BEQ.S MakeITab ;if so, do not calculate style here.
LEA FONDProperty(A0),A0 ;point to start of table
MOVE.W (A0)+,D6 ;get plain extra
EXT.L D6
; If the FOND has a width table with a style already calculated in it, it is not necessary to figure out the
; style extra for the styles already contained in the widths. Earlier, in GotEntry, a style with the correct
; widths found was saved in a local.
MOVE.B FOutCurStyle,D1 ;get style byte
BEQ.S @gotFractExtra ;if plain, skip the loop
BTST #6,saveFondFlags ;does this FOND have width tables at all?
BNE.S @noStyleInWidths ;if set (like for Courier) there are no width tables in FOND
MOVE fwidStyle(A6),D0 ;get style of widths already found
NOT D0 ;use as mask,
AND D0,D1 ;to turn off any style attributes already in widths
@noStyleInWidths
; we must fill out the style record the hard way, by looping through the
; driver-supplied style definition table
MOVEQ #7,D0 ;consider 8 bits worth
@exStyloop
MOVE.W (A0)+,D2 ;get extra value
LSR #1,D1 ;examine next style bit
BCC.S @nextExBit ;if its off, don't bother
; here we can add Adobe fix to look for funny sign bit sort of negative number
CMP #$8FFF,D2 ;is it -7.001 or smaller?
BGT.S @doNormalAdd
BCLR #15,D2 ;throw away sign bit
NEG D2 ;make into a normal twos complement number
@doNormalAdd
EXT.L D2
ADD.L D2,D6 ;add it in
@nextExBit
DBRA D0,@exStyloop ;loop till done
@gotFractExtra
ASL.L #4,D6 ;adjust 4.12 to 16.16 fixed point
SUBQ #6,SP ;space for FixMul, FixRound results
CLR.W -(SP) ;fraction part zero.
BSR DerefWidthTab ;get pointer to width table in A0
MOVE.W WidthASize(A0),-(SP) ;get the actual size.
MOVE.L D6,-(SP) ;compute floating extra times pointsize
_FixMul
MOVE.L (SP),D6 ;get fixed point answer
_FixRound ;round in case fractions are disabled
MOVE (SP)+,D0 ;pop the answer
;————————————————————————————————————————————————————————————————————
TST.B FractEnable ;fractional widths? <06Nov85>
BNE.S MakeWTab ;yes, then dont use the rounded result.
; Must overwrite default value of FoutExtra if FractEnable is not true but we are using fractional extra
; anyway—e.g. the FOND flags specify always use fractional widths. <PMAB559 BAL 9/7/88>
MOVE.B D0,FOutExtra ;and save the byte-sized result <PMAB569 BAL 9/7/88>
MakeITab
MOVEQ #0,D6 ;clear out D6
MOVE.B FOutExtra,D6 ;get extra value
EXT.W D6 ;sign extend it
SWAP D6 ;make it fixed point
MakeWTab
; the font changed so we have to make the table from scratch. First
; init the meta fields in the new table.
BSR DerefWidthTab ;get a pointer to the width table in A0
CMP #-1,widthFID(A0) ;is it a new one?
BNE AdjustSpace ;just take care of space extra
LEA WidthSExtra(A0),A1 ;point just past widths
CLR.L (A1)+ ;set lastSpExtra to 0
MOVE.L D6,(A1) ;set lastStyExtra to value
ADD.W #WidthAFID-WidthStyle,A1
MOVE.W FONDID,(A1)+
MOVE.L LastFOND,(A1)
; there are two cases for building the width table, depending on whether
; the font comes with a fixed-point table or not. Point A1 at either
; the offset/width table or the fixed-point width table
; better load it if it purged
MOVE.L FOutFontHandle,A0 ;get the current font handle, prepare for deref. later
BSR DeRefResource ;load resource who's handle is in A0.
; D2 holds the flags word, D3 has firstChar and D4 has lastChar. Compute
; the size of the tables in D5.
MOVEM.W (A0),D2-D4 ;get flags, first, last
MOVE D4,D5 ;copy lastChar
SUB.W D3,D5 ;compute lastChar-firstChar
MOVE D5,D1 ;keep # in D1
ADDQ #3,D5 ;# of chars, including missing
ADD.W D5,D5 ;compute size of table
EXT.L D5 ;make it a longWord
; compute address of offset/width table into A1
IF bugFix THEN
MOVE.W fNDescent(A0),D0 ;possibly the high word of owTLoc
SWAP D0 ;put it in the high word
BPL.S @notNegative
ENDIF
MOVEQ #0,D0
@notNegative
MOVE.W fOWTLoc(A0),D0 ;get size till owTable
ADD.L D0,D0 ;double for bytes
LEA fOWTLoc(A0,D0.L),A1
;————————————————————————————————————————————————————————————————————
; case out on the font format, pointing A1 at the right table and getting
; the width of the missing character in long format in D7
MOVEQ #0,D7 ;clear out D7
TST.B FractEnable ;use expanded widths?
BEQ.S @noExWidth ;if not, skip
BTST #1,D2 ;expanded width table present?
BNE.S @gotExWidth ;if so, skip
BTST #6,saveFondFlags ;set if FOND fractional widths are not (to be) used.
BNE.S @noExWidth ;if not, compute integral values from the font.
; See if we have a family width table for this font. A4 contains an offset to it if there is one
; (set up by MapFont) or is NIL.
MOVE.L A4,D0 ;got family width table?
BEQ.S @noExWidth ;if not, skip
; handle case of figuring out missing character width for family width table
MOVE.L LastFOND,A1 ;get famDef record
MOVE.L (A1),A1 ;handle -> pointer
ADD.L A4,A1 ;compute width tab ptr
BSR DerefWidthTab ;get pointer to width table in A0
MOVE.W WidthASize(A0),D0 ;get size in D0
MOVE.W -4(A1,D5),D7 ;get fixed point width
MULS D0,D7 ;scale it up
ASL.L #4,D7 ;convert to 32 bits <28Jun AJH>
BRA.S DoWTable ;back to common code
; this font doesn't have an expanded width table, so A1 is cool. Fetch
; the width of the missing character.
@noExWidth
MOVE.B -3(A1,D5),D7 ;get byte width
SWAP D7 ;convert to fixed point
BRA.S DoWTable ;go make the table
; the font does have an expanded width table, so adjust A1 and fetch the
; width of the missing character
@gotExWidth
ADD.L D5,A1 ;bump to expanded table
MOVE.W -4(A1,D5),D7 ;get fixed point width
ASL.L #8,D7 ;convert to 32 bits
;————————————————————————————————————————————————————————————————————
; build the width table
DoWTable
; set up D5 with a boolean that specifies whether we have to call FixMul
; to do the scale-disable scaling
CMP.L #$10000,FScaleHFact ;scale factor = 1
SNE D5 ;if = 1, make it 0 <10-30-85>
AND.B FScaleDisable,D5 ;FScaleDisable must be on, too
; OK, start making the width table by filling in the missing characters
; for "minChar" characters
MOVE.L D7,D0 ; <10-30-85>
BSR.S AddD6ScaleD0 ;add extra to missing width, scale by FScaleHFactor.
MOVE.L D0,D7 ; <10-30-85>
BSR DerefWidthTab ;get pointer to width table in A0
BRA.S @minCharSkip ;WHILE, not REPEAT
@minCharLoop
MOVE.L D7,(A0)+ ;stuff in missing width
@minCharSkip
DBRA D3,@minCharLoop ;repeat till done
; now we case out to two separate loops for filling out the body of the
; width table, depending on if we have an expanded table.
CLR.B UsedFWidths ;assume we don't use them
TST.B FractEnable ;fraction widths enabled?
BEQ.S CalcOldWLoop ;if not, skip
BTST #1,D2 ;which format? (check for width table in font)
BEQ.S CheckFracWidths ;if not expanded, see if there is a FOND.
@gotXWid1
MOVEQ #0,D0 ;clear out D0
MOVE.W (A1)+,D3 ;get 8.8 character width
CMP.W #-1,D3 ;is it missing?
BNE.S @notMissing ;if not, go handle
MOVE.L D7,D0 ;use missing width
BRA.S @stuffWidth ;go stuff it
@notMissing
MOVE.W D3,D0 ;get width
ASL.L #8,D0 ;make it 16.16 fixed-point
BSR.S AddD6ScaleD0 ;add extra, and scale if enabled
@stuffWidth ;
MOVE.L D0,(A0)+ ;stuff it
DBRA D1,@gotXWid1 ;loop for # of chars
ST UsedFWidths ;we used them
BRA.S FillTheRest
;————————————————————————————————————————————————————————————————————
; we might have a family width table -- if we do, use a different loop
CheckFracWidths
BTST #6,saveFondFlags ;set if no fractional family widths
BNE.S CalcOldWLoop ;if set, compute integral values from the font.
MOVE.L A4,D0 ;got a family one?
BEQ.S CalcOldWLoop ;if not, must be old way.
; use family widths to figure sizes
MOVE.L WidthTabHandle,A4
MOVE.L (A4),A4
MOVE.W WidthASize(A4),-(SP) ;get the actual size, keep on stack.
MOVE.L D0,A4 ;restore index to family widths
@fxWidLoop
MOVEQ #0,D0 ;clear out D0
MOVE.W (A1)+,D3 ;get 4.12 1-point width
CMP.W #-1,D3 ;is it missing?
BNE.S @0 ;if not, go handle
MOVE.L D7,D0 ;use missing width
BRA.S @1 ;go stuff it
@0
MOVE.W D3,D0 ;get width
MULU (SP),D0 ;scale it up
ASL.L #4,D0 ;adjust to 16.16 fixed point
BSR.S AddD6ScaleD0 ;add extra, and scale if enabled
@1 ; <10-30-85>
MOVE.L D0,(A0)+ ;stuff it
DBRA D1,@fxWidLoop ;loop for # of chars
ADDQ #2,SP ;pop off point size
ST UsedFWidths ;we used them
BRA.S FillTheRest
;————————————————————————————————————————————————————————————————————
; common utility routine
; AddD6ScaleD0 adds in the style extra in D6, then multiplies the value in D0 by the
; FScaleDisable scale factor.
AddD6ScaleD0
TST.L D0 ;is it zero?
BEQ.S @0 ;if it has no width, do nothing
ADD.L D6,D0 ;add in style extra first
TST.B D5 ; need to scale it?
BEQ.S @0
; *** note that the smaller ELSE case is OK, since changing FixMuls register conventions breaks applications
IF 0 THEN
MOVEM.L A1/A0/D1,-(SP) ;save registers used by FixMul (D1, A0, A1)
SUBQ #4,SP ;make room for result
MOVE.L D0,-(SP) ;pass param D0
MOVE.L FScaleHFact,-(SP)
_FixMul ;
MOVEM.L (SP)+,D0-D1/A0-A1 ;function result (D0), restore registers (D1, A0, A1)
ELSE
MOVEM.L A1/A0/D1/D0,-(SP) ;save registers used by FixMul (A0, A1)
;make room for result (D1), pass param D0
MOVE.L FScaleHFact,-(SP)
_FixMul ;
MOVEM.L (SP)+,D0/A0-A1 ;function result (D0), restore registers (A0, A1)
ENDIF
@0
RTS
;————————————————————————————————————————————————————————————————————
CalcOldWLoop
; its the old format, so walk down the o/w table, computing the fixed point
; widths and stuffing them into the table.
MOVEQ #0,D0 ;clear out D0
MOVE.W (A1)+,D3 ;get offset/width
CMP #-1,D3 ;is it missing?
BNE.S @skipMiss ;if non-missing, skip
MOVE.L D7,D0 ;use missing width
BRA.S @stuffIt ;go stuff it
@skipMiss
MOVE.B D3,D0 ;get width
SWAP D0 ;make it fixed-point
BSR.S AddD6ScaleD0 ; nop if not scale disabled
@stuffIt ;
MOVE.L D0,(A0)+ ;stuff it
DBRA D1,CalcOldWLoop ;loop for # of chars
;————————————————————————————————————————————————————————————————————
; OK, now fill out the end of the table with the missing character width
FillTheRest
MOVE #255,D0
SUB.W D4,D0 ;how many left?
BRA.S @whileStart ;let DBRA decrement first
@maxCharLoop
MOVE.L D7,(A0)+ ;stuff the width
@whileStart
DBRA D0,@maxCharLoop ;repeat till done
;————————————————————————————————————————————————————————————————————
; Short cut space extra check at the beginning of SwapFont jumps to here. Also, cached widths case jumps
; here.
AdjustSpace
BSR DerefWidthTab ;get pointer to width table in A0
LEA widthSExtra(A0),A1 ;figure where space is
; Believe it or not, it is possible that QuickDraw is not around at all, so test first.
MOVE.L (A1),D7
TST.B QDExist ;is QuickDraw around
BMI.S @noQuickDraw
MOVE.L grafGlobals(A5),A0 ;get grafGlobals
MOVE.L thePort(A0),D0 ;get thePort
BEQ.S @noQuickDraw
MOVE.L D0,A0
MOVE.L spExtra(A0),D7 ;get current space extra
@noQuickDraw
MOVE.L D7,LastSpExtra ;and remember it for next time.
SUB.L (A1),D7 ;subtract old with current
BEQ.S @checkDevice ;if same, nothing to do
; D7 has the difference in the value of spaceExtra. The only problem is spaceExtra is given in screen
; coordinates but we must return stuff in font coordinate space. Thus we must scale spaceExtra before
; adding it in. FMInNumer.h FOutDenom.h
; width = ———————— * ———————— * spExtra
; FMInDenom.h FOutNumer.h
ADD.L D7,(A1) ;remember new value
SUB.W #12,SP ;make space on stack
MOVE.W FMInNumer+2(A3),-(SP) ;push x input numer
MOVE.W FMInDenom+2(A3),-(SP) ;push x input denom
_FixRatio ;compute ratio
SUBQ #4,SP ;make space for result
MOVE.W FOutDenom+2,-(SP) ;push x output denom
MOVE.W FOutNumer+2,-(SP) ;push x output numer
_FixRatio ;compute ratio
_FixMul ;calculate scale factor
MOVE.L D7,-(SP) ;push space extra
_FixMul ;scale it
; we have the adjustment factor on the stack, so add it into the table
BSR DerefWidthTab ;get pointer to width table in A0
MOVE.L (SP)+,D0 ;get scaled delta
ADD.L D0,4*' '(A0) ;adjust space width
; Now that we finally have everything the way we want it, let the current
; device have a crack at changing things if it wants to.
@checkDevice
MOVEQ #-1,D0 ;get lots of ones
MOVE.B FMInDevice(A3),D0 ;get the device number
BEQ.S @doneStyle ;if its the screen, we're done
; call the driver to give it a chance to change the output record
LEA paramBlk(A6),A0 ;point A0 at OS block
MOVE.W D0,IORefNum(A0) ;set up the refNum
MOVE.W #FMgrCtl1,CSCode(A0) ;set up the control code
MOVE.L A3,CSParam(A0) ;pass the input record as a parameter
MOVE.W FMInDevice(A3),CSParam+4(A0) ;pass subclass, too
_Control
; All done now so copy the input record into the current record for the next time.
@doneStyle
MOVE.L 8(A6),A3 ;point to original input record
MOVE.L A3,A0
LEA CurFMInput,A1 ;point to current record
MOVE.L (A0)+,(A1)+ ;copy first 4 bytes
MOVE.L (A0)+,(A1)+ ;copy next 4 bytes
MOVE.L (A0)+,(A1)+ ;copy next 4 bytes
MOVE.L (A0)+,(A1)+ ;copy last 4 bytes
BSR DerefWidthTab ;get pointer to width table in A0
CMP #-1,widthFID(A0) ;already filled out? (cache case)
BNE.S @skipFill
MOVE.B UsedFWidths,WidthUsedFam(A0);update UsedFam.
MOVE.B FOutCurStyle,WidthAFace(A0) ;update Actual Face.
LEA widthFID(A0),A1 ;point to request info (Font ID etc) in width.
BSR FamSizeInD0
MOVE.L D0,(A1)+ ;update requested Font ID and Size.
ADDQ #4,A3
MOVE.L (A3)+,(A1)+ ;update requested face and device.
CLR.B -3(A1) ;but clear the needBits field
MOVE.L (A3)+,(A1)+ ;update numer, denom
MOVE.L (A3),(A1) ; of the scale factors.
@skipFill
MOVEM.L (SP)+,D3-D7/A2-A4 ;restore work registers.
MOVE saveMap(A6),D0 ;saved resource map or 0
BEQ.S @skipSave
MOVE D0,curMap
@skipSave
UNLK A6
BRA CheckPurged
;———————————————————————————————————————————————————————————————————
; MapFont does all the hard work in FMSwapFont. Given a pointer to the
; font input record in A3, it normalizes the scale, finds the best set
; of bits it can and installs them into the output record.
;———————————————————————————————————————————————————————————————————
MapFont
SUB.L A4,A4 ;no family widths yet!
MOVE.W fmInSize(A3),D5 ;get the size in D5
MOVE.W fmInFamily(A3),D3 ;get the family
; OK, now D3 has the family we want. Now scale the size based on the current
; DotsPerInch and numer/denom and build the resource ID of the font we want
; (even though we might not have it)
CalcRealSize
SUB #14,SP ;make space for function results
MOVE.W FMDotsPerInch+2,-(SP) ;push horizontal dots/inch
MOVE.W #80,-(SP) ;push nominal dots/inch
_FixRatio ;turn into fixed point
SUBQ #4,SP ;make some room
MOVE.W fmInNumer+2(A3),-(SP) ;push horizontal numerator
MOVE.W fmInDenom+2(A3),-(SP) ;push horizontal denominator
_FixRatio ;make that a fixed point, too
_FixMul ;multiply them together.
CLR.W -(SP) ;fraction part is 0
MOVE.W D5,-(SP) ; push the size
_FixMul ;scale the size.
_FixRound ;round it off
; At this point the desired family is in D3 and the desired size is on the top of the stack. See if we have a
; family definition record for this family; if so, handle it the new way. Try to get a record of type
; <FOND,D3> into D0. Since this is sometimes speed critical, we implement a cache to skip the difficult
; resource search if we can. The FOND in the first element of the cache, WidthTabHandle, is always
; unpurgable.
TryForFond
CMP.W FondID,D3 ;same as last time
BEQ.S @sameFDef ;if so, short-circuit
MOVE.L LastFOND,A0 ;get old one (if zero, _HSetState will reject)
MOVE.B FondState,D0
_HSetState ;restore purge state
MOVE D3,D1
MOVE.W #MapTRUE,ROMMapInsert ;get from ROM if possible <10 Jul 85>
BSR GetFOND ;use common utility below (GetFontName)
BEQ.S @doneFDEFGet ;if no FOND, skip caching
; OK, we're changing the state of the cache so restore the purge state of
; the old one (if any), and make the new one unpurgable
MOVE.L (A0),A1 ;get a byte of FOND flag word and save it in low mem.
MOVE.B (A1),saveFondFlags ;bit 6 will be used to disable fractional junk.
_HGetState
MOVE.B D0,FondState ;save the old state
_HNoPurge ;make it non-purgable
@doneFDEFGet
; Check disk switch status here; better late than never…
CMP.B #-1,FontFlag
BEQ Pop6SubFont ;if so, go start over.
MOVE.W D3,FONDID ;moved these two lines from above <DLD,8-19-85>
MOVE.L A0,LastFOND ;so we will cache when no FOND. <DLD,8-19-85>
; the cache worked, so fetch it from low memory
@sameFDef
MOVE.L LastFOND,D0
BNE NewFontLookUp ;if so, go look up size
CMP #512,D3 ;if greater than 511, must have FOND
BLO.S OldFontLookUp ;if in old range, use old method
BRA Pop6SubFont ;if not, start up the great substitution engine
; utility subroutine to save code -- or in the size
OrInSize
AND #$FF80,D3 ;use high nine bits from that
OR D0,D3 ;combine family and size
BSR GetFontHandle ;got it? return to caller
BVS Pop8SubFont ;go start over if disk switch hook came up.
RTS
; after all that work, the desired size is on the top of the stack. Now we'll
; use it to build the resource ID of the desired font in D3
OldFontLookUp
MOVE.W (SP)+,D0 ;get the desired size
BNE.S @notZero ;this calculated if zero, should be made 1.
MOVEQ #1,D0
@notZero
AND #$007F,D0 ;use only low 7 bits
ASL #7,D3 ;make room for size field
OR D0,D3 ;add in the size bits
MOVE D0,D7 ;save target size
; At this point, D3 has the resource ID of the font we want. See if its there.
BSR GetFontHandle ;get the font, if we can
BVS Pop4SubFont ;;go start over if disk switch hook came up.
BNE.S GotTheFont ;if we got it, stop searching
; we couldn't find the one we wanted so try for 2X and .5X for the general
; search.
MOVE.W D3,D4 ;remember where we started
MOVE D7,D0 ;get target size
CMP #64,D0 ;is it > 64?
BGE.S SkipDouble ;if so, forget about doubling
ADD D0,D0 ;compute doubled size
BSR.S OrInSize ;or in the size
BNE.S GotTheFont ;if so, use it
; well, 2X didn't work so try .5X
SkipDouble
MOVE D7,D0 ;get target size
LSR #1,D0 ;divide by 2
BCS.S SkipHalf ;if odd, we're out of luck
BSR.S OrInSize ;or in the size
BNE.S GotTheFont ;if so, go use it
; we couldn't find a 2X or 1/2X match so start scanning up. If that doesn't
; work, scan down.
SkipHalf
MOVE D4,D3 ;retreive starting place
MOVEQ #1,D6 ;search up first
TST.B FScaleDisable ;scaling disabled?
BEQ.S scanFontLoop
MOVEQ #-1,D6 ;search down then
ScanFontLoop
ADD D6,D3 ;bump to the next size
AND #$007F,D3 ;only the low 7 bits are significant
BEQ ScanDone ;if we reach zero, done direction
MOVE D4,D0 ;get the original
AND #$FF80,D0 ;mask off size
OR D0,D3 ;build new one
; see if we have this one
BSR GetFontHandle ;get the font handle if we can
BVS Pop4SubFont ;go start over if disk switch hook came up.
BEQ.S ScanFontLoop ;if we couldn't, loop again
; we found a font so install it and compute the appropriate numer/denom
;
; Numer' := Numer * requested size * DotsPerInch
; -----------------------------------------------
; Denom' := Denom * actual size * 80
;
; Font handle in A0, size in D3.
GotTheFont
MOVE.L A0,FOutFontHandle ;install the font handle
BSR BuildCharTable ;make the character (height) table
SUBQ #4,SP ;make room for result
MOVE fmInSize(A3),-(SP) ;push desired size
MOVE D3,-(SP) ;push actual size
AND #$007F,(SP) ;use only low 7 bits
_FixRatio ;make it a fixed point number.
MOVE.L (SP)+,D6 ;keep size scale in D6
BSR DerefWidthTab ;get pointer to width table in A0
MOVE.W D3,WidthASize(A0) ;save actual size in width table.
MOVE.L FOutFontHandle,WidTabFont(A0)
MOVEQ #0,D5 ;first do the vertical
BSR.S MapScale ;calculate numer.v/denom.v
MOVEQ #2,D5 ;now do the horizontal
; compute the new numer/demon as a fixed point number, then rationalize it
; and stick it where it belongs
MapScale
SUB #12,SP ;make some space for results *** was 12 ***
MOVE.W fmInNumer(A3,D5),-(SP) ;push the numer
MOVE.W fmInDenom(A3,D5),-(SP) ;push the denom
_FixRatio ;compute the ratio.
SUBQ #4,SP ;make room for result
LEA FMDotsPerInch,A0 ;point to the dots/inch factor
MOVE.W 0(A0,D5),-(SP) ;push the dots/inch
MOVE.W #80,-(SP) ;the screen is 80 dots/inch
_FixRatio ;make it a rational number.
_FixMul ;multiply them together.
MOVE.L D6,-(SP) ;push the size scale
_FixMul ;multiply that in, too.
LEA FOutNumer,A0 ;point to the place to stuff result
MOVE.L (SP)+,D0 ;get the fixed point result
ADD.L #$80,D0 ;*** round it up
LSR.L #8,D0 ;take the middle 16 bits
MOVE.W D0,0(A0,D5) ;store the numerator
MOVE.W #256,4(A0,D5) ;the denom is 256
MOVE.L FPointOne,D1 ;set up FScaleHFact, FScaleVFact when disabled
TST.B FScaleDisable ;scaling disabled?
BEQ.S GoScaleLess ;if not, skip
MOVEQ #0,D1 ;zero top half of scale factor
MOVE.W D0,D1 ;remember it
MOVE #256,D0 ;start value for numerator
@2
CMP #512,D1 ; scale up > 2 x
BLO.S @4
ASL #1,D0 ; multiply numer by two
ASR #1,D1 ; divide scale factor by two
BRA.S @2
@4
CMP #192,D1 ; scale down < .75?
BHS.S @6
ASR #1,D0 ; multiply by 1/2
ASL #1,D1 ; divide by 1/2
BRA.S @4
@6
CMP #256,D1 ; scale down between 1x and 2x
BHS.S @doneScale
MOVE D0,D2 ; * 3
ADD D0,D0
ADD D2,D0
ASR #2,D0 ; multiply by 3/4ths
ASL #2,D1 ; divide by 3/4ths
DIVU #3,D1
EXT.L D1
@doneScale
MOVE.W D0,0(A0,D5) ;stuff numer
ASL.L #8,D1 ;fixate scale factor
; scaling is disabled so calculate the width factor adjustment
GoScaleLess
TST D5 ;horizontal?
BEQ.S @didVChange ;if not, skip
MOVE.L D1,FScaleHFact ;save new scale factor
BRA.S @scaleless
; compute vertical scaling factor too
@didVChange
MOVE.L D1,FScaleVFact ; record new V factor
@scaleless
MOVE.L WidthTabHandle,A1
MOVE.L (A1),A1 ;and remember it in the width table too.
LEA WidthVOutput(A1),A1
MOVE.W D0,0(A1,D5)
ASR.L #8,D1 ;shift scale factor back to a word.
MOVE.W D1,WidthVFactor-WidthVOutput(A1,D5)
RTS ;second time through, this ends MapFont
;———————————————————————————————————————————————————————————————————
; At this point, we've scanned all we can in one direction. If scaling is not allowed, then we started
; scanning down so now we must scan up; the opposite is true if scaling is allowed. If we have scanned
; in both directions, then start up the great font substitution machine.
ScanDone
TST.B FScaleDisable ; scaling disabled?
BEQ.S @0
NEG D6 ;negate the direction
BMI.S Pop4SubFont ;if negative now, we must substitute
BRA.S @1 ; go on
@0
NEG D6 ;negate the direction
BPL.S Pop4SubFont ;if positive now, we must substitute
@1
MOVE D4,D3 ;start with the target again
BRA ScanFontLoop ;try our luck scanning down
;————————————————————————————————————————————————————————————————————
;A word or two about font substitution:
;
; FontFlag is set to the current substitution level. If we get to SubFont, then the font requested is not
; available, or the disk switch hook drew in the system font while loading the requested FOND, FONT or
; NFNT. The value in FontFlag indicates what just happened, and what should be substituted next:
; -2 = The LoadResource failed at CheckPurged, although the font is the same one returned the last
; time SwapFont was called. (Maybe the user filled up memory, purging a large font.) Try for
; the same font again, so that a family-related substitute will be returned.
; -1 = The code was re-entered by the SysError (either a real problem or the disk switch hook.) The
; requested FOND, NFNT, or FONT may have been loaded, but the cache & low memory is no good.
; Try for the same font again.
; 0 = The requested font is not available, nor any reasonable family-related substitute. Try the
; ApFontID, if it is in the same neighborhood.
; 2 = The ApFontID family is not available. Try the base of the neighborhood.
; 4 = The base of the neighborhood is not available (Geneva, for the Roman neighborhood). Try the
; SysFontFam if it is in the same neighborhood.
; 6 = The SysFontFam family is not available. Try Font 0, setting curMap to the system map.
; 8 = (Disk switch only.) Give Chicago 12 a shot (same as 6).
; we have to substitute; use either the application or system font.
; Substitution order is:
; if the apFontID is in the same neighborhood as the requested font, use it.
; if not, or not available, use the base of the neighborhood (Geneva if the neighborhood is Roman.)
; if not available, use the sysFontFam, but only if it is in the same neighborhood as the request.
; if not, or not available, use the ROM font (hard coded to family 0, Chicago.)
Pop8SubFont
ADDQ #2,SP ;entry for throwing 2 return addresses away
Pop6SubFont
ADDQ #2,SP ;entry for throwing away scaled size, return address
Pop4SubFont
ADDQ #4,SP ;throw away return address for next time through
SubFont
; determine which to go to next
MOVE (A3),D3 ;set up font family
MOVEQ #0,D0
MOVE.B FontFlag,D0
BPL.S @noDiskSwitch
BSR InvalWidthTab ;otherwise, toss first cache entry
CLR.B FontFlag ;set up to 0 to start all over
BRA.S @skipDispatch
@noDiskSwitch
ADDQ.B #2,FontFlag
MOVE SubJump(D0),D0
JSR SubJump(D0)
@skipDispatch
MOVE.L 8(A6),A1 ;get pointer to original input record
MOVE D3,fmInFamily(A3) ;set up new substitute family
MOVE fmInSize(A1),fmInSize(A3) ;copy size since may have to map to system font.
BRA TryAgain
SubJump DC.W tryApFontID-SubJump ;0
DC.W tryNeighborhoodBase-SubJump ;2
DC.W trySysFontFam-SubJump ;4
DC.W tryChicago-SubJump ;6
DC.W tryChicago-SubJump ;8
; Use apFontID if it is in the same neighborhood.
tryApFontID
MOVE ApFontID,D1
checkNeighborhood ;common entry point for system family as well.
MOVEQ #9,D2 ;convenient constant
LSR D2,D1
SUB #31,D1
BPL.S @apForiegn
MOVEQ #0,D1
@apForiegn
MOVE D3,D0 ;copy family
LSR D2,D0 ;divide by 512 (unsigned)
SUB #31,D0 ;first $4000 is Roman, rest are neighborhoods
BPL.S @notRoman
MOVEQ #0,D0 ;Roman is 0, first neighborhood 1, etc.
@notRoman
CMP D0,D1 ;is apFontID in the same neighborhood as D3?
BNE.S Pop4SubFont ;if not, use next substitution method
MOVE ApFontID,D3
RTS
; Use the base of the neighborhood.
tryNeighborhoodBase
CMP #$4000,D3
BLO.S @mustBeRoman
AND #$FE00,D3 ;base is neighborhood & ~512
RTS
@mustBeRoman
MOVEQ #3,D3 ;hard code to Geneva
RTS
; Use the SysFontFam if it is in the same neighborhood.
trySysFontFam
MOVE SysFontFam,D1
BRA.S checkNeighborhood
; This entry point is called from the top of SwapFont if from within SysError we failed.
GoTryChicago
LINK A6,#stackFrame
MOVEM.L D3-D7/A2-A4,-(SP) ;save work registers
MOVE.L 8(A6),A3 ;get input pointer
BSR.S tryChicago
BRA MoreDifFont
; Use the ROM font.
; have to be very careful here that D3 is not later substituted
tryChicago
MOVE CurMap,saveMap(A6) ;save the current map
MOVE SysMap,CurMap ;hard code to the system map
MOVEQ #0,D3 ;hard code to Chicago
RTS
; ——————————————————————————————————————————————————————————————————
; SetNewDevice is called when we notice that the device has changed.
; If the device is 0 (the screen), fill out the info ourselves,
; otherwise make a status call to the driver to get it. Called only in DifFont after noting that the device
; has changed.
SetNewDevice
IF patch THEN
IF onMac THEN
JMP $40EE82
ELSEIF onMacPP THEN
JMP $419A9A ; *NB Patch* need addresses for both SE and Plus.
ENDIF
ELSE
TST D0 ;is it the screen?
BEQ.S SetScreenDevice ;if so, no need to call the driver
MOVEQ #-1,D0 ;get some ones
MOVE.B fmInDevice(A3),D0 ;build the refNum
MOVEQ #IOQElSize,D1 ;get size of pBlock
SUB.L D1,SP ;make space for control record
LEA IORefNum(SP),A0 ;point A0 at OS block
MOVE.W D0,(A0)+ ;set up the refNum
MOVE.W #FMgrCtl1,(A0)+ ;set up the control code
LEA FMDotsPerInch,A1 ;get place to stash info
MOVE.L A1,(A0)+ ;tell the driver about it
MOVE.W fmInDevice(A3),(A0)+ ;pass subclass, too
MOVE.L SP,A0 ;point A0 at pBlock
_Status ;ask the driver
ADD.L D1,SP ;pop off parameter block
RTS
ENDIF
; Set up parameters for the screen
SetScreenDevice
IF patch THEN
IF onMac THEN
JMP $40EEAC
ELSEIF onMacPP THEN
JMP $419AC4 ; *NB Patch* need addresses for both SE and Plus.
ENDIF
ELSE
LEA FMDotsPerInch,A1 ;get place to stash info
LEA ScreenStyleTab,A0 ;point to the info
MOVEQ #28,D0 ;28 bytes of info to move
_BlockMove ;move it in
RTS
ENDIF
; we found it, but better make sure we can load it
;——————————————————————————————————————————————————————————————————
;
; Four ways to get a font handle:
;
; GetStrike: returns handle to unloaded FONT to get resource attributes of ID passed in D1.
; GetFontHandle: returns handle to loaded FONT passed in D3.
; GoLoadStrike: returns handle to loaded FONT or NFNT inside FOND offset in A0.
; LoadNewStrike: returns handle to loaded FONT or NFNT passed in D0.
;
; All routines return the font handle in A0 and D0, with the Z-flag set to reflect if it is nil.
;——————————————————————————————————————————————————————————————————
GoLoadStrike
MOVE.L (A0),D0 ;get style/ID words from FOND
MOVE.L D0,styleID(A6) ;remember for later
LoadNewStrike
MOVE.W #MapTRUE,ROMMapInsert ;ResLoad True for GetResource <10 july 85>
LoadNoROM
MOVE D0,-(SP) ;preserve ID
SUBQ #4,SP
MOVE.L #'NFNT',-(SP) ;push NFNT
MOVE.W D0,-(SP)
_GetResource ;got it?
MOVE.L (SP)+,D0
BEQ.S fontOnlyLoad ;if not, look for FONT
ADDQ #2,SP ;don't need original ID
BRA.S weGotIt ;return z clear, handle in D0.
; we couldn't find the NFNT, so look for a FONT
; Change GetStrike to GetResource with loading off, in order to get handle, but to bypass doomed GetHandleSize. <PBM164>
GetStrike
MOVE.W #MapFALSE,ROMMapInsert ;don't load the font <10 July 85>
SUBQ #4,SP ;make space for function result <PBM164>
MOVE.L #'FONT',-(SP) ;'FONT' is resType
MOVE.W D1,-(SP) ;push ID
_GetResource
MOVE.L (SP)+,D0 ;get the love handle
BRA.S weGotIt ;use common code
GetFontHandle
MOVE D3,-(SP)
fontOnlyLoad
MOVE.W #MapTRUE,ROMMapInsert ;get FONT from ROM if possible <10july 85>
MOVE (SP)+,D0 ;recover ID
SUBQ #4,SP ;make space for function result
MOVE.L #'FONT',-(SP) ;'FONT' is resType
MOVE.W D0,-(SP) ;push ID
_GetResource
; But wait! What if we didnt get a font at all? (Most probably because of some quirk of data in FOND, we just asked
; for and got the zero size FONT, which exists only in name.)
MOVE.L (SP)+,D0 ;sets Z flag
BEQ.S @weDidntGetIt ;if missing, skip checking size
MOVE.L D0,-(SP) ;protect handle from resource manager call
SUBQ #4,SP ;make room for function result
MOVE.L D0,-(SP)
_MaxSizeRsrc ;<1July87>
; A font with a single character has a $1A header, at least a 1 word strike, 2 word loc table, 2 entry o/w table, thus:
;
; Since Radius returns a 16 point system font which is not a resource, errors from MaxSizeRsrc
; are ignored.
CMP.L #$24,(SP)+ ;is it smaller than the minimal size
SLO D0 ;set D0 if it is too small to be useful
MOVE.L (SP)+,A0 ;restore handle to font
BRA.S setZBit
@weDidntGetIt
weGotIt
MOVE.L D0,A0 ;return it in A0
SEQ D0 ;save Z flag
setZBit
AND #4,D0 ;set only Z bit
CMP.B #-1,FontFlag ;was there a disk switch?
BNE.S @noDskSwitch ;if not, leave V flag clear
BSET #1,D0 ;set V bit
@noDskSwitch
MOVE D0,CCR ;return V set if switch, Z set if no resource
RTS
;——————————————————————————————————————————————————————————————————
; FindSize is a utility the scans the font family data structure for the
; size that's passed in D3. It uses the famDef handle in A2.
; >> rather than implied return for GoLoadStrike, may need to check FontFlag for -1.
;——————————————————————————————————————————————————————————————————
FindSize
MOVE.L (A2),A0 ;handle->pointer
LEA FONDAssoc(A0),A0 ;bump past header
MOVE.W (A0)+,D1 ;get the # of entries
@fSizeLoop
CMP.W (A0)+,D3 ;this the one?
BEQ.S GoLoadStrike ;if so, go load it (code above)
BLT.S @cantFind ;if too big, too late
ADDQ #FAssocSiz-2,A0 ;bump to next entry
DBRA D1,@fSizeLoop ;check them all out
@cantFind
MOVEQ #0,D0 ;z-flag set, return NIL
RTS
;————————————————————————————————————————————————————————————————————
; NewFontLookUp is passed the family definition record in D0 and the
; desired size on the top of the stack. It decides on the best strike
; to use, then uses common code to finish up.
;————————————————————————————————————————————————————————————————————
NewFontLookUp
MOVE.W (SP)+,D5 ;get desired size
MOVE.L D0,A2 ;keep fDef handle in A2
; first go for an exact match
MOVE D5,D3
BSR.S FindSize
BVS.S NewFailed
BNE.S GoFoundTheSize
; if FScaleDisable is on, don't bother to look for 2X and .5X first
TST.B FScaleDisable
BNE.S FindClosest
; now try for the one that's twice the size
ADD.W D3,D3
BSR.S FindSize
BVS.S NewFailed
BNE.S GoFoundTheSize
; try for the half-size one
MOVE D5,D3
LSR #1,D3
BCS.S FindClosest ;skip if the original size is odd.
BSR.S FindSize
BVS.S NewFailed
GoFoundTheSize
BNE.S FoundTheSize
; oh, well, beggars can't be choosers. Scan to find the closest one
; in size
FindClosest
MOVE.L (A2),A0 ;point to famDef
LEA FONDAssoc(A0),A0 ;point to size list
MOVE.W (A0)+,D4 ;get # of entries-1
MOVEQ #0,D1 ;no font yet
; << note the unnecessary limit of the 127 point size
; *** lets try 32767 instead
MOVE #$7FFF,D2 ;closest delta so far
Scan4SizeLoop
MOVE.W D5,D0 ;get one we want <DLD-12-Sep-85>
SUB.W (A0),D0 ;compute delta
BPL.S @2
TST.B FScaleDisable ; scaling disabled?
BEQ.S @1 ; if so, see if we've got one lower
TST D1 ; if so, skip town
BNE.S sizeFound ; because we want to scale up
@1
NEG.W D0 ;absolute value
@2
CMP D2,D0 ;closest one yet
BGT.S NxtSizeLoop ;if not, skip
MOVE D0,D2 ;remember it
MOVE (A0),D1 ;remember font, too
NxtSizeLoop
ADDQ #FAssocSiz,A0 ;bump to next entry
DBRA D4,Scan4SizeLoop ;search them all
sizeFound
MOVE D1,D3 ;get best alternative
BSR.S FindSize ;try to get it...
BVS.S NewFailed
BEQ.S NewFailed ;if cant get it, skip
; OK, we found the size so now worry about the style. The Font handle is
; in D0.
FoundTheSize
MOVE.L A0,D0 ;save the font handle in D0
MOVE.L (A2),A0 ;handle->pointer
LEA FONDAssoc(A0),A0 ;skip header
MOVE.W (A0)+,D1 ;fetch # of entries
FTSLoop
CMP.W (A0),D3 ;search for matching size
BEQ.S GotEntry
ADDQ #FAssocSiz,A0
DBRA D1,FTSLoop
;when could this ever fall through?
NewFailed ;we can't find any in the family FOND record so try the old way
MOVE D5,-(SP) ;put size on stack
MOVE (A3),D3 ;get the requested family
BRA OldFontLookUp
; Modification history:
; 13-Aug-86 CRC Fixed bugs with uninitialized FOND entry pointer, looking at data past end of FOND.
;
; Registers used:
; D0 = handle to font (input) D1 = left in assoc. table (input) D2 = user style descriptor, scratch
; D3 = actual size (input) D4 = best style weight, temp. D5 = scratch
; D6 = FOND style descriptor D7 = scratch A0 = FOND data pointer (input)
; A1 = best style entry A2 = handle to FOND A3 = input record
; A4 = offset to width table in FOND
;
; A0 points to the first entry of this size in the FOND, but maybe the FOND contains a stylized font that
; is better. Loop through to pick up the best qualifying one. The first font in the actual
; size pointed to by the FOND has already been successfully loaded, and is pointed to by D0.
; Both this routine and the earlier call to FindSize only make one call to GetResource; if that call fails,
; then other styles in the same size are not tried before going on to other methods of font substitution.
; A major reorganization of the code should include a thorough family search, retrying after failure until
; the family has been exhausted.
; >>> Styleweights needs to be driver supplied, at least for alternate display devices?
; StyleWeights is a table of weights for the font style bits, to determine which strike to display on
; the screen. Styles not provided by the strike returned are generated by QuickDraw.
StyleWeights
DC.B 4 ;weight for bold
DC.B 8 ;weight for italic
DC.B 1 ;weight for underline
DC.B 3 ;weight for outline
DC.B 3 ;weight for shadow
DC.B 2 ;weight for condensed
DC.B 1 ;weight for extended
DC.B 0 ;bit 7 unused
GotEntry
MOVEQ #0,D2 ;zero high byte of style
ADDQ #2,A0 ;point to style field
MOVEQ #-2,D4 ;init best metric
MOVE.B fmInFace(A3),D2 ;get style we want
@selectStyleLoop
MOVE.W (A0),D6 ;get style descriptor (want low byte only)
CMP D6,D2 ;do they match?
BNE.S @noStyleMatch
MOVE.L A0,A1 ;if so, we've got it!
BRA.S @foundMatch0
@noStyleMatch
MOVEQ #-1,D5 ;take the first entry for starters
MOVE D2,D7
NOT D7
AND D6,D7 ;can we use it?
BNE.S @nextStyle ;if not, skip
; it qualifies, so determine its weighting
MOVEQ #0,D5 ;initial weight is 0
MOVEQ #7,D7 ;start with bit 8
AND D2,D6 ;only bits set in both request & available
@styMagLoop
ASL.B #1,D6 ;bit set?
BCC.S @nextStyMag ;if not, skip
ADD.B StyleWeights(D7),D5 ;add in weight
@nextStyMag
DBRA D7,@styMagLoop ;loop for 8 bits
; OK, now see if the resulting weight (in D1) is the biggest so far
@nextStyle
CMP D5,D4 ;best so far?
BGE.S @loopBottom ;if not, forget it!
; its the biggest so far, so remember it
MOVE D5,D4 ;remember metric value
MOVE.L A0,A1 ;remember entry
; if we have more to consider, go handle them
@loopBottom
ADDQ #FAssocSiz-2,A0 ;bump to next entry
CMP.W (A0)+,D3 ;next one same size?
DBNE D1,@selectStyleLoop ;if not, or if out of entries, decide the style
; no more of this size so the winner is the one pointed to by A1. If the
; ID is the same as the one we already got, we don't have to get it
; again
@foundMatch0
MOVE.W (A1)+,D6 ;get the style of winner
MOVE.W styleID+2(A6),D1 ;get resID of one in D0
CMP.W (A1),D1 ;do we already have it?
MOVE.L D0,A0 ;keep fontHandle from now on in addr. reg.
BEQ.S @foundItAll ;if so, don't have to load
; it changed, so we have to get it again
MOVE.L A0,D4 ;remember old fonHandle
MOVE.W (A1),D0 ;get ID
BSR LoadNewStrike ; << this is the only call to this subroutine,
; << but it is inside goLoadStrike (which is
; << also called only once.)
; << uses only A0, D0
BVS.S NewFailed ;disk switch, oh no.
BNE.S @foundItAll
@noTweakedFont
; we couldn't load it, so stick with the old one
MOVE.L D4,A0 ;recover fontHandle
MOVE.W styleID(A6),D6 ;recover style
; OK, the fontHandle is in D0 and its style is in D6. Set up FOutCurStyle
; with the proper value, and dive back in to the font manager proper.
@foundItAll
NOT D6 ;invert mask of what we got
AND.B D6,FOutCurStyle ;turn off built-in properties
; at this point D6 has the inverse of the style we actually got. A2 has
; the family definition record handle. Look for a matching width table;
; if we got one, return its offset in A4.
MOVE.L (A2),A1 ;point to famDef
MOVE.W FONDLast(A1),D1 ;get lastChar
BEQ.S @noFamWidths ;if zero, must be a “null” FOND set up by Font/DA Mover
SUB.W FONDFirst(A1),D1 ;compute # of chars-1
ADDQ #4,D1 ;compute word size of wTab (include style wd.)
ADD.W D1,D1 ;compute size of table
MOVE.L FONDWTabOff(A1),D0 ;get offset to widthTabs
BEQ.S @noFamWidths ;if none, skip
ADD.L D0,A1 ;point to the width tables
MOVE.W (A1)+,D2 ;get # of tables-1
BMI.S @noFamWidths ;skip if none
; here's the loop where we search for the appropriate family width table
; >> Adobe pointed out a bug here. If the FOND has a style width table, but the style screen font is not
; >> around, the plain width table will be used incorrectly. The right solution is for the styles to be
; >> searched and compared on a weighted basis just like the screen styles, except for the weights are
; >> different. Bold first, Condensed next, and Italic third? What about the idea of masking out
; >> underline, outline, shadow, and always forcing stylistic extras to be used, unless an exact match
; >> is found?
; >> Certainly, if a style width has styles outside of the requested style, it can not be used.
; >> Although this code is very similar to the screen font code above, I cant see any trival way of
; >> rolling them together. For one, all registers are used.
;———————————————————————————————————————————————————————————————
; bug fix, implemented as a patch on Aladdin - the problem is that FOND widths will only be used
; if FractEnable is true; otherwise, the widths will be gotten from the strike.
; probably can skip this whole mess if FractEnable is false ---
IF bugFix THEN
@srchFamWTab
MOVEQ #-1,D4 ;best match found so far
TST.B FractEnable ;are fractions allowed?
BNE.S @useBestStyle ;if so, use the best width table around
NOT D6 ;reverse strike style once more
MOVE D6,-(SP) ;use width table equivalent to strike
BRA.S @nextFamWTab
@useBestStyle
MOVEQ #0,D0 ;zero high word
MOVE.B fmInFace(A3),D0 ;get original requested style
MOVE D0,-(SP) ;push it
@nextFamWTab
MOVE (SP),D0 ;get the style word
ELSE
@srchFamWTab
MOVEQ #-1,D4 ;best match found so far
MOVEQ #0,D0 ;zero high byte of style
@nextFamWTab
MOVE.B fmInFace(A3),D0 ;get original requested style
ENDIF
;———————————————————————————————————————————————————————————————
CMP (A1),D0 ;exact match?
BEQ.S @figureWidthPos ;dont worry no more
NOT D0 ;set all cleared bits
AND (A1),D0 ;nonzero if style in width is not in request
BNE.S @wrongFamWidths ;dont consider widths with too much info.
MOVEQ #0,D5 ;accumulated weight
;———————————————————————————————————————————————————————————————
; more of the same bug fix
IF bugFix THEN
MOVE (SP),D0
ELSE
MOVE.B fmInFace(A3),D0 ;bits in requested style
ENDIF
;———————————————————————————————————————————————————————————————
AND (A1),D0 ;and in available bits
MOVEQ #7,D7 ;number of bits in style byte
@nextBit
ASL.B #1,D0 ;
BCC.S @skipWeight ;
ADD.B widthWeights(D7),D5
@skipWeight
DBRA D7,@nextBit ;if no carry and not zero, go to next bit
CMP D5,D4
BGE.S @wrongFamWidths
MOVE D5,D4 ;save best
MOVE.L A1,D6 ;location of best width found so far
@wrongFamWidths
ADD D1,A1 ;advance to next table entry
DBRA D2,@nextFamWTab
TST D4
BMI.S @tossStackSpace ;<1July87>
MOVE.L D6,A1
@figureWidthPos
MOVE (A1)+,fwidStyle(A6) ;keep best found style
SUB.L (A2),A1
MOVE.L A1,A4
@tossStackSpace
IF bugFix THEN
ADDQ #2,SP
ENDIF
@noFamWidths
BRA GotTheFont ;dive back in
; output registers: (double dashes indicate registers are written before read)
; D0 = -- D1 = -- D2 = --
; D3 = actual size (input) D4 = -- D5 = --
; D6 = -- D7 = -- A0 = handle to font (input)
; A1 = -- A2 = -- A3 = input record
; A4 = offset to width table in FOND
; end of GotEntry
; WidthWeights are used to determine which width table in the FOND is the best approximation of the
; requested style widths. Styles not provided by the FOND width table are added in from the FOND values
; in style extra.
WidthWeights
DC.B 1 ;weight for bold
DC.B 3 ;weight for italic
DC.B 5 ;weight for underline
DC.B 4 ;weight for outline
DC.B 4 ;weight for shadow
DC.B 2 ;weight for condensed
DC.B 2 ;weight for extended
DC.B 0 ;bit 7 unused
FPointOne DC.W 1
DC.W 0
; PROCEDURE GetFontName(familyID: INTEGER; VAR theName: Str255);
;
; Fix File Date Patch# Fix Routine(s) Routine(s) Fixed
;AppleSystemPatch FontMgrPatch.a 01Jan1904 #??? (GetFontName) (GetFontName)
;
; Get the name of the font, given the family ID
GetFontName
; first check if we have a family definition record
MOVE.L (SP)+,A1 ;save return address
MOVE.L (SP)+,D2 ;save pointer to string
MOVE.W (SP)+,D1 ;get the requested family ID
MOVE.W #MapFALSE,ROMMapInsert ;set ResLoading False <10 Jul 85>
BSR.S GetFONDMap ;is there a FOND for this family?
BNE.S @askForName ;if so, skip
; make sure the ID is in range
CMP.W #512,D1 ;ID in range?
BCC.S @returnNilString ;if not, skip
; no luck, so try it the old way
ASL #7,D1 ;set size field to 0
BSR GetStrike ;get the fontHandle
BEQ.S @returnNilString ;if NIL, return empty string
@askForName
MOVE.L A0,-(SP) ;push the resource handle
CLR.L -(SP) ;no place for ID (don't care)
CLR.L -(SP) ;no place for type (don't care)
MOVE.L D2,-(SP) ;place for name (where app wants)
MOVE.W #MapFALSE,ROMMapInsert ;get from ROM if possible <10 Jul 85>
_GetResInfo ;get it!
BRA.S @doneGetFName ;all done
@returnNilString
MOVE.L D2,A0 ;get the string pointer
CLR.B (A0) ;make it NIL
@doneGetFName
JMP (A1) ;return to caller
; Common code used by GetFontName and RealFont. GetFOND entry point is used by TryFOND.
;
; Fix File Date Patch# Fix Routine(s) Routine(s) Fixed
;AppleSystemPatch FontMgrPatch.a 01Jan1904 #??? (GetFONDMap) (GetFONDMap)
;
; Need to map D1 into proper ID if 0 or 1
GetFONDMap
TST D1
BNE.S @notSysFont
MOVE SysFontFam,D1
BRA.S GetFOND
@notSysFont
CMP #1,D1 ;is it the same as the apFontID?
BNE.S GetFOND
MOVE ApFontID,D1
GetFOND
SUBQ #4,SP
MOVE.L #'FOND',-(SP) ;push type "FOND"
MOVE.W D1,-(SP) ;push the ID
_GetResource ;look for it
MOVE.L (SP)+,D0
MOVE.L D0,A0
RTS
; FUNCTION RealFont(famID: INTEGER; size: INTEGER): BOOLEAN;
;
; Fix File Date Patch# Fix Routine(s) Routine(s) Fixed
;AppleSystemPatch FontMgrPatch.a 01Jan1904 #??? (RealFont) (RealFont)
;
; RealFont is a boolean function that returns true if we have a real bitmap
; (as opposed to a stretched one) for the requested font
;
; Modification History:
;
; 26-Aug-86 CRC Use same substitution scheme as SwapFont. Do not play with cache state
; anymore.
RealFont
MOVE.L (SP)+,A1 ;save return address
MOVE.W (SP)+,D2 ;get size
BNE.S @notSizeZero ;if nonzero, no prob with Bob
TST (SP) ;sysFontFam?
BNE.S @notSysFont ;if not, use FMDefaultSize
MOVE SysFontSize,D2 ;must be 0,0
BNE.S @notSizeZero ;if non zero, it is fine
@notSysFont
MOVEQ #0,D2 ;zero high order byte
MOVE.B FMDefaultSize,D2 ;pick up preset default
BNE.S @notSizeZero ;take it as long as it is not zero.
MOVEQ #12,D2 ;hardcode to 12 if low memory is no help
@notSizeZero
MOVE.W (SP)+,D1 ;get the font family
CLR.W (SP) ;assume we don't have it (set result false)
MOVE.W #MapTRUE,ROMMapInsert ;set ResLoading True
BSR.S GetFONDMap ;is there a FOND for this family?
BEQ.S @oldKindOfFont ;if not, try for old
; we have a family definition record (handle in D0), so scan it to see
; if the record contains an entry for that size
MOVE.L (A0),A0 ;handle->pointer
LEA FONDAssoc(A0),A0 ;skip header
MOVE.W (A0)+,D0 ;pick up the count
BMI.S @notReal ;if none, skip
@nrfLoop
CMP.W (A0),D2 ;got it?
BEQ.S @itsReal ;if so, its real
BLT.S @notReal ;if past it we're done
ADDQ #FAssocSiz,A0 ;skip to next entry
DBRA D0,@nrfLoop ;check em all out
BRA.S @notReal ;it must not be real...
@oldKindOfFont
; make sure the ID is in range for an old-style font
CMP.W #512,D1 ;ID in range?
BCC.S @notReal ;if not, return false
; there's no family definition record so do it the old way
ASL #7,D1 ;shift FamID into place
AND.W #$007F,D2 ;only use low 7 bits of size
OR D2,D1 ;compute resource ID
BSR GetStrike ;do we have it
BEQ.S @notReal ;good! (branch if we couldn't find it)
@itsReal
ADDQ.B #1,(SP) ;return TRUE
@notReal
JMP (A1) ;return to caller
; PROCEDURE SetFontLock(lockFlag:Boolean) -- makes the current font purgable
; or unpurgable.
SetFontLock
MOVE.L FOutFontHandle,A0 ;get the font handle
MOVE.L (SP)+,A1 ;get return address
TST.B (SP)+ ;set or clear lock?
BEQ.S @unlockFont ;if set, go lock it down
; we want to lock the font down so make sure its loaded and make it unpurgable
MOVE.L A0,-(SP) ;push font handle for release/load
MOVE.W #MapTrue,ROMMapInsert ;get it from ROM if possible <10 Jul 85>
_LoadResource ;load it in
_HNoPurge ;turn off purge bit
BCLR #purge,FondState
BRA.S @doneSFL
; we no longer need the font so make it purgable
@unlockFont
_HPurge ;make it purgable
BSET #purge,FondState
@doneSFL
JMP (A1) ;return to caller
; PROCEDURE SetFScaleDisable(scaleDis:BOOLEAN);
;
; Set to turn ScaleDisable on and off, invalidating the width cache.
SetFScaleDisable
MOVE.L (SP)+,A0
MOVE.B (SP)+,FScaleDisable
setFScaleTail
MOVE.L MinusOne,LastSpExtra ;note that widths are invalid
JMP (A0)
; PROCEDURE SetFractEnable(fractEnable:BOOLEAN);
;
; Set to turn FractEnable on and off, invalidating the width cache.
SetFractEnable
MOVE.L (SP)+,A0 ;return address
MOVE.B (SP)+,FractEnable
BRA.S setFScaleTail
; PROCEDURE FontMetrics(VAR theMetrics:FontMetricRec);
;
; Fix File Date Patch# Fix Routine(s) Routine(s) Fixed
;AppleSystemPatch FontMgrPatch.a 01Jan1904 #??? (FontMetrics) (FontMetrics)
;
; FontMetrics returns fractional information about the current font
; as specified in thePort. It returns a Font Metric Record whose format
; is:
;
; ascent: Fixed;
; descent: Fixed;
; leading: Fixed;
; widMax: Fixed;
; WTabHandle: Handle;
;
; first use CharWidth to force a SwapFont
FontMetrics
SUBQ #2,SP ;make room for result
MOVE #' ',-(SP) ;push ASCII for blank
_CharWidth ;run through SwapFont
ADDQ #2,SP ;we don't really care about result
; get the parameter pointer
MOVE.L A2,-(SP) ;save work register
MOVE.L 8(SP),A2 ;point to result record
; always derive things from the font itself
MOVE.L FOutFontHandle,A1 ;get font handle
MOVE.L (A1),A1 ;handle->pointer
LEA FAscent(A1),A0 ;point to ascent field
PEA FWidMax(A1) ;save pointer to FWidMax for later
BSR.S ScaleVFVal ;process ascent
BSR.S ScaleVFVal ;process descent
BSR.S ScaleVFVal ;process leading
MOVE.L (SP)+,A0
MOVE.L FScaleHFact,D1
LEA fmOutNumer+FOutRec+2,A1 ;point to horizontal numerator.
BSR.S ScaleFVal ;process widMax
; stuff the width table handle
MOVE.L WidthTabHandle,A0
MOVE.L A0,(A2) ;remember width handle
; now adjust the results to compensate for style
MOVE.L 8(SP),A2 ;get result pointer back.
MOVEQ #0,D0
MOVE.B fmOutShadow+FOutRec,D0 ;get shadow count
BEQ.S @noShadow ;skip if zero
ADD.W #1,(A2) ;adjust ascent
ADD.W D0,4(A2) ;adjust descent
@noShadow
MOVE.L (A0),A0 ;pointer to widths
MOVE.L WidthStyle(A0),D0 ;get the style extra.
ADD.L D0,12(A2) ;add it in to the WidMax field.
; now we're done
MOVE.L (SP)+,A2 ;restore work register
MOVE.L (SP)+,(SP) ;strip parameter
RTS
; ScaleFVal is a code saving utility that fetches the value pointed
; to by A0, multiplies it by the scale factor and scale disable adjustment,
; and stuffs the normalized long result where A2 points
ScaleVFVal
MOVE.L FScaleVFact,D1
LEA fmOutNumer+FOutRec,A1 ;point to vertical numerator.
ScaleFVal
MOVE.W (A0)+,D0 ;get ascent
MOVE.L A0,-(SP)
TST.B FScaleDisable ;use 1.0 if scaling is enabled.
BNE.S @2
MOVE.L FPointOne,D1
@2
SUBQ #4,SP ;make space for result
MOVE.L D1,-(SP) ;FScale adjustment for FixMul
SUBQ #4,SP
CLR.W -(SP) ;push the font's info as a fixed point value.
MOVE.W D0,-(SP)
SUBQ #4,SP
; reversed next 2 lines <28May86>
MOVE.W (A1),-(SP) ;push V output numer
MOVE.W 4(A1),-(SP) ;push V output denom
_FixRatio ;compute ratio.
; multiply by the appropriate FScaleDisable factor in D1
_FixMul ;compute FScaleExtra*Value
_FixMul ;compute FScaleExtra*Value*ScaleFactor
MOVE.L (SP)+,(A2)+ ;remember it
MOVE.L (SP)+,A0
RTS
;———————————————————————————————————————————————————————————————————
; BuildCharTable operates on the font passed in A0. It makes room for
; a character height table at the end of the font and then loops from
; FirstChar to LastChar+1, computing it.
;
; Fix File Date Patch# Fix Routine(s) Routine(s) Fixed
;AppleSystemPatch FontMgrPatch.a 01Jan1904 #??? (BuildCharTable) (BuildCharTable)
;
; Registers used:
;
; D0 = scratch D1 = scratch D2 = scratch D3 = character height
; D4 = constant (16) D5 = table size D6 = next entry, width D7 = locTable entry
; A0 = fontHandle (input) A1 = strike pointer A2 = fontPtr, locTable A3 = fontHandle
; A4 = character height A5 = mask table
RightMask EQU $0 ;position of right masks in QuickDraws table.
LeftMask EQU $20 ;position of left masks in QuickDraws table.
BuildCharTable
MOVEM.L D3-D7/A2-A5,-(SP) ;save registers
MOVE.L A0,A3 ;keep fontHandle in A3
_GetMaskTable
MOVE.L A0,A5 ;keep pointer to left masks around
MOVE.L (A3),A1 ;point to the font
MOVE.W (A1)+,D0 ;get format word?
LSR #1,D0 ;already got table?
BCS.S DoneBCT ;if so, we're done
; get firstChar, lastChar and compute size of table
MOVE.W (A1)+,D0 ;get firstChar
MOVEQ #0,D5 ;zero high word
MOVE.W (A1),D5 ;get lastChar
SUB.W D0,D5 ;compute lastChar-firstChar
ADDQ #3,D5 ;# of chars, including missing
ADD.W D5,D5 ;compute size of table
; compute total new size of font: position of OWTable + 2 * D5
MOVE.L (A3),A1 ;point to font
MOVEQ #0,D0
IF bugFix THEN
MOVE.W fNDescent(A1),D0 ;possibly the high word of owTLoc
BLE.S @negative
SWAP D0 ;put it in the high word
ENDIF
@negative
MOVE.W fOWTLoc(A1),D0 ;get size till owTable
ADDQ.L #8,D0 ;8 header words in front
ADD.L D0,D0 ;double for bytes
MOVE.L D0,D1 ;remember in D1
SUB.L D5,D1 ;compute offset to LocTable
ADD.L D5,D0 ;add in owTable
MOVE.L D0,D2 ;remember offset to height table for later
ADD.L D5,D0 ;add in newTable
; if the font has a built-in width table, make sure we take that into
; account
BTST #1,1(A1) ;built in width table?
BEQ.S @growTheFont ;if not, skip
ADD.L D5,D0 ;increase new size
ADD.L D5,D2 ;bump where heights go, too
; grow it to include the table
@growTheFont
MOVE.L A3,A0 ;get the font handle
_SetHandleSize ;try to grow it
BEQ.S MakeCTable ;if we can, good
; we couldn't grow the handle so give up.
DoneBCT
MOVEM.L (SP)+,D3-D7/A2-A5
RTS
; OK, D2 has the offset to the beginning of the character offset table,
; D1 has offset to locTable, D3 has firstChar and D4 has lastChar. Loop
; for the # of characters, walking down both tables, using locTable to
; build the mask, counting the rows and filling out the charTable.
MakeCTable
MOVE.L (A3),A2 ;point to font
OR #1,(A2) ;turn on mode bit
MOVE.W fFRectHeight(A2),D3 ;hold total height
ADD.L D1,A2 ;A2 points to locTable
MOVE.L (A3),A4 ;point to font
ADD.L D2,A4 ;point to charTable
; here's the start of the loop. D5 has the number of entries *2 to
; process. From the words that A2 points to, make a mask/offset combo
; in A1/D0.
SUBQ #2,D5 ;don't need extra bounds
CTabLoop0
MOVE #$FF00,(A4) ;init top to FF, bot to 0
MOVE.W (A2)+,D7 ;get locTable entry
MOVE.W (A2),D6 ;get next entry, too
SUB.W D7,D6 ;compute length in pixels
BEQ.S EmptyChar ;if zero, its easy
; Here's where we re-enter the loop for wide characters. Make A1 point
; into word of font, and start building the mask in D0.
CTab1Loop
MOVE.W D7,D2 ;remember start
MOVE.W D7,D0 ;get start in D0
LSR.W #4,D0 ;divide by 16
ADD.W D0,D0 ;double for byte offset
MOVE.L (A3),A1 ;get font pointer
ADD.W #FRowWords+2,A1 ;point to strike
ADD.W D0,A1 ;point to proper word
; now build the leftMask based on the remainder
AND #15,D2 ;compute start mod 16
MOVE D2,D1 ;copy it
ADD.W D1,D1 ;double for word index
MOVEQ #0,D0 ;clear high part of D0
MOVE.W LeftMask(A5,D1),D0 ;get leftMask
SWAP D0 ;keep in high word
; now compute how many pixels were used up in the first word, and decrement
; the width value
MOVEQ #16,D4 ;useful constant!
MOVE D4,D1 ;at most 16 used
SUB.W D2,D1 ;compute number used
ADD.W D1,D7 ;bump left index
SUB.W D1,D6 ;compute number left
BEQ.S MaskBuilt ;if none, done building mask
BPL.S @moreMask ;if >0, turn on more bits
; the width remaining is < 0, so we must turn off bits in the mask
MOVE D6,D1 ;get the delta
ADD.W D4,D1 ;compute 16-delta
ADD.W D1,D1 ;double for word index
MOVE.L RightMask(A5,D1),D2 ;get inverse mask in high word
AND.L D2,D0 ;turn off right bits
BRA.S MaskBuilt ;OK, we got it
; here we handle the case where there's more in the next word to process,
; so extend the mask into the low word.
@moreMask
MOVE.W D6,D1 ;get remaining count
CMP.W D4,D1 ;bigger than 16?
BLE.S @notTopEnd ;if not, skip
MOVE.W D4,D1 ;if so, max out at 16
@notTopEnd
ADD.W D1,D1 ;double for word index
MOVE.W RightMask(A5,D1),D2 ;get mask
OR D2,D0 ;extend the mask
SUB.W D4,D6 ;decrement remaining width
ADD.W D4,D7 ;bump index to next word
; at this point, A1 points to the top long in the character and D0 has
; the mask. D3 has the number of scan lines. Loop, fetching a long
; and masking to find top of character.
MaskBuilt
MOVE.L A1,-(SP) ;remember first pointer
MOVE D3,D1 ;init height counter
SUBQ #1,D1 ;bias for DBRA
MOVE.L (A3),A0 ;get font pointer
MOVE.W fRowWords(A0),A0 ;get rowWords in A0
ADD.W A0,A0 ;compute rowBytes
MOVEQ #0,D4 ;D4 is current top
TopMaskLoop
MOVE.L (A1),D2 ;get the bits
AND.L D0,D2 ;any relevant one on?
BNE.S MergeInTop ;if on, done with top
ADDQ #1,D4 ;bump top
ADD.W A0,A1 ;add in RowBytes
DBRA D1,TopMaskLoop ;loop for all height
; all blank so set up as (0,0)
ADDQ.L #4,SP ;strip saved A1
MOVEQ #0,D6
EmptyChar
CLR.W (A4)+ ;stick 0,0 in table
BRA.S NextChar ;go process next char
; OK, so top is in D4. Merge it into the table.
; (A4) starts at $FF, so any other value is smaller by unsigned <28May86>
; compare; we're looking for the lowest value possible. <28May86>
MergeInTop
CMP.B (A4),D4 ;is it smaller?
BHS.S @0 ;if not, skip
MOVE.B D4,(A4) ;update top
; now try the bottom up
@0
MOVE.L (SP)+,A1 ;recover character ptr
MOVE D3,D2 ;get height
SUBQ #1,D2 ;compute height-1
MOVE A0,D4 ;get rowBytes
MULU D4,D2 ;compute offset to bottom
ADD.L D2,A1 ;start with bottom word
MOVE D3,D4 ;start with height
MOVE D3,D1 ;get # of lines
SUBQ #1,D1 ;bias for DBRA
BotMaskLoop
MOVE.L (A1),D2 ;get the long
AND.L D0,D2 ;any relevant bits on?
BNE.S MergeInBot
SUBQ #1,D4 ;one less high
SUB.W A0,A1 ;back up a scan line
DBRA D1,BotMaskLoop
BRA.S EmptyChar ;impossible to get here...
; compute the height of the character and merge it in
; Herein lies the bug: until now the delta was computed along the <28May86>
; way, so information could be lost about characters that slanted <28May86>
; from lower left to upper right. Nowadays, keep the low point in the <28May86>
; second byte until the character is finished; then compute the delta <28May86>
; into the second byte.
MergeInBot
ADDQ.L #1,A4 ;skip top offset <28May86>
CMP.B (A4)+,D4 ;compare with last height
BCS.S NextChar ; <28May86>
MOVE.B D4,-1(A4) ;its bigger, so use it
; we're finally done with this band of the character (at least!) so see
; if we're really done with it
NextChar
SUBQ.L #2,A4 ;back up
TST D6 ;done with this character?
BGT CTab1Loop ;if not, dive in again
; Get here when finished with a char. Have high and low pts in (A4), <28May86>
; so must compute low-high in 1(A4) as incrementing. <28May86>
MOVE.B (A4)+,D0 ;high pt <28May86>
SUB.B D0,(A4)+ ;low-high <28May86>
SUBQ #2,D5 ;more to do?
BGT CTabLoop0 ;if so, go do it
BRA DoneBCT ;if not, we're done
FMgrEnd
;*******************************************************************
;*******************************************************************
;*******************************************************************