-- Copyright (C) 1983, 1984 by Xerox Corporation. All rights reserved. -- DisplayImplA.mesa - last edited by -- Rick 12-Nov-83 14:49:19 -- Bruce 25-Feb-83 10:12:40 -- Mark 12-Feb-83 22:11:52 -- Daniels 7-Jun-84 14:37:54 DIRECTORY BitBlt USING [BITBLT, BitBltFlags], Display USING [bitFlags, paintGrayFlags], DisplayOps USING [ AbsPlace, Color, DIVMOD, HasUnder, LogError, FillList, FillObject, Intersect, Shade], Environment USING [BitAddress], Inline USING [DIVMOD, LongDivMod, LongMult, LowHalf], SpecialDisplay USING [DashCnt, defaultContext, LineStyle, solid, Special], Window USING [Box, BoxHandle, Place], WindowOps USING [ AbsoluteBox, AbsoluteBoxHandle, bbPtr, bitmapAddress, DisplayList, GetContext, lock, nullGray, Object, RecList, ScanLine, ScreenBox, SpecialTimesWpl]; DisplayImplA: MONITOR LOCKS WindowOps.lock IMPORTS BitBlt, DisplayOps, Inline, SpecialDisplay, WindowOps EXPORTS Display, SpecialDisplay, Window = BEGIN -- exported types Handle: TYPE = LONG POINTER TO Object; Object: PUBLIC TYPE = WindowOps.Object; FillHandle: TYPE = LONG POINTER TO FillObject; FillObject: PUBLIC TYPE = DisplayOps.FillObject; -- copied types because John doesn't like them LineStyle: TYPE = SpecialDisplay.LineStyle; Special: TYPE = SpecialDisplay.Special; black: CARDINAL ← LAST[CARDINAL]; blackSrc: Environment.BitAddress = [word: @black, bit: 0]; Point: PUBLIC ENTRY PROC [window: Handle, point: Window.Place] = { -- This routine assumes that point is in 8000 box. ENABLE UNWIND => NULL; -- switch to screen coords abs: Window.Place = DisplayOps.AbsPlace[window, point]; IF ~window.inTree THEN RETURN; FOR r: WindowOps.RecList ← WindowOps.DisplayList[window], r.link UNTIL r = NIL DO IF abs.x ~IN [r.box.left..r.box.right] OR abs.y ~IN [r.box.top..r.box.bottom] THEN LOOP; -- abs.y must be positive here IF DisplayOps.HasUnder[r] THEN SpPointInternal[r, abs, black, SpecialDisplay.defaultContext] ELSE { bitAddress: WindowOps.ScanLine = WindowOps.bitmapAddress + WindowOps.SpecialTimesWpl[abs.y]; bitAddress[abs.x] ← TRUE}; -- set a bit RETURN; -- rectangles never overlap ENDLOOP}; SpPoint: PUBLIC ENTRY PROC [ window: Handle, point: Window.Place, flags: BitBlt.BitBltFlags, context: Special ← SpecialDisplay.defaultContext] = { ENABLE UNWIND => NULL; IF window.inTree THEN { rec: WindowOps.RecList = DisplayOps.FillList[window, context.alloc # NIL]; abs: Window.Place = DisplayOps.AbsPlace[window, point]; color: DisplayOps.Color = DisplayOps.Shade[flags]; SpPointInternal[rec, abs, color, context]}}; SpPointInternal: INTERNAL PROC [ rec: WindowOps.RecList, abs: Window.Place, color: DisplayOps.Color, context: Special] = { FOR r: WindowOps.RecList ← rec, r.link UNTIL r = NIL DO IF abs.x IN [r.box.left..r.box.right] AND abs.y IN [r.box.top..r.box.bottom] THEN { -- abs.y must be positvie here ctx: Special = WindowOps.GetContext[r, context]; bitAddress: WindowOps.ScanLine = ctx.bmAddress + WindowOps.SpecialTimesWpl[abs.y, ctx]; SELECT color FROM white => bitAddress[abs.x] ← FALSE; black => bitAddress[abs.x] ← TRUE; ENDCASE => bitAddress[abs.x] ← ~bitAddress[abs.x]; RETURN}; -- rectangles never overlap ENDLOOP}; -- lines OrthogonalLine: PUBLIC ENTRY PROC [window: Handle, line: Window.Box] = { -- This routine assumes that the bounding box of any line displayed intersects -- with the Display.clip.box. ENABLE UNWIND => NULL; absBounds: WindowOps.ScreenBox = WindowOps.AbsoluteBox[window, line]; IF ~window.inTree THEN RETURN; FOR r: WindowOps.RecList ← WindowOps.DisplayList[window], r.link UNTIL r = NIL DO left: INTEGER = MAX[absBounds.left, r.box.left]; width: INTEGER = MIN[absBounds.right, r.box.right] - left; top: INTEGER = MAX[absBounds.top, r.box.top]; height: INTEGER = MIN[absBounds.bottom, r.box.bottom] - top; offset, bit: INTEGER; IF DisplayOps.HasUnder[r] THEN { SpOrthoInternal[ window, absBounds, SpecialDisplay.solid, Display.paintGrayFlags, SpecialDisplay.defaultContext]; RETURN}; IF height <= 0 OR width <= 0 THEN LOOP; -- At this point, we know that -- left and left + width IN [r.box.left..r.box.right] -- top and top + height IN [r.box.top..r.box.bottom] [quotient: offset, remainder: bit] ← Inline.DIVMOD[left, 16]; WindowOps.bbPtr↑ ← [ dst: [ word: WindowOps.bitmapAddress + WindowOps.SpecialTimesWpl[top] + offset, bit: bit], dstBpl: SpecialDisplay.defaultContext.bpl, src: blackSrc, srcDesc: WindowOps.nullGray, width: width, height: height, flags: Display.bitFlags]; BitBlt.BITBLT[WindowOps.bbPtr]; ENDLOOP}; SpOrthoLine: PUBLIC ENTRY PROC [ window: Handle, line: Window.Box, dashes: LineStyle, flags:BitBlt.BitBltFlags, context: Special ← SpecialDisplay.defaultContext] = { ENABLE UNWIND => NULL; IF window.inTree THEN { absBounds: WindowOps.ScreenBox = WindowOps.AbsoluteBox[window, line]; SpOrthoInternal[window, absBounds, dashes, flags, context]}}; SpOrthoInternal: INTERNAL PROC [ window: Handle, absBounds: WindowOps.ScreenBox, dashes: LineStyle, flags: BitBlt.BitBltFlags, context: Special] = { filled: BOOLEAN = context.alloc # NIL; flags.gray ← TRUE; FOR r: WindowOps.RecList ← DisplayOps.FillList[window, context.alloc # NIL], r.link UNTIL r = NIL DO ctx: Special = WindowOps.GetContext[r, context]; clipLeft: INTEGER = r.box.left; left: INTEGER ← MAX[absBounds.left, clipLeft]; width: INTEGER = MIN[absBounds.right, r.box.right] - left; clipTop: INTEGER = r.box.top; -- this is positive top: INTEGER = MAX[absBounds.top, clipTop]; height: INTEGER = MIN[absBounds.bottom, r.box.bottom] - top; visible: BOOLEAN ← TRUE; dashIndex: [0..SpecialDisplay.DashCnt) ← 0; offset, bit: INTEGER; mark: INTEGER ← dashes.widths[0]; dashLeft: INTEGER ← 0; dashSum: CARDINAL ← 0; IF height <= 0 OR width <= 0 THEN LOOP; FOR i: CARDINAL IN [0..SpecialDisplay.DashCnt) DO dashSum ← dashSum + dashes.widths[i]; ENDLOOP; IF height <= width AND ~filled THEN BEGIN startBmAddr: LONG POINTER ← ctx.bmAddress + WindowOps.SpecialTimesWpl[top, ctx]; IF clipLeft > absBounds.left THEN { dashSum ← (clipLeft - absBounds.left) MOD dashSum; FOR i: CARDINAL IN [0..SpecialDisplay.DashCnt) DO IF dashSum < dashes.widths[i] THEN EXIT; dashSum ← dashSum - dashes.widths[i]; dashIndex ← dashIndex + 1; visible ← ~visible; ENDLOOP; mark ← dashes.widths[dashIndex] - dashSum}; WindowOps.bbPtr↑ ← [ dst:, dstBpl: ctx.bpl, src: blackSrc, srcDesc: WindowOps.nullGray, width:, height: height, flags: flags]; WHILE dashLeft < width DO IF visible THEN { IF width - dashLeft < mark THEN mark ← width - dashLeft; [quotient: offset, remainder: bit] ← DisplayOps.DIVMOD[ dashLeft + left, 16]; WindowOps.bbPtr.dst ← [word: startBmAddr + offset, bit: bit]; WindowOps.bbPtr.width ← mark; BitBlt.BITBLT[WindowOps.bbPtr]}; dashLeft ← dashLeft + mark; visible ← ~visible; dashIndex ← (dashIndex + 1) MOD SpecialDisplay.DashCnt; mark ← dashes.widths[dashIndex]; ENDLOOP; END ELSE BEGIN dashTop: INTEGER ← 0; IF filled THEN { fill: FillHandle ← ctx.alloc[window, top, height]; left ← MAX[0, left]; FOR i: INTEGER IN [0..height - 1] DO fill.xs[i] ← left; ENDLOOP} ELSE { IF clipTop > absBounds.top THEN { dashSum ← (clipTop - absBounds.top) MOD dashSum; FOR i: CARDINAL IN [0..SpecialDisplay.DashCnt) DO IF dashSum < dashes.widths[i] THEN EXIT; dashSum ← dashSum - dashes.widths[i]; dashIndex ← dashIndex + 1; visible ← ~visible; ENDLOOP; mark ← dashes.widths[dashIndex] - dashSum}; WindowOps.bbPtr↑ ← [ dst:, dstBpl: ctx.bpl, src: blackSrc, srcDesc: WindowOps.nullGray, width: width, height:, flags: flags]; WHILE dashTop < height DO IF visible THEN { IF height - dashTop < mark THEN mark ← height - dashTop; [quotient: offset, remainder: bit] ← Inline.DIVMOD[left, 16]; WindowOps.bbPtr.dst ← [ word: ctx.bmAddress + WindowOps.SpecialTimesWpl[INTEGER[top + dashTop], ctx]+offset, bit: bit]; WindowOps.bbPtr.height ← mark; BitBlt.BITBLT[WindowOps.bbPtr]}; dashTop ← dashTop + mark; visible ← ~visible; dashIndex ← (dashIndex + 1) MOD SpecialDisplay.DashCnt; mark ← dashes.widths[dashIndex]; ENDLOOP}; END; ENDLOOP}; PositiveSteepLine: PUBLIC ENTRY PROC [ window: Handle, start, stop: Window.Place, bounds: Window.BoxHandle] = { -- because it's positive and steep, we know: -- start.x < stop.x -- start.y > stop.y -- stop.x - start.x < start.y - stop.y -- This routine intersects the bounding box of any line displayed with the -- bounding box of each reclist. Given this, the fact that start.y >= stop.y, -- and the specific type of line being delt with here it is assumed that: -- start.x <= r.box.right -- stop.x >= r.box.left -- start.y >= r.box.top -- stop.y <= r.box.bottom or else DisplayOps.Intersect fails. ENABLE UNWIND => NULL; absBounds: WindowOps.ScreenBox = WindowOps.AbsoluteBoxHandle[window, bounds]; -- switch to screen coords absStart: Window.Place = DisplayOps.AbsPlace[window, start]; absStop: Window.Place = DisplayOps.AbsPlace[window, stop]; startError: INTEGER = absStart.y - absStop.y; twoy: INTEGER = startError*2; -- positive twox: CARDINAL = (absStop.x - absStart.x)*2; -- positive bitIndex: INTEGER; startAddress: WindowOps.ScanLine = WindowOps.bitmapAddress + WindowOps.SpecialTimesWpl[INTEGER[absStart.y]]; IF ~window.inTree THEN RETURN; FOR r: WindowOps.RecList ← WindowOps.DisplayList[window], r.link UNTIL r = NIL DO IF DisplayOps.Intersect[r, absBounds] THEN { wpl: CARDINAL = SpecialDisplay.defaultContext.wpl; bitAddress: WindowOps.ScanLine ← startAddress; left: INTEGER = r.box.left; top: INTEGER = r.box.top; right: INTEGER = r.box.right; bottom: INTEGER = r.box.bottom; error: INTEGER ← startError; IF DisplayOps.HasUnder[r] THEN { SpPStInternal[ window, absStart, absStop, absBounds, SpecialDisplay.solid, Display.paintGrayFlags, SpecialDisplay.defaultContext]; RETURN}; start ← absStart; stop ← absStop; IF bottom - 1 < start.y THEN { netError: LONG INTEGER ← error - Inline.LongMult[twox, start.y - bottom + 1]; difx: INTEGER; bitAddress ← bitAddress - WindowOps.SpecialTimesWpl[INTEGER[start.y-bottom+1]]; start.y ← bottom - 1; IF netError < 0 THEN { netError ← -netError; [difx, error] ← Inline.LongDivMod[netError, twoy]; IF error # 0 THEN {difx ← difx + 1; error ← twoy - error}; start.x ← difx + start.x} ELSE error ← Inline.LowHalf[netError]}; IF left > start.x THEN { difx: CARDINAL; netError: LONG CARDINAL ← Inline.LongMult[twoy, left - start.x - 1] + error; start.x ← left; [difx, error] ← Inline.LongDivMod[netError, twox]; error ← error + twoy - twox; start.y ← start.y - difx - 1; bitAddress ← bitAddress - WindowOps.SpecialTimesWpl[INTEGER[difx + 1]]}; IF right - 1 < stop.x THEN { netError: LONG INTEGER; difx, errorTemp: CARDINAL; IF right - 1 < start.x THEN LOOP; netError ← Inline.LongMult[twoy, right - start.x - 1] + error; [difx, errorTemp] ← Inline.LongDivMod[netError, twox]; stop.y ← start.y - difx}; IF top > stop.y THEN stop.y ← top; bitIndex ← start.x; THROUGH [stop.y..start.y] DO bitAddress[bitIndex] ← TRUE; -- set a bit error ← error - twox; IF error < 0 THEN {bitIndex ← bitIndex + 1; error ← error + twoy}; bitAddress ← bitAddress - wpl; ENDLOOP}; ENDLOOP}; SpPositiveSteepLine: PUBLIC ENTRY PROC [ window: Handle, start, stop: Window.Place, bounds: Window.BoxHandle, dashes: LineStyle, flags: BitBlt.BitBltFlags, context: Special ← SpecialDisplay.defaultContext] = { -- because it's positive and steep, we know: -- start.x < stop.x -- start.y > stop.y -- stop.x - start.x < start.y - stop.y -- This routine intersects the bounding box of any line displayed with the -- bounding box of each reclist. Given this, the fact that start.y >= stop.y, -- the specific type of line being delt with here it is assumed that: -- start.x <= r.box.right -- stop.x >= r.box.left -- start.y >= r.box.top -- stop.y <= r.box.bottom or else DisplayOps.Intersect fails ENABLE UNWIND => NULL; IF window.inTree THEN { absBounds: WindowOps.ScreenBox = WindowOps.AbsoluteBoxHandle[window,bounds]; -- switch to screen coords absStart: Window.Place = DisplayOps.AbsPlace[window, start]; absStop: Window.Place = DisplayOps.AbsPlace[window, stop]; SpPStInternal[ window, absStart, absStop, absBounds, dashes, flags, context]}}; SpPStInternal: INTERNAL PROC [ window: Handle, absStart, absStop: Window.Place, absBounds: WindowOps.ScreenBox, dashes: LineStyle, flags: BitBlt.BitBltFlags, context: Special] = { startError: INTEGER = absStart.y - absStop.y; twoy: CARDINAL = startError*2; -- positive twox: CARDINAL = (absStop.x - absStart.x)*2; -- positive dashCnt, dashSum: CARDINAL; filled: BOOLEAN = context.alloc # NIL; widths: ARRAY [0..SpecialDisplay.DashCnt) OF CARDINAL; inc1, inc2, inc3, inc4, inc5, inc6: CARDINAL; low: INTEGER = absStart.x - dashes.thickness/2; initStopX: INTEGER ← absStop.x - dashes.thickness/2 - 1; high: INTEGER = low + dashes.thickness; fill: FillHandle ← NIL; fillcnt, fillLength, bitIndex: INTEGER; dashstretch: CARDINAL = SELECT twoy FROM > twox*15/4 => 13, -- 0 to 15 degrees > twox*7/4 => 12, -- 15 to 30 degrees ENDCASE => 11; -- 30 to 45 degrees FOR i: CARDINAL IN [0..SpecialDisplay.DashCnt) DO widths[i] ← dashes.widths[i]*dashstretch/14; ENDLOOP; inc1 ← 0; inc2 ← widths[0]; inc3 ← inc2 + widths[1]; inc4 ← inc3 + widths[2]; inc5 ← inc4 + widths[3]; inc6 ← inc5 + widths[4]; dashSum ← 0; FOR i: CARDINAL IN [0..SpecialDisplay.DashCnt) DO dashSum ← dashSum + widths[i]; ENDLOOP; FOR r: WindowOps.RecList ← DisplayOps.FillList[window, filled], r.link UNTIL r = NIL DO IF DisplayOps.Intersect[r, absBounds] THEN BEGIN ctx: Special = WindowOps.GetContext[r, context]; left: INTEGER ← MAX[r.box.left, absBounds.left]; top: INTEGER = MAX[r.box.top, absBounds.top]; right: INTEGER ← MIN[r.box.right, absBounds.right]; bottom: INTEGER = MIN[r.box.bottom, absBounds.bottom]; stopX: INTEGER ← initStopX; IF top = bottom THEN GOTO nextRectangle; IF filled THEN { left ← MAX[0, left]; right ← absBounds.right; fillLength ← bottom - top; fill ← ctx.alloc[window, top, fillLength]; fill.xs[0] ← left}; FOR loopx: INTEGER IN [low..high) DO startX: INTEGER ← loopx; startY: INTEGER ← absStart.y; error: INTEGER ← startError; stopY: INTEGER ← absStop.y; bitAddress: WindowOps.ScanLine ← ctx.bmAddress + WindowOps.SpecialTimesWpl[INTEGER[startY], ctx]; stopX ← stopX + 1; dashCnt ← 0; IF bottom - 1 < startY THEN { netError: LONG INTEGER ← error - Inline.LongMult[twox, startY - bottom + 1]; difx: INTEGER; bitAddress ← bitAddress-WindowOps.SpecialTimesWpl[INTEGER[startY-bottom+1],ctx]; dashCnt ← (startY - bottom + 1) MOD dashSum; startY ← bottom - 1; IF netError < 0 THEN { netError ← -netError; [difx, error] ← Inline.LongDivMod[netError, twoy]; IF error # 0 THEN {difx ← difx + 1; error ← twoy - error}; startX ← difx + startX} ELSE error ← Inline.LowHalf[netError]}; IF left > startX THEN { difx: CARDINAL; netError: LONG CARDINAL ← Inline.LongMult[twoy, left - startX - 1] + error; startX ← left; [difx, error] ← Inline.LongDivMod[netError, twox]; error ← error + twoy - twox; startY ← startY - difx - 1; dashCnt ← (difx + 1 + dashCnt) MOD dashSum; bitAddress←bitAddress-WindowOps.SpecialTimesWpl[INTEGER[difx+1],ctx]}; IF right - 1 < stopX THEN { netError: LONG INTEGER; difx, errorTemp: CARDINAL; IF right - 1 < startX THEN GOTO nextRectangle; netError ← Inline.LongMult[twoy, right - startX - 1] + error; [difx, errorTemp] ← Inline.LongDivMod[netError, twox]; stopY ← startY - difx; stopX ← right - 1}; IF top > stopY THEN stopY ← top; bitIndex ← startX; IF startY - stopY < 0 THEN GOTO nextRectangle; IF filled THEN { fillcnt ← startY - top; fill.xs[fillcnt] ← MAX[startX, 0]; fill.xs[0] ← MAX[stopX, 0]}; THROUGH [stopY..startY] DO IF filled THEN { IF fillcnt ~IN [0..fillLength) THEN DisplayOps.LogError[]; fill.xs[fillcnt] ← bitIndex; fillcnt ← fillcnt - 1} ELSE { IF dashCnt IN [inc1..inc2) OR dashCnt IN [inc3..inc4) OR dashCnt IN [inc5..inc6) THEN bitAddress[bitIndex] ← (SELECT DisplayOps.Shade[flags] FROM white => FALSE, black => TRUE, ENDCASE => ~bitAddress[bitIndex]); bitAddress ← bitAddress - ctx.wpl; dashCnt ← (dashCnt + 1) MOD dashSum}; error ← error - twox; IF error < 0 THEN {bitIndex ← bitIndex + 1; error ← error + twoy}; ENDLOOP; ENDLOOP; EXITS nextRectangle => NULL; END; ENDLOOP}; NegativeSteepLine: PUBLIC ENTRY PROC [ window: Handle, start, stop: Window.Place, bounds: Window.BoxHandle] = { -- because it's negative and steep, we know: -- start.x > stop.x -- start.y > stop.y -- start.x - stop.x < start.y - stop.y -- This routine intersects the bounding box of any line displayed with the -- bounding box of each reclist. Given this, the fact that start.y >= stop.y, -- and the specific type of line being delt with here it is assumed that: -- start.x >= r.box.left -- stop.x <= r.box.right -- start.y >= r.box.top -- stop.y <= r.box.bottom or else DisplayOps.Intersect fails. ENABLE UNWIND => NULL; absBounds: WindowOps.ScreenBox = WindowOps.AbsoluteBoxHandle[window, bounds]; -- switch to screen coords absStart: Window.Place = DisplayOps.AbsPlace[window, start]; absStop: Window.Place = DisplayOps.AbsPlace[window, stop]; startError: INTEGER = absStart.y - absStop.y; twoy: INTEGER = startError*2; -- positive twox: CARDINAL = (absStart.x - absStop.x)*2; -- positive startAddress: WindowOps.ScanLine = WindowOps.bitmapAddress + WindowOps.SpecialTimesWpl[INTEGER[absStart.y]]; bitIndex: INTEGER; IF ~window.inTree THEN RETURN; FOR r: WindowOps.RecList ← WindowOps.DisplayList[window], r.link UNTIL r = NIL DO IF DisplayOps.Intersect[r, absBounds] THEN { wpl: CARDINAL = SpecialDisplay.defaultContext.wpl; bitAddress: WindowOps.ScanLine ← startAddress; left: INTEGER = r.box.left; top: INTEGER = r.box.top; right: INTEGER = r.box.right; bottom: INTEGER = r.box.bottom; error: INTEGER ← startError; IF DisplayOps.HasUnder[r] THEN { SpNStInternal[ window, absStart, absStop, absBounds, SpecialDisplay.solid, Display.paintGrayFlags, SpecialDisplay.defaultContext]; RETURN}; start ← absStart; stop ← absStop; IF bottom - 1 < start.y THEN { netError: LONG INTEGER ← error - Inline.LongMult[twox, start.y - bottom + 1]; difx: INTEGER; bitAddress ← bitAddress - WindowOps.SpecialTimesWpl[INTEGER[start.y-bottom+1]]; start.y ← bottom - 1; IF netError < 0 THEN { netError ← -netError; [difx, error] ← Inline.LongDivMod[netError, twoy]; IF error # 0 THEN {difx ← difx + 1; error ← twoy - error}; start.x ← start.x - difx} ELSE error ← Inline.LowHalf[netError]}; IF right - 1 < start.x THEN { difx: CARDINAL; netError: LONG CARDINAL ← Inline.LongMult[twoy, start.x - right]+error; start.x ← right - 1; [difx, error] ← Inline.LongDivMod[netError, twox]; error ← error + twoy - twox; start.y ← start.y - difx - 1; bitAddress ← bitAddress - WindowOps.SpecialTimesWpl[INTEGER[difx + 1]]}; IF left > stop.x THEN { difx, errorTemp: CARDINAL; netError: LONG INTEGER; IF start.x < left THEN LOOP; netError ← Inline.LongMult[twoy, start.x - left] + error; [difx, errorTemp] ← Inline.LongDivMod[netError, twox]; stop.y ← start.y - difx}; IF top > stop.y THEN stop.y ← top; bitIndex ← start.x; THROUGH [stop.y..start.y] DO bitAddress[bitIndex] ← TRUE; -- set a bit error ← error - twox; IF error < 0 THEN {bitIndex ← bitIndex - 1; error ← error + twoy}; bitAddress ← bitAddress - wpl; ENDLOOP}; ENDLOOP}; SpNegativeSteepLine: PUBLIC ENTRY PROC [ window: Handle, start, stop: Window.Place, bounds: Window.BoxHandle, dashes: LineStyle, flags: BitBlt.BitBltFlags, context: Special ← SpecialDisplay.defaultContext] = { -- because it's negative and steep, we know: -- start.x > stop.x -- start.y > stop.y -- start.x - stop.x < start.y - stop.y -- This routine intersects the bounding box of any line displayed with the -- bounding box of each reclist. Given this, the fact that start.y >= stop.y, -- and the specific type of line being delt with here it is assumed that: -- start.x >= r.box.left -- stop.x <= r.box.right -- start.y >= r.box.top -- stop.y <= r.box.bottom or else DisplayOps.Intersect fails. ENABLE UNWIND => NULL; IF window.inTree THEN { absBounds: WindowOps.ScreenBox = WindowOps.AbsoluteBoxHandle[window,bounds]; -- switch to screen coords absStart: Window.Place = DisplayOps.AbsPlace[window, start]; absStop: Window.Place = DisplayOps.AbsPlace[window, stop]; SpNStInternal[ window, absStart, absStop, absBounds, dashes, flags, context]}}; SpNStInternal: INTERNAL PROC [ window: Handle, absStart, absStop: Window.Place, absBounds: WindowOps.ScreenBox, dashes: LineStyle, flags: BitBlt.BitBltFlags, context: Special] = { startError: INTEGER = absStart.y - absStop.y; twoy: INTEGER = startError*2; -- positive twox: CARDINAL = (absStart.x - absStop.x)*2; -- positive dashCnt, dashSum: CARDINAL; filled: BOOLEAN = context.alloc # NIL; widths: ARRAY [0..SpecialDisplay.DashCnt) OF CARDINAL; inc1, inc2, inc3, inc4, inc5, inc6: CARDINAL; low: INTEGER = absStart.x - dashes.thickness/2; high: INTEGER = low + dashes.thickness; initStopX: INTEGER ← absStop.x - dashes.thickness/2 - 1; fill: FillHandle ← NIL; fillcnt, fillLength, bitIndex: INTEGER; dashstretch: CARDINAL = SELECT twoy FROM > twoy*15/4 => 13, -- 0 to 15 degrees > twoy*7/4 => 12, -- 15 to 30 degrees ENDCASE => 11; -- 30 to 45 degrees FOR i: CARDINAL IN [0..SpecialDisplay.DashCnt) DO widths[i] ← dashes.widths[i]*dashstretch/14; ENDLOOP; inc1 ← 0; inc2 ← widths[0]; inc3 ← inc2 + widths[1]; inc4 ← inc3 + widths[2]; inc5 ← inc4 + widths[3]; inc6 ← inc5 + widths[4]; dashSum ← 0; FOR i: CARDINAL IN [0..SpecialDisplay.DashCnt) DO dashSum ← dashSum + widths[i]; ENDLOOP; FOR r: WindowOps.RecList ← DisplayOps.FillList[window, filled], r.link UNTIL r = NIL DO IF DisplayOps.Intersect[r, absBounds] THEN BEGIN ctx: Special = WindowOps.GetContext[r, context]; left: INTEGER ← MAX[r.box.left, absBounds.left]; top: INTEGER = MAX[r.box.top, absBounds.top]; right: INTEGER ← MIN[r.box.right, absBounds.right]; bottom: INTEGER = MIN[r.box.bottom, absBounds.bottom]; stopX: INTEGER ← initStopX; IF top = bottom THEN GOTO nextRectangle; IF filled THEN { left ← MAX[0, left]; right ← absBounds.right; fillLength ← bottom - top; fill ← ctx.alloc[window, top, fillLength]; fill.xs[0] ← left}; FOR loopx: INTEGER IN [low..high) DO startX: INTEGER ← loopx; startY: INTEGER ← absStart.y; error: INTEGER ← startError; stopY: INTEGER ← absStop.y; bitAddress: WindowOps.ScanLine ← ctx.bmAddress + WindowOps.SpecialTimesWpl[INTEGER[startY], ctx]; stopX ← stopX + 1; dashCnt ← 0; IF bottom - 1 < startY THEN { netError: LONG INTEGER ← error - Inline.LongMult[twox, startY - bottom + 1]; difx: INTEGER; bitAddress ← bitAddress-WindowOps.SpecialTimesWpl[INTEGER[startY-bottom+1],ctx]; dashCnt ← (startY - bottom + 1) MOD dashSum; startY ← bottom - 1; IF netError < 0 THEN { netError ← -netError; [difx, error] ← Inline.LongDivMod[netError, twoy]; IF error # 0 THEN {difx ← difx + 1; error ← twoy - error}; startX ← startX - difx} ELSE error ← Inline.LowHalf[netError]}; IF right - 1 < startX THEN { difx: CARDINAL; netError: LONG CARDINAL ← Inline.LongMult[twoy, startX - right] + error; startX ← right - 1; [difx, error] ← Inline.LongDivMod[netError, twox]; error ← error + twoy - twox; startY ← startY - difx - 1; dashCnt ← (difx + 1 + dashCnt) MOD dashSum; bitAddress←bitAddress-WindowOps.SpecialTimesWpl[INTEGER[difx+1],ctx]}; IF left > stopX THEN { difx, errorTemp: CARDINAL; netError: LONG INTEGER; IF startX < left THEN GOTO nextRectangle; netError ← Inline.LongMult[twoy, startX - left] + error; [difx, errorTemp] ← Inline.LongDivMod[netError, twox]; stopY ← startY - difx}; IF top > stopY THEN stopY ← top; bitIndex ← startX; IF startY - stopY < 0 THEN GOTO nextRectangle; IF filled THEN { fillcnt ← startY - top; fill.xs[fillcnt] ← MAX[startX, 0]; fill.xs[0] ← MAX[stopX, 0]}; THROUGH [stopY..startY] DO IF filled THEN { IF fillcnt ~IN [0..fillLength) THEN DisplayOps.LogError[]; fill.xs[fillcnt] ← bitIndex; fillcnt ← fillcnt - 1} ELSE { IF dashCnt IN [inc1..inc2) OR dashCnt IN [inc3..inc4) OR dashCnt IN [inc5..inc6) THEN bitAddress[bitIndex] ← (SELECT DisplayOps.Shade[flags] FROM white => FALSE, black => TRUE, ENDCASE => ~bitAddress[bitIndex]); bitAddress ← bitAddress - ctx.wpl; dashCnt ← (dashCnt + 1) MOD dashSum}; error ← error - twox; IF error < 0 THEN {bitIndex ← bitIndex - 1; error ← error + twoy}; ENDLOOP; ENDLOOP EXITS nextRectangle => NULL; END; ENDLOOP}; END.