; ; File: RomanNewJust.a ; ; Contains: New Roman routines for text drawing, measuring, and hit testing with ; justified text. ; ; Written by: PKE Peter Edberg ; ; Copyright: © 1990-1992 by Apple Computer, Inc., all rights reserved. ; ; Change History (most recent first): ; ; 9/17/92 kc Fix bug in PortChExtra. The rts was missing, and it was falling ; through to the next procedure. This was benign until we added a ; vector to the end of the procedure. ; <24> 7/8/92 HA #1035313 : In NChar2Pixel, when we call StdTxMeas, we use ; the fixed value that is returned in field fontAdj field of QD ; globals . This would make NC2P more accurate and consistent with ; measurements returned by NMeasureJust. ; <23> 4/29/92 FM Get rid of conditionals: smgrSys7Extensions ; <22> 4/14/92 PKE #1026778,: Adapt for ScriptRecord pointer on stack instead ; of selector. ; <21> 10/8/91 PKE For Cube-E (and Bruges): Fix (N)Pixel2Char so that TRUE for ; leadingEdge is always $FF (not sometimes 1); bug #1012676. ; <20> 4/1/91 PKE JDT, #86037, #86038, #86039, #86068, #86074: Force all slop to ; be allocated to spaces, as in 6.x. This is necessary to fix a ; number of bugs having to do with use of the QuickDraw qdChExtra ; field. Some of these bugs are in printing, but we prevent them ; by doing this. ; <19> 2/1/91 PKE JSM,#PKE-Sys-017,#81409,#59217: Fix NPixel2Char to set ; widthRemaining correctly for large pixelWidth values (this ; change marked with ). Have (N)MeasureJust use a custom ; txMeasProc if installed, else measure using width table; stop ; using slimy way of passing scaling parameters to MeasureText via ; ExpandMem. Used heuristic to limit negative values of addSpExtra ; and addChExtra so net character widths donÕt get negative; had ; to rearrange CalcSpChExtra somewhat to do this. Reduced code ; size by combining InitFontAndFlags and InitScaleFac into ; InitFontAndScale, and have it also compute output scaling. ; <18> 1/19/91 PKE (ngk) Fix remaining end-of-line and scaled text problems in ; (N)Pixel2Char and (N)Char2Pixel (rest of bug #70716). Also fixed ; a problem introduced in <17> that caused some linebreaking ; problems in TE: leadingEdge was not set correctly for widths ; beyond end of text (needed cmp.l, not cmp.w!). ; <17> 1/14/91 PKE (stb, jh) Fix measuring discrepancies in NChar2Pixel and ; NPixel2Char for scaled text. Speed up NPixel2Char by walking ; width tables, fix its handling of end adjustments and make it ; work with R-to-L line direction. Check FOND to see if it ; disallows interchar spacing, and act accordingly. Fixed handling ; of left and right style runs (each behaved like the other ; should). Use PicComment in NDrawJust to make LaserWriter ; printing work correctly if smgrCharPortion value does not match ; LaserWriter default value (1:10). Rearrange internal routines in ; order to do this: add InitFontAndFlags; rename InitJustData as ; InitWeight to better reflect function; split AdjustSpChExtra ; into CalcSpChExtra and DoSpChExtra; add flags to prevent ; redundant computation if CalcSpChExtra is called a second time ; (for LaserWriter layout calculations). Eliminate ; UseCharExtraTrap and ScaleSMgrCharExtra conditionals used with ; earlier versions of this code. ; <16> 9/19/90 PKE Fix bugs with zero-length strings and protect against divide by ; 0. ; <15> 9/1/90 PKE Need to set up JustDataRec scaling parameters even if slop is 0 ; (Pixel2Char was having problems cause hScaleTrue was bogus). To ; do this, break out the code that sets scaling parameters into a ; new routine InitScaleFac called by PortionText and ; AdjustSpChExtra. Also, add branches to avoid useless code if ; addChExtra is 0. ; <14> 8/31/90 PKE For NChar2Pixel and NPixel2Char, need to scale DOWN addChExtra ; by numer/denom to make pen moves at beginning and end of run ; accurate. For NDrawJust and NMeasureJust we donÕt scale it. ; <13> 8/30/90 PKE Change interaction of scaling, slop, and charExtra to be ; correct: need to scale down qdChExtra and spExtra by numer/denom ; scaling factor. ; <12> 8/24/90 PKE Remove setting of obsolete smgrCharExtra and smgrSlop (in ; SMgrRecord). Use new names qdChExtra and qdRunSlop instead of ; QDSmgrCharExtra and QDSmgrSlop (in GrafGlobals). ; <11> 8/9/90 PKE If grafProcs are installed, DrawJust should call textProc ; instead of StdText! Otherwise printing doesnÕt work. (Fixes BRC ; #68148). ; <10> 8/8/90 PKE New parameter to AdjustSpChExtra controls whether we scale ; addChExtra (need to for NDrawJust, NMeasureJust). Now we always ; pass real numer and denom to AdjustSpChExtra, and InitJustData ; computes numer.h/denom.h and saves it in JustDataRec. Use ; fractional pen position for pen moves in NDrawJust for increased ; accuracy. These changes fix BRC #70716 and other problems. ; Deleted code that was conditionalized out. ; <9> 8/2/90 PKE Set smgrCharExtra and smgrSlop value in QD private globals. For ; now, continue to set them in SMgrRecord as well. ; <8> 6/8/90 PKE Scale smgrCharExtra by font size instead of scaling it to ; compensate for StretchBits; this way it is scaled like the ; charExtra field in a color port instead of like the output of ; calcCharExtra. Now we no longer need GetScaledFontInfo call in ; AdjustSpChExtra, so move it to DrawJust instead. ; <7> 6/7/90 PKE Moved GetScaledFontInfo to ScriptMgrExtTail.a, made it use as ; much ROM code as possible. Rearranged parameter order for ; GetScaledFontInfo. Implemented guts of num/denom scaling for ; NMeasureJust, which requires setting up new ExpandMem fields ; emNumer and emDenom that will be used by MeasureText. ; <6> 6/6/90 PKE Implement guts of num/denom scaling for NPixel2Char. Add a ; little optimization for num/denom scaling in NChar2Pixel and ; NPixel2Char. ; <5> 6/1/90 PKE Implement guts of num/denom scaling for NPortionText, NDrawJust, ; NChar2Pixel. ; <4> 5/24/90 PKE Add numer/denom scaling parameters to NPortionText, NDrawJust, ; NMeasureJust, NChar2Pixel, and NPixel2Char. For now, these ; parameters are ignored. ; <3> 4/25/90 PKE Use smgrCharExtra for both B&W and color ports, instead of using ; _CharExtra on new ports. ; <2> 4/25/90 PKE Put slop value in smgrSlop global across calls to DrawText, ; MeasureText, TextWidth so it gets saved in pict. Clear it ; afterwards. ; <1> 4/10/90 PKE New today - extracted from ScriptMgrExtTail.a and ; conditionalized so it can be used with ROM builds too. ; ; Relevant recent comments from ScriptMgrExtTail.a below ; 2/22/90 PKE For 7.0, moved Char2Pixel, DrawJust, MeasureJust here because we ; patch them out entirely for ROM; added these to NewRomanTable so ; their vectors get filled in. Added new InitJustData, ; AdjustSpChExtra, and RestoreSpChExtra utility routines for ; handling justification parameters with intercharacter spacing, ; using new JustDataRec structure. Added other utility routines ; GetFontSize, DrawGap, SignFixRound. Rewrote (N)PortionText, ; (N)DrawJust, (N)MeasureJust, (N)Char2Pixel and (N)Pixel2Char ; routines to fully implement the new justification model, using ; the above utility routines. Also made the ÔNÕ versions standard ; for these routines, so that the old interfaces just redo the ; stack and fall through to the new routines. ; 1/11/90 PKE Moved Roman PortionText and Pixel2Char here so we can fix them ; later for all systems (deal with color grafPorts, etc.) and also ; to reduce duplication of code in new interfaces. We may move ; other Roman routines here later. Added crude implementations of ; some new interfaces: NPortionText, NDrawJust, NMeasureJust, ; NChar2Pixel, and NPixel2Char. These ignore styleRunPosition, but ; otherwise behave as specified. Added code to expand the ; RomanUtil dispatch table if necessary (i.e. for ROM version of ; ScriptMgr) and fill in vectors for PortionText, Pixel2Char, and ; new interfaces listed above. Updated header to be in BBS format. ;___________________________________________________________________________________________________ ; To Do: ; ;___________________________________________________________________________________________________ LOAD 'StandardEqu.d' include 'ScriptPriv.a' FixMathNonPortable equ 1 ; We require Mac Plus or newer include 'FixMath.a' ; include 'ColorEqu.a' ; blanks on string asis FixedPoint5 equ $00008000 ; Fixed 0.5 ;UseCharExtraTrap equ 0 ; 0: Always use qdChExtra instead of _CharExtra <3><17> ;ScaleSMgrCharExtra equ 1 ; 1: Scale qdChExtra by font size (& not num/denom) <8><17> useInterChar equ 0 ; Give up on interchar spacing for now <20> ; (but make minimum changes to do this) ; ----------------------------------------------------------------------- ; Function PortionText ( ; textPtr : Ptr; ; textLen : Longint ; ): Fixed; {proportion} ; ; Find proportion for line of text. This sets up a call to NPortionText with ; styleRunPosition = smOnlyStyleRun, then falls through into NPortionText. ; ---------------------------------------------------------------------------- ; ----------------------------------------------------------------------- <4> ; Function NPortionText ( ; textPtr: Ptr; ; textLen: Longint; ; styleRunPosition: JustStyleCode; {Integer} ; numer: Point; {Longint} ; denom: Point {Longint} ; ): Fixed; {proportion} ; ; Find proportion for line of text. This now handles intercharacter spacing ; too, using the smgrCharPortion value in the Script Manager globals. ; ---------------------------------------------------------------------------- proc export PortionText,NPortionText import InitFontAndScale,InitWeight,StdUnlink ; <17><19> ;ptRecord record {a6link},decr ;result ds.l 1 ; Fixed result ;ptArgs equ *-8 ; size of arguments. ;textPtr ds.l 1 ; text pointer. ;textLen ds.l 1 ; text length (LongInt). ;scriptRecPtr ds.l 1 ; ScriptRecord ptr <22> ;return ds.l 1 ; return address. ;a6link ds.l 1 ; old a6 register. ;ptLocals equ * ; size of local variables. ; endr nptRecord record {a6link},decr result ds.l 1 ; Fixed result nptArgs equ *-8 ; size of arguments. textPtr ds.l 1 ; text pointer. textLen ds.l 1 ; text length (LongInt). stylRunPos ds.w 1 ; style run position code. numer ds.l 1 ; Point <4> denom ds.l 1 ; Point <4> scriptRecPtr ds.l 1 ; ScriptRecord pointer <22> return ds.l 1 ; return address. a6link ds.l 1 ; old a6 register. jdRec ds JustDataRec ; nptLocals equ * ; size of local variables. endr PortionText move.l (sp)+,a0 ; pop return address move.l (sp)+,a1 ; pop ScriptRecord ptr <22> move.w #smOnlyStyleRun,-(sp) ; no info, so assume only style run move.l #$00010001,d0 ; no info, assume 1/1 scaling <4> move.l d0,-(sp) ; push numer <4> move.l d0,-(sp) ; push denom <4> move.l a1,-(sp) ; push ScriptRecord ptr <22> move.l a0,-(sp) ; push return address ; now we are set up for NPortionText NPortionText with nptRecord link a6,#nptLocals ; link the stack. ; Algorithm for Roman was simply to take (#spaces + #otherChars/8) * rawFontSize / 32. ; Now we call InitFontAndScale which tells us if the font allows interchar spacing and <19> ; sets the scaling factors, InitWeight to set weight; then get weight (s*sp+nc*cp) from ; JustDataRec into d2, multiply that by rawFontSize, and scale for compatibility with ; old numbers. move.l numer(a6),-(sp) ; push numer <17> move.l denom(a6),-(sp) ; push denom <17> pea jdRec(a6) ; push ptr to JustDataRec <17> bsr InitFontAndScale ; check font <17><19> move.l textPtr(a6),-(sp) ; push textPtr move.l textLen(a6),-(sp) ; push textLen move.w stylRunPos(a6),-(sp) ; push styleRunPosition pea jdRec(a6) ; push ptr to JustDataRec bsr InitWeight ; Fill out weight <17> move.l jdRec.weight(a6),d2 ; Get nc*cp+ns*sp in d2 ; get raw font size move.l (a5),a0 ; grafGlobals move.l thePort(a0),a0 ; get thePort pointer move.w txSize(a0),d0 ; get size bne.s @GotRealSize ; ok? move.w SysFontSize,d0 ; get size bne.s @GotRealSize ; ok? move.w #12,d0 ; ok, give up @GotRealSize ; Now we have font size (integer) in d0.w and ns*sp+nc*cp (Fixed) in d2.l. ; Divide latter by 32 for compatibility with old numbers, then multiply by ; raw font size. lsr.l #5,d2 ; divide by 32 swap d0 ; make font size fixed clr.w d0 ; and clear frac part subq #4,sp ; make space for FixMul result <5><10> move.l d2,-(sp) ; push scaled weight move.l d0,-(sp) ; push font size as Fixed _FixMul ; multiply, leave result on stack ; Now multiply it by previous result by numer.h/denom.h if necessary <5><10> tst.b jdRec.inScalTrue(a6) ; do we have any scaling? <19> beq.s @doneScaleAdjust ; skip if not move.l (sp),-(sp) ; first param & space for result move.l jdRec.inScaling(a6),-(sp) ; second param = numer/denom <19> _FixMul ; (numer/denom) * (result of above) @doneScaleAdjust ; set result, unlink the stack and return to the caller. move.l (sp)+,result(a6) ; set return value move.w #nptArgs,d0 ; for std exit bra StdUnlink ; StdUnlink endWith endproc ; ----------------------------------------------------------------------- ; procedure DrawJust(textPtr: Ptr; textLength,slop: Integer); ; input (sp).l Text pointer. ; (sp).w Text length. ; (sp).w Extra pixel width. ; warning This routine builds a stack frame. ; This routine follows Pascal register conventions. ; ; Draw the given text, fully justified. The justification width is the ; original text width plus the slop. This is equivalent to the QuickDraw ; DrawText trap in ROM. ; ----------------------------------------------------------------------- ; ----------------------------------------------------------------------- <4> ; PROCEDURE NDrawJust( ; textPtr: Ptr; {long} ; textLength: Longint; {long} ; slop: Fixed; {long} ; styleRunPosition: JustStyleCode; {Integer} ; numer: Point; {Longint} ; denom: Point {Longint} ; ); ; ; notes This routine builds a stack frame. ; This routine follows Pascal register conventions. ; ; Draw the given text, fully justified. The justification width is the ; original text width plus the slop. ; ----------------------------------------------------------------------- proc export DrawJust,NDrawJust import InitFontAndScale,CalcSpChExtra,DoSpChExtra,RestoreSpChExtra ; <17><19> import SignFixRound,StdUnlink import GetScaledFontInfo ; <8> import GetFontSize ; <17> ;djRecord record {a6link},decr ;djArgs equ *-8 ; size of arguments. ;textPtr ds.l 1 ; text pointer. ;textLen ds.w 1 ; text length. ;slop ds.w 1 ; extra pixel width. ;scriptRecPtr ds.l 1 ; ScriptRecord ptr <22> ;return ds.l 1 ; return address. ;a6link ds.l 1 ; old a6 register. ;djLocals equ * ; size of local variables. ; endr ndjRecord record {a6link},decr ndjArgs equ *-8 ; size of arguments. textPtr ds.l 1 ; text pointer. textLen ds.l 1 ; text length (LongInt). slop ds.l 1 ; extra pixel width (Fixed). stylRunPos ds.w 1 ; style run position code. numer ds.l 1 ; Point <4> denom ds.l 1 ; Point <4> scriptRecPtr ds.l 1 ; ScriptRecord pointer <22> return ds.l 1 ; return address. a6link ds.l 1 ; old a6 register. jdRec ds JustDataRec ; local record fntInfo ds.w 4 ; FontInfo record <17> numerVar ds.l 1 ; For StdTxMeas <17> denomVar ds.l 1 ; For StdTxMeas <17> portSpExScal ds.l 1 ; Fixed, port's sp extra, scaled by numer/denom <17> portChExScal ds.l 1 ; Fixed, port's ch extra, scaled by numer/denom <17> portSpEx1pt ds.l 1 ; Fixed, port's sp extra, scaled to 1 pt <17> portChEx1pt ds.l 1 ; Fixed, port's ch extra, scaled to 1 pt <17> jdRecLaser ds JustDataRec ; local record for LaserWriter stuff ndjLocals equ * ; size of local variables. endr ndjRegs reg a2/d3 ; <17> DrawJust move.l (sp)+,a0 ; pop 'n save return addr move.l (sp)+,a1 ; pop ScriptRecord ptr <22> move.w (sp)+,d0 ; pop slop clr.w -(sp) ; zero-extend textLen on stack to long <22> swap d0 ; make slop a FixedÉ clr.w d0 ; clear frac partÉ move.l d0,-(sp) ; push slop as Fixed move.w #smOnlyStyleRun,-(sp) ; default styleRunPosition move.l #$00010001,d0 ; no info, assume 1/1 scaling <4> move.l d0,-(sp) ; push numer <4> move.l d0,-(sp) ; push denom <4> move.l a1,-(sp) ; push ScriptRecord ptr <22> move.l a0,-(sp) ; restore return address ; Now we are set up like NDrawJust, so just fall through NDrawJust ; Link the stack and set the drawing params in thePort to correctly fill ; justify the text. with ndjRecord link a6,#ndjLocals ; link the stack. movem.l ndjRegs,-(sp) ; save regs <17> ; set the drawing params move.l numer(a6),-(sp) ; push numer <17> move.l denom(a6),-(sp) ; push denom <17> pea jdRec(a6) ; push ptr to JustDataRec <17> bsr InitFontAndScale ; check font <17><19> move.l textPtr(a6),-(sp) ; push text pointer. move.l textLen(a6),-(sp) ; push text length. move.l slop(a6),-(sp) ; push slop. move.w stylRunPos(a6),-(sp) ; push styleRunPosition move.l numer(a6),-(sp) ; push numer <5> move.l denom(a6),-(sp) ; push denom <5> pea jdRec(a6) ; push local JustDatRec addr bsr CalcSpChExtra ; calculate drawing params <17> ; Handle initial forward pen motion IF useInterChar THEN ; <20> tst.l jdRec.addChExtra(a6) ; any addÕl CharExtra? <15> beq.s @doneStartMove ; if not, skip this <15> tst.b jdRec.startNoFwd(a6) ; do we move at beginning bne.s @doneStartMove ; if TRUE, we don't get addÕl CharExtra ; Fill out FontInfo Record to get scaled ascent, descent for DrawGap. pea fntInfo(a6) ; push address of FontInfo rec (VAR param) <7><8><17> move.l numer(a6),-(sp) ; push numer <5><7> move.l denom(a6),-(sp) ; push denom <5><7> bsr GetScaledFontInfo ; handles scaling params too <5> move.l jdRec.addChExtra(a6),d0 ; additional CharExtra asr.l #1,d0 ; divide by 2 (signed!) move.l d0,-(sp) ; push size of move pea fntInfo(a6) ; push addr of FontInfo rec <17> bsr DrawGap @doneStartMove ENDIF ; <20> IF useInterChar THEN ; <20> ; Set LaserWriter line layout params (new section). <17> ; Do this either if a pic is open, or if we are drawing to a printer. ; Skip if slop is 0 or font disallows interchar (because LaserWriter is ok for these). tst.l slop(a6) beq @donePrinterSetup tst.b jdRec.noInterCh(a6) bne @donePrinterSetup move.l grafGlobals(a5),a0 ; Point to QuickDraw globals move.l thePort(a0),a0 ; Get current grafport tst.l picSave(a0) ; Is a picture open? bne.s @doPrinterSetup ; If so, must do nasty LaserWriter stuff tst.l grafProcs(a0) ; Do we have grafProcs? beq @donePrinterSetup ; If not, we can't be printing, É ; É so skip nasty LaserWriter stuff ; Maybe we can add a better test to see if this is a printing port. ; Note that device field may be 0 even if we are printing. ; We could also check PrintVars to see if it is a LaserWriterÉ @doPrinterSetup ; Get port's spExtra and chExtra (16.16 Fixed, 1 pt and real sizes). move.l grafGlobals(a5),a0 ; find the QuickDraw globals. move.l thePort(a0),a0 ; get thePort pointer bsr GetFontSize ; assume thePort^ in a0, get font size in d0.w swap d0 ; make Fixed clr.w d0 ; clear frac part move.l d0,d3 ; save in d3 move.l a0,a2 ; save thePort ptr clr.l portSpEx1pt(a6) ; initialize move.l spExtra(a2),d1 ; get port's spExtra for txSize move.l d1,portSpExScal(a6) ; first assume no scaling beq.s @donePortSpExtra subq #4,sp ; space for result move.l d1,-(sp) move.l d3,-(sp) _FixDiv move.l (sp)+,portSpEx1pt(a6) ; get spExtra for 1 pt tst.b jdRec.inScalTrue(a6) ; do we have any scaling? <19> beq.s @donePortSpExtra ; skip if not subq #4,sp ; space for result move.l spExtra(a2),-(sp) ; unscaled spExtra move.l jdRec.inScaling(a6),-(sp) ; second param = numer/denom <19> _FixDiv move.l (sp)+,portSpExScal(a6) ; now we have scaled version @donePortSpExtra clr.l portChEx1pt(a6) ; assume port has no chExtra clr.l portChExScal(a6) ; tst.w portVersion(a2) ; negative if cGrafPort bpl.s @donePortChExtra ; otherwise, get port's chExtra move.w chExtra(a2),d1 ; get 4.12 fixed format beq.s @donePortChExtra ; if 0, we are done ext.l d1 ; extend sign bits asl.l #4,d1 ; convert to 16.16 format. move.l d1,portChEx1pt(a6) ; save port's chExtra for 1 pt subq #4,sp ; space for result move.l d1,-(sp) ; push chExtra for 1-point size move.l d3,-(sp) ; push size _FixMul ; unscaled size on stack tst.b jdRec.inScalTrue(a6) ; do we have any scaling? <19> beq.s @stuffChExtra ; skip if not move.l (sp),-(sp) ; result space and first param move.l jdRec.inScaling(a6),-(sp) ; second param = numer/denom <19> _FixDiv @stuffChExtra move.l (sp)+,portChExScal(a6) ; get real chExtra for our size @donePortChExtra ; Get LaserWriter width without slop (using FOND or TrueType metrics). ; Must be before DoSpChExtra. subq #4,sp ; space for result move.l textPtr(a6),-(sp) ; push text pointer. move.l textLen(a6),-(sp) ; push text length. move.l numer(a6),-(sp) ; push numer move.l denom(a6),-(sp) ; push denom move.l portSpEx1pt(a6),-(sp) ; push port spExtra for 1 pt move.l portChEx1pt(a6),-(sp) ; push port chExtra for 1 pt pea jdRec(a6) ; push local JustDatRec addr for scaling bsr LaserWidth ; Fixed width on stack ; Get the screen width without slop. ; Must be before DoSpChExtra. move.l numer(a6),numerVar(a6) move.l denom(a6),denomVar(a6) subq #2,sp ; make room for result move.w textLen+2(a6),-(sp) ; push byte count move.l textPtr(a6),-(sp) ; push the text pointer. pea numerVar(a6) ; VAR numer in pea denomVar(a6) ; VAR denom in pea fntInfo(a6) ; VAR info move.l grafGlobals(a5),a0 ; Point to QuickDraw globals move.l thePort(a0),a0 ; Get current grafport move.l grafProcs(a0),d0 ; Is grafprocs NIL? beq.s @useMeasTrap ; Yes, use std proc move.l d0,a0 ; move.l txMeasProc(a0),a0 ; No, get proc ptr jsr (a0) ; Go to it bra.s @doneTxMeas ; Measure text with txMeas grafProc @useMeasTrap ; _StdTxMeas ; Measure text with std proc @doneTxMeas ; move.w (sp)+,d0 ; get integer width swap d0 ; make it fixed clr.w d0 ; clear frac part to get screen width move.w numerVar+h(a6),d1 ; get output numer move.w denomVar+h(a6),d2 ; get output denom cmp.w d1,d2 ; same? beq.s @doneScaleAdjust ; if so, skip adjust subq #4,sp ; space for FixMul result move.l d0,-(sp) ; first FixMul param subq #4,sp ; space for FixRatio result = second FixMul param move.w d1,-(sp) ; push output numer.h, first FixRatio paramm move.w d2,-(sp) ; push output denom.h, second FixRatio param _FixRatio ; divide _FixMul ; multiply move.l (sp)+,d0 ; get scaled width @doneScaleAdjust ; Find total desired width of line add.l slop(a6),d0 ; desired width of line move.l d0,d3 ; save in d3 for underline length ; do we need to calculate new extra values? lea jdRec(a6),a2 ; use screen spExtra, chExtra tst.l (sp) ; valid printer width? bpl.s @calcNewExtra ; if so, continue normally addq #4,sp ; otherwise, discard width bra @setupPicComment ; ready for PicComment ; Copy JustDataRec for printer layout @calcNewExtra with JustDataRec lea jdRecLaser(a6),a1 ; ptr to dest record move.w #(jdRecSize/4),d1 ; jdRecSize guaranteed to be multiple of 4 bra.s @endCopyLoop @copyLoop move.l (a2)+,(a1)+ @endCopyLoop dbra d1,@copyLoop ; compute new SpExtra and ChExtra for LaserWriter ; at this point, printer width is on stack, total desired width is in d0 sub.l (sp)+,d0 ; subtract LaserWriter width to get its slop move.l textPtr(a6),-(sp) ; push text pointer. move.l textLen(a6),-(sp) ; push text length. move.l d0,-(sp) ; push slop. move.w stylRunPos(a6),-(sp) ; push styleRunPosition move.l numer(a6),-(sp) ; push numer move.l denom(a6),-(sp) ; push denom pea jdRecLaser(a6) ; push local JustDatRec addr bsr CalcSpChExtra ; calculate drawing params lea jdRecLaser(a6),a2 ; use printer spExtra, chExtra ; Compute major (spExtra) and minor (chExtra) for the PicComment. ; - Note that minor applies to all characters, incl space, so we ; must subtract our minor value from the major value. ; - Also note that we must account for any spExtra or chExtra in ; the port too. ; Assume that a2 points to JustDataRec to use ; ; Need to scale down underline len by input numer/denom. @setupPicComment tst.b inScalTrue(a2) ; do we have any scaling? <19> beq.s @doneScaleUL ; skip if not subq #4,sp ; space for result move.l d3,-(sp) ; underline length move.l inScaling(a2),-(sp) ; second param = numer/denom <19> _FixDiv move.l (sp)+,d3 @doneScaleUL move.l portSpExScal(a6),d2 ; get port's spExtra add.l addSpExScal(a2),d2 ; get total spExtra move.l portChExScal(a6),d1 ; get port's chExtra add.l addChExScal(a2),d1 ; get total chExtra sub.l d1,d2 ; subtract chExtra from spExtra endwith ;JustDataRec ; Get ClientLLRecord handle from SMgr globals with ClientLLRecord,SMgrRecord move.l IntlSpec,a0 move.l smgrClientLLRecHndl(a0),d0 ; get reusable handle beq.s @donePrinterSetup ; bail if it's not there move.l d0,a0 ; put handle in a0 ; Fill out ClientLLRecord move.l (a0),a1 move.w textLen+2(a6),chCount(a1) move.l d2,major(a1) move.w #$20,spChar(a1) move.l d1,minor(a1) move.l d3,ulLength(a1) ; ok, now make the comment move.w #clientLLComment,-(sp) move.w #cllRecSize,-(sp) move.l a0,-(sp) ; handle to ClientLLRecord _PicComment endwith ;ClientLLRecord,SMgrRecord @donePrinterSetup ENDIF ; <20> ; Setup spacing params. Do this after printer setup, so it doesn't affect <17> ; StdTxMeas in that code. pea jdRec(a6) ; push local JustDatRec addr <17> bsr DoSpChExtra ; set drawing params <17> ; Draw the text - change to use StdText (or text grafProc if present) <5> move.w textLen+2(a6),-(sp) ; push text length as word. move.l textPtr(a6),-(sp) ; push text pointer. move.l numer(a6),-(sp) ; push numer <5> move.l denom(a6),-(sp) ; push denom <5> move.l grafGlobals(a5),a0 ; Point to QuickDraw globals <11> move.l thePort(a0),a0 ; Get current grafport <11> move.l grafProcs(a0),d0 ; Is grafprocs NIL? <11> beq.s @useTrap ; Yes, use std proc <11> move.l d0,a0 ; <11> move.l textProc(a0),a0 ; No, get proc ptr <11> jsr (a0) ; Go to it <11> bra.s @doneDrawText ; Draw text with text grafProc <11> @useTrap ; <11> _StdText ; Draw text with std proc @doneDrawText ; <11> ; Restore drawing params (RestoreSpChExtra doesn't modify jdRec) pea jdRec(a6) ; push local JustDataRec addr bsr RestoreSpChExtra ; Handle final pen motion IF useInterChar THEN ; <20> move.l jdRec.addChExtra(a6),d0 ; get charExtra beq.s @doneEndMove ; if 0, no move necessary <15> tst.b jdRec.endBackup(a6) ; bne.s @doneCalcEndMove ; if TRUE, we don't divide by 2 asr.l #1,d0 ; divide by 2 (signed!) @doneCalcEndMove neg.l d0 ; negate <10> bsr MovePen ; move pen, preserving fractional info <10> @doneEndMove ; <15> ENDIF ; <20> ; Unlink the stack and return to the caller. movem.l (sp)+,ndjRegs ; restore regs <17> move.w #ndjArgs,d0 ; for std exit bra StdUnlink ; StdUnlink endWith IF useInterChar THEN ; <20> ; ----------------------------------------------------------------------------- ; PROCEDURE DrawGap(gapSize: Fixed; info: FontInfo); ; ; This will draw a rect simulating a blank intercharacter text area, using ; current text characteristics, beginning at the current position and continuing ; for gapSize pixels, moving the pen gapSize pixels horizontally from its original ; location. ; ; This is a first pass without any optimization, which it needs. ; We could also use horiz pen fraction for more accurate computation of the ; gapRect. ; ----------------------------------------------------------------------------- ; export DrawGap ; comment out <17> ; import SignFixRound,StdUnlink ; comment out <17> dgRecord record {a6link},decr dgArgs equ *-8 ; size of arguments. gapSize ds.l 1 ; gapSize value (Fixed) infoPtr ds.l 1 ; ptr to filled FontInfo record return ds.l 1 ; return address. a6link ds.l 1 ; old a6 register. gapRect ds.w 4 ; Rect - rect for gap saveMode ds.w 1 ; saved pnMode savePat ds.b 8 ; Pattern - saved pnPat or pnPixPat dgLocals equ * ; size of local variables. endr DrawGap with dgRecord link a6,#dgLocals ; link the stack. move.l a2,-(sp) ; save reg move.l grafGlobals(a5),a0 ; find the QuickDraw globals. move.l thePort(a0),a2 ; save thePort pointer move.l infoPtr(a6),a1 ; a1 points to FontInfo record move.w pnLoc+v(a2),d0 ; current v move.w d0,d1 ; copy sub.w ascent(a1),d0 ; top of rect = v-ascent move.w d0,gapRect+top(a6) ; stuff it add.w descent(a1),d1 ; bottom of rect = v+descent move.w d1,gapRect+bottom(a6) ; stuff it move.w pnLoc+h(a2),d1 ; current h move.l gapSize(a6),d0 ; get gap as Fixed (signed!) bsr SignFixRound ; round it bpl.s @posGap ; gap is negative move.w d1,gapRect+right(a6) ; right side of rect = h add.w d0,d1 ; left side of rect = h+gap move.w d1,gapRect+left(a6) ; stuff it bra.s @doneSetGap ; gap is positive @posGap move.w d1,gapRect+left(a6) ; left side of rect = h add.w d0,d1 ; right side of rect = h+gap move.w d1,gapRect+right(a6) ; stuff it @doneSetGap ; save pnMode, then set it from txMode move.w pnMode(a2),saveMode(a6) ; save pnMode move.w txMode(a2),pnMode(a2) ; set pnMode from txMode ; next we have to save the pnPat/pnPixPat, set it from the background, call ; PaintRect, then restore the pnPat/pmPixPat. How we do this depends on ; what kind of port it is. We can't just use _EraseRect, because it ignores ; the pnMode but we care about the pnMode. tst.w portVersion(a2) ; negative if cGrafPort bmi.s @colorPort ; ; draw rect in old-style port - save pnPat, set it from bkPat, ; draw rect, restore pnPat. move.l pnPat(a2),savePat(a6) ; save pnPat move.l pnPat+4(a2),savePat+4(a6) ; " move.l bkPat(a2),pnPat(a2) ; set pnPat from bkPat move.l bkPat+4(a2),pnPat+4(a2) ; " pea gapRect(a6) ; push rect _PaintRect move.l savePat(a6),pnPat(a2) ; restore pnPat move.l savePat+4(a6),pnPat+4(a2) ; " bra.s @restorePnMode ; draw rect in color port - save pnPixPat, set it from bkPixPat, ; draw rect, restore pnPixPat. @colorPort move.l pnPixPat(a2),savePat(a6) ; save pnPixPat move.l bkPixPat(a2),pnPixPat(a2) ; set pnPixPat from bkPixPat pea gapRect(a6) ; push rect _PaintRect move.l savePat(a6),pnPixPat(a2) ; restore pnPixPat ; Now restore pnMode @restorePnMode move.w saveMode(a6),pnMode(a2) ; restore pnMode ; Now move pen to end of this gap move.l gapSize(a6),d0 ; get h increment <10> bsr MovePen ; move pen, preserving fractional info <10> ; all done, return move.l (sp)+,a2 ; restore reg move.w #dgArgs,d0 ; for std exit bra StdUnlink ; StdUnlink endWith ENDIF ; <20> ; ----------------------------------------------------------------------------- <10> ; routine: MovePen ; input: d0.l Signed Fixed: horizontal increment for pen movement ; ; Moves pen by setting both integer and fractional parts of horizontal pen ; position. ; ; Trashes a0, a1, d1 ; ----------------------------------------------------------------------------- MovePen move.l grafGlobals(a5),a0 ; find the QuickDraw globals. move.l thePort(a0),a1 ; save thePort pointer move.w pnLoc+h(a1),d1 ; get integer part of current pos swap d1 ; put in Fixed format tst.w portVersion(a1) ; negative if cGrafPort bpl.s @notColorPort ; ; for color port move.w pnLocHFrac(a1),d1 ; get frac part of current pos add.l d0,d1 ; add pen increment move.w d1,pnLocHFrac(a1) ; save frac part of new pos bra.s @common ; for old ports @notColorPort move.w pnLocFixed(a0),d1 ; get frac part of current pos add.l d0,d1 ; add pen increment move.w d1,pnLocFixed(a0) ; save frac part of new pos ; common finish @common swap d1 ; get integer part of new pos move.w d1,pnLoc+h(a1) ; and save it rts IF useInterChar THEN ; <20> ; ----------------------------------------------------------------------------- <17> ; FUNCTION LaserWidth( ; textPtr: Ptr; ; textLen: Long; ; numer: Point; ; denom: Point; ; portSpEx1pt: Fixed; ; portChEx1pt: Fixed; ; jdRecPtr: ^JustDataRec ; ): Fixed; ; ; Returns Fixed width of text computed from metrics that the LaserWriter ; driver will use, including scaling factors obtained from the JustDataRec. ; ; Returns neg value if bitmap font but no FOND or FOND width table. ; ; For more information on what this routine should really be trying to do, see ; the following routines in the LaserWriter sources (thanks, Hugo): ; 1. SetPrWidTab (in the file LpMisc68k.a), which fills out a table of ; printer widths. ; 2. ChangeFont (in the file LpDraft.p), which calls SetPrWidTab. ; The file LpMisc68k.a also has the LaserWriter line layout code. ; ; It would be nice to pre-allocate ThPrWidthTable with pointer in SMgrRecord ; and cache widths for a particular font/style/etc, so we don't recalculate them ; if current request matches last request. However, we have no way to know if ; the width tables used for printing have been changed (we can't get driver's ; value of modFlag in their ThPrWidthTable), so we just recalculate them each ; time. Sigh. ; ; The potSpEx1pt and portChEx1pt values are the spExtra and chExtra values from ; from the port, scaled to 1 pt. ; ----------------------------------------------------------------------------- lwRecord record {a6link},decr result ds.l 1 ; result: Fixed width lwArgs equ *-8 ; size of arguments. textPtr ds.l 1 ; text pointer. textLen ds.l 1 ; text length. numer ds.l 1 ; Point denom ds.l 1 ; Point portSpEx1pt ds.l 1 ; Fixed portChEx1pt ds.l 1 ; Fixed jdRecPtr ds.l 1 ; pointer to JustDataRec return ds.l 1 ; return address. a6link ds.l 1 ; old a6 register. myPrWidTab ds ThPrWidthTable ; lwLocals equ * ; size of local variables. endr lwRegs reg a2/d3-d7 SB_FILLPRINTER_WIDTHS EQU $0003 _SplineCall OPWORD $A854 LaserWidth with lwRecord,JustDataRec link a6,#lwLocals ; link the stack. movem.l lwRegs,-(sp) ; save regs move.l #-1,result(a6) ; initially assume can't get widths ; Do we have a TrueType font for this? clr.w -(sp) ; room for current status _GetOutlinePreferred ; leave result on stack move.w #-1,-(sp) ; pass TRUEÉ _SetOutlinePreferred ; we want an outline if possible clr.w -(sp) ; room for Boolean result move.l numer(a6),-(sp) ; push numer move.l denom(a6),-(sp) ; push denom _IsOutline ; Note: this calls FMWwapFont with needbits=T tst.w (sp)+ ; use a TrueType font? bne @getOutlineWidths ; if so, get a different width table ; Get widths from table in FOND move.l LastFOND,d0 ; Do we have a FOND handle? beq @cleanup ; bail if not move.l d0,a0 move.l (a0),a0 ; Get FOND pointer move.l ffWTabOff(a0),d0 ; Get offset to width table beq @cleanup ; bail if no table ; initialize local table move.w #255,d1 lea myPrWidTab.theTable(a6),a1 @clearLoop clr.l (a1)+ dbra d1,@clearLoop ; set up params to search for width table that is best match for style move.w ffFirst(a0),d6 ; get first char in table move.w ffLast(a0),d7 ; get last char in table lea 0(a0,d0.l),a0 ; point to FOND width table move.l grafGlobals(a5),a1 ; grafGlobals move.l thePort(a1),a1 ; get thePort pointer moveq #0,d3 ; for longizing move.b txFace(a1),d3 ; get style ; search for width table. This code is almost exactly copied from SetPrWidTab. move.w (a0)+,d5 ; counter move.l d3,d4 ; initialize remainder move.l a0,a2 ; initial table choice move.w d7,a1 ; get to width tables sub.w d6,a1 ; by LastChar-FirstChar addq.w #4,a1 ; +3 for missing etc and +1 for style entry add.l a1,a1 ; two bytes per entry bra.s @4 @3 add.l a1,a0 ; next width table move.w (a0),d2 ; get this width table style jsr MatchStyles ; return with match (a0,a1 preserved) beq.s @4 ; if zero, its no better than current match move.l a0,a2 ; found better match so take this table @4 dbra d5,@3 ; update count ; now a2 points to table in FOND (begins with style code). Copy it into printer ; width table, expanding from 4.12 to 16.16. This code is almost exactly copied ; from SetPrWidTab. addq.w #2,a2 ; skip style entry lsl.w #2,d6 ; 4 bytes per entry lea myPrWidTab.theTable(a6),a0 add.w d6,a0 ; skip to FirstChar in printer width table @5 move.w (a2)+,d0 ; get width entry ext.l d0 ; make full longword asl.l #4,d0 ; make into fixed point format from 4.12 format move.l d0,(a0)+ ; put down this value subq.w #1,d7 ; loop count LastChar cmp.w d7,d6 ; compare with FirstChar ble.s @5 ; continue till end of table ; now printer width table is set up, go measure text bra @addWidths ; Get width table for outlines, using private Bass call. @getOutlineWidths move.l FOutFontHandle,a2 ; handle to 'sfnt' resource move.l a2,a0 _HGetState move.w d0,-(sp) ; save state move.l a2,a0 _HLock clr.l -(sp) ; room for result code pea myPrWidTab.theTable(a6) ; width table ptr move.l a2,-(sp) ; sfnt handle moveq #SB_FILLPRINTER_WIDTHS,d0 ; selector for our call, needs to be a long _SplineCall ; get printer widths move.l (sp)+,d2 ; get result of call move.l a2,a0 move.w (sp)+,d0 ; get saved state _HSetState ; restore it tst.l d2 ; success? bne @cleanup ; if not, bail ; Now add up widths @addWidths moveq #0,d0 ; initialize width move.l textPtr(a6),a0 move.l textLen(a6),d1 move.l portSpEx1pt(a6),d4 move.l portChEx1pt(a6),d5 lea myPrWidTab.theTable(a6),a1 moveq #0,d2 ; for longizing char bra.s @endWidthLoop @widthLoop move.b (a0)+,d2 move.l d2,d3 lsl.w #2,d3 ; make a long offset add.l 0(a1,d3.w),d0 ; add in width cmp.b #$20,d2 bne.s @addChExtra add.l d4,d0 ; add in spExtra bra.s @endWidthLoop @addChExtra add.l d5,d0 ; add in chExtra @endWidthLoop dbra d1,@widthLoop ; Now we have Fixed width in d0, need to scale it by font size and numer.h/denom.h subq #4,sp move.l d0,-(sp) ; push 1-point width move.l grafGlobals(a5),a0 ; find the QuickDraw globals. move.l thePort(a0),a0 ; get thePort pointer bsr GetFontSize ; assume thePort^ in a0, get font size in d0.w swap d0 ; make Fixed clr.w d0 ; clear frac part move.l d0,-(sp) ; push font size _FixMul ; leave result on stack move.l jdRecPtr(a6),a0 ; get JustDataRec ptr tst.b inScalTrue(a0) ; do we have any scaling? <19> beq.s @doneScale ; skip if not move.l (sp),-(sp) ; result space and first FixMul param move.l inScaling(a0),-(sp) ; second param = numer/denom <19> _FixMul @doneScale move.l (sp)+,result(a6) ; get Fixed result ; All done, return @cleanup _SetOutlinePreferred ; restore outline pref status movem.l (sp)+,lwRegs ; restore regs move.w #lwArgs,d0 ; for std exit bra StdUnlink ; StdUnlink endWith ;lwRecord,JustDataRec ;------------------------------------------------------------------------------- <17> ; MatchStyles (exactly copied from SetPrWidTab) ; ; d2 Current ; d3 Desired ; d4 Remainder (may be updated) ; ; Result in cc: eq if we did not find a better match, ne if we did ; ; The Current input is compared against Desired and Remainder parameters. ; If Current is closer to Desired than Remainder, then Remainder is updated. ; Remainder should be initialized to Desired. ; ; This Function can be called continuously over the entire range of styles ; being checked. Before each call only set the value for Current. ; The values for Current should be set in order from default to least likely. ; After the full range has been parsed, then the closest style ; match is given by = Desired-Remainder (i.e. Desired¥ÂRemainder) ; ; Uses d0,d1 ;------------------------------------------------------------------------------- MatchStyles move.w d2,d0 ; get Current move.w d3,d1 ; get Desired not.w d1 ; ÂDesired and.w d0,d1 ; Current¥ÂDesired (Current-Desired) bne.s @1 ; Perfect match if equal to zero not.w d0 ; ÂCurrent and.w d3,d0 ; Desired¥ÂCurrent (Desired-Current) move.w d0,d1 ; Save potential new Remainder not.w d0 ; ÂNewRemainder and.w d4,d0 ; Remainder¥ÂNewRemainder (Remainder-NewRemainder) beq.s @1 ; Check New against Old for better move.w d1,d4 ; we found a better match moveq #-1,d0 ; return result in d0 @2 rts ; go home @1 moveq #0,d0 ; return results in d0 bra.s @2 endproc ENDIF ; <20> ; ----------------------------------------------------------------------- ; procedure MeasureJust(textPtr: Ptr; textLength,slop: Integer; ; charLocs: Ptr); ; input (sp).l Text pointer. ; (sp).w Text length. ; (sp).w Extra pixel width. ; (sp).l Character location array pointer. ; warning This routine builds a stack frame. ; This routine follows Pascal register conventions. ; ; Measure the given text, fully justified. The cumulative width of each ; character is left in the charLocs array. This is equivalent to the ; QuickDraw MeasureText trap in new ROMs. ; ----------------------------------------------------------------------- ; ----------------------------------------------------------------------- <4> ; procedure NMeasureJust( ; textPtr: Ptr; ; textLen: LongInt; ; slop: Fixed; ; charLocs: Ptr; ; styleRunPosition: JustStyleCode; {Integer} ; numer: Point; {Longint} ; denom: Point {Longint} ; ); ; ; notes This routine builds a stack frame. ; This routine follows Pascal register conventions. ; ; Measure the given text, fully justified. The cumulative width of each ; character is left in the charLocs array. ; ; At the moment, this just converts the parameters to MeasureJust format ; and then calls MeasureJust. ; ----------------------------------------------------------------------- proc export MeasureJust,NMeasureJust import InitFontAndScale,CalcSpChExtra,DoSpChExtra,RestoreSpChExtra ; <17><19> import SignFixRound,StdUnlink import GetMeasProc,DoSwapFont,GetPortChExtra ; <19> ;mjRecord record {a6link},decr ;mjArgs equ *-8 ; size of arguments. ;textPtr ds.l 1 ; text pointer. ;textLen ds.w 1 ; text length. ;slop ds.w 1 ; extra pixel width. ;charLocs ds.l 1 ; character location array. ;scriptRecPtr ds.l 1 ; ScriptRecord ptr <22> ;return ds.l 1 ; return address. ;a6link ds.l 1 ; old a6 register. ;mjLocals equ * ; size of local variables. ; endr nmjRecord record {a6link},decr nmjArgs equ *-8 ; size of arguments. textPtr ds.l 1 ; text pointer. textLen ds.l 1 ; text length (LongInt). slop ds.l 1 ; extra pixel width (Fixed). charLocs ds.l 1 ; pointer stylRunPos ds.w 1 ; style run position code. numer ds.l 1 ; Point <4> denom ds.l 1 ; Point <4> scriptRecPtr ds.l 1 ; ScriptRecord pointer <22> return ds.l 1 ; return address. a6link ds.l 1 ; old a6 register. jdRec ds JustDataRec ; local record measProc ds.l 1 ; address of current measure proc <19> customProc ds.w 1 ; flag that custom proc is being used <19> numerVar ds.l 1 ; Point <19> denomVar ds.l 1 ; Point <19> fntInfo ds.w 4 ; FontInfo record <19> nmjLocals equ * ; size of local variables. endr nmjRegs reg a2-a4/d3-d7 ; <19> MeasureJust move.l (sp)+,a0 ; pop 'n save return addr move.l (sp)+,d1 ; pop ScriptRecord ptr <22> move.l (sp)+,a1 ; pop 'n save charLocs pointer move.w (sp)+,d0 ; pop slop (word) clr.w -(sp) ; zero-extend textLen on stack to long <22> swap d0 ; make slop a FixedÉ clr.w d0 ; clear frac partÉ move.l d0,-(sp) ; push slop as Fixed move.l a1,-(sp) ; push charLocs pointer move.w #smOnlyStyleRun,-(sp) ; default styleRunPosition move.l #$00010001,d0 ; no info, assume 1/1 scaling <4> move.l d0,-(sp) ; push numer <4> move.l d0,-(sp) ; push denom <4> move.l d1,-(sp) ; push ScriptRecord ptr <22> move.l a0,-(sp) ; restore return address ; Now we are set up like NMeasureJust, so just fall through NMeasureJust ; Link the stack and fix drawing params in thePort to correctly fill ; justify the text. with nmjRecord link a6,#nmjLocals ; link the stack. movem.l nmjRegs,-(sp) ; save regs <19> ; set up some regs, initialize charLocs[0] new<19> move.l charLocs(a6),a2 ; get charLocs ptr clr.w (a2)+ ; width=0 for offset 0 move.l textLen(a6),d7 ; any length? beq @done ; if not, we are done move.l textPtr(a6),a3 ; save text ptr ; set the drawing params move.l numer(a6),-(sp) ; push numer <17> move.l denom(a6),-(sp) ; push denom <17> pea jdRec(a6) ; push ptr to JustDataRec <17> bsr InitFontAndScale ; check font <17><19> move.l a3,-(sp) ; push text pointer. <19> move.l d7,-(sp) ; push text length. <19> move.l slop(a6),-(sp) ; push slop. move.w stylRunPos(a6),-(sp) ; push styleRunPosition move.l numer(a6),-(sp) ; push numer <5> move.l denom(a6),-(sp) ; push denom <5> pea jdRec(a6) ; push local JustDatRec addr bsr CalcSpChExtra ; calculate drawing params <17> pea jdRec(a6) ; push local JustDatRec addr <17> bsr DoSpChExtra ; set drawing params <17> ;------------ ; Rewrote the next section to avoid the slimy way we were using MeasureText, new<19> ; since that wouldn't work for custom txMeasProcs anyway. Code down to next ; dotted line replaces previous code. ; register usage ; a2.l charLocs ptr (already set up) ; a3.l text pointer (already set up) ; a4.l measProc ptr ; d3.l x ; d4.l left end width adjust + rounding amount ; d5.l right end width adjust (will be saved on stack) ; d6.w current character offset ; d7.w text length (already set up) ; Set up for measure loops new<19> moveq #0,d6 ; initial char offset moveq #0,d5 ; assume right adjust = 0 move.l #FixedPoint5,d4 ; rounding + left adjust (assumed 0) ; get real start and end adjustments new<19> IF useInterChar THEN ; <20> move.l jdRec.addChExtra(a6),d0 ; get charExtra beq.s @doneEndAdjust ; if 0, no adjustments necessary asr.l #1,d0 ; divide by 2 (signed!) tst.b jdRec.startNoFwd(a6) ; adjust widths for left flush? beq.s @doneStartAdjust ; if no, skip sub.l d0,d4 ; update start adjust @doneStartAdjust tst.b jdRec.endBackup(a6) ; adjust widths for right flush? beq.s @doneEndAdjust ; if no, skip move.l d0,d5 @doneEndAdjust ENDIF ; <20> move.l d5,-(sp) ; save for later ; Now get address of measuring routine to use, and see if it is not standard new<19> bsr GetMeasProc ; get flag in d0, addr in a0 tst.w d0 ; use custom proc? beq.s @useTable ; if not, go use width tables ; Measuring width of text with custom proc. new<19> move.l a0,a4 ; save proc ptr @customLoop add.w #1,d6 ; include next char move.l numer(a6),numerVar(a6) ; copy numer move.l denom(a6),denomVar(a6) ; copy denom subq #2,sp ; make room for result move.w d6,-(sp) ; push byte count move.l a3,-(sp) ; push the text pointer. pea numerVar(a6) ; VAR numer in pea denomVar(a6) ; VAR denom in pea fntInfo(a6) ; VAR info jsr (a4) ; go do measure move.w (sp)+,d0 ; get width swap d0 ; make a fixed clr.w d0 ; scale it tst.b jdRec.outScalTrue(a6) ; any scaling? beq.s @doneScaleCustom subq #4,sp ; space for result move.l d0,-(sp) ; push width move.l jdRec.outScaling(a6),-(sp) ; push scaling _FixMul move.l (sp)+,d0 ; scaled width @doneScaleCustom ; do left side adjustment, round width, and stuff in charLocs add.l d4,d0 ; adjust width for left side & add 0.5 cmp.w d7,d6 ; have we reached end of string? bge @lastChar ; swap d0 ; get integer part move.w d0,(a2)+ ; stuff in charLocs bra.s @customLoop ; ; We'll be using width tables. new<19> ; ; register changes for this section ; a4.l WidthTable ptr ; d3.l current width total (initialized from d4) ; d4.l total chExtra to add (screen scaling) ; d5.l current char @useTable ; Call SwapFont again to force SpExtra into width tables. new<19> move.l numer(a6),-(sp) ; push numer move.l denom(a6),-(sp) ; push denom pea jdRec(a6) ; push ptr to JustDataRec bsr DoSwapFont ; reset width table ; Get WidthTablePtr and initialize width accumulator. new<19> move.l WidthTabHandle,a4 ; handle to global width table move.l (a4),a4 ; now ptr move.l d4,d3 ; initialize accum with left adj & rounding value ; Need to get any chExtra from port, then add in our own. new<19> bsr GetPortChExtra ; get port chExtra in d2 move.l d2,d4 ; save in d4 add.l jdRec.addChExtra(a6),d4 ; add our charExtra to port's ; Loop: for each char, get width from table, scale it, add chExtra if not a space new<19> moveq #0,d5 @widthLoop add.w #1,d6 ; include next char move.b (a3)+,d5 move.w d5,d0 lsl.w #2,d0 move.l 0(a4,d0.w),d0 ; scale it tst.b jdRec.outScalTrue(a6) ; any scaling? beq.s @doneScaleTableWidth ; skip if none subq #4,sp ; space for result move.l d0,-(sp) ; push width move.l jdRec.outScaling(a6),-(sp) ; push scaling _FixMul move.l (sp)+,d0 ; scaled width @doneScaleTableWidth ; handle chExtra cmp.b #$20,d5 ; space? beq.s @doneAddChExtra ; if so, skip chExtra add.l d4,d0 ; add chExtra to width @doneAddChExtra add.l d0,d3 ; add to char width to accum move.l d3,d0 ; copy here for swap cmp.w d7,d6 ; have we reached end of string? bge.s @lastChar swap d0 ; make rounded integer move.w d0,(a2)+ ; stuff in charLocs bra.s @widthLoop ; Now we are back to common code to handle last char new<19> @lastChar sub.l (sp)+,d0 ; adjust for right side swap d0 ; get integer part move.w d0,(a2) ; stuff in charLocs ; end of new block ;------------- ; Restore drawing params (RestoreSpChExtra doesn't modify jdRec) pea jdRec(a6) ; push local JustDataRec addr bsr RestoreSpChExtra ; Unlink the stack and return to the caller. @done movem.l (sp)+,nmjRegs ; restore regs <19> move.w #nmjArgs,d0 ; for std exit bra StdUnlink ; StdUnlink endWith endproc ; ---------------------------------------------------------------------------- ; function Char2Pixel(textPtr: Ptr; textLen,slop,textOff: Integer; ; direction: Integer): Integer; ; input (sp).l Text pointer. ; (sp).w Text length. ; (sp).w Extra slop pixels. ; (sp).w Text offset. ; (sp).w Direction flag. ; output (sp).w Pixel width. ; warning This routine follows Pascal register conventions. ; This routine builds a stack frame. ; ; Translate a character offset in a string into a pixelWidth. For Roman ; scripts, this is similar to TextWidth. The difference is that Char2Pixel ; allows a slop for justification, which changes the width of the space ; characters. ; ---------------------------------------------------------------------------- ; ----------------------------------------------------------------------- <4> ; function NChar2Pixel( ; textPtr: Ptr; ; textLen: Longint; ; slop: Fixed; ; offset: Longint; ; direction: Integer; ; styleRunPosition: JustStyleCode; {Integer} ; numer: Point; {Longint} ; denom: Point {Longint} ; ): Integer; {pixel width} : ; notes This routine follows Pascal register conventions. ; This routine builds a stack frame. ; ; Translate a character offset in a string into a pixelWidth. For Roman ; scripts, this is similar to TextWidth. The difference is that Char2Pixel ; allows a slop for justification, which changes the width of the space ; characters. ; ----------------------------------------------------------------------- proc export Char2Pixel,NChar2Pixel import InitFontAndScale,CalcSpChExtra,DoSpChExtra,RestoreSpChExtra ; <17><19> import SignFixRound,StdUnlink ;c2pRecord record {a6link},decr ;result ds.w 1 ; pixel width. ;c2pArgs equ *-8 ; size of arguments. ;textPtr ds.l 1 ; textBuf. ;textLen ds.w 1 ; textLen. ;slop ds.w 1 ; pixel slop. ;textOff ds.w 1 ; textOffset. ;direction ds.w 1 ; direction flag. ;scriptRecPtr ds.l 1 ; ScriptRecord ptr <22> ;return ds.l 1 ; return address. ;a6link ds.l 1 ; old a6 register. ;c2pLocals equ * ; size of local variables. ; endr nc2pRecord record {a6link},decr result ds.w 1 ; pixel width. nc2pArgs equ *-8 ; size of arguments. textPtr ds.l 1 ; text pointer. textLen ds.l 1 ; text length (LongInt). slop ds.l 1 ; extra pixel width (Fixed). textOff ds.l 1 ; offset (LongInt) direction ds.w 1 ; direction flag. stylRunPos ds.w 1 ; style run position code. numer ds.l 1 ; Point <4> denom ds.l 1 ; Point <4> scriptRecPtr ds.l 1 ; ScriptRecord pointer <22> return ds.l 1 ; return address. a6link ds.l 1 ; old a6 register. jdRec ds JustDataRec ; local record fntInfo ds.w 4 ; FontInfo record <17> nc2pLocals equ * ; size of local variables. endr Char2Pixel move.l (sp)+,a0 ; pop 'n save return addr move.l (sp)+,a1 ; pop ScriptRecord ptr <22> move.w (sp)+,d2 ; pop direction moveq #0,d0 ; for longizing move.w (sp)+,d0 ; pop textOff, make it long move.l d0,d1 ; save it in d1 <22> move.w (sp)+,d0 ; pop slop swap d0 ; make it a Fixed clr.w -(sp) ; zero-extend textLen on stack to long <22> move.l d0,-(sp) ; push slop as Fixed move.l d1,-(sp) ; push offset as long <22> move.w d2,-(sp) ; push direction, still a word move.w #smOnlyStyleRun,-(sp) ; default styleRunPosition move.l #$00010001,d0 ; no info, assume 1/1 scaling <4> move.l d0,-(sp) ; push numer <4> move.l d0,-(sp) ; push denom <4> move.l a1,-(sp) ; push ScriptRecord ptr <22> move.l a0,-(sp) ; restore return address ; Now we are set up like NChar2Pixel, so just fall through NChar2Pixel ; Link the stack, set the new drawing params for thePort. with nc2pRecord link a6,#nc2pLocals ; link the stack. ; get font mgr output rec to get output scaling <17> ; (this whole section is new) <17> move.l numer(a6),-(sp) ; push numer move.l denom(a6),-(sp) ; push denom pea jdRec(a6) ; push ptr to JustDataRec bsr InitFontAndScale ; check font <19> ; set the drawing params move.l textPtr(a6),-(sp) ; push text pointer. move.l textLen(a6),-(sp) ; push text length. move.l slop(a6),-(sp) ; push slop. move.w stylRunPos(a6),-(sp) ; push styleRunPosition move.l numer(a6),-(sp) ; push numer <10> move.l denom(a6),-(sp) ; push denom <10> pea jdRec(a6) ; push local JustDatRec addr bsr CalcSpChExtra ; calculate drawing params <17> pea jdRec(a6) ; push local JustDatRec addr <17> bsr DoSpChExtra ; set drawing params <17> ; Check the text offset against zero on the left side and the text length ; on the right side. Do these checks with word quantities. move.w textOff+2(a6),d0 ; text offset >= 0?. bpl.s @0 ; yes -> skip this. moveq #0,d0 ; set text offset to zero. @0 cmp.w textLen+2(a6),d0 ; text offset <= text length? ble.s @1 ; yes -> skip this. move.w textLen+2(a6),d0 ; set text offset to length. @1 ; Call StdTxMeas/txMeasProc instead of TextWidth, for correct scaled metrics <17> ; (this section replace the section that called TextWidth) <17> subq #2,sp ; make room for result move.w d0,-(sp) ; push byte count move.l textPtr(a6),-(sp) ; push the text pointer. pea numer(a6) ; VAR numer in - ok to change now pea denom(a6) ; VAR denom in - ok to change now pea fntInfo(a6) ; VAR info move.l grafGlobals(a5),a0 ; Point to QuickDraw globals move.l thePort(a0),a0 ; Get current grafport move.l grafProcs(a0),d0 ; Is grafprocs NIL? beq.s @useTrap ; Yes, use std proc move.l d0,a0 ; move.l txMeasProc(a0),a0 ; No, get proc ptr jsr (a0) ; Go to it CLR.W -(SP) ; save fraction of 0 on stack <24> bra.s @doneTxMeas ; Measure text with txMeas grafProc @useTrap ; _StdTxMeas ; Measure text with std proc MOVE.L grafGlobals(A5),A0 ; get pointer to graf globals <24> MOVE.L fontAdj(A0),D2 ; load fixed width <24> MOVE.W D2,-(SP) ; save real frac part on stack <24> @doneTxMeas ; ; leave pixel width on stack ; Restore drawing params (RestoreSpChExtra doesn't modify jdRec) pea jdRec(a6) ; push local JustDataRec addr bsr RestoreSpChExtra ; Make pixel width FixedÉ move.l (sp)+,d2 ; get frac part in hi word, integer in low word moveq #0,d0 ; assume zero width move.w textOff+2(a6),d1 ; get textOff as word ble.s @done ; if ² 0, nothing to do swap d2 ; put integer & frac in correct place <10> ;;;;; clr.w d2 ; comment out <10><24> move.l d2,d0 ; get TextWidth in d0 <15> ; Now adjust Fixed width in d0.l by scaling parameters. <5><10> ; Moved this section up here <18> tst.b jdRec.outScalTrue(a6) ; do we have any scaling? <10><17><19> beq.s @doneWidthAdjust ; skip if not <10> subq #4,sp ; room for FixMul result move.l d0,-(sp) ; first FixMul param move.l jdRec.outScaling(a6),-(sp) ; second param = numer/denom <10><17><19> _FixMul move.l (sp)+,d0 ; get Fixed result @doneWidthAdjust ; Pen position adjustments for ends of style run IF useInterChar THEN ; <20> move.l jdRec.addChExtra(a6),d2 ; get additional charExtra <15><17><18> beq.s @doneEndAdjust ; if 0, no adjustment needed <15> asr.l #1,d2 ; divide by 2 (signed!) <15> tst.b jdRec.startNoFwd(a6) ; adjust width for left flush? beq.s @doneStartAdjust ; if no, skip sub.l d2,d0 ; subtract 0.5 ce from width <10> @doneStartAdjust tst.b jdRec.endBackup(a6) ; adjust widths for right flush? beq.s @doneEndAdjust ; if no, skip cmp.w textLen+2(a6),d1 ; width to last char? bne.s @doneEndAdjust ; if not, skip sub.l d2,d0 ; subtract 0.5 ce from width <10> @doneEndAdjust ENDIF ; <20> ; Set result, unlink the stack and return to the caller. bsr SignFixRound ; round Fixed width to Integer <10> @done move.w d0,result(a6) move.w #nc2pArgs,d0 ; for std exit bra StdUnlink ; StdUnlink endWith endproc ; ----------------------------------------------------------------------- ; function Pixel2Char( ; textPtr: Ptr; ; textLen: Integer; ; slop: Integer; ; pixelWidth: Integer; ; Var leadingEdge: Boolean ; ): Integer; {character offset} ; ; notes This routine follows Pascal register conventions. ; This routine builds a stack frame. ; ; This routine converts a pixel width and string into a character offset into ; the string and a leadingEdge flag that signals which side of the character ; the pixel fell on. ; ---------------------------------------------------------------------------- ; ----------------------------------------------------------------------- <4> ; function NPixel2Char( ; textPtr: Ptr; ; textLen: Longint; ; slop: Fixed; ; pixelWidth: Fixed; ; Var leadingEdge: Boolean; ; Var widthRemaining: Fixed; ; styleRunPosition: JustStyleCode; {Integer} ; numer: Point; {Longint} ; denom: Point {Longint} ; ): Integer; {character offset} ; ; notes This routine follows Pascal register conventions. ; This routine builds a stack frame. ; ; This routine converts a pixel width and string into a character offset into ; the string and a leadingEdge flag that signals which side of the character ; the pixel fell on. ; ; Substantially rewritten to fix bugs, using ideas from Mark Davis's <17> ; SingleByteFastP2C.a code, but adapting it for scaling, slop, custom ; txMeasProcs, etc. ; ---------------------------------------------------------------------------- proc export Pixel2Char,NPixel2Char import InitFontAndScale,CalcSpChExtra,DoSpChExtra,RestoreSpChExtra ; <17><19> import GetFontSize ; <17> import SignFixRound,StdUnlink import DoSwapFont,GetMeasProc,GetPortChExtra ; <19> ;p2cRecord record {a6link},decr ;result ds.w 1 ; result, char offset. ;p2cArgs equ *-8 ; size of arguments. ;textPtr ds.l 1 ; text pointer. ;textLen ds.w 1 ; text length. ;slop ds.w 1 ; slop pixels. ;pixelWidth ds.w 1 ; pixel offset. ;leadEdgeAdr ds.l 1 ; leadingEdge address. ;scriptRecPtr ds.l 1 ; ScriptRecord ptr <22> ;return ds.l 1 ; return address. ;a6link ds.l 1 ; old a6 register. ;widRemPtr ds.l 1 ; addr of widthRemaining parm (nil if none) ;p2cLocals equ * ; size of local variables. ; endr np2cRecord record {a6link},decr result ds.w 1 ; result, char offset. np2cArgs equ *-8 ; size of arguments. textPtr ds.l 1 ; text pointer. textLen ds.l 1 ; text length (Longint). slop ds.l 1 ; slop pixels (Fixed). pixelWidth ds.l 1 ; pixel offset (Fixed). leadEdgeAdr ds.l 1 ; address of Boolean leadingEdge. widRemAdr ds.l 1 ; address of Fixed widthRemaining. stylRunPos ds.w 1 ; style run position code. numer ds.l 1 ; Point <4> denom ds.l 1 ; Point <4> scriptRecPtr ds.l 1 ; ScriptRecord pointer <22> return ds.l 1 ; return address. a6link ds.l 1 ; old a6 register. jdRec ds JustDataRec ; local record fntInfo ds.w 4 ; FontInfo record <17> measProc ds.l 1 ; address of current measure proc <17> customProc ds.w 1 ; flag that custom proc is being used <17> lastWidAdj ds.l 1 ; subtract this from width of last char <17> numerVar ds.l 1 ; Point <17> denomVar ds.l 1 ; Point <17> np2cLocals equ * ; size of local variables. endr minusOneFixed equ $FFFF0000 ; -1.0 in Fixed format p2cRegs reg a2-a4/d3-d7 ; <19> Pixel2Char move.l (sp)+,a0 ; pop and save return addr move.l (sp)+,d2 ; pop ScriptRecord ptr <22> move.l (sp)+,a1 ; pop and save leadingEdge addr move.w (sp)+,d0 ; pop pixelWidth as Integer swap d0 ; make it a FixedÉ clr.w d0 ; and clear fraction part move.w (sp)+,d1 ; pop slop as Integer swap d1 ; make it a FixedÉ clr.w d1 ; and clear fraction part clr.w -(sp) ; zero-extend textLen on stack to long <22> move.l d1,-(sp) ; push slop as a Fixed move.l d0,-(sp) ; push pixelWidth as a Fixed move.l a1,-(sp) ; push leadingEdge addr clr.l -(sp) ; push nil for widthRemaining addr move.w #smOnlyStyleRun,-(sp) ; default styleRunPosition move.l #$00010001,d0 ; no info, assume 1/1 scaling <4> move.l d0,-(sp) ; push numer <4> move.l d0,-(sp) ; push denom <4> move.l d2,-(sp) ; push ScriptRecord ptr <22> move.l a0,-(sp) ; restore return addr ; Now we are set up like NPixel2Char, so just fall through ; NPixel2Char register usage. ; ; a2.l address of leadingEdge. ; a3.l text pointer. ; a4.l measProc ptr, also used at end ; d3.l pixelWidth, will get scaled. ; d4.w character offset. ; d5.l text width measurement. ; d6.l previous measurement. ; d7.w text length NPixel2Char with np2cRecord link a6,#np2cLocals ; link the stack. movem.l p2cRegs,-(sp) ; save the registers. <19> ; Initialize widthRemaining to -1 move.l widRemAdr(a6),d0 ; should we set widthRemaining? beq.s @doneInitWidRem ; skip if not move.l d0,a0 ; copy widRemAdr move.l #minusOneFixed,(a0) ; initialize widthzemaining to -1 @doneInitWidRem ; load up some regs move.l leadEdgeAdr(a6),a2 ; load leadingEdge pointer. move.l textPtr(a6),a3 ; load text pointer. move.l pixelWidth(a6),d3 ; get width. before or at start? ble p2cBeforeStart ; if we are, go handle <17> ; get font mgr output rec to get output scaling <17> ; (this whole section is new) <17> move.l numer(a6),-(sp) ; push numer <17> move.l denom(a6),-(sp) ; push denom <17> pea jdRec(a6) ; push ptr to JustDataRec <17> bsr InitFontAndScale ; check font <17><19> ; set drawing/measuring params move.l a3,-(sp) ; push text pointer. move.l textLen(a6),-(sp) ; push text length. move.l slop(a6),-(sp) ; push slop. move.w stylRunPos(a6),-(sp) ; push styleRunPosition move.l numer(a6),-(sp) ; push numer <10> move.l denom(a6),-(sp) ; push denom <10> pea jdRec(a6) ; push local JustDatRec addr bsr CalcSpChExtra ; calculate drawing params <17> pea jdRec(a6) ; push local JustDatRec addr <17> bsr DoSpChExtra ; set drawing params <17> ; Adjust pixelwidth for left side, save width adjustment for last char <17> move.l jdRec.addChExtra(a6),d0 ; get additional charExtra <17><18> IF useInterChar THEN ; <20> beq.s @doneCalcAdjust ; if 0, no adjustment necessary <15><17> asr.l #1,d0 ; divide by 2 (signed!) tst.b jdRec.startNoFwd(a6) ; adjust width for left flush? beq.s @doneStartAdjust ; if no, skip add.l d0,d3 ; bump width to hit next char sooner <17> @doneStartAdjust ; moved this up here <17> tst.b jdRec.endBackup(a6) ; adjust widths for right flush? bne.s @doneCalcAdjust ; if so, don't reset d0 <17> moveq #0,d0 ; no final width adjust <17> @doneCalcAdjust ; <17> ENDIF ; <20> move.l d0,lastWidAdj(a6) ; subtract this from width of last char <17> ; Get pixelWidth param and scale it down by outnumer.h/outdenom.h <6><10><17> ; Moved down here, and now scale lastWidAdj too. <18> tst.b jdRec.outScalTrue(a6) ; do we have any output scaling? <10><17><19> beq.s @doneWidthAdjust ; if not, skip this part <6> subq #4,sp ; room for FixDiv result <6><10> move.l d3,-(sp) ; width is first FixDiv arg <6><10> move.l jdRec.outScaling(a6),-(sp) ; second param = numer/denom <10><17><19> _FixDiv ; <10> move.l (sp)+,d3 ; get scaled width <6> move.l lastWidAdj(a6),d0 ; do we need to scale this too? <18> beq.s @doneWidthAdjust ; skip if not <18> subq #4,sp ; room for FixDiv result <18> move.l d0,-(sp) ; lastWidAdj is first FixDiv arg <18> move.l jdRec.outScaling(a6),-(sp) ; second param = numer/denom <18><19> _FixDiv ; <18> move.l (sp)+,lastWidAdj(a6) ; get scaled width <18> @doneWidthAdjust ; Now get address of measuring routine to use, and see if it is not standard new<17> bsr GetMeasProc ; get flag in d0, addr in a0 <19> move.w d0,customProc(a6) ; set flag <19> move.l a0,measProc(a6) ; save addr of the proc we want ; Set up to do measuring new<17> moveq #0,d4 ; initial char offset moveq #0,d5 ; measurement for current offset moveq #0,d6 ; measurement for previous offset move.w textLen+2(a6),d7 ; textLen ble p2cAfterEnd tst.w customProc(a6) ; can we use width table? beq.s @useTable ; Measuring width of text with custom proc. new<17> move.l measProc(a6),a4 ; get proc ptr <19> @customLoop add.w #1,d4 ; include next char move.l d5,d6 ; save last meast move.l numer(a6),numerVar(a6) ; copy numer move.l denom(a6),denomVar(a6) ; copy denom subq #2,sp ; make room for result move.w d4,-(sp) ; push byte count move.l a3,-(sp) ; push the text pointer. pea numerVar(a6) ; VAR numer in pea denomVar(a6) ; VAR denom in pea fntInfo(a6) ; VAR info jsr (a4) ; go do measure <19> move.w (sp)+,d5 ; get width swap d5 ; make a fixed clr.w d5 cmp.w d7,d4 ; have we reached end of string? bge @lastChar ; <18> cmp.l d3,d5 blt.s @customLoop bra @gotHit ; <18> ; We'll be using width tables. @useTable ; additional registers for this section ; a1 ptr to width table ; d1.l char from string ; d2.l total chExtra (port's plus ours, scaled to match table) ; Call SwapFont again to force SpExtra into width tables. <17> ; (this whole section is new) <17> move.l numer(a6),-(sp) ; push numer move.l denom(a6),-(sp) ; push denom pea jdRec(a6) ; push ptr to JustDataRec bsr DoSwapFont ; reset width table <19> ; Need to get any chExtra from port, then add in our own and scale result. new<17> ; Moved part of this into subroutine for code sharing with MeasureJust. <19> bsr GetPortChExtra ; get port chExtra in d2 <19> add.l jdRec.addChExtra(a6),d2 ; add our charExtra to port's tst.b jdRec.outScalTrue(a6) ; do we have any output scaling? beq.s @doneTotalChExScal ; if not, skip this part subq #4,sp ; result space move.l d2,-(sp) ; total chExtra move.l jdRec.outScaling(a6),-(sp) ; second param = numer/denom _FixDiv ; move.l (sp)+,d2 ; get scaled result @doneTotalChExScal ; Here we have chExtra in d2. Get WidthTablePtr and start adding widths. new<17> ; SpExtra is in table, but have to add in chExtra. move.l WidthTabHandle,a1 ; handle to global width table move.l (a1),a1 ; now ptr moveq #0,d1 @widthLoop add.w #1,d4 ; include next char move.l d5,d6 ; save last meast move.b (a3)+,d1 move.w d1,d0 lsl.w #2,d0 add.l 0(a1,d0.w),d5 cmp.b #$20,d1 ; space? beq.s @doneAddChExtra add.l d2,d5 @doneAddChExtra cmp.w d7,d4 ; have we reached end of string? bge.s @lastChar cmp.l d3,d5 blt.s @widthLoop bra.s @gotHit ; Now we are back to common code to handle last char new<17> @lastChar sub.l lastWidAdj(a6),d5 ; adjust for end pen move cmp.l d3,d5 ; change to .l <18> blt p2cAfterEnd ; At this point we have a hit with the following: ; d4.w current offset ; d5.l width for current offset ; d6.l width for previous offset @gotHit ; Determine whether the pixelWidth occurs on the left or right side of ; the character and return the right or left offset accordingly. sf (a2) ; assume leadingEdge false. <21> add.l d3,d3 ; double pixelWidth. add.l d5,d6 ; average measurements. cmp.l d6,d3 ; compare width to average. bhi.s DoneP2C ; if width < average, st (a2) ; set leadingEdge true. <21> sub.w #1,d4 ; decrement result. ; Restore drawing params (RestoreSpChExtra doesn't modify jdRec). ; Save the P2C result. DoneP2C pea jdRec(a6) ; push local JustDataRec addr bsr RestoreSpChExtra ; restore orig drawing params move.w d4,result(a6) ; return width. ; Restore regs, unlink the stack and return to the caller. p2cExit movem.l (sp)+,p2cRegs ; restore the registers. <19> move.w #np2cArgs,d0 ; for std exit bra StdUnlink ; StdUnlink p2cBeforeStart ; if width <= 0, then before start of the line, so <17> ; return leadingEdge = teSysJust, offset = 0 move.w #0,result(a6) ; <18> move.b TESysJust,(a2) ; set leading edge beq.s p2cExit ; if 0, offset ok <18> move.w textLen+2(a6),result(a6) ; else set it to length <18> bra.s p2cExit p2cAfterEnd ; if width exceeds length, then past the end of the line, so <17> ; return leadingEdge = ÂteSysJust, offset = length (should already ; be in d4). Width for offset is in d5. tst.b TESysJust ; <18> seq (a2) ; set leadingEdge = ÂteSysJust <18> beq.s @doneSetLength ; if TESysJust ­$0, É <18> moveq #0,d4 ; É then reset length <18> @doneSetLength ; <18> move.l widRemAdr(a6),d1 ; should we set widthRemaining? beq.s DoneP2C ; if not, just return length move.l d1,a4 ; copy widRemAdr sub.l d5,d3 ; remaining width <17> ; we have to scale up remaining width. <17> tst.b jdRec.outScalTrue(a6) ; do we have any scaling? <19> beq.s @doneWidthScaleup ; if not, skip this part subq #4,sp ; room for FixDiv result move.l d3,-(sp) ; width is first FixMul arg move.l jdRec.outScaling(a6),-(sp) ; second param = numer/denom <19> _FixMul ; move.l (sp)+,d3 ; get scaled width @doneWidthScaleup ; now set it, then go set offset and return. move.l d3,(a4) ; set widthRemaining <17><19> bra.s DoneP2C ; go return length. endWith endproc ; ----------------------------------------------------------------------- <17> ; PROCEDURE InitFontAndScale( ; numer: Point; ; denom: Point; ; jdRecPtr: ^JustDataRec ; ); ; ; This calls FMSwapFont, checks the FontClass field of the style mapping ; table in the FOND (if present), and sets the noInterCh flag field of the ; JustDataRec, based on this info. It sets up the input and output scaling <19> ; factors and the relevant flags to 0. It also initializes all of the other ; flags (except restoreSE) to 0 (false). ; ; Changed to not clear restoreSE, since it is initialized by DoSpChExtra <18> ; anyway, and since we need to preserve its state when we call this ; routine to force FMSwapFont before getting widths from the width table. ; (Now it doesn't matter, since we call DoSwapFont when we need to preserve <19> ; the state of restoreSE) ; ; PROCEDURE DoSwapFont( <19> ; numer: Point; ; denom: Point; ; jdRecPtr: ^JustDataRec ; ); ; ; This just calls SwapFont. The jdRecPtr parameter is not used, but is ; passed for stack frame compatibility so we can share code more easily. ; ----------------------------------------------------------------------- proc export InitFontAndScale,DoSwapFont import StdUnlink ifsRecord record {a6link},decr ifsArgs equ *-8 ; size of arguments. numer ds.l 1 ; Point - numer denom ds.l 1 ; Point - denom jdRecPtr ds.l 1 ; pointer to JustDataRec return ds.l 1 ; return address. a6link ds.l 1 ; old a6 register. fmInRec ds.b 16 ; FMInput record ifsLocals equ * ; size of local variables. endr smtFontClass equ 0 ; offset of Font Class in style map table fcNoInterCh equ 10 ; Font Class bit flag for no interchar sp fixed1 equ $00010000 ; 1.0 in 16.16 Fixed format <19> InitFontAndScale with ifsRecord,JustDataRec ; <19> link a6,#ifsLocals ; link the stack. ; Compute input numer.h/denom.h and set inScaling and inScalTrue. ; This was moved from InitScaleFac routine. <19> move.l jdRecPtr(a6),a1 ; pointer to JustDataRec move.l #fixed1,inScaling(a1) ; initially assume 1,1 scaling <19> sf inScalTrue(a1) ; follows from above <19> move.w numer+h(a6),d1 ; get numer move.w denom+h(a6),d2 ; get denom beq.s @doneInScaling ; if 0, then skip next part <16> cmp.w d1,d2 ; if they're the sameÉ beq.s @doneInScaling ; Éthen skip next part subq #4,sp ; room for FixRatio result move.w d1,-(sp) ; push numer.h move.w d2,-(sp) ; push denom.h _FixRatio ; divide move.l jdRecPtr(a6),a1 ; restore pointer to JustDataRec move.l (sp)+,inScaling(a1) ; save computed scaling <19> st inScalTrue(a1) ; follows from above <19> @doneInScaling ; Fill font mgr input record, call font mgr to set up FOND handle so we can see if ; FOND allows interchar spacing. Also sets up Width table. ; Common routine returns FMOutRec ptr in a0. <19> bsr.s CommonSwapFont ; <19> ; Compute output numer.h/denom.h and set outScaling and outScalTrue. ; New section; code to do this used to be duplicated in Char2Pix, Pix2Char, etc. <19> move.l jdRecPtr(a6),a1 ; pointer to JustDataRec move.l #fixed1,outScaling(a1) ; initially assume 1,1 scaling sf outScalTrue(a1) ; follows from above move.w fmOutNumer+h(a0),d1 ; get numer move.w fmOutDenom+h(a0),d2 ; get denom beq.s @doneOutScaling ; if 0, then skip next part cmp.w d1,d2 ; if they're the sameÉ beq.s @doneOutScaling ; Éthen skip next part subq #4,sp ; room for FixRatio result move.w d1,-(sp) ; push numer.h move.w d2,-(sp) ; push denom.h _FixRatio ; divide move.l jdRecPtr(a6),a1 ; restore pointer to JustDataRec move.l (sp)+,outScaling(a1) ; save computed scaling st outScalTrue(a1) ; follows from above @doneOutScaling ; Check if FOND allows intercharacter spacing ;; move.l jdRecPtr(a6),a1 ; get ptr to passed JustDataRec sf noInterCh(a1) ; initialize move.l LastFOND,d0 ; Do we have a FOND handle? beq.s @doneFONDCheck ; skip this if not move.l d0,a0 move.l (a0),a0 ; Get FOND pointer move.l ffStylOff(a0),d0 ; Get offset to style-map table beq.s @doneFONDCheck ; skip if no table move.w smtFontClass(a0,d0.l),d0 ; get Font Class from table btst #fcNoInterCh,d0 ; Does FOND forbid interchar spacing? sne noInterCh(a1) ; set according to result @doneFONDCheck ; Initialize other flags to 0 sf startNoFwd(a1) sf endBackup(a1) sf haveWeight(a1) ;; sf restoreSE(a1) ; don't do this one <18> ; Restore regs, unlink stack, and return move.w #ifsArgs,d0 ; for std exit bra StdUnlink ; StdUnlink endwith ;ifsRecord,JustDataRec ; Common routine for to set up SwapFont input record and call it. <19> ; Expects stack frame to be set up. ; Returns FMOutRec ptr in a0. CommonSwapFont with ifsRecord lea fmInRec(a6),a1 ; Point to local FMInput record <19> subq #4,sp ; Room for result (FMOutput ptr) <19> move.l a1,-(sp) ; push ptr to input record <19> move.l grafGlobals(a5),a0 ; Point to QuickDraw globals move.l thePort(a0),a0 ; Get current grafport move.w txFont(a0),(a1)+ ; Get family from thePort move.w txSize(a0),(a1)+ ; Get size from thePort move.b txFace(a0),(a1)+ ; Get face from thePort sf (a1)+ ; Set needBits false move.w device(a0),(a1)+ ; Get device from thePort move.l numer(a6),(a1)+ ; Get numer from input params move.l denom(a6),(a1) ; Get denom from input params _FMSwapFont move.l (sp)+,a0 ; get FMOutPtr <19> rts endwith ;ifsRecord ; Little routine just to do the swap font stuff (same parameters) <19> DoSwapFont with ifsRecord link a6,#ifsLocals ; link the stack. bsr.s CommonSwapFont ; move.w #ifsArgs,d0 ; for std exit bra StdUnlink ; StdUnlink endwith ;ifsRecord endproc ; ----------------------------------------------------------------------- ; PROCEDURE InitWeight( ; textPtr: Ptr; ; textLen: Longint; ; styleRunPosition: JustStyleCode; ; jdRecPtr: ^JustDataRec ; ); ; ; This initializes some of the fields in a JustDataRec, based on the ; text, the styleRunPosition, and the smgrCharPortion field in the ; SMgrRecord. It sets up the following: ; weight ; charPortion ; spPortion ; startNoFwd ; endBackup ; ; NOTE: trashes a0-a1,d0-d2 ; ----------------------------------------------------------------------- proc export InitWeight ; <17> import StdUnlink iwRecord record {a6link},decr iwArgs equ *-8 ; size of arguments. textPtr ds.l 1 ; text pointer. textLen ds.l 1 ; text length. stylRunPos ds.w 1 ; style run position code. jdRecPtr ds.l 1 ; pointer to JustDataRec return ds.l 1 ; return address. a6link ds.l 1 ; old a6 register. iwLocals equ * ; size of local variables. endr portion100 equ $1000 ; 100% in 4.12 format InitWeight ; <17> with iwRecord link a6,#iwLocals ; link the stack. movem.l d3-d4,-(sp) ; save regs ; Initialize char portion and space portion to 0% and 100% (moved here) <17> moveq #0,d3 ; also use for longizing CharPortion move.l #portion100,d4 IF useInterChar THEN ; <20> ; Check if FOND allows intercharacter spacing (new section) <17> with JustDataRec ; move.l jdRecPtr(a6),a0 ; pointer to JustDataRec tst.b noInterCh(a0) ; interchar forbidden? bne.s @doneGetPortion ; If so, don't get char portion endwith ;JustDataRec ; ; Get char portion (cp) in d3, ensure that it is in the range 0.0 to 1.0, ; and then get space portion (sp = 1-cp) in d4. with SMgrRecord GetSMgrCore a1 ; get SMgrRecord pointer move.w smgrCharPortion(a1),d3 ; get CharPortion, 4.12 fixed cmp.w d4,d3 ; within range 0.0 to 1.0? bls.s @doneFixPortion ; if so, skip fix move.w d4,d3 ; fix char proportion @doneFixPortion sub.w d3,d4 ; get space proportion in d4 endwith @doneGetPortion ENDIF ; <20> ; Now compute #chars*cp + #spaces*sp by looping through the text buffer, ; testing each character, and then adding cp or sp to d2. Here, d2 is a ; 20.12 fixed-point number. move.l textPtr(a6),a0 ; get text ptr move.l textLen(a6),d0 ; get text len move.l a0,a1 ; copy text pointer moveq #0,d2 ; initialize accumulator bra.s @testLength ; jump to end of loop @loopStart move.b (a0)+,d1 ; get next char cmp.b #' ',d1 ; space? bne.s @notSpace ; if not, handle it separately add.l d4,d2 ; add space proportion bra.s @testLength ; @notSpace add.l d3,d2 ; add char proportion @testLength subq.l #1,d0 ; decrement length bge.s @loopStart ; loop while still chars ; Now, we use StyleRunPosition to adjust d2 and set d0/d1. First, we make ; d2 a 19.13 format fixed, and we can treat d3 as 0.5*cp in 19.13 format. with JustDataRec move.l jdRecPtr(a6),a0 ; pointer to JustDataRec sf startNoFwd(a0) ; initialize startNoFwd <16> sf endBackup(a0) ; initialize endBackup <16> add.l d2,d2 ; now accum is 19.13 fixed <16> beq.s @doneLeftAdjust ; if no chars, skip adjust <16> move.w stylRunPos(a6),d0 ; get styleRunPosition <16> ; Adjust for right end of style run btst.l #0,d0 ; any adjustments for right end? <17> bne.s @doneRightAdjust ; no,,skip cmp.b #' ',d1 ; was last char a space? beq.s @doneRightAdjust ; if so, skip sub.l d3,d2 ; subtract 0.5 cp from accum st endBackup(a0) ; now move for right end is -1 ce @doneRightAdjust ; Adjust for left end of style run btst.l #1,d0 ; any adjustment for left end? <17> bne.s @doneLeftAdjust move.b (a1),d1 cmp.b #' ',d1 ; is first char a space? beq.s @doneLeftAdjust ; if so, skip sub.l d3,d2 ; subtract 0.5 cp from accum st startNoFwd(a0) ; now move for left end is 0 @doneLeftAdjust ; Now make d2 and d3 16.16 Fixed and save them lsl.l #3,d2 ; now accum is 16.16 Fixed. move.l d2,weight(a0) ; save it lsl.l #4,d3 ; now cp is 16.16 Fixed move.l d3,charPortion(a0) ; save it too lsl.l #4,d4 ; now sp is 16.16 Fixed move.l d4,spPortion(a0) ; guess what? ; Restore regs, unlink stack, and return movem.l (sp)+,d3-d4 ; restore regs move.w #iwArgs,d0 ; for std exit bra StdUnlink ; StdUnlink endwith ; JustDataRec endwith ; iwRecord endproc ; ----------------------------------------------------------------------------- <17> ; PROCEDURE CalcSpChExtra( ; textPtr: Ptr; ; textLen: Long; ; slop: Fixed; {signed} ; styleRunPosition: JustStyleCode; ; numer: Point; ; denom: Point; ; jdRecPtr: ^JustDataRec; ; ); ; ; CalcSpChExtra finds the correct spExtra and charExtra values for the passed ; string, based on its length, the slop value, the styleRunPosition, and the ; scaling factors. It assumes InitFontAndScale has been called to set the <19> ; scaling factor, and calls InitWeight if the slop is nonzero to set the weight. ; ; InitFontAndScale must be called before calling this. ; ; Sets addSpExtra, addSpExScal, addChExtra, addChExScal, runSlop. ; Uses and may modify haveWeight. ; ; NOTE: trashes a0-a1,d0-d2 ; ----------------------------------------------------------------------------- proc export CalcSpChExtra import StdUnlink import GetFontSize ; <19> csceRecord record {a6link},decr csceArgs equ *-8 ; size of arguments. textPtr ds.l 1 ; text pointer. textLen ds.l 1 ; text length. slop ds.l 1 ; slop pixels. stylRunPos ds.w 1 ; style run position code. numer ds.l 1 ; Point - numer <5> denom ds.l 1 ; Point - denom <5> jdRecPtr ds.l 1 ; pointer to JustDataRec return ds.l 1 ; return address. a6link ds.l 1 ; old a6 register. csceLocals equ * ; size of local variables. endr csceRegs reg a3/d3-d4 ; <19> CalcSpChExtra with csceRecord,JustDataRec,SMgrRecord link a6,#csceLocals ; link the stack. movem.l csceRegs,-(sp) ; save regs <17><19> move.l jdRecPtr(a6),a3 ; get ptr to JustDataRec <17> clr.l addSpExtra(a3) ; Initialize fields we set directly <17> clr.l addSpExScal(a3) ; clr.l addChExtra(a3) ; clr.l addChExScal(a3) ; move.l slop(a6),runSlop(a3) ; beq @csceRestoreRegs ; if slop zero, skip this whole mess tst.b haveWeight(a3) ; have we already done this? <17> bne.s @gotWeight ; if so, skip <17> move.l textPtr(a6),-(sp) ; push textPtr move.l textLen(a6),-(sp) ; push textLen move.w stylRunPos(a6),-(sp) ; push styleRunPosition move.l a3,-(sp) ; push ptr to JustDataRec bsr InitWeight ; Fill out weight <17> st haveWeight(a3) ; don't do it again <17> @gotWeight ; <17> tst.l weight(a3) ; Check nc*cp+ns*sp beq @csceRestoreRegs ; if 0, nothing to do ; Determine limit on negative spExtra & chExtra. new<19> ; This uses a simple heuristic test. The basic idea is don't let the additional ; Script Mgr spExtra or chExtra be < -3 for an unscaled 12 pt font (with appropriate ; adjustments for font size and scaling). This ignores any existing spExtra or ; chExtra in the port, and doesn't check the actual width of a space or narrow char. move.l grafGlobals(a5),a0 ; grafGlobals move.l thePort(a0),a0 ; get thePort pointer bsr GetFontSize ; expects thePort^ in a0, returns size in d0 swap d0 ; make a Fixed clr.w d0 ; and clear frac part tst.b inScalTrue(a3) ; any num/denom scaling? beq.s @doneSizeAdjust ; if not, skip size adjust subq #4,sp ; space for FixMul return move.l d0,-(sp) ; push size move.l inScaling(a3),-(sp) ; push numer.h/denom.h _FixMul move.l (sp)+,d0 ; get scaled size @doneSizeAdjust asr.l #2,d0 ; divide by 12/3 neg.l d0 ; move.l d0,d4 ; save limit ; Make slop/(nc*cp + ns*sp) subq #4,sp ; make stack space for result move.l runSlop(a3),-(sp) ; push slop (numerator) move.l weight(a3),-(sp) ; push weight (denom) _FixDiv ; Now slop/(nc*cp + ns*sp) is on the stack. If cp is 0, this is slop/ns, ; which is the desired additional spExtra, so skip the unnecessary charExtra ; stuff, skip multiplying slop/weight by sp (which is 1.0), and go straight ; to where we set addSpExtra from result on stack. Otherwise, save slop/weight ; in d3 and then proceed with charExtra stuff. IF useInterChar THEN ; <20> move.l charPortion(a3),d0 ; get charPortion beq.s @setSpExtra ; if 0, skip a lot of stuff move.l (sp)+,d3 ; get slop/weight ; Determine additional chExtra. subq #4,sp ; make stack space for result move.l d0,-(sp) ; push charPortion move.l d3,-(sp) ; push slop/weight _FixMul ; get unscaled additional charExtra move.l (sp)+,d0 ; <19> move.l d0,addChExtra(a3) ; save in JustDataRec <17><19> move.l d0,addChExScal(a3) ; initialize this too <19> cmp.l d4,d0 ; do we exceed limit? <19> blt.s @recalcExtra ; if so, go recalculate Extra values <19> ; Determine additional spExtra subq #4,sp ; make stack space for result move.l spPortion(a3),-(sp) ; push spPortion move.l d3,-(sp) ; push slop/weight _FixMul ; get unscaled additional spExtra on stack @setSpExtra ENDIF ; <20> move.l (sp)+,d0 ; get unscaled additional spExtra <19> move.l d0,addSpExtra(a3) ; save in JustDataRec <17><19> move.l d0,addSpExScal(a3) ; initialize this too <19> cmp.l d4,d0 ; do we exceed limit? <19> bge.s @doScaling ; if not, skip pinning or recalculation <19> ; If charPortion is 0, all we can do is pin spExtra. new<19> IF useInterChar THEN ; <20> tst.l charPortion(a3) ; is charPortion zero? bne.s @recalcExtra ; if no, go recalculate Extra values ENDIF ; <20> move.l d4,addSpExtra(a3) ; pin spExtra move.l d4,addSpExScal(a3) ; this too IF useInterChar THEN ; <20> bra.s @doScaling ; now go to scaling ; We have hit a neg limit, and charPortion is not 0. Set spExtra and chExtra to the new<19> ; greater of Extra limit (d4) or slop/(adjusted number of chars). @recalcExtra move.l textLen(a6),d0 ; get length swap d0 ; make Fixed clr.w d0 ; clear frac part move.l #FixedPoint5,d1 ; get value for adjusting number of chars tst.b startNoFwd(a3) ; only .5 chExtra for left char? beq.s @doneStartAdjust ; skip if not sub.l d1,d0 ; adjust number of chars @doneStartAdjust ; tst.b endBackup(a3) ; only .5 chExtra for right char? beq.s @doneEndAdjust ; skip if not sub.l d1,d0 ; adjust number of chars @doneEndAdjust ; subq #4,sp ; result space move.l runSlop(a3),-(sp) ; push slop (numerator) move.l d0,-(sp) ; push adjusted number of chars (denom) _FixDiv ; move.l (sp)+,d0 ; get new value for spExtra and chExtra cmp.l d4,d0 ; does it exceed limit? bge.s @stuffNewExtra ; if not, use it move.l d4,d0 ; else, just pin everything @stuffNewExtra ; move.l d0,addChExtra(a3) ; stuff it everywhere move.l d0,addChExScal(a3) ; move.l d0,addSpExtra(a3) ; move.l d0,addSpExScal(a3) ; ENDIF ; <20> ; Scale spExtra and chExtra by numer/denom (collected here from above) <19> @doScaling tst.b inScalTrue(a3) ; do we have any scaling? <10><19> beq.s @doneScaleExtra ; skip if not <10> IF useInterChar THEN ; <20> move.l addChExtra(a3),d0 ; get unscaled value <19> beq.s @doneScaleChExtra ; skip if 0 <19> subq #4,sp ; make stack space for result <19> move.l d0,-(sp) ; push unscaled chExtra <19> move.l inScaling(a3),-(sp) ; second param = numer/denom <10><19> _FixDiv ; get (unscaled chExtra)/(numer/denom) <17> move.l (sp)+,addChExScal(a3) ; save in JustDataRec <10><17><19> @doneScaleChExtra ; <10> ENDIF ; <20> move.l addSpExtra(a3),d0 ; get unscaled value <19> beq.s @doneScaleExtra ; skip if 0 <19> subq #4,sp ; make stack space for result <19> move.l d0,-(sp) ; push unscaled spExtra <19> move.l inScaling(a3),-(sp) ; second param = numer/denom <13><19> _FixDiv ; (spExtra)/(num/den) <13> move.l (sp)+,addSpExScal(a3) ; save in JustDataRec <17><19> @doneScaleExtra ; <13><19> ; Restore regs, unlink the stack and return to the caller. @csceRestoreRegs movem.l (sp)+,csceRegs ; restore regs <17><19> @csceUnlink move.w #csceArgs,d0 ; for std exit bra StdUnlink ; StdUnlink endwith endproc ; ----------------------------------------------------------------------------- <17> ; PROCEDURE DoSpChExtra( ; jdRecPtr: ^JustDataRec; ; ); ; ; SetSpChExtra sets the spExtra value of the port and the GrafGlobal qdChExtra, ; based on values in the JustDataRec. If addSpExScal is non-zero, the routine ; saves the current value of spExtra, adds in the addSpExScal value, and sets ; the restoreSE flag. The addChExScal value is scaled down by the font size and ; put in qdChExtra. The runSlop is also saved in qdRunSlop. ; ; ----------------------------------------------------------------------------- proc export DoSpChExtra import StdUnlink import GetFontSize dsceRecord record {a6link},decr dsceArgs equ *-8 ; size of arguments. jdRecPtr ds.l 1 ; pointer to JustDataRec return ds.l 1 ; return address. a6link ds.l 1 ; old a6 register. dsceLocals equ * ; size of local variables. endr DoSpChExtra with dsceRecord,JustDataRec link a6,#dsceLocals ; link the stack. move.l jdRecPtr(a6),a1 ; get ptr to passed JustDataRec sf restoreSE(a1) ; initialize restoreSE move.l grafGlobals(a5),a0 ; grafGlobals clr.l qdChExtra(a0) ; initialize move.l runSlop(a1),qdRunSlop(a0) ; put slop in globals so pics can save it beq.s @dsceUnlink ; if no slop, skip all of this move.l thePort(a0),a0 ; get thePort pointer ; If addSpExScal is non-zero, add it in to port's value, first saving old value move.l addSpExScal(a1),d0 beq.s @doneSpExtra ; Now we have scaled spExtra in d0. Save the current spExtra value, then update it. move.l spExtra(a0),d1 ; get original spExtra move.l d1,oldSpExtra(a1) ; save original spExtraÉ st restoreSE(a1) ; and remember to restore it add.l d0,d1 ; add in scaled extra value add.l #$00000001,d1 ; old fix for QD bug - it rounds ; differently for measuring and drawing ; (is this fix still needed? does it ; work right for neg spExtra? -pke) move.l d1,spExtra(a0) ; adjust spExtra @doneSpExtra IF useInterChar THEN ; <20> ; If addChExScal is non-zero, scale it by font size (like CharExtra field in port) ; and stuff it in qdChExtra. move.l addChExScal(a1),d1 beq.s @doneChExtra ; This does essentially the same thing as QuickDrawÕs CharExtra routine. bsr GetFontSize ; assume thePort^ in a0, get font size in d0.w swap d0 ; make it a Fixed clr.w d0 ; clear the fraction part subq #4,sp ; space for result move.l d1,-(sp) ; addChExScal move.l d0,-(sp) ; font size as Fixed _FixDiv ; addChExScal/(font size) move.l grafGlobals(a5),a0 ; grafGlobals move.l (sp)+,qdChExtra(a0) ; get 16.16 Fixed result for use by QuickDraw @doneChExtra ENDIF ; <20> ; Unlink the stack and return to the caller. @dsceUnlink move.w #dsceArgs,d0 ; for std exit bra StdUnlink ; StdUnlink endwith endproc ; ----------------------------------------------------------------------------- ; PROCEDURE RestoreSpChExtra( ; jdRecPtr: ^JustDataRec ; ); ; ; This restores the original spExtra value, and clears qdChExtra and qdRunSlop. <17> ; ----------------------------------------------------------------------------- proc export RestoreSpChExtra import StdUnlink rsceRecord record {a6link},decr rsceArgs equ *-8 ; size of arguments. jdRecPtr ds.l 1 ; pointer to JustDataRec return ds.l 1 ; return address. a6link ds.l 1 ; old a6 register. rsceLocals equ * ; size of local variables. endr RestoreSpChExtra with rsceRecord,JustDataRec link a6,#rsceLocals ; link the stack. move.l grafGlobals(a5),a0 ; grafGlobals <9><17> clr.l qdChExtra(a0) ; never hurts to clear it <9><12> clr.l qdRunSlop(a0) ; we're done with this too <9><12> move.l jdRecPtr(a6),a1 ; get JustDataRec pointer <17> tst.b restoreSE(a1) ; do we need to bother? <17> beq.s @doneRestoreSE move.l thePort(a0),a0 ; get thePort pointer <10><17> move.l oldSpExtra(a1),spExtra(a0) ; restore old spExtra <10><17> @doneRestoreSE move.w #rsceArgs,d0 ; for std exit bra StdUnlink ; StdUnlink endWith endproc ; ----------------------------------------------------------------------------- <19> ; routine GetPortChExtra ; ; input: none ; output: d2.l port's chExtra, converted to 16.16 and scaled back up by font size ; ----------------------------------------------------------------------------- proc export GetPortChExtra import GetFontSize GetPortChExtra move.l grafGlobals(a5),a0 ; find the QuickDraw globals. move.l thePort(a0),a0 ; get thePort pointer moveq #0,d2 ; assume port has no chExtra tst.w portVersion(a0) ; negative if cGrafPort bpl.s @donePortChExtra ; otherwise, get port's chExtra move.w chExtra(a0),d2 ; get 4.12 fixed format beq.s @donePortChExtra ; if zero, we're done ext.l d2 ; extend sign bits asl.l #4,d2 ; convert to 16.16 format. bsr GetFontSize ; assume thePort^ in a0, get font size in d0.w swap d0 ; make Fixed clr.w d0 ; clear frac part subq #4,sp ; space for result move.l d0,-(sp) ; push size move.l d2,-(sp) ; push chExtra for 1-point size _FixMul ; chExtra on stack move.l (sp)+,d2 ; get real chExtra for our size @donePortChExtra ; rts endproc ; ----------------------------------------------------------------------------- ; routine: GetFontSize ; input: a0 Pointer to thePort <8><17> ; output: d0.w Font size ; ; Copied from QD code in CharExtra. ; ----------------------------------------------------------------------------- proc export GetFontSize GetFontSize MOVE.w txSize(A0),D0 ;get the text size <17> BNE.S @notZero ;not FMDefault TST.w txFont(A0) ;system font? <17> BNE.S @apFont ;if not, use default MOVE.w SysFontSize,D0 ;if family is zero, use system font size BNE.S @notZero @apFont MOVE.B FMDefaultSize,D0 ;if family nonzero or system font size zero, BNE.S @notZero ; use the default size MOVEQ #12,D0 ;if the default is zero, hardcode to 12 @notZero rts endproc ; ----------------------------------------------------------------------------- ; routine: SignFixRound ; input: d0.l signed fixed ; output: d0.w integer produced by rounding ; ----------------------------------------------------------------------------- proc export SignFixRound SignFixRound tst.l d0 bmi.s @neg add.l #FixedPoint5,d0 swap d0 rts @neg sub.l #FixedPoint5,d0 swap d0 rts endproc ; ----------------------------------------------------------------------------- <19> ; routine: GetMeasProc ; input: none ; output: d0.l 0 if StdTxMeas used, -1 if custom txMeasProc used ; a0.l ptr to meas proc to use ; ; Extracted this from Pixel2Char because it will be used by MeasureJust too ; ----------------------------------------------------------------------------- proc export GetMeasProc stdTxMeasTrap equ $A8ED ; GetMeasProc move.w #stdTxMeasTrap,d0 _GetTrapAddress ; get address of StdTxMeas in a0 moveq #0,d0 ; set flag: no custom proc move.l grafGlobals(a5),a1 ; Point to QuickDraw globals move.l thePort(a1),a1 ; Get current grafport move.l grafProcs(a1),d1 ; Is grafprocs NIL? beq.s @gotProc ; if so, we use StdTxMeas move.l d1,a1 ; else, check grafprocs move.l txMeasProc(a1),d1 ; get txMeasProc cmp.l a0,d1 ; is it same as StdTxMeas? beq.s @gotProc ; if so, skip reset move.l d1,a0 ; else, we use custom proc moveq #-1,d0 ; and say so @gotProc rts endproc ;------------------------------------------ <5> ; ; GetScaledFontInfo procedure ; ; Copied from QuickDraw, but modified to accept scaling parameters and ; to use record for stack frame. ; Rearranged parameter order. <7> ; Moved to ScriptMgrExtTail.a <7> ; end