sys7.1-doc-wip/Toolbox/FontMgr/FontMgrPatch.a

2923 lines
109 KiB
Plaintext
Raw Normal View History

2019-07-27 14:37:48 +00:00
;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
;*******************************************************************
;*******************************************************************
;*******************************************************************