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