-- Copyright (C) 1983, 1984 by Xerox Corporation. All rights reserved. -- DisplayImplB.mesa - last edited by -- Rick 12-Nov-83 14:44:30 -- Bruce 15-Feb-83 10:14:37 -- Daniels 7-Jun-84 15:19:02 DIRECTORY BitBlt USING [BitBltFlags], Display USING [paintGrayFlags], DisplayOps USING [ AbsPlace, HasUnder, LogError, FillList, FillObject, Intersect, Shade], SpecialDisplay USING [DashCnt, defaultContext, LineStyle, solid, Special], Window USING [BoxHandle, Place], WindowOps USING [ AbsoluteBoxHandle, bitmapAddress, DisplayList, GetContext, lock, Object, RecList, ScanLine, ScreenBox, SpecialTimesWpl]; DisplayImplB: MONITOR LOCKS WindowOps.lock IMPORTS DisplayOps, SpecialDisplay, WindowOps EXPORTS 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; -- lines Positive45Line: PUBLIC ENTRY PROC [ window: Handle, place: Window.Place, stopX: INTEGER, bounds: Window.BoxHandle] = { -- 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 abs: Window.Place = DisplayOps.AbsPlace[window, place]; absX: INTEGER = stopX + window.place.x; startAddress: WindowOps.ScanLine = WindowOps.bitmapAddress + WindowOps.SpecialTimesWpl[INTEGER[abs.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 { bitAddress: WindowOps.ScanLine ¬ startAddress; left: INTEGER = r.box.left; top: INTEGER = r.box.top; right: INTEGER = r.box.right; bottom: INTEGER = r.box.bottom; IF top = bottom THEN LOOP; IF DisplayOps.HasUnder[r] THEN { SpP45Internal[ window, abs, absX, absBounds, SpecialDisplay.solid, Display.paintGrayFlags, SpecialDisplay.defaultContext]; RETURN}; place ¬ abs; stopX ¬ absX; IF bottom - 1 < place.y THEN { place.x ¬ place.x + place.y - bottom + 1; bitAddress ¬ bitAddress - WindowOps.SpecialTimesWpl[INTEGER[place.y-bottom+1]]; place.y ¬ bottom - 1}; IF left > place.x THEN { IF left > place.y + place.x THEN LOOP; place.y ¬ place.y + place.x - left; bitAddress ¬ bitAddress - WindowOps.SpecialTimesWpl[INTEGER[left-place.x]]; place.x ¬ left}; IF top > place.y - stopX + place.x THEN stopX ¬ place.y + place.x - top; IF right < stopX THEN stopX ¬ right - 1; FOR bitIndex: INTEGER IN [place.x..stopX] DO bitAddress[bitIndex] ¬ TRUE; -- set a bit bitAddress ¬ bitAddress - SpecialDisplay.defaultContext.wpl; ENDLOOP}; ENDLOOP}; SpPositive45Line: PUBLIC ENTRY PROC [ window: Handle, place: Window.Place, stopX: INTEGER, bounds: Window.BoxHandle, dashes: LineStyle, flags: BitBlt.BitBltFlags, context: Special ¬ SpecialDisplay.defaultContext] = { -- 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; IF window.inTree THEN { absBounds: WindowOps.ScreenBox = WindowOps.AbsoluteBoxHandle[window,bounds]; -- switch to screen coords abs: Window.Place = DisplayOps.AbsPlace[window, place]; absX: INTEGER = stopX + window.place.x; SpP45Internal[window, abs, absX, absBounds, dashes, flags, context]}}; SpP45Internal: INTERNAL PROC [ window: Handle, abs: Window.Place, absX: INTEGER, absBounds: WindowOps.ScreenBox, dashes: LineStyle, flags: BitBlt.BitBltFlags, context: Special] = { dashCnt, dashSum: CARDINAL; filled: BOOLEAN = context.alloc # NIL; widths: ARRAY [0..SpecialDisplay.DashCnt) OF CARDINAL; inc1, inc2, inc3, inc4, inc5, inc6: CARDINAL; low: INTEGER = abs.y - dashes.thickness/2; high: INTEGER = low + dashes.thickness; fillcnt, fillLength: INTEGER; fill: FillHandle ¬ NIL; FOR i: CARDINAL IN [0..SpecialDisplay.DashCnt) DO widths[i] ¬ dashes.widths[i]*5/7; ENDLOOP; inc1 ¬ 0; inc2 ¬ widths[0]; inc3 ¬ inc2 + widths[1]; inc4 ¬ inc3 + widths[2]; inc5 ¬ inc4 + widths[3]; inc6 ¬ inc5 + widths[4]; dashSum ¬ inc6 + widths[5]; FOR r: WindowOps.RecList ¬ DisplayOps.FillList[window, filled], r.link UNTIL r = NIL DO IF DisplayOps.Intersect[r, absBounds] THEN { 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]; 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 loopy: INTEGER IN [low..high) DO placey: INTEGER ¬ loopy; placex: INTEGER ¬ abs.x; tempX: INTEGER ¬ absX; bitAddress: WindowOps.ScanLine ¬ ctx.bmAddress + WindowOps.SpecialTimesWpl[INTEGER[placey], ctx]; dashCnt ¬ 0; IF bottom - 1 < placey THEN { dashCnt ¬ (placey - bottom + 1) MOD dashSum; placex ¬ placex + placey - bottom + 1; bitAddress ¬ bitAddress-WindowOps.SpecialTimesWpl[INTEGER[placey-bottom+1],ctx]; placey ¬ bottom - 1}; IF left > placex THEN { dashCnt ¬ (left - placex + dashCnt) MOD dashSum; IF left > placey + placex THEN GOTO nextRectangle; placey ¬ placey + placex - left; bitAddress ¬ bitAddress - WindowOps.SpecialTimesWpl[INTEGER[left - placex], ctx]; placex ¬ left}; IF top > placey - tempX + placex THEN { IF top > placey + placex THEN GOTO nextRectangle; tempX ¬ placey + placex - top}; IF right < tempX THEN tempX ¬ right - 1; IF tempX - placex <= 0 THEN LOOP; IF filled THEN fillcnt ¬ placey - top; FOR bitIndex: INTEGER IN [placex..tempX] 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])}; dashCnt ¬ (dashCnt + 1) MOD dashSum; bitAddress ¬ bitAddress - ctx.wpl}; ENDLOOP; ENDLOOP; EXITS nextRectangle => NULL}; ENDLOOP}; Negative45Line: PUBLIC ENTRY PROC [ window: Handle, place: Window.Place, stopX: INTEGER, bounds: Window.BoxHandle] = { -- 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 abs: Window.Place = DisplayOps.AbsPlace[window, place]; absX: INTEGER = stopX + window.place.x; startAddress: WindowOps.ScanLine = WindowOps.bitmapAddress + WindowOps.SpecialTimesWpl[INTEGER[abs.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 { bitAddress: WindowOps.ScanLine ¬ startAddress; left: INTEGER = r.box.left; top: INTEGER = r.box.top; right: INTEGER = r.box.right; bottom: INTEGER = r.box.bottom; IF top = bottom THEN LOOP; IF DisplayOps.HasUnder[r] THEN { SpN45Internal[ window, abs, absX, absBounds, SpecialDisplay.solid, Display.paintGrayFlags, SpecialDisplay.defaultContext]; RETURN}; place ¬ abs; stopX ¬ absX; IF bottom - 1 < place.y THEN { IF place.y > place.x + bottom - 1 THEN LOOP; place.x ¬ place.x + bottom - 1 - place.y; bitAddress ¬ bitAddress - WindowOps.SpecialTimesWpl[INTEGER[place.y-bottom+1]]; place.y ¬ bottom - 1}; IF right - 1 < place.x THEN { IF place.x > place.y + right - 1 THEN LOOP; place.y ¬ place.y + right - 1 - place.x; bitAddress ¬ bitAddress - WindowOps.SpecialTimesWpl[INTEGER[place.x-right+1]]; place.x ¬ right - 1}; IF top > place.y + stopX - place.x THEN stopX ¬ place.x - place.y + top; IF left > stopX THEN stopX ¬ left; FOR bitIndex: INTEGER DECREASING IN [stopX..place.x] DO bitAddress[bitIndex] ¬ TRUE; -- set a bit bitAddress ¬ bitAddress - SpecialDisplay.defaultContext.wpl; ENDLOOP}; ENDLOOP}; SpNegative45Line: PUBLIC ENTRY PROC [ window: Handle, place: Window.Place, stopX: INTEGER, bounds: Window.BoxHandle, dashes: LineStyle, flags: BitBlt.BitBltFlags, context: Special ¬ SpecialDisplay.defaultContext] = { -- 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 abs: Window.Place = DisplayOps.AbsPlace[window, place]; absX: INTEGER = stopX + window.place.x; SpN45Internal[window, abs, absX, absBounds, dashes, flags, context]}}; SpN45Internal: INTERNAL PROC [ window: Handle, abs: Window.Place, absX: INTEGER, absBounds: WindowOps.ScreenBox, dashes: LineStyle, flags: BitBlt.BitBltFlags, context: Special] = { dashCnt, dashSum: CARDINAL; filled: BOOLEAN = context.alloc # NIL; widths: ARRAY [0..SpecialDisplay.DashCnt) OF CARDINAL; inc1, inc2, inc3, inc4, inc5, inc6: CARDINAL; low: INTEGER = abs.y - dashes.thickness/2; high: INTEGER = low + dashes.thickness; fillcnt, fillLength: INTEGER; fill: FillHandle ¬ NIL; FOR i: CARDINAL IN [0..SpecialDisplay.DashCnt) DO widths[i] ¬ dashes.widths[i]*5/7; ENDLOOP; inc1 ¬ 0; inc2 ¬ widths[0]; inc3 ¬ inc2 + widths[1]; inc4 ¬ inc3 + widths[2]; inc5 ¬ inc4 + widths[3]; inc6 ¬ inc5 + widths[4]; dashSum ¬ inc6 + widths[5]; FOR r: WindowOps.RecList ¬ DisplayOps.FillList[window, filled], r.link UNTIL r = NIL DO IF DisplayOps.Intersect[r, absBounds] THEN { 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]; 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 loopy: INTEGER IN [low..high) DO placey: INTEGER ¬ loopy; placex: INTEGER ¬ abs.x; tempX: INTEGER ¬ absX; bitAddress: WindowOps.ScanLine ¬ ctx.bmAddress + WindowOps.SpecialTimesWpl[INTEGER[placey], ctx]; dashCnt ¬ 0; IF bottom - 1 < placey THEN { dashCnt ¬ (placey - bottom + 1) MOD dashSum; IF placey > placex + bottom - 1 THEN GOTO nextRectangle; placex ¬ placex + bottom - 1 - placey; bitAddress ¬ bitAddress-WindowOps.SpecialTimesWpl[INTEGER[placey-bottom+1],ctx]; placey ¬ bottom - 1}; IF right - 1 < placex THEN { dashCnt ¬ (placex - right + 1 + dashCnt) MOD dashSum; IF placex > placey + right - 1 THEN GOTO nextRectangle; placey ¬ placey + right - 1 - placex; bitAddress ¬ bitAddress - WindowOps.SpecialTimesWpl[INTEGER[placex-right+1],ctx]; placex ¬ right - 1}; IF top > placey + tempX - placex THEN tempX ¬ placex - placey + top; IF left > tempX THEN tempX ¬ left; IF placex - tempX <= 0 THEN GOTO nextRectangle; IF filled THEN fillcnt ¬ placey - top; FOR bitIndex: INTEGER DECREASING IN [tempX..placex] 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])}; dashCnt ¬ (dashCnt + 1) MOD dashSum; bitAddress ¬ bitAddress - ctx.wpl}; ENDLOOP; ENDLOOP; EXITS nextRectangle => NULL}; ENDLOOP}; PositiveShallowLine: PUBLIC ENTRY PROC [ window: Handle, start, stop: Window.Place, bounds: Window.BoxHandle] = { -- because it's positive and shallow, 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 = absStop.x - absStart.x; twox: INTEGER = startError*2; -- positive twoy: CARDINAL = (absStart.y - absStop.y)*2; -- positive 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 { 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 top = bottom THEN LOOP; IF DisplayOps.HasUnder[r] THEN { SpPShInternal[ window, absStart, absStop, absBounds, SpecialDisplay.solid, Display.paintGrayFlags, SpecialDisplay.defaultContext]; RETURN}; start ¬ absStart; stop ¬ absStop; IF bottom - 1 < start.y THEN { netError: LONG CARDINAL = Inline.LongMult[twox, start.y - bottom] + error; difx: INTEGER; [difx, error] ¬ Inline.LongDivMod[netError, twoy]; error ¬ error + twox - twoy; start.x ¬ difx + start.x + 1; bitAddress ¬ bitAddress - WindowOps.SpecialTimesWpl[INTEGER[start.y-bottom+1]]; start.y ¬ bottom - 1}; IF left > start.x THEN { difx: NATURAL; netError: LONG INTEGER ¬ error - Inline.LongMult[twoy, left - start.x]; start.x ¬ left; IF netError < 0 THEN { netError ¬ -netError; [difx, error] ¬ Inline.LongDivMod[netError, twox]; IF error # 0 THEN {difx ¬ difx + 1; error ¬ twox - error}; start.y ¬ start.y - difx; bitAddress ¬ bitAddress - WindowOps.SpecialTimesWpl[difx]} ELSE error ¬ Inline.LowHalf[netError]}; IF top > stop.y THEN { netError: LONG CARDINAL; difx, errorTemp: INTEGER; IF start.y < top THEN LOOP; netError ¬ Inline.LongMult[twox, start.y - top] + error; [difx, errorTemp] ¬ Inline.LongDivMod[netError, twoy]; stop.x ¬ difx + start.x}; IF right - 1 < stop.x THEN stop.x ¬ right - 1; FOR bitIndex: INTEGER IN [start.x..stop.x] DO bitAddress[bitIndex] ¬ TRUE; -- invert a bit error ¬ error - twoy; IF error < 0 THEN { bitAddress ¬ bitAddress - SpecialDisplay.defaultContext.wpl; error ¬ error + twox}; ENDLOOP}; ENDLOOP}; SpPositiveShallowLine: 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 shallow, 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; 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]; SpPShInternal[ window, absStart, absStop, absBounds, dashes, flags, context]}}; SpPShInternal: INTERNAL PROC [ window: Handle, absStart, absStop: Window.Place, absBounds: WindowOps.ScreenBox, dashes: LineStyle, flags: BitBlt.BitBltFlags, context: Special] = { startError: INTEGER = absStop.x - absStart.x; twox: INTEGER = startError*2; -- positive twoy: CARDINAL = (absStart.y - absStop.y)*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.y - dashes.thickness/2; high: INTEGER = low + dashes.thickness; difY: INTEGER ¬ absStop.y - absStart.y; fill: FillHandle ¬ NIL; fillcnt, fillLength: INTEGER; dashstretch: CARDINAL = SELECT twox 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 { 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]; 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 loopy: INTEGER IN [low..high) DO startX: INTEGER ¬ absStart.x; startY: INTEGER ¬ loopy; stopX: INTEGER ¬ absStop.x; stopY: INTEGER ¬ startY + difY; error: INTEGER ¬ startError; bitAddress: WindowOps.ScanLine ¬ ctx.bmAddress + WindowOps.SpecialTimesWpl[INTEGER[startY], ctx]; dashCnt ¬ 0; IF bottom - 1 < startY THEN { netError: LONG CARDINAL = Inline.LongMult[twox, startY - bottom] + error; difx: INTEGER; [difx, error] ¬ Inline.LongDivMod[netError, twoy]; error ¬ error + twox - twoy; startX ¬ difx + startX + 1; dashCnt ¬ (difx + 1) MOD dashSum; bitAddress ¬ bitAddress-WindowOps.SpecialTimesWpl[INTEGER[startY-bottom+1],ctx]; startY ¬ bottom - 1}; IF left > startX THEN { difx: NATURAL; netError: LONG INTEGER ¬ error - Inline.LongMult[twoy, left - startX]; dashCnt ¬ (left - startX + dashCnt) MOD dashSum; startX ¬ left; IF netError < 0 THEN { netError ¬ -netError; [difx, error] ¬ Inline.LongDivMod[netError, twox]; IF error # 0 THEN {difx ¬ difx + 1; error ¬ twox - error}; startY ¬ startY - difx; bitAddress ¬ bitAddress - WindowOps.SpecialTimesWpl[difx, ctx]} ELSE error ¬ Inline.LowHalf[netError]}; IF top > stopY THEN { netError: LONG CARDINAL; difx, errorTemp: INTEGER; IF startY < top THEN GOTO nextRectangle; netError ¬ Inline.LongMult[twox, startY - top] + error; [difx, errorTemp] ¬ Inline.LongDivMod[netError, twoy]; stopX ¬ difx + startX; stopY ¬ top}; IF right - 1 < stopX THEN { IF filled THEN { difx: CARDINAL; errorTemp: INTEGER; netError: LONG INTEGER; IF right <= startX + 1 THEN GOTO nextRectangle; netError ¬ error - Inline.LongMult[twoy, right - 1 - startX]; IF netError < 0 THEN { netError ¬ -netError; [difx, errorTemp] ¬ Inline.LongDivMod[netError, twox]; IF errorTemp # 0 THEN difx ¬ difx + 1; stopY ¬ startY - difx}}; stopX ¬ right - 1}; 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]}; FOR bitIndex: INTEGER IN [startX..stopX] DO IF ~filled THEN { 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]); dashCnt ¬ (dashCnt + 1) MOD dashSum}; error ¬ error - twoy; IF error < 0 THEN { IF filled THEN { IF fillcnt ~IN [0..fillLength) THEN DisplayOps.LogError[]; fill.xs[fillcnt] ¬ bitIndex; fillcnt ¬ fillcnt - 1} ELSE bitAddress ¬ bitAddress - ctx.wpl; error ¬ error + twox}; ENDLOOP; ENDLOOP; EXITS nextRectangle => NULL}; ENDLOOP}; NegativeShallowLine: PUBLIC ENTRY PROC [ window: Handle, start, stop: Window.Place, bounds: Window.BoxHandle] = { -- because it's positive and shallow, 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.x - absStop.x; twox: INTEGER = startError*2; -- positive twoy: CARDINAL = (absStart.y - absStop.y)*2; -- positive 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 { 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 top = bottom THEN LOOP; IF DisplayOps.HasUnder[r] THEN { SpNShInternal[ window, absStart, absStop, absBounds, SpecialDisplay.solid, Display.paintGrayFlags, SpecialDisplay.defaultContext]; RETURN}; start ¬ absStart; stop ¬ absStop; IF bottom - 1 < start.y THEN { netError: LONG CARDINAL = Inline.LongMult[twox, start.y - bottom] + error; difx: INTEGER; [difx, error] ¬ Inline.LongDivMod[netError, twoy]; error ¬ error + twox - twoy; start.x ¬ start.x - difx - 1; bitAddress ¬ bitAddress - WindowOps.SpecialTimesWpl[INTEGER[start.y-bottom+1]]; start.y ¬ bottom - 1}; IF right - 1 < start.x THEN { difx: NATURAL; netError: LONG INTEGER ¬ error - Inline.LongMult[twoy, start.x - right + 1]; start.x ¬ right - 1; IF netError < 0 THEN { netError ¬ -netError; [difx, error] ¬ Inline.LongDivMod[netError, twox]; IF error # 0 THEN {difx ¬ difx + 1; error ¬ twox - error}; start.y ¬ start.y - difx; bitAddress ¬ bitAddress - WindowOps.SpecialTimesWpl[difx]} ELSE error ¬ Inline.LowHalf[netError]}; IF top > stop.y THEN { netError: LONG CARDINAL; difx, errorTemp: INTEGER; IF start.y < top THEN LOOP; netError ¬ Inline.LongMult[twox, start.y - top] + error; [difx, errorTemp] ¬ Inline.LongDivMod[netError, twoy]; stop.x ¬ start.x - difx}; IF left > stop.x THEN stop.x ¬ left; FOR bitIndex: INTEGER DECREASING IN [stop.x..start.x] DO bitAddress[bitIndex] ¬ TRUE; -- set a bit error ¬ error - twoy; IF error < 0 THEN { bitAddress ¬ bitAddress - SpecialDisplay.defaultContext.wpl; error ¬ error + twox}; ENDLOOP}; ENDLOOP}; SpNegativeShallowLine: 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 shallow, 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]; SpNShInternal[ window, absStart, absStop, absBounds, dashes, flags, context]}}; SpNShInternal: INTERNAL PROC [ window: Handle, absStart, absStop: Window.Place, absBounds: WindowOps.ScreenBox, dashes: LineStyle, flags: BitBlt.BitBltFlags, context: Special] = { startError: INTEGER = absStart.x - absStop.x; twox: INTEGER = startError*2; -- positive twoy: CARDINAL = (absStart.y - absStop.y)*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.y - dashes.thickness/2; high: INTEGER = low + dashes.thickness; difY: INTEGER ¬ absStop.y - absStart.y; fill: FillHandle ¬ NIL; fillcnt, fillLength: INTEGER; dashstretch: CARDINAL = SELECT twox 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 { 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]; 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 loopy: INTEGER IN [low..high) DO startX: INTEGER ¬ absStart.x; startY: INTEGER ¬ loopy; stopX: INTEGER ¬ absStop.x; stopY: INTEGER ¬ startY + difY; error: INTEGER ¬ startError; bitAddress: WindowOps.ScanLine ¬ ctx.bmAddress + WindowOps.SpecialTimesWpl[INTEGER[startY], ctx]; dashCnt ¬ 0; IF bottom - 1 < startY THEN { netError: LONG CARDINAL = Inline.LongMult[twox, startY - bottom] + error; difx: INTEGER; [difx, error] ¬ Inline.LongDivMod[netError, twoy]; error ¬ error + twox - twoy; startX ¬ startX - difx - 1; dashCnt ¬ (difx + 1) MOD dashSum; bitAddress ¬ bitAddress-WindowOps.SpecialTimesWpl[INTEGER[startY-bottom+1],ctx]; startY ¬ bottom - 1}; IF right - 1 < startX THEN { difx: NATURAL; netError: LONG INTEGER ¬ error - Inline.LongMult[twoy, startX - right + 1]; dashCnt ¬ (startX - right + 1 + dashCnt) MOD dashSum; startX ¬ right - 1; IF netError < 0 THEN { netError ¬ -netError; [difx, error] ¬ Inline.LongDivMod[netError, twox]; IF error # 0 THEN {difx ¬ difx + 1; error ¬ twox - error}; startY ¬ startY - difx; bitAddress ¬ bitAddress - WindowOps.SpecialTimesWpl[difx, ctx]} ELSE error ¬ Inline.LowHalf[netError]}; IF top > stopY THEN { netError: LONG CARDINAL; difx, errorTemp: INTEGER; IF startY < top THEN GOTO nextRectangle; netError ¬ Inline.LongMult[twox, startY - top] + error; [difx, errorTemp] ¬ Inline.LongDivMod[netError, twoy]; stopX ¬ startX - difx; stopY ¬ top}; IF left > stopX THEN { IF filled THEN { difx: CARDINAL; errorTemp: INTEGER; netError: LONG INTEGER; IF startX <= left THEN GOTO nextRectangle; netError ¬ error - Inline.LongMult[twoy, startX - left]; IF netError < 0 THEN { netError ¬ -netError; [difx, errorTemp] ¬ Inline.LongDivMod[netError, twox]; IF errorTemp # 0 THEN difx ¬ difx + 1; stopY ¬ startY - difx}}; stopX ¬ left}; 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]}; FOR bitIndex: INTEGER DECREASING IN [stopX..startX] DO IF ~filled THEN { 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]); dashCnt ¬ (dashCnt + 1) MOD dashSum}; error ¬ error - twoy; IF error < 0 THEN { IF filled THEN { IF fillcnt ~IN [0..fillLength) THEN DisplayOps.LogError[]; fill.xs[fillcnt] ¬ bitIndex; fillcnt ¬ fillcnt - 1} ELSE bitAddress ¬ bitAddress - ctx.wpl; error ¬ error + twox}; ENDLOOP; ENDLOOP; EXITS nextRectangle => NULL}; ENDLOOP}; END.