;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 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, donÕt 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 applicationÕs 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 ;donÕt 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 didnÕt 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, donÕt check space extra MOVE.L D0,A0 @checkLastSp MOVE.L LastSpExtra,D0 ;get spaceExtra CMP.L SpExtra(A0),D0 ;did it change? 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 isnÕt a nonpurged entry then weÕre out of luck; donÕt use cache. ; if a memory allocation call fails, then the system heap is in bad shape; donÕt 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 ;donÕt 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 _HNoPurge ; Make the Width Table non-purgeable 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 MOVE.L (A4), A4 ; Pointer to Width Table Handles ADD D5, A4 ; Add Offset of current Width Table MOVE.L (A4), A1 ; Handle to Width Table MOVE.L (A1), A1 ; Width Table ptr LEA WidthUsedFam(A1), A1 ; Load the address of the WidthUsedFam 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, didnÕt 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 ;donÕt 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 canÕt 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 itÕs 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, donÕt 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 twoÕs 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 donÕt 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. MOVE.B D0,FOutExtra ;and save the byte-sized result 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 FixMulÕs 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 ; 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 MOVE.L A0,LastFOND ;so we will cache when no FOND. ; 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. GetStrike MOVE.W #MapFALSE,ROMMapInsert ;don't load the font <10 July 85> SUBQ #4,SP ;make space for function result 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 didnÕt 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 ; *** letÕs try 32767 instead MOVE #$7FFF,D2 ;closest delta so far Scan4SizeLoop MOVE.W D5,D0 ;get one we want 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 canÕt 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 canÕt 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 ;donÕt worry no more NOT D0 ;set all cleared bits AND (A1),D0 ;nonzero if style in width is not in request BNE.S @wrongFamWidths ;donÕt 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 QuickDrawÕs table. LeftMask EQU $20 ;position of left masks in QuickDrawÕs 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 ;******************************************************************* ;******************************************************************* ;*******************************************************************