<> <> <> DIRECTORY Basics USING [BITAND, bitsPerWord, LongMult], FunctionCache USING [Cache, CompareProc, Create, Insert, Lookup], Imager USING [ClassRep, Context, SetXYRel, StateRep], ImagerBitmapDevicePrivate USING [Data], ImagerCache USING [Fetch, GetNamedCache, Ref], ImagerDevice USING [CharMaskRep, Device], ImagerFastShow USING [], ImagerFont USING [Font, XChar, XStringProc], ImagerFontPrivate USING [FontAtom], ImagerPixelMap USING [DeviceRectangle, PixelMap], ImagerPrivate USING [ClassRep], ImagerRaster USING [Create, CreateClass, FontTuner, NewBitmapDevice], ImagerRasterPrivate USING [AndFlags, Data, Flags, NoteStateChanges, RasterShow, ValidateIfNeeded], ImagerState USING [notChanged, State, StateRep], ImagerTransformation USING [InverseTransform, Transform, Transformation], PrincOps USING [BBTableSpace, BitBltFlags, BitBltTablePtr], PrincOpsUtils USING [AlignedBBTable, BITBLT], Real, Scaled USING [Float, FromReal, half, MINUS, PLUS, Value, zero], Vector2 USING [Mul, VEC]; ImagerFastShowImpl: CEDAR PROGRAM IMPORTS Basics, FunctionCache, Imager, ImagerCache, ImagerRaster, ImagerRasterPrivate, ImagerTransformation, PrincOpsUtils, Real, Scaled, Vector2 EXPORTS Imager, ImagerFastShow ~ BEGIN OPEN ImagerRasterPrivate; bitsPerWord: NAT ~ Basics.bitsPerWord; ClassRep: PUBLIC TYPE ~ ImagerPrivate.ClassRep; -- export to Imager.ClassRep Context: TYPE ~ Imager.Context; Device: TYPE ~ ImagerDevice.Device; DeviceRectangle: TYPE ~ ImagerPixelMap.DeviceRectangle; Font: TYPE ~ ImagerFont.Font; FontAtom: TYPE ~ ImagerFontPrivate.FontAtom; RasterMask: TYPE ~ REF ImagerDevice.CharMaskRep.raster; State: TYPE ~ ImagerState.State; StateRep: PUBLIC TYPE ~ ImagerState.StateRep; -- export to Imager.StateRep Transformation: TYPE ~ ImagerTransformation.Transformation; VEC: TYPE ~ Vector2.VEC; XChar: TYPE ~ ImagerFont.XChar; XStringProc: TYPE ~ ImagerFont.XStringProc; fastShowClass: REF Imager.ClassRep ~ FastShowClass[]; FastShowClass: PROC RETURNS [c: REF ImagerPrivate.ClassRep] ~ { c _ ImagerRaster.CreateClass[$FastShowBitmap]; IF c.Show # ImagerRasterPrivate.RasterShow THEN ERROR; c.Show _ FastShow; }; rastWeight: REAL _ 2.0; Create: PUBLIC PROC [pm: ImagerPixelMap.PixelMap, pixelsPerInch: REAL _ 72, pixelUnits: BOOL, fontTuner: ImagerRaster.FontTuner] RETURNS [Context] ~ { device: ImagerDevice.Device ~ ImagerRaster.NewBitmapDevice[ frame: pm, pixelsPerInch: pixelsPerInch]; bitmapFontCache: ImagerCache.Ref ~ ImagerCache.GetNamedCache[ atom: $Bitmap, createSize: 4000]; RETURN[ImagerRaster.Create[device: device, pixelUnits: pixelUnits, fontCache: bitmapFontCache, rastWeight: rastWeight, fontTuner: fontTuner, class: fastShowClass]]; }; Validate: PROC [data: ImagerRasterPrivate.Data, state: State, needs: ImagerRasterPrivate.Flags] RETURNS [BOOL] ~ INLINE { IF state.changed#ImagerState.notChanged THEN ImagerRasterPrivate.NoteStateChanges[data, state]; IF ImagerRasterPrivate.AndFlags[data.valid, needs]#needs THEN ImagerRasterPrivate.ValidateIfNeeded[data, state, needs]; RETURN [TRUE] }; showNeeds: ImagerRasterPrivate.Flags ~ [clientClipper: TRUE, deviceColor: TRUE, devicePriority: TRUE, clientToDevice: TRUE, fontInfo: TRUE]; worryNat: NAT ~ NAT.LAST/2-1; worryReal: REAL _ worryNat; space: XChar ~ [0, ORD[' ]]; Trust: UNSAFE PROC [INTEGER] RETURNS [NAT] ~ UNCHECKED MACHINE CODE {}; NatBox: TYPE ~ RECORD [smin, fmin, smax, fmax: NAT]; SSizeOf: PROC [b: NatBox] RETURNS [NAT] ~ INLINE { RETURN [b.smax - b.smin] }; ContainingBox: PROC [s, f: INTEGER, boxes: LIST OF DeviceRectangle] RETURNS [b: NatBox] ~ { FOR p: LIST OF DeviceRectangle _ boxes, p.rest UNTIL p=NIL DO d: DeviceRectangle ~ p.first; IF s IN [d.sMin..d.sMin+d.sSize) AND f IN [d.fMin..d.fMin+d.fSize) THEN RETURN [[ smin: MAX[d.sMin, 0], fmin: MAX[d.fMin, 0], smax: MAX[d.sMin+d.sSize, 0], fmax: MAX[d.fMin+d.fSize, 0] ]] ENDLOOP; RETURN [[0,0,0,0]] }; sSizeBoxMin: NAT _ 4; CommonChar: TYPE ~ [32..127]; charArrayCache: FunctionCache.Cache _ FunctionCache.Create[maxEntries: 24]; GetCharArray: PROC [fontAtom: REF] RETURNS [r: REF ARRAY CommonChar OF RasterMask] ~ { compare: FunctionCache.CompareProc ~ {RETURN [argument = fontAtom]}; r _ NARROW[FunctionCache.Lookup[charArrayCache, compare].value]; IF r = NIL THEN { r _ NEW[ARRAY CommonChar OF RasterMask _ ALL[NIL]]; [] _ FunctionCache.Insert[charArrayCache, fontAtom, r, SIZE[ARRAY CommonChar OF RasterMask]]; }; }; Ord: PROC [char: XChar] RETURNS [CARDINAL] ~ INLINE {RETURN [LOOPHOLE[char]]}; FastShow: PROC [context: Context, string: XStringProc, xrel: BOOL] ~ { state: State ~ context.state; rasterData: Data ~ NARROW[context.data]; device: Device ~ rasterData.device; bitmapData: ImagerBitmapDevicePrivate.Data ~ NARROW[device.data]; cache: ImagerCache.Ref ~ rasterData.fontCache; font: Font ~ state.font; valid: BOOL _ Validate[rasterData, state, showNeeds]; scaledCPValid: BOOL _ FALSE; sCP: Scaled.Value; -- device coordinates, offset by 1/2 pixel fCP: Scaled.Value; -- ditto box: NatBox; UpdateCP: PROC ~ { IF scaledCPValid THEN state.p.cp _ rasterData.viewToDevice.InverseTransform[ [sCP.MINUS[Scaled.half].Float, fCP.MINUS[Scaled.half].Float] ]; }; TryScaledCP: PROC RETURNS [BOOL]~ { cp: VEC _ rasterData.viewToDevice.Transform[state.p.cp]; IF ABS[cp.x] < worryReal AND ABS[cp.y] < worryReal THEN { sCP _ Scaled.FromReal[cp.x].PLUS[Scaled.half]; fCP _ Scaled.FromReal[cp.y].PLUS[Scaled.half]; scaledCPValid _ TRUE; } ELSE scaledCPValid _ FALSE; IF scaledCPValid THEN box _ ContainingBox[s: sCP.integerPart, f: fCP.integerPart, boxes: rasterData.clientClipMask]; RETURN [scaledCPValid] }; charArray: REF ARRAY CommonChar OF RasterMask _ GetCharArray[rasterData.fontAtom]; Lookup: PROC [char: XChar] RETURNS [m: RasterMask _ NIL] ~ { WITH ImagerCache.Fetch[cache, rasterData.fontAtom, char] SELECT FROM r: RasterMask => { IF MAX[r.sSizeBB, r.fSizeBB, ABS[r.sWidth.integerPart], ABS[r.fWidth.integerPart]] < worryNat THEN { m _ r; IF Ord[char] IN CommonChar THEN { charArray[Ord[char]] _ m; <> }; }; }; ENDCASE => NULL; }; lastAmplified: RasterMask _ NIL; sCPAmp: Scaled.Value _ Scaled.zero; fCPAmp: Scaled.Value _ Scaled.zero; Amplify: PROC [m: RasterMask] ~ { IF m # lastAmplified THEN { IF state.np.amplifySpace = 1.0 THEN { sCPAmp _ m.sWidth; fCPAmp _ m.fWidth; } ELSE { width: VEC ~ Vector2.Mul[[m.sWidth.Float, m.fWidth.Float], state.np.amplifySpace]; IF MAX[ABS[width.x], ABS[width.y]] < worryReal THEN { sCPAmp _ Scaled.FromReal[width.x]; fCPAmp _ Scaled.FromReal[width.y]; } ELSE { UpdateCP[]; Imager.SetXYRel[context, width]; [] _ TryScaledCP[]; RETURN; }; }; lastAmplified _ m; }; sCP _ sCP.PLUS[sCPAmp]; fCP _ fCP.PLUS[fCPAmp]; }; IF NOT xrel AND bitmapData.case = constant AND state.np.correctPass = 0 AND state.np.noImage = 0 AND cache # NIL AND TryScaledCP[] AND SSizeOf[box] > sSizeBoxMin THEN TRUSTED { dstBase: LONG POINTER ~ bitmapData.frame.pointer; dstWpl: NAT ~ bitmapData.frame.rast; bbspace: PrincOps.BBTableSpace; bbPtr: PrincOps.BitBltTablePtr ~ InitBITBLT[]; InitBITBLT: PROC RETURNS [PrincOps.BitBltTablePtr] ~ TRUSTED { bb: PrincOps.BitBltTablePtr ~ PrincOpsUtils.AlignedBBTable[@bbspace]; flags: PrincOps.BitBltFlags _ bitmapData.maskBitsFlags; flags.gray _ FALSE; flags.disjoint _ TRUE; bb.dst _ [word: NIL, bit: 0]; bb.dstBpl _ dstWpl*bitsPerWord; bb.src _ [word: NIL, bit: 0]; bb.flags _ flags; RETURN [bb]; }; FastCharAction: PROC [char: XChar] ~ TRUSTED { bb: PrincOps.BitBltTablePtr ~ bbPtr; m: RasterMask _ NIL; QuickLook: PROC RETURNS [ok: BOOL] ~ CHECKED INLINE { IF Ord[char] IN CommonChar THEN { m _ charArray[Ord[char]]; IF m # NIL THEN RETURN [TRUE]; }; m _ Lookup[char]; RETURN [m#NIL] }; s0, f0: INTEGER; sSize, fSize: NAT; fast: BOOL ~ ( scaledCPValid AND QuickLook[] AND (s0 _ sCP.integerPart + m.sMinBB) >= box.smin AND (f0 _ fCP.integerPart + m.fMinBB) >= box.fmin AND (s0 + (sSize _ LOOPHOLE[m.sSizeBB])) <= box.smax AND (f0 + (fSize _ LOOPHOLE[m.fSizeBB])) <= box.fmax ); IF fast THEN { IF sSize # 0 THEN { bplMask: CARDINAL ~ LAST[CARDINAL]-(bitsPerWord-1); bb.dst.word _ dstBase + Basics.LongMult[Trust[s0], dstWpl] + Trust[f0]/bitsPerWord; bb.dst.bit _ Trust[f0] MOD bitsPerWord; bb.height _ sSize; bb.width _ fSize; bb.src.word _ @m[0]; bb.srcDesc _ [srcBpl[LOOPHOLE[Basics.BITAND[fSize+(bitsPerWord-1), bplMask]]]]; PrincOpsUtils.BITBLT[bb]; }; IF NOT m.amplified THEN { fCP _ fCP.PLUS[m.fWidth]; sCP _ sCP.PLUS[m.sWidth]; } ELSE IF m = lastAmplified THEN { sCP _ sCP.PLUS[sCPAmp]; fCP _ fCP.PLUS[fCPAmp]; } ELSE Amplify[m]; } ELSE { oneChar: XStringProc ~ CHECKED {charAction[char]}; UpdateCP[]; ImagerRasterPrivate.RasterShow[context, oneChar, FALSE]; [] _ TryScaledCP[]; }; }; string[FastCharAction]; UpdateCP[]; } ELSE ImagerRasterPrivate.RasterShow[context, string, xrel]; }; END.