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