DIRECTORY Basics USING [BITAND, BITNOT, BITOR, bitsPerWord, CARD, LongMult], II, IIBackdoor, IIBox USING [Box, BoxFromExtents, BoxFromRectangle, Rectangle, RectangleFromBox], IIDevice USING [AllowedMasks, DeviceClass, DeviceClassRep, DeviceParm], IIFont USING [Font, FontBoundingBox, Typeface, TypefaceRep, XChar, XStringProc], IIManhattan, IIMaskCache USING [BitmapFromCharMask, BoxesFromCharMask, CharMask, CharMaskRep, MaskCache], IIPath USING [MapOutline, PathProc], IIPixel USING [MakePixelMap, PixelBuffer, PixelMap, Resample], IIPixelArray USING [MaxSampleValue, maxVec, PixelArray, Transfer], IIPrivate, IIRaster USING [Interceptor], IIRasterShow, RefText, IISample, IIScanConverter USING [BoundingBox, ConvertToBoxes, ConvertToManhattanPolygon, Create, CreatePath, DevicePath, GenerateEdges, maxBox, Monotone, SetPath], IIState USING [ChangeFlags, notChanged, RasterData, RasterDataRep, State, StateClip, StateClipRectangle, StateClipRectangleI, StateConcatT, StateCorrect, StateCorrectMask, StateCorrectSpace, StateDontCorrect, StateDoSave, StateGetClipper, StateGetColor, StateGetCP, StateGetFont, StateGetInt, StateGetReal, StateGetT, StateMaskUnderline, StateMove, StateRep, StateRotateT, StateScale2T, StateSetClipper, StateSetColor, StateSetCorrectMeasure, StateSetCorrectTolerance, StateSetFont, StateSetGray, StateSetInt, StateSetReal, StateSetSampledBlack, StateSetSampledColor, StateSetT, StateSetXY, StateSetXYRel, StateSpace, StateStartUnderline, StateTranslateT], IIStroke USING [PathFromStroke, PathFromVector], IITransformation, IITypeface USING [MakeFont, Typeface, TypefaceRep], Process USING [CheckForAbort], Real USING [Fix, Round], RealFns USING [AlmostEqual], Rope USING [ROPE], Scaled USING [Floor, FromReal, Round, Value], SF, Vector2 USING [Div, VEC]; IIRasterImpl: CEDAR PROGRAM IMPORTS Basics, II, IIBackdoor, IIBox, IIFont, IIManhattan, IIMaskCache, IIPath, IIPixel, IIPixelArray, IIPrivate, IIRasterShow, IISample, IIScanConverter, IIState, IIStroke, IITransformation, IITypeface, Process, Real, RealFns, RefText, Scaled, SF, Vector2 EXPORTS II, IIFont, IIRaster, IIRasterShow, IIState ~ BEGIN Class: TYPE ~ IIPrivate.Class; ClassRep: PUBLIC TYPE ~ IIPrivate.ClassRep; -- export to II.ClassRep Typeface: TYPE ~ IITypeface.Typeface; TypefaceRep: PUBLIC TYPE ~ IITypeface.TypefaceRep; -- export to IIFont.TypefaceRep State: TYPE ~ IIState.State; StateRep: PUBLIC TYPE ~ IIState.StateRep; -- export to II.StateRep ROPE: TYPE ~ Rope.ROPE; ChangeFlags: TYPE ~ IIState.ChangeFlags; notChanged: ChangeFlags ~ IIState.notChanged; CharMask: TYPE ~ IIMaskCache.CharMask; CharMaskRep: TYPE ~ IIMaskCache.CharMaskRep; Clipper: TYPE ~ IIBackdoor.Clipper; Color: TYPE ~ II.Color; ColorOperator: TYPE ~ II.ColorOperator; Context: TYPE ~ II.Context; CoordSys: TYPE ~ IIBackdoor.CoordSys; DeviceClass: TYPE ~ IIDevice.DeviceClass; DeviceParm: TYPE ~ IIDevice.DeviceParm; DevicePath: TYPE ~ IIScanConverter.DevicePath; Font: TYPE ~ IIFont.Font; Interceptor: TYPE ~ IIRaster.Interceptor; IntVec: TYPE ~ RECORD [s, f: INT]; ManhattanPolygon: TYPE ~ IIManhattan.Polygon; nullBox: SF.Box ~ [min: [0, 0], max: [0, 0]]; Object: TYPE ~ II.Object; PathProc: TYPE ~ IIPath.PathProc; PixelArray: TYPE ~ IIPixelArray.PixelArray; RawArray: TYPE ~ IISample.RawArray; RawDescriptor: TYPE ~ IISample.RawDescriptor; Rectangle: TYPE ~ IIBox.Rectangle; SampleMap: TYPE ~ IISample.SampleMap; ScanMode: TYPE ~ IITransformation.ScanMode; ShowData: TYPE ~ IIRasterShow.ShowData; ShowDataRep: TYPE ~ IIRasterShow.ShowDataRep; Transformation: TYPE ~ IITransformation.Transformation; Visibility: TYPE ~ IIBackdoor.Visibility; VEC: TYPE ~ Vector2.VEC; XChar: TYPE ~ IIFont.XChar; bitsPerWord: NAT ~ Basics.bitsPerWord; rawArraySize: NAT ~ IISample.rawArraySize; Flags: TYPE ~ RECORD [ clientToDevice: BOOL _ FALSE, -- clientToDevice is valid compositeClipper: BOOL _ FALSE, -- compositeClip and compositeBox are valid fontInfo: BOOL _ FALSE, -- charToDevice and fontAtom are valid fontBB: BOOL _ FALSE, -- fontBB is valid deviceColor: BOOL _ FALSE, -- color last set by SetColor[device, ...] is valid devicePriority: BOOL _ FALSE, -- priority last set by SetPriority[device, ...] is valid unused: [0..1777B] _ 0 ]; RasterData: TYPE ~ REF RasterDataRep; RasterDataRep: PUBLIC TYPE ~ RECORD [ -- Export to IIState.RasterDataRep deviceParm: DeviceParm _ NIL, -- parameters for the particular raster device deviceClass: DeviceClass _ NIL, -- the device class, perhaps layered to call modify proc interceptor: IIRaster.Interceptor _ NIL, devicePath: DevicePath _ NIL, -- scratch storage for scan converter valid: Flags _ [], allow: IIDevice.AllowedMasks _ [FALSE, FALSE, FALSE, FALSE, FALSE, FALSE], deviceClipBox: SF.Box _ nullBox, -- always valid surfaceToDevice: Transformation _ NIL, -- always valid viewToDevice: Transformation _ NIL, -- always valid viewClip: ManhattanPolygon _ NIL, -- deviceClipBox device coords; always valid viewBox: SF.Box _ nullBox, -- bb of viewClip; device coords; always valid clientToDevice: Transformation _ NIL, -- valid iff valid.clientToDevice compositeClip: ManhattanPolygon _ NIL, -- device coords; valid iff valid.compositeClipper compositeBox: SF.Box _ nullBox, -- device coords; valid iff valid.compositeClipper fontAtom: IIFont.Font _ NIL, -- valid iff valid.fontInfo charToDevice: Transformation _ NIL, -- valid iff valid.fontInfo showData: ShowData _ NIL ]; worryNat: NAT ~ LAST[NAT]/2-1; worryReal: REAL _ worryNat; CreateClass: PUBLIC PROC [type: ATOM, deviceClass: DeviceClass] RETURNS [Class] ~ { class: Class ~ NEW [ClassRep _ rasterClassTemplate^]; class.type _ type; IF deviceClass.DrawBitmap = NIL THEN class.DrawBitmap _ NIL; RETURN[class]; }; Create: PUBLIC PROC [class: Class, deviceParm: DeviceParm, data: REF, pixelUnits: BOOL] RETURNS [Context] ~ { rasterData: RasterData ~ NEW [RasterDataRep _ [ deviceParm: deviceParm, deviceClass: deviceParm.class, interceptor: NIL, devicePath: IIScanConverter.Create[], valid: [], deviceClipBox: [max: [deviceParm.sSize, deviceParm.fSize]], surfaceToDevice: IITransformation.XYToSF[deviceParm.scanMode, deviceParm.sSize, deviceParm.fSize], viewToDevice: IITransformation.Scale[1], viewClip: NIL, viewBox: nullBox, clientToDevice: IITransformation.Scale[1], compositeClip: NIL, compositeBox: nullBox, fontAtom: NIL, charToDevice: IITransformation.Scale[1], showData: NEW[ShowDataRep] ]]; state: State ~ NEW[StateRep _ [rasterData: rasterData]]; metersToSurface: VEC ~ Vector2.Div[deviceParm.surfaceUnitsPerInch, II.metersPerInch]; context: Context ~ NEW [II.ContextRep _ [class: class, state: state, data: data]]; state.T _ IF pixelUnits THEN IITransformation.Scale[1] ELSE IITransformation.Scale2[metersToSurface]; state.color _ II.black; RasterViewReset[context]; rasterData.showData.viewToDevice _ rasterData.viewToDevice; rasterData.showData.fontCache _ deviceParm.fontCache; rasterData.showData.deviceParm _ deviceParm; RETURN[context]; }; ValidateClientToDevice: PROC [state: State] ~ { rasterData: RasterData ~ state.rasterData; rasterData.clientToDevice.ApplyCat[state.T, rasterData.viewToDevice]; rasterData.valid.clientToDevice _ TRUE; }; ValidateFontInfo: PROC [context: Context] ~ { state: State ~ context.state; rasterData: RasterData ~ state.rasterData; font: Font ~ state.font; IF font = NIL THEN ERROR II.Error[[code: $noFont, explanation: "Failed to set font before calling Show."]] ELSE { typeface: Typeface ~ font.typeface; IF NOT rasterData.valid.clientToDevice THEN ValidateClientToDevice[state]; rasterData.charToDevice^ _ rasterData.clientToDevice^; rasterData.charToDevice.ApplyTranslateTo[[0, 0]]; rasterData.charToDevice.ApplyPreConcat[font.charToClient]; rasterData.fontAtom _ IITypeface.MakeFont[typeface, rasterData.charToDevice]; rasterData.valid.fontInfo _ TRUE; }; }; ValidateFontBB: PROC [context: Context] ~ { state: State ~ context.state; rasterData: RasterData ~ state.rasterData; font: Font ~ state.font; m: Transformation; Verify[rasterData, [clientToDevice: TRUE]]; m _ IITransformation.Copy[rasterData.clientToDevice]; IITransformation.ApplyTranslateTo[m, [0, 0]]; rasterData.showData.fontBB _ IIBox.BoxFromRectangle[IITransformation.TransformRectangle[m, IIBox.RectangleFromBox[IIBox.BoxFromExtents[IIFont.FontBoundingBox[state.font]]]]]; rasterData.valid.fontBB _ TRUE; IITransformation.Destroy[m]; }; ValidateClientClipper: PROC [context: Context] ~ { state: State ~ context.state; rasterData: RasterData ~ state.rasterData; cc: IIManhattan.Polygon _ NIL; IIManhattan.Destroy[rasterData.compositeClip]; cc _ IIManhattan.Copy[rasterData.viewClip]; cc _ IIManhattan.DestructiveClip[cc, rasterData.deviceClipBox]; FOR each: Clipper _ state.clipper, each.rest UNTIL each=NIL DO Combine: PROC [a, b: ManhattanPolygon] RETURNS [ManhattanPolygon] _ ( IF each.first.exclude THEN IIManhattan.DestructiveDifference ELSE IIManhattan.DestructiveIntersection ); path: PathProc ~ { IIPath.MapOutline[outline: each.first.outline, moveTo: moveTo, lineTo: lineTo, curveTo: curveTo, conicTo: conicTo, arcTo: arcTo] }; devicePath: DevicePath _ IIScanConverter.CreatePath[path: path, transformation: rasterData.viewToDevice, clipBox: rasterData.viewBox, scratch: rasterData.devicePath]; this: ManhattanPolygon _ IIScanConverter.ConvertToManhattanPolygon[devicePath: devicePath, clipBox: rasterData.viewBox, oddWrap: each.first.oddWrap]; cc _ Combine[cc, this]; IIManhattan.Destroy[this]; ENDLOOP; rasterData.compositeClip _ cc; rasterData.compositeBox _ IIManhattan.BoundingBox[cc]; rasterData.valid.compositeClipper _ TRUE; }; ValidateColor: PROC [context: Context] ~ { state: State ~ context.state; rasterData: RasterData ~ state.rasterData; rasterData.allow _ rasterData.deviceClass.SetColor[context, state.color, rasterData.viewToDevice]; rasterData.valid.deviceColor _ TRUE; }; ValidatePriority: PROC [context: Context] ~ { state: State ~ context.state; rasterData: RasterData ~ state.rasterData; IF rasterData.deviceParm.class.SetPriority # NIL THEN rasterData.deviceClass.SetPriority[context, state.np.priorityImportant#0]; rasterData.valid.devicePriority _ TRUE; }; OrFlags: PROC [f1, f2: Flags] RETURNS [Flags] ~ INLINE { RETURN[LOOPHOLE[Basics.BITOR[LOOPHOLE[f1], LOOPHOLE[f2]]]]; }; AndFlags: PROC [f1, f2: Flags] RETURNS [Flags] ~ INLINE { RETURN[LOOPHOLE[Basics.BITAND[LOOPHOLE[f1], LOOPHOLE[f2]]]]; }; NotFlags: PROC [f: Flags] RETURNS [Flags] ~ INLINE { RETURN[LOOPHOLE[Basics.BITNOT[LOOPHOLE[f]]]]; }; NoteStateChanges: PUBLIC PROC [context: Context] ~ { state: State ~ context.state; rasterData: RasterData ~ state.rasterData; changed: IIState.ChangeFlags ~ state.changed; state.changed _ IIState.notChanged; IF changed.T THEN rasterData.valid.clientToDevice _ rasterData.valid.fontInfo _ rasterData.valid.fontBB _ FALSE; IF changed.color THEN rasterData.valid.deviceColor _ FALSE; IF changed.priority THEN rasterData.valid.devicePriority _ FALSE; IF changed.clipper THEN rasterData.valid.compositeClipper _ FALSE; IF changed.font THEN rasterData.valid.fontInfo _ rasterData.valid.fontBB _ FALSE; }; ValidateIfNeeded: PUBLIC PROC [context: Context, needs: Flags] ~ { state: State ~ context.state; rasterData: RasterData ~ state.rasterData; fix: Flags ~ AndFlags[needs, NotFlags[rasterData.valid]]; IF fix.clientToDevice THEN ValidateClientToDevice[state]; IF fix.deviceColor THEN ValidateColor[context]; IF fix.devicePriority THEN ValidatePriority[context]; IF fix.compositeClipper THEN ValidateClientClipper[context]; IF fix.fontInfo THEN ValidateFontInfo[context]; IF fix.fontBB THEN ValidateFontBB[context]; IF AndFlags[rasterData.valid, needs]#needs THEN ERROR; }; Validate: PROC [context: Context, needs: Flags] ~ INLINE { state: State ~ context.state; rasterData: RasterData ~ state.rasterData; IF state.changed#IIState.notChanged THEN NoteStateChanges[context]; IF AndFlags[rasterData.valid, needs]#needs THEN ValidateIfNeeded[context, needs]; }; Verify: PROC [rasterData: RasterData, needs: Flags] ~ INLINE { IF AndFlags[rasterData.valid, needs]#needs THEN ERROR; }; GetDeviceParm: PUBLIC PROC [context: Context] RETURNS [DeviceParm] ~ { state: State ~ context.state; rasterData: RasterData ~ state.rasterData; RETURN [rasterData.deviceParm] }; ValidateState: PUBLIC PROC [context: Context] RETURNS [IIDevice.AllowedMasks] ~ { state: State ~ context.state; rasterData: RasterData ~ state.rasterData; Validate[context, [deviceColor: TRUE, devicePriority: TRUE]]; RETURN [rasterData.allow]; }; GetShowData: PUBLIC PROC [context: Context] RETURNS [ShowData] ~ { state: State ~ context.state; rasterData: RasterData ~ state.rasterData; showData: ShowData ~ rasterData.showData; Validate[context, [deviceColor: TRUE, devicePriority: TRUE, fontInfo: TRUE, compositeClipper: TRUE, fontBB: TRUE]]; showData.fontAtom _ rasterData.fontAtom; showData.clipBounds _ rasterData.compositeBox; showData.deviceClass _ rasterData.deviceClass; showData.allow _ rasterData.allow; RETURN [showData] }; SMul: PROC [a: INTEGER, b: INTEGER] RETURNS [INT] ~ INLINE {RETURN [IF a#0 THEN Smul[a,b] ELSE 0]}; Smul: PROC [a: INTEGER, b: INTEGER] RETURNS [INT] ~ { HighBit: PROC [a: INTEGER] RETURNS [[0..1]] ~ INLINE { RETURN [LOOPHOLE[a, PACKED ARRAY [0..Basics.bitsPerWord) OF [0..1]][0]]; }; Card: PROC [i: INTEGER] RETURNS [NAT] ~ INLINE {RETURN [LOOPHOLE[i]]}; SELECT HighBit[a]*2+HighBit[b] FROM 0 => RETURN [Basics.LongMult[Card[a], Card[b]]]; 1 => RETURN [-Basics.LongMult[Card[a], Card[-b]]]; 2 => RETURN [-Basics.LongMult[Card[-a], Card[b]]]; 3 => RETURN [Basics.LongMult[Card[-a], Card[-b]]]; ENDCASE => ERROR; }; IsAllInteger: PROC [m: Transformation] RETURNS [BOOL] ~ { Is: PROC [r: REAL] RETURNS [BOOL] ~ { IF r IN [-worryReal..worryReal] THEN { ir: INT ~ Real.Round[r]; IF r = ir THEN RETURN [TRUE]; IF RealFns.AlmostEqual[r, Real.Round[r], -18] THEN RETURN [TRUE]; }; RETURN [FALSE]; }; RETURN [Is[m.a] AND Is[m.b] AND Is[m.c] AND Is[m.d] AND Is[m.e] AND Is[m.f]]; }; Floor: PROC [r: REAL] RETURNS [i: INT] ~ INLINE { i _ Real.Round[r]; IF i > r THEN i _ i - 1; }; Ceiling: PROC [r: REAL] RETURNS [i: INT] ~ INLINE { i _ Real.Round[r]; IF i < r THEN i _ i + 1; }; ClippedBounds: PROC [clipBox: SF.Box, p0, p1: IntVec] RETURNS [SF.Box] ~ { IF p0.s > p1.s THEN {t: INT _ p0.s; p0.s _ p1.s; p1.s _ t}; IF p0.f > p1.f THEN {t: INT _ p0.f; p0.f _ p1.f; p1.f _ t}; p0.s _ MAX[p0.s, clipBox.min.s]; p0.f _ MAX[p0.f, clipBox.min.f]; p1.s _ MIN[p1.s, clipBox.max.s]; p1.f _ MIN[p1.f, clipBox.max.f]; IF p0.s < p1.s AND p0.f < p1.f THEN RETURN [[min: [p0.s, p0.f], max: [p1.s, p1.f]]] ELSE RETURN [[min: clipBox.min, max: clipBox.min]]; }; MaskDeviceBoxes: PUBLIC PROC [context: Context, bounds: SF.Box, boxes: SF.BoxGenerator] ~ { state: State ~ context.state; rasterData: RasterData ~ state.rasterData; Validate[context, maskNeeds]; IF rasterData.compositeClip # NIL THEN { IF SF.Inside[bounds, rasterData.compositeClip.first] -- AND rasterData.allow.unorderedBoxes -- THEN {rasterData.deviceClass.MaskBoxes[context: context, bounds: bounds, boxes: boxes]} ELSE { manhattan: IIManhattan.Polygon ~ IIManhattan.DestructiveIntersection[IIManhattan.CreateFromBoxes[boxes], rasterData.compositeClip]; IF manhattan # NIL THEN { ManhattanBoxes: SF.BoxGenerator ~ { FOR each: LIST OF SF.Box _ manhattan, each.rest UNTIL each=NIL DO boxAction[each.first]; ENDLOOP; }; rasterData.deviceClass.MaskBoxes[context: context, bounds: IIManhattan.BoundingBox[manhattan], boxes: ManhattanBoxes]; IIManhattan.Destroy[manhattan]; }; }; }; }; boxesFromPathNeeds: Flags ~ [compositeClipper: TRUE]; BoxesFromPath: PROC [rasterData: RasterData, path: PathProc, oddWrap: BOOL _ FALSE, transformation: Transformation _ NIL, action: PROC [bounds: SF.Box, boxGenerator: SF.BoxGenerator] ] ~ { clipBox: SF.Box ~ rasterData.compositeBox; clipMask: ManhattanPolygon ~ rasterData.compositeClip; devicePath: DevicePath ~ IIScanConverter.CreatePath[path: path, transformation: transformation, clipBox: clipBox, scratch: rasterData.devicePath]; pathBox: SF.Box ~ IIScanConverter.BoundingBox[devicePath]; bounds: SF.Box ~ SF.Intersect[pathBox, clipBox]; runs: --SF.BoxGenerator-- PROC [boxAction: SF.BoxAction] ~ { IF clipMask#NIL AND clipMask.rest=NIL THEN { IIScanConverter.ConvertToBoxes[devicePath: devicePath, oddWrap: oddWrap, clipBox: clipMask.first, boxAction: boxAction]; } ELSE { rem: ManhattanPolygon _ clipMask; clipBoxAction: --SF.BoxAction-- PROC [box: SF.Box] ~ { WHILE rem#NIL AND rem.first.max.s<=box.min.s DO rem _ rem.rest ENDLOOP; FOR l: LIST OF SF.Box _ rem, l.rest UNTIL l=NIL OR l.first.min.s>=box.max.s DO clipped: SF.Box ~ SF.Intersect[box, l.first]; IF SF.Nonempty[clipped] THEN boxAction[clipped]; ENDLOOP; }; IIScanConverter.ConvertToBoxes[devicePath: devicePath, oddWrap: oddWrap, clipBox: clipBox, boxAction: clipBoxAction]; }; }; Verify[rasterData, boxesFromPathNeeds]; Process.CheckForAbort[]; action[bounds, runs]; }; maskBoxesNeeds: Flags ~ OrFlags[boxesFromPathNeeds, [deviceColor: TRUE, devicePriority: TRUE]]; MaskFillViaBoxes: PROC [context: Context, path: PathProc, oddWrap: BOOL _ FALSE, transformation: Transformation _ NIL] ~ { state: State ~ context.state; rasterData: RasterData ~ state.rasterData; maskBoxesAction: PROC [bounds: SF.Box, boxGenerator: SF.BoxGenerator] ~ { rasterData.deviceClass.MaskBoxes[context: context, bounds: bounds, boxes: boxGenerator]; }; Verify[rasterData, maskBoxesNeeds]; BoxesFromPath[rasterData: rasterData, path: path, oddWrap: oddWrap, transformation: transformation, action: maskBoxesAction]; }; ClipBoxToMask: PUBLIC PROC [box: SF.Box, mask: ManhattanPolygon, action: PROC [SF.Box]] ~ { FOR list: LIST OF SF.Box _ mask, list.rest UNTIL list=NIL DO c: SF.Box ~ SF.Intersect[box, list.first]; IF SF.Nonempty[c] THEN action[c]; ENDLOOP; }; maskNeeds: Flags ~ OrFlags[maskBoxesNeeds, [clientToDevice: TRUE]]; RasterMaskFill: PROC [context: Context, path: PathProc, oddWrap: BOOL] ~ { state: State ~ context.state; IF state.np.noImage=0 THEN { rasterData: RasterData ~ state.rasterData; Validate[context, maskNeeds]; MaskFillViaBoxes[context: context, path: path, oddWrap: oddWrap, transformation: rasterData.clientToDevice]; }; }; RasterMaskRectangle: PROC [context: Context, r: Rectangle] ~ { state: State ~ context.state; IF state.np.noImage=0 THEN { rasterData: RasterData ~ state.rasterData; deviceClass: DeviceClass ~ rasterData.deviceClass; Validate[context, maskNeeds]; IF rasterData.clientToDevice.form # 0 AND (rasterData.allow.unorderedBoxes OR rasterData.compositeClip = NIL OR rasterData.compositeClip.rest = NIL) THEN { clientToDevice: Transformation ~ rasterData.clientToDevice; clip: SF.Box ~ rasterData.compositeBox; p0: VEC ~ IITransformation.Transform[clientToDevice, [r.x, r.y]]; p1: VEC ~ IITransformation.Transform[clientToDevice, [r.x+r.w, r.y+r.h]]; s0: INT _ Real.Fix[MAX[MIN[p0.x+0.5, clip.max.s], clip.min.s]]; s1: INT _ Real.Fix[MAX[MIN[p1.x+0.5, clip.max.s], clip.min.s]]; f0: INT _ Real.Fix[MAX[MIN[p0.y+0.5, clip.max.f], clip.min.f]]; f1: INT _ Real.Fix[MAX[MIN[p1.y+0.5, clip.max.f], clip.min.f]]; Process.CheckForAbort[]; IF s1 { delta: SF.Vec ~ [s: maskToDevice.tx, f: maskToDevice.ty]; box: SF.Box ~ SF.Intersect[rasterData.compositeBox, SF.Displace[IISample.GetBox[bitmap], delta]]; boxes: PROC [action: PROC[SF.Box]] ~ { ClipBoxToMask[box: box, mask: rasterData.compositeClip, action: action] }; deviceClass.MaskBitmap[context: context, bitmap: bitmap, delta: delta, bounds: box, boxes: boxes]; }; maskToDevice.form#0 AND rasterData.allow.unorderedBoxes AND IsAllInteger[maskToDevice] => { a: INTEGER ~ Real.Round[maskToDevice.a]; b: INTEGER ~ Real.Round[maskToDevice.b]; c: INTEGER ~ maskToDevice.tx; d: INTEGER ~ Real.Round[maskToDevice.d]; e: INTEGER ~ Real.Round[maskToDevice.e]; f: INTEGER ~ maskToDevice.ty; Map: PROC [p: SF.Vec] RETURNS [IntVec] ~ {RETURN [[SMul[a, p.s] + SMul[b, p.f] + c, SMul[d, p.s] + SMul[e, p.f] + f]]}; srcBox: SF.Box ~ IISample.GetBox[bitmap]; -- Overall bounds, in source bitmap coordinates; dstBox: SF.Box ~ ClippedBounds[rasterData.compositeBox, Map[srcBox.min], Map[srcBox.max]]; -- Overall bounds, in device coordinates; boxGenerator: --SF.BoxGenerator-- PROC [boxAction: SF.BoxAction] ~ { FOR each: LIST OF SF.Box _ rasterData.compositeClip, each.rest UNTIL each = NIL DO visibleBox: SF.Box ~ SF.Intersect[dstBox, each.first]; IF SF.Nonempty[visibleBox] THEN { srcVisibleRealBox: IIBox.Box ~ IIBox.BoxFromRectangle[ IITransformation.InverseTransformRectangle[maskToDevice, [ x: visibleBox.min.s, y: visibleBox.min.f, w: visibleBox.max.s-visibleBox.min.s, h: visibleBox.max.f-visibleBox.min.f]] ]; srcVisibleBox: SF.Box ~ ClippedBounds[clipBox: srcBox, p0: [Floor[srcVisibleRealBox.xmin], Floor[srcVisibleRealBox.ymin]], p1: [Ceiling[srcVisibleRealBox.xmax], Ceiling[srcVisibleRealBox.ymax]] ]; processPartiallyVisibleBox: --SF.BoxAction-- PROC [box: SF.Box] ~ { clippedBox: SF.Box ~ ClippedBounds[visibleBox, Map[box.min], Map[box.max]]; IF SF.Nonempty[clippedBox] THEN boxAction[clippedBox]; }; visibleBitmap: SampleMap ~ IISample.Clip[bitmap, srcVisibleBox]; IISample.BoxesFromBitmap[map: visibleBitmap, boxAction: processPartiallyVisibleBox]; TRUSTED {IISample.ReleaseDescriptor[visibleBitmap]}; }; ENDLOOP; }; rasterData.deviceClass.MaskBoxes[context: context, bounds: dstBox, boxes: boxGenerator]; }; rasterData.allow.unorderedBoxes AND IITransformation.SingularValues[maskToDevice].y > 1.0 => FastHardMaskSampledBits[context, bitmap, maskToDevice]; ENDCASE => HardMaskSampledBits[context, bitmap, maskToDevice]; }; FastHardMaskSampledBits: PROC [context: Context, bitmap: SampleMap, maskToDevice: Transformation] ~ { deviceToView: Transformation ~ IIBackdoor.GetTransformation[context: context, from: device, to: view]; maskToView: Transformation ~ IITransformation.Concat[maskToDevice, deviceToView]; proc: PROC ~ { box: SF.Box _ IISample.GetBox[bitmap]; clip: IIBox.Box; IIBackdoor.SetT[context, maskToView]; clip _ IIBox.BoxFromRectangle[IIBackdoor.GetBounds[context]]; IF box.min.s < clip.xmin THEN box.min.s _ Floor[clip.xmin]; IF box.min.f < clip.ymin THEN box.min.f _ Floor[clip.ymin]; IF box.max.s > clip.xmax THEN box.max.s _ Ceiling[clip.xmax]; IF box.max.f > clip.ymax THEN box.max.f _ Ceiling[clip.ymax]; IF SF.Nonempty[box] THEN { bytes: NAT ~ (box.max.f-box.min.f+7)/8; textBuf: REF TEXT ~ RefText.ObtainScratch[nChars: bytes]; String: II.XStringProc ~ { FOR i: NAT IN [0..bytes) DO charAction[[set: 0, code: ORD[textBuf[i]]]]; ENDLOOP; }; textBufAsSampleMap: SampleMap _ NIL; TRUSTED { pointer: LONG POINTER ~ LOOPHOLE[textBuf, LONG POINTER] + SIZE[TEXT[0]]; textBufAsSampleMap _ IISample.ObtainUnsafeDescriptor[size: [s: 1, f: box.max.f-box.min.f], bitsPerSample: 1, bitsPerLine: bytes*8, base: [word: pointer, bit: 0], ref: textBuf, words: SIZE[TEXT[textBuf.maxLength]]-SIZE[TEXT[0]]]; }; IISample.Clear[textBufAsSampleMap]; II.SetFont[context, IIRasterShow.BitFont[]]; FOR s: INTEGER IN [box.min.s..box.max.s) DO IISample.BasicTransfer[dst: textBufAsSampleMap, src: bitmap, srcMin: [s, box.min.f], size: [1, box.max.f-box.min.f]]; II.SetXY[context, [s, box.min.f]]; II.Show[context, String]; ENDLOOP; TRUSTED { IISample.ReleaseDescriptor[textBufAsSampleMap] }; RefText.ReleaseScratch[textBuf]; }; }; II.DoSaveAll[context, proc]; IITransformation.Destroy[deviceToView]; IITransformation.Destroy[maskToView]; }; HardMaskSampledBits: PROC [context: Context, bitmap: SampleMap, maskToDevice: Transformation] ~ { state: State ~ context.state; rasterData: RasterData ~ state.rasterData; srcBox: SF.Box ~ IISample.GetBox[bitmap]; maskBoundary: PathProc ~ { x0: REAL ~ srcBox.min.s; y0: REAL ~ srcBox.min.f; x1: REAL ~ srcBox.max.s; y1: REAL ~ srcBox.max.f; moveTo[[x0, y0]]; lineTo[[x1, y0]]; lineTo[[x1, y1]]; lineTo[[x0, y1]]; }; Nest1: PROC [bounds: SF.Box, boxGenerator: SF.BoxGenerator] ~ { Nest2: --SF.BoxGenerator-- PROC [boxAction: SF.BoxAction] ~ { pixelMap: IIPixel.PixelMap ~ IIPixel.MakePixelMap[bitmap]; Nest3: --IIPixel.ResampleAction-- PROC [pixels: IIPixel.PixelBuffer, min: SF.Vec] ~ { count: NAT ~ pixels.length; buffer: IISample.SampleBuffer ~ pixels[0]; state: {off, on} _ off; f0: NAT _ 0; FOR f: NAT IN [0..count) DO x: IISample.Sample ~ buffer[f]; SELECT state FROM off => IF x#0 THEN { f0 _ f; state _ on }; on => IF x=0 THEN { boxAction[[min: [min.s, min.f+f0], max: [min.s+1, min.f+f]]]; state _ off }; ENDCASE => ERROR; ENDLOOP; IF state=on THEN boxAction[[min: [min.s, min.f+f0], max: [min.s+1, min.f+count]]]; }; IIPixel.Resample[self: pixelMap, m: maskToDevice, interpolate: FALSE, boxes: boxGenerator, bounds: bounds, action: Nest3]; }; rasterData.deviceClass.MaskBoxes[context: context, bounds: bounds, boxes: Nest2]; }; BoxesFromPath[rasterData: rasterData, path: maskBoundary, transformation: maskToDevice, action: Nest1]; }; RasterMaskBitmap: PROC [context: Context, bitmap: SampleMap, referencePoint: SF.Vec, scanMode: ScanMode, position: VEC] ~ { state: State ~ context.state; Validate[context, maskNeeds]; IF state.np.noImage=0 THEN { rasterData: RasterData ~ state.rasterData; m: Transformation _ IITransformation.Copy[rasterData.clientToDevice]; IITransformation.ApplyPreTranslate[m, position]; IITransformation.ApplySFToXY[m, scanMode, 0, 0]; IITransformation.ApplyPreTranslate[m, [-referencePoint.s, -referencePoint.f]]; MaskSampledBits[context: context, bitmap: bitmap, maskToDevice: m]; IITransformation.Destroy[m]; }; }; RasterDrawBitmap: PROC [context: Context, bitmap: SampleMap, referencePoint: SF.Vec, scanMode: ScanMode, position: VEC] ~ { state: State ~ context.state; Validate[context, maskNeeds]; IF state.np.noImage=0 THEN { rasterData: RasterData ~ state.rasterData; deviceClass: DeviceClass ~ rasterData.deviceClass; m: Transformation _ IITransformation.Copy[rasterData.clientToDevice]; IITransformation.ApplyPreTranslate[m, position]; IITransformation.ApplySFToXY[m, scanMode, 0, 0]; IITransformation.ApplyPreTranslate[m, [-referencePoint.s, -referencePoint.f]]; IF m.form=3 AND m.integerTrans AND rasterData.deviceParm.class.DrawBitmap # NIL THEN { delta: SF.Vec ~ [s: m.tx, f: m.ty]; box: SF.Box ~ SF.Intersect[rasterData.compositeBox, SF.Displace[IISample.GetBox[bitmap], delta]]; boxes: PROC [action: PROC [SF.Box]] ~ { ClipBoxToMask[box: box, mask: rasterData.compositeClip, action: action] }; deviceClass.DrawBitmap[context: context, bitmap: bitmap, delta: delta, bounds: box, boxes: boxes]; } ELSE IIPrivate.DefaultDrawBitmap[context, bitmap, referencePoint, scanMode, position]; IITransformation.Destroy[m]; }; }; bitsPerChunk: INT _ 100000; RasterMaskPixel: PROC [context: Context, pa: PixelArray] ~ { state: State ~ context.state; IF pa.samplesPerPixel#1 THEN ERROR II.Error[[code: $illegalPixelMask, explanation: "MaskPixel argument must have one sample per pixel."]]; IF IIPixelArray.MaxSampleValue[pa, 0]#1 THEN ERROR II.Error[[code: $illegalPixelMask, explanation: "MaskPixel argument must have one bit per sample."]]; Validate[context, maskNeeds]; IF state.np.noImage=0 THEN TRUSTED { rasterData: RasterData ~ state.rasterData; sBufSize: NAT ~ MIN[pa.sSize, MAX[((bitsPerChunk+pa.fSize-1)/pa.fSize+15)/16, 1]*16]; scratch: IISample.SampleMap ~ IISample.ObtainScratchMap[box: [max: [sBufSize, pa.fSize]]]; bitmap: IISample.SampleMap _ scratch; maskToDevice: Transformation _ IITransformation.Concat[pa.m, rasterData.clientToDevice]; FOR s: INT _ 0, s+sBufSize WHILE s < pa.sSize DO IF pa.sSize-s < sBufSize THEN bitmap _ IISample.Clip[scratch, [max: [s: pa.sSize-s, f: pa.fSize]]]; IIPixelArray.Transfer[self: pa, dst: bitmap, s: s]; MaskSampledBits[context: context, bitmap: bitmap, maskToDevice: maskToDevice]; IITransformation.ApplyPreTranslate[maskToDevice, [sBufSize, 0]]; ENDLOOP; IF bitmap # scratch THEN TRUSTED { IISample.ReleaseDescriptor[bitmap] }; IISample.ReleaseScratchMap[scratch]; IITransformation.Destroy[maskToDevice]; }; }; MaskCharMask: PUBLIC PROC [context: Context, charMask: CharMask] RETURNS [ok: BOOL _ FALSE] ~ { state: State ~ context.state; rasterData: RasterData ~ state.rasterData; cp: VEC _ rasterData.viewToDevice.Transform[state.p.cp]; Verify[rasterData, [compositeClipper: TRUE]]; IF rasterData.compositeClip = NIL THEN RETURN [ok: TRUE]; IF charMask#NIL AND ABS[cp.x] < worryReal AND ABS[cp.y] < worryReal THEN { sCP: Scaled.Value ~ Scaled.FromReal[cp.x]; fCP: Scaled.Value ~ Scaled.FromReal[cp.y]; s: INTEGER ~ Scaled.Round[sCP]; f: INTEGER ~ Scaled.Round[fCP]; box: SF.Box ~ SF.Displace[charMask.box, [s, f]]; dstBox: SF.Box ~ SF.Intersect[box, rasterData.compositeBox]; IF SF.Empty[dstBox] THEN RETURN [ok: TRUE]; IF charMask.rep = culled OR charMask.rep = maskNotCacheable THEN RETURN [ok: FALSE]; -- only the metrics were in cache IF SF.Inside[box, rasterData.compositeClip.first] AND ((charMask.rep = raster AND rasterData.allow.rasterChar) OR (charMask.rep = runs AND rasterData.allow.runGroupChar)) THEN { rasterData.deviceClass.MaskChar[context: context, delta: [s, f], mask: charMask]; RETURN [ok: TRUE]; }; IF charMask.rep = raster AND rasterData.allow.bitmap THEN { bitmap: SampleMap ~ IIMaskCache.BitmapFromCharMask[charMask]; boxes: PROC [action: PROC[SF.Box]] ~ { ClipBoxToMask[box: dstBox, mask: rasterData.compositeClip, action: action] }; rasterData.deviceClass.MaskBitmap[context: context, bitmap: bitmap, delta: [s, f], bounds: dstBox, boxes: boxes]; TRUSTED { IISample.ReleaseDescriptor[bitmap] }; } ELSE { boxGenerator: --SF.BoxGenerator-- PROC [boxAction: SF.BoxAction] ~ { FOR each: LIST OF SF.Box _ rasterData.compositeClip, each.rest UNTIL each = NIL DO IIMaskCache.BoxesFromCharMask[charMask: charMask, boxAction: boxAction, delta: [s, f], clip: each.first]; ENDLOOP; }; rasterData.deviceClass.MaskBoxes[context: context, bounds: dstBox, boxes: boxGenerator]; }; RETURN [ok: TRUE]; }; }; GetContainingBox: PUBLIC PROC [context: Context, p: SF.Vec] RETURNS [SF.Box] ~ { state: State ~ context.state; rasterData: RasterData ~ state.rasterData; Validate[context, [compositeClipper: TRUE]]; FOR each: LIST OF SF.Box _ rasterData.compositeClip, each.rest UNTIL each = NIL DO box: SF.Box ~ each.first; IF each.rest = NIL OR SF.In[p, box] THEN RETURN [box]; ENDLOOP; RETURN [[]]; }; GetDeviceClipBox: PUBLIC PROC [context: Context] RETURNS [SF.Box] ~ { state: State ~ context.state; rasterData: RasterData ~ state.rasterData; RETURN [rasterData.deviceClipBox] }; SetDeviceClipBox: PUBLIC PROC [context: Context, clipBox: SF.Box] ~ { state: State ~ context.state; rasterData: RasterData ~ state.rasterData; rasterData.deviceClipBox _ clipBox; rasterData.valid.compositeClipper _ FALSE; }; RasterGetBounds: PROC [context: Context] RETURNS [Rectangle] ~ { state: State ~ context.state; rasterData: RasterData ~ state.rasterData; Validate[context, [clientToDevice: TRUE, compositeClipper: TRUE]]; { box: SF.Box ~ rasterData.compositeBox; size: SF.Vec ~ SF.Size[box]; m: Transformation ~ rasterData.clientToDevice; r: Rectangle ~ m.InverseTransformRectangle[[x: box.min.s, y: box.min.f, w: size.s, h: size.f]]; RETURN[r]; }; }; RasterTestViewRectangle: PUBLIC PROC [context: Context, x, y, w, h: INTEGER] RETURNS [Visibility] ~ { state: State ~ context.state; rasterData: RasterData ~ state.rasterData; viewToDevice: Transformation ~ rasterData.viewToDevice; viewClip: ManhattanPolygon ~ rasterData.viewClip; IF viewClip = NIL THEN RETURN [none]; IF IITransformation.EasyTransformation[viewToDevice] THEN { box: SF.Box ~ IITransformation.EasyTransformBox[m: viewToDevice, x: x, y: y, w: w, h: h, clip: SF.maxBox]; IF SF.Inside[box, SF.Intersect[viewClip.first, rasterData.deviceClipBox]] THEN RETURN [all]; IF SF.Empty[SF.Intersect[box, rasterData.viewBox]] THEN RETURN [none]; }; RETURN [part]; }; RasterDoWithBuffer: PROC [context: Context, action: PROC, x, y, w, h: INTEGER, backgroundColor: Color] ~ { state: State ~ context.state; rasterData: RasterData ~ state.rasterData; deviceClass: DeviceClass ~ rasterData.deviceClass; IF rasterData.deviceParm.class.DoBuffered # NIL THEN { Validate[context, [clientToDevice: TRUE]]; IF IITransformation.EasyTransformation[rasterData.clientToDevice] THEN { oldDeviceClipBox: SF.Box ~ rasterData.deviceClipBox; box: SF.Box ~ IITransformation.EasyTransformBox[m: rasterData.clientToDevice, x: x, y: y, w: w, h: h, clip: SF.Intersect[rasterData.viewBox, oldDeviceClipBox]]; fillAction: PROC ~ { savedColor: Color ~ state.color; II.SetColor[context, backgroundColor]; II.MaskRectangleI[context, x, y, w, h]; II.SetColor[context, savedColor]; action[]; }; saveAction: PROC ~ { II.DoSaveAll[context, IF backgroundColor=NIL THEN action ELSE fillAction]; }; rasterData.deviceClipBox _ box; rasterData.valid.compositeClipper _ FALSE; Validate[context, [compositeClipper: TRUE]]; IF rasterData.compositeClip # NIL THEN deviceClass.DoBuffered[ context: context, bounds: box, copy: backgroundColor=NIL OR NOT SF.Inside[box, rasterData.compositeClip.first], action: saveAction ! UNWIND => SetDeviceClipBox[context, oldDeviceClipBox]]; rasterData.deviceClipBox _ oldDeviceClipBox; rasterData.valid.compositeClipper _ FALSE; RETURN; }; }; IIPrivate.DefaultDoWithBuffer[context: context, action: action, x: x, y: y, w: w, h: h, backgroundColor: backgroundColor]; }; RasterViewReset: PROC [context: Context] ~ { state: State ~ context.state; rasterData: RasterData ~ state.rasterData; rasterData.viewToDevice^ _ rasterData.surfaceToDevice^; rasterData.viewBox _ [max: [rasterData.deviceParm.sSize, rasterData.deviceParm.fSize]]; IIManhattan.Destroy[rasterData.viewClip]; rasterData.viewClip _ IIManhattan.CreateFromBox[rasterData.viewBox]; rasterData.valid.clientToDevice _ FALSE; rasterData.valid.compositeClipper _ FALSE; rasterData.valid.fontInfo _ FALSE; rasterData.valid.deviceColor _ FALSE; }; RasterViewTranslateI: PROC [context: Context, x, y: INTEGER] ~ { state: State ~ context.state; rasterData: RasterData ~ state.rasterData; rasterData.viewToDevice.ApplyPreTranslate[[x, y]]; rasterData.valid.clientToDevice _ FALSE; rasterData.valid.compositeClipper _ FALSE; rasterData.valid.deviceColor _ FALSE; }; RasterViewClipRectangleI: PROC [context: Context, x, y, w, h: INTEGER, exclude: BOOL] ~ { state: State ~ context.state; rasterData: RasterData ~ state.rasterData; viewToDevice: Transformation ~ rasterData.viewToDevice; IF IITransformation.EasyTransformation[viewToDevice] THEN { old: ManhattanPolygon ~ rasterData.viewClip; box: SF.Box ~ IITransformation.EasyTransformBox[m: viewToDevice, x: x, y: y, w: w, h: h, clip: rasterData.viewBox]; v: ManhattanPolygon _ rasterData.viewClip; IF exclude THEN { t: ManhattanPolygon ~ IIManhattan.CreateFromBox[box]; v _ IIManhattan.DestructiveDifference[v, t]; IIManhattan.Destroy[t] } ELSE v _ IIManhattan.DestructiveClip[v, box]; rasterData.viewClip _ v; rasterData.viewBox _ IIManhattan.BoundingBox[v]; rasterData.valid.compositeClipper _ FALSE; } ELSE { path: PathProc ~ {moveTo[[x,y]]; lineTo[[x+w,y]]; lineTo[[x+w,y+h]]; lineTo[[x,y+h]]}; RasterViewClip[context: context, path: path, oddWrap: FALSE, exclude: exclude]; }; }; RasterGetTransformation: PROC [context: Context, from, to: CoordSys] RETURNS [Transformation] ~ { state: State ~ context.state; rasterData: RasterData ~ state.rasterData; m: Transformation _ NIL; Validate[context, [clientToDevice: TRUE]]; SELECT to FROM client => m _ IITransformation.Copy[rasterData.clientToDevice]; view => m _ IITransformation.Copy[rasterData.viewToDevice]; surface => m _ IITransformation.Copy[rasterData.surfaceToDevice]; device => m _ IITransformation.Scale[1.0]; ENDCASE => ERROR; IITransformation.ApplyInvert[m]; SELECT from FROM client => IITransformation.ApplyPreConcat[m, rasterData.clientToDevice]; view => IITransformation.ApplyPreConcat[m, rasterData.viewToDevice]; surface => IITransformation.ApplyPreConcat[m, rasterData.surfaceToDevice]; device => NULL; ENDCASE => ERROR; RETURN [m] }; RasterViewClip: PROC [context: Context, path: PathProc, oddWrap: BOOL, exclude: BOOL] ~ { state: State ~ context.state; rasterData: RasterData ~ state.rasterData; this: ManhattanPolygon; Combine: PROC [a, b: ManhattanPolygon] RETURNS [ManhattanPolygon] _ ( IF exclude THEN IIManhattan.DestructiveDifference ELSE IIManhattan.DestructiveIntersection ); IIScanConverter.SetPath[devicePath: rasterData.devicePath, path: path, transformation: rasterData.viewToDevice, clipBox: rasterData.viewBox]; this _ IIScanConverter.ConvertToManhattanPolygon[devicePath: rasterData.devicePath, clipBox: rasterData.viewBox, oddWrap: oddWrap]; rasterData.viewClip _ Combine[rasterData.viewClip, this]; IIManhattan.Destroy[this]; rasterData.viewBox _ IIManhattan.BoundingBox[rasterData.viewClip]; rasterData.valid.compositeClipper _ FALSE; }; RasterMoveViewRectangle: PROC [context: Context, width, height, fromX, fromY, toX, toY: INTEGER] ~ { state: State ~ context.state; rasterData: RasterData ~ state.rasterData; deviceClass: DeviceClass ~ rasterData.deviceClass; viewToDevice: Transformation ~ rasterData.viewToDevice; IF IITransformation.EasyTransformation[viewToDevice] AND rasterData.deviceParm.class.MoveBox # NIL THEN { clipBox: SF.Box ~ SF.Intersect[rasterData.viewBox, rasterData.deviceClipBox]; srcBox: SF.Box ~ IITransformation.EasyTransformBox[m: viewToDevice, x: fromX, y: fromY, w: width, h: height, clip: clipBox]; dstBox: SF.Box ~ IITransformation.EasyTransformBox[m: viewToDevice, x: toX, y: toY, w: width, h: height, clip: clipBox]; size: SF.Vec ~ SF.Size[srcBox]; IF SF.Size[dstBox] = size THEN { deviceClass.MoveBox[context: context, dstMin: dstBox.min, srcMin: srcBox.min, size: size]; RETURN; }; }; ERROR II.Error[[$unimplemented, "MoveViewRectangle not implemented for this case"]]; }; ModifySetColor: PROC [context: Context, color: Color, viewToDevice: Transformation] RETURNS [IIDevice.AllowedMasks]~ { state: State ~ context.state; rasterData: RasterData ~ state.rasterData; RETURN [rasterData.deviceParm.class.SetColor[context, color, viewToDevice]]; }; ModifySetPriority: PROC [context: Context, priorityImportant: BOOL] ~ { state: State ~ context.state; rasterData: RasterData ~ state.rasterData; rasterData.deviceParm.class.SetPriority[context, priorityImportant]; }; ModifyMaskBoxes: PROC [context: Context, bounds: SF.Box, boxes: SF.BoxGenerator] ~ { state: State ~ context.state; rasterData: RasterData ~ state.rasterData; action: PROC ~ {rasterData.deviceClass.MaskBoxes[context, bounds, boxes]}; ModifyRaster[context, bounds, action]; }; ModifyMaskRegion: PROC [context: Context, bounds: SF.Box, edgeGenerator: PROC [IISample.EdgeAction]] ~ { state: State ~ context.state; rasterData: RasterData ~ state.rasterData; action: PROC ~ {rasterData.deviceClass.MaskRegion[context, bounds, edgeGenerator]}; ModifyRaster[context, bounds, action]; }; ModifyMaskBitmap: PROC [context: Context, bitmap: SampleMap, delta: SF.Vec, bounds: SF.Box, boxes: SF.BoxGenerator] ~ { state: State ~ context.state; rasterData: RasterData ~ state.rasterData; action: PROC ~ {rasterData.deviceClass.MaskBitmap[context, bitmap, delta, bounds, boxes]}; ModifyRaster[context, bounds, action]; }; ModifyMaskRawBitmaps: PROC [context: Context, n: [0..rawArraySize], a: POINTER TO RawArray] ~ { state: State ~ context.state; rasterData: RasterData ~ state.rasterData; action: PROC ~ {rasterData.deviceClass.MaskRawBitmaps[context, n, a]}; bounds: SF.Box _ [min: SF.maxVec, max: SF.minVec]; TRUSTED { p: POINTER TO RawDescriptor _ @(a[0]); FOR i: NAT IN [0..n) DO bounds.min _ SF.Min[bounds.min, p^.box.min]; bounds.min _ SF.Max[bounds.max, p^.box.max]; p _ p + SIZE[RawDescriptor]; ENDLOOP; }; IF SF.Nonempty[bounds] THEN ModifyRaster[context, bounds, action]; }; ModifyDrawBitmap: PROC [context: Context, bitmap: SampleMap, delta: SF.Vec, bounds: SF.Box, boxes: SF.BoxGenerator] ~ { state: State ~ context.state; rasterData: RasterData ~ state.rasterData; action: PROC ~ {rasterData.deviceClass.DrawBitmap[context, bitmap, delta, bounds, boxes]}; ModifyRaster[context, bounds, action]; }; ModifyMaskChar: PROC [context: Context, delta: SF.Vec, mask: CharMask] ~ { state: State ~ context.state; rasterData: RasterData ~ state.rasterData; action: PROC ~ {rasterData.deviceClass.MaskChar[context, delta, mask]}; ModifyRaster[context, SF.Displace[mask.box, delta], action]; }; ModifyMoveBox: PROC [context: Context, dstMin, srcMin, size: SF.Vec] ~ { state: State ~ context.state; rasterData: RasterData ~ state.rasterData; action: PROC ~ {rasterData.deviceClass.MoveBox[context, dstMin, srcMin, size]}; min: SF.Vec ~ SF.Min[dstMin, srcMin]; max: SF.Vec ~ SF.Add[dstMin, srcMin].Sub[min].Add[size]; ModifyRaster[context, [min: min, max: max], action]; }; ModifyDoBuffered: PROC [context: Context, bounds: SF.Box, copy: BOOL, action: PROC] ~ { state: State ~ context.state; rasterData: RasterData ~ state.rasterData; proc: PROC ~ {rasterData.deviceClass.DoBuffered[context, bounds, copy, action]}; ModifyRaster[context, bounds, proc]; }; ModifyRaster: PUBLIC PROC [context: Context, box: SF.Box, action: PROC] ~ { state: State ~ context.state; rasterData: RasterData ~ state.rasterData; interceptor: Interceptor ~ rasterData.interceptor; parmClass: DeviceClass ~ rasterData.deviceParm.class; IF rasterData.deviceClass # modifiedDeviceClass THEN ERROR; -- should not have called IF interceptor.intercept = NIL THEN ERROR; rasterData.deviceClass _ rasterData.deviceParm.class; interceptor.intercept[interceptor, box, action, context ! UNWIND => rasterData.deviceClass _ modifiedDeviceClass ]; rasterData.deviceClass _ modifiedDeviceClass; }; InterceptorInEffect: PUBLIC PROC [context: Context] RETURNS [BOOL] ~ { state: State ~ context.state; rasterData: RasterData ~ state.rasterData; RETURN [rasterData.deviceClass = modifiedDeviceClass] }; SetInterceptor: PUBLIC PROC [context: Context, interceptor: Interceptor] RETURNS [old: Interceptor _ NIL] ~ { state: State ~ context.state; rasterData: RasterData ~ state.rasterData; old _ rasterData.interceptor; rasterData.interceptor _ interceptor; rasterData.deviceClass _ IF interceptor = NIL THEN rasterData.deviceParm.class ELSE modifiedDeviceClass; }; modifiedDeviceClass: DeviceClass ~ NEW [IIDevice.DeviceClassRep _ [ SetColor: ModifySetColor, SetPriority: ModifySetPriority, MaskBoxes: ModifyMaskBoxes, MaskRegion: ModifyMaskRegion, MaskBitmap: ModifyMaskBitmap, MaskRawBitmaps: ModifyMaskRawBitmaps, DrawBitmap: ModifyDrawBitmap, MaskChar: ModifyMaskChar, MoveBox: ModifyMoveBox, DoBuffered: ModifyDoBuffered ]]; rasterClassTemplate: Class ~ NEW [ClassRep _ [ type: $RasterTemplate, DoSave: IIState.StateDoSave, SetInt: IIState.StateSetInt, SetReal: IIState.StateSetReal, SetT: IIState.StateSetT, SetFont: IIState.StateSetFont, SetColor: IIState.StateSetColor, SetClipper: IIState.StateSetClipper, GetInt: IIState.StateGetInt, GetReal: IIState.StateGetReal, GetT: IIState.StateGetT, GetFont: IIState.StateGetFont, GetColor: IIState.StateGetColor, GetClipper: IIState.StateGetClipper, ConcatT: IIState.StateConcatT, Scale2T: IIState.StateScale2T, RotateT: IIState.StateRotateT, TranslateT: IIState.StateTranslateT, Move: IIState.StateMove, SetXY: IIState.StateSetXY, SetXYRel: IIState.StateSetXYRel, GetCP: IIState.StateGetCP, StartUnderline: IIState.StateStartUnderline, MaskUnderline: IIState.StateMaskUnderline, CorrectMask: IIState.StateCorrectMask, CorrectSpace: IIState.StateCorrectSpace, Space: IIState.StateSpace, SetCorrectMeasure: IIState.StateSetCorrectMeasure, SetCorrectTolerance: IIState.StateSetCorrectTolerance, Correct: IIState.StateCorrect, DontCorrect: IIState.StateDontCorrect, SetGray: IIState.StateSetGray, SetSampledColor: IIState.StateSetSampledColor, SetSampledBlack: IIState.StateSetSampledBlack, Clip: IIState.StateClip, ClipRectangle: IIState.StateClipRectangle, ClipRectangleI: IIState.StateClipRectangleI, Show: IIRasterShow.RasterShow, MaskFill: RasterMaskFill, MaskRectangle: RasterMaskRectangle, MaskStroke: RasterMaskStroke, MaskPixel: RasterMaskPixel, ShowAndFixedXRel: IIPrivate.DefaultShowAndFixedXRel, ShowText: IIPrivate.DefaultShowText, MaskRectangleI: RasterMaskRectangleI, MaskVector: RasterMaskVector, MaskDashedStroke: IIPrivate.DefaultMaskDashedStroke, MaskBitmap: RasterMaskBitmap, DrawBitmap: RasterDrawBitmap, DrawPixels: IIPrivate.DefaultDrawPixels, DoIfVisible: IIPrivate.DefaultDoIfVisible, DoWithBuffer: RasterDoWithBuffer, DrawObject: IIPrivate.DefaultDrawObject, GetBounds: RasterGetBounds, ViewReset: RasterViewReset, ViewTranslateI: RasterViewTranslateI, ViewClip: RasterViewClip, ViewClipRectangleI: RasterViewClipRectangleI, Transform: IIPrivate.DefaultTransform, GetTransformation: RasterGetTransformation, MoveViewRectangle: RasterMoveViewRectangle, TestViewRectangle: RasterTestViewRectangle, propList: NIL ]]; END. úIIRasterImpl.mesa Copyright Ó 1984, 1985, 1986 by Xerox Corporation. All rights reserved. Michael Plass, December 10, 1986 4:23:28 pm PST Doug Wyatt, August 4, 1986 11:08:19 am PDT Types and Constants Class and Context Creation Device State Maintainence Easy Transformations Overflow cannot happen. Computes bounding box of p0 and p1, clipped against clipBox. Mask Support MaskFill MaskRectangle MaskStroke USING [T, color, clipper, strokeWidth, strokeStyle, noImage, priorityImportant] IF rasterData.allow.unorderedBoxes AND rasterData.compositeClip.rest = NIL THEN { ... IIScanConverter.ObjectsFromPath[strokePath, rasterData.compositeBox, object, rasterData.devicePath]; RETURN; }; MaskPixel Come here once for each box in the clipping region. Come here once for each box in the clipping region that intersects the bitmap area. This box indicates a region of 1-bits in the source bitmap coordinates; transform to device coordinates, clip it and pass it to the device. Show All visible: go for it Partly visible: clip it Clipping Region Support Could distingush cases more carefully here, but we've got the most common ones done. Double Buffering View Note that translation doesn't invalidate charToDevice Intercepting Raster Accesses Raster Context Class Template Ê.˜codešœ™KšœH™HK™/Kšœ*™*—K˜šÏk ˜ Jš œœœœœœ ˜BJšœ˜Jšœ ˜ JšœœF˜QJšœ œ9˜GJšœœD˜PJšœ ˜ Jšœ œK˜\Jšœœ˜$Jšœœ1˜>Jšœ œ0˜BJšœ ˜ Jšœ œ˜Jšœ ˜ J˜Jšœ ˜ Jšœœ„˜™Jšœœƒ˜Jšœ œ"˜0Jšœ˜Jšœ œ#˜3Jšœœ˜Jšœœ˜Jšœœ˜Jšœœœ˜Jšœœ!˜-Jšœ˜Jšœœœ˜—K˜KšÐbl œœ˜Kšœïœ ˜Kšœ,˜3Kšœ˜head™Kšœœ˜Kšœ œœÏc˜DK˜Kšœ œ˜%šœ œœŸ˜RK˜—Kšœœ˜Kšœ œœŸ˜BK˜šœœœ˜K˜—Kšœ œ˜(Kšœ-˜-Kšœ œ˜&Kšœ œ˜,Kšœ œ˜#Kšœœ ˜Kšœœ˜'Kšœ œ˜Kšœ œ˜%Kšœ œ˜)Kšœ œ˜'Kšœ œ˜.Kšœœ˜Kšœ œ˜)Kšœœœœ˜"Kšœœ˜-Kšœ œ"˜-Kšœœ ˜Kšœ œ˜!Kšœ œ˜+Kšœ œ˜#Kšœœ˜-Kšœ œ˜"Kšœ œ˜%Kšœ œ˜+Kšœ œ˜'Kšœ œ˜-Kšœœ#˜7Kšœ œ˜)Kšœœ œ˜šœœ˜K˜—Kšœ œ˜&šœœ˜*K˜—šœœœ˜KšœœœŸ˜8KšœœœŸ+˜KKšœ œœŸ&˜>KšœœœŸ˜(Kšœ œœŸ3˜NKšœœœŸ9˜WJ˜J˜J˜—Kšœ œœ˜%šœœœœŸ"˜HKšœœŸ.˜LKšœœŸ8˜XKšœ$œ˜(KšœœŸ%˜CKšœ˜Kš œ œœœœœœ˜JKšœœŸ˜0Kšœ"œŸ˜6KšœœŸ˜3KšœœŸ,˜NKšœ œŸ.˜IKšœ!œŸ!˜GKšœ"œŸ2˜YKšœœŸ2˜RKšœœŸ˜8KšœœŸ˜?Kšœ˜K˜K˜—Kšœ œœœ˜Kšœ œ ˜—™š Ïn œœœœœ ˜SKšœœ#˜5K˜Kšœœœœ˜š œœœ˜Ešœ˜Jšœ"˜&Jšœ$˜(—Jšœ˜—Kšœ˜˜˜Kšœ¦˜¦Kšœ•˜•Kšœ˜Kšœ˜Kšœ˜—Kšœ˜Kšœ6˜6Kšœ$œ˜)K˜K˜—š  œœ˜*Kšœ˜Kšœ*˜*Kšœb˜bKšœœ˜$K˜K˜—š œœ˜-Kšœ˜Kšœ*˜*šœ+˜0KšœK˜O—Kšœ"œ˜'K˜K˜—š œœœ œ˜8Kš œœœœœ˜;K˜K˜—š œœœ œ˜9Kš œœœœœ˜Kšœ)œœ˜6K˜K˜—K˜š  œœœœ˜FKšœ˜Kšœ*˜*Kšœ˜Kšœ˜K˜—š  œœœœ˜QKšœ˜Kšœ*˜*Kšœ œœ˜=Kšœ˜Kšœ˜K˜—š  œœœœ˜BKšœ˜Kšœ*˜*Kšœ)˜)Kš œ œœ œœ œ˜sKšœ(˜(Kšœ.˜.Kšœ.˜.Kšœ"˜"Kšœ ˜Kšœ˜K˜——™Kš œœœœœœœœœœ œ˜cš  œœœœœœ˜5J™š  œœœœ œ˜6Kš œœœœœ ˜HKšœ˜—Kš œœœœœœœœ˜Fšœ˜#Kšœœ%˜0Kšœœ'˜2Kšœœ'˜2Kšœœ'˜2Kšœœ˜—Jšœ˜J˜—š  œœœœ˜9š  œœœœœ˜%šœœœ˜&Kšœœ˜Kšœœœœ˜Kšœ,œœœ˜AKšœ˜—Kšœœ˜Kšœ˜—Kš œ œ œ œ œ œ ˜MJšœ˜J˜—š  œœœœœœ˜1J˜Jšœœ ˜Jšœ˜J˜—š  œœœœœœ˜3J˜Jšœœ ˜Jšœ˜J˜—š   œœ œœœ ˜JKšœ<™Kšœ˜šœœ˜Kšœ*˜*Jšœ2˜2Kšœ˜šœ$œ"œœœ!œœ˜›Jšœ;˜;Jšœœ˜'Jšœœ:˜AJšœœB˜IJšœœ œœ%˜?Jšœœ œœ%˜?Jšœœ œœ%˜?Jšœœ œœ%˜?K˜Kšœœ œ˜5Kšœœ œ˜5šœœœ˜Jšœœ&˜-šœœ œœ ˜&KšœH˜HKšœ˜—JšœC˜CJšœ˜—Jšœ˜—šœ˜šœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜—Kšœc˜cJšœ˜—K˜—Kšœ˜K˜—š œœ œ˜FKšœ˜Kšœ˜šœœ˜Kšœ*˜*Kšœ;˜;šœ5œ"œœœ!œœ˜¬Kšœœ^˜ešœœ œœ ˜&KšœH˜HKšœ˜—JšœN˜NK˜—Kšœ8˜—K˜K˜—š œœH˜eJšœf˜fKšœQ˜Qšœœ˜Jšœœ˜&Jšœ˜Jšœ%˜%Jšœ=˜=Jšœœ˜;Jšœœ˜;Jšœœ ˜=Jšœœ ˜=•StartOfExpansion[nChars: NAT]šœœœ˜Jšœœ˜'Jšœ œœ(˜9š œœ˜šœœœ ˜Kšœœ˜,Kšœ˜—Kšœ˜—Jšœ œ˜$šœ˜ Jšœ œœœ œœœœ˜HJš œ·œœœœ˜äJšœ˜—Jšœ#˜#Jšœ*˜,šœœœ˜+Kšœu˜uKšœ ˜"Kšœ˜Kšœ˜—Kšœ4˜;Kšœ ˜ Kšœ˜—Kšœ˜—Kšœ˜Kšœ'˜'Kšœ%˜%Kšœ˜—K˜š œœH˜aKšœ˜Kšœ*˜*Kšœœ˜)šœ˜Kšœœœœ˜1Kšœœœœ˜1KšœG˜GKšœ˜—š œœ œœ˜?š œŸœœ œ˜=Kšœ:˜:š œŸœœ$œ ˜UKšœœ˜Kšœ*˜*K˜Kšœœ˜ šœœœ ˜Kšœ˜šœ˜Kšœœœ˜*šœœœ˜Kšœ=˜=Kšœ ˜ Kšœ˜—Kšœœ˜—Kšœ˜—Kšœ œB˜RKšœ˜—Kšœ?œ6˜zKšœ˜—KšœQ˜QKšœ˜—Kšœg˜gK˜K˜—š œœ7œ$œ˜{Kšœ˜Kšœ˜šœœ˜Kšœ*˜*KšœE˜EKšœ0˜0Kšœ0˜0KšœN˜NKšœC˜CKšœ˜Kšœ˜—K˜K˜—š œœ7œ$œ˜{Kšœ˜Kšœ˜šœœ˜Kšœ*˜*Kšœ2˜2KšœE˜EKšœ0˜0Kšœ0˜0KšœN˜Nš œ œœ*œœ˜VKšœœ˜#Kšœœœ$œ+˜aKšœœ œœU˜rKšœb˜bKšœ˜—KšœR˜VKšœ˜K˜—K˜K˜—Kšœœ ˜š œœ'˜˜JKšœ&˜&Kšœ˜K˜—š œœœœ˜hK˜Kšœ*˜*KšœœG˜SKšœ&˜&Kšœ˜K˜—š  œœ.œœ œ˜wK˜Kšœ*˜*KšœœN˜ZKšœ&˜&Kšœ˜K˜—š œœ-œœ˜_K˜Kšœ*˜*Kšœœ:˜FKšœœ œœ ˜2šœ˜ Kšœœœ˜&šœœœ˜Kšœ œ˜,Kšœ œ˜,Kšœœ˜Kšœ˜—Kšœ˜—Kšœœœ'˜BKšœ˜K˜—š  œœ.œœ œ˜wK˜Kšœ*˜*KšœœN˜ZKšœ&˜&Kšœ˜K˜—š œœœ˜JK˜Kšœ*˜*Kšœœ;˜GKšœœ$˜