-- 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.