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