-- Copyright (C) 1982, 1983  by Xerox Corporation. All rights reserved. 
-- WindowImplC.mesa - last edited by 
-- Rick		 4-Aug-82 10:36:58  
-- Bruce	18-Dec-82 13:14:16
-- Daniels	29-Nov-83 16:25:25

DIRECTORY
  BitBlt: TYPE USING [
    AlignedBBTable, BBptr, BBTableSpace, BitAddress, BITBLT, BitBltFlags, DstFunc,
    GrayParm],
  Display: TYPE USING [
    boxFlags, BreakReason, Brick, fiftyPercent, infinity, TrajectoryProc,
    xorBoxFlags],
  Environment: TYPE USING [Block],
  Inline: TYPE USING [BITAND, DBITSHIFT, LongMult, LongNumber, LowHalf],
  RecOps: TYPE USING [Coalesce, Convert, ConvertBox, FreeRecList, Intersect],
  SpecialDisplay: TYPE USING [defaultContext, Special],
  Window: TYPE USING [Box, BoxHandle, nullBox, Place],
  WindowFont: TYPE USING [defaultFont, Handle],
  WindowOps: TYPE USING [
    AbsoluteBox, AbsoluteBoxHandle, Bounds, DisplayList, DIVMOD16, GetContext,
    lock, Object, Offset, RecList, ScreenBox, SpecialTimesWpl];

WindowImplC: MONITOR LOCKS WindowOps.lock
  IMPORTS BitBlt, Inline, RecOps, SpecialDisplay, WindowOps, WindowFont
  EXPORTS Display, SpecialDisplay, Window, WindowOps =
  BEGIN

  Handle: TYPE = LONG POINTER TO Object;
  Object: PUBLIC TYPE = WindowOps.Object;
  Place: TYPE = Window.Place;

  bbTable: BitBlt.BBTableSpace;
  bbPtr: PUBLIC BitBlt.BBptr ← BitBlt.AlignedBBTable[@bbTable];

  -- box things 

  White: PUBLIC PROC [window: Handle, box: Window.Box] = {
    white: ARRAY [0..1) OF CARDINAL ← ALL[0];
    IF window.inTree THEN SpGray[
      window, box, DESCRIPTOR[white], Display.boxFlags]};

  SpWhite: PUBLIC PROC [
    window: Handle, box: Window.Box, context: SpecialDisplay.Special] = {
    white: ARRAY [0..1) OF CARDINAL ← ALL[0];
    SpGray[window, box, DESCRIPTOR[white], Display.boxFlags, context]};

  Black: PUBLIC PROC [window: Handle, box: Window.Box] = {
    black: ARRAY [0..1) OF CARDINAL ← ALL[CARDINAL.LAST];
    IF window.inTree THEN SpGray[
      window, box, DESCRIPTOR[black], Display.boxFlags]};

  SpBlack: PUBLIC PROC [
    window: Handle, box: Window.Box, context: SpecialDisplay.Special] = {
    black: ARRAY [0..1) OF CARDINAL ← ALL[CARDINAL.LAST];
    SpGray[window, box, DESCRIPTOR[black], Display.boxFlags, context]};

  Invert: PUBLIC PROC [window: Handle, box: Window.Box] = {
    black: ARRAY [0..1) OF CARDINAL ← ALL[CARDINAL.LAST];
    IF window.inTree THEN SpGray[
      window, box, DESCRIPTOR[black], Display.xorBoxFlags]};

  SpInvert: PUBLIC PROC [
    window: Handle, box: Window.Box, context: SpecialDisplay.Special] = {
    black: ARRAY [0..1) OF CARDINAL ← ALL[CARDINAL.LAST];
    SpGray[window, box, DESCRIPTOR[black], Display.xorBoxFlags, context]};

  Gray: PUBLIC PROC [
    window: Handle, box: Window.Box, gray: Display.Brick,
    dstFunc: BitBlt.DstFunc] = {
    flags: BitBlt.BitBltFlags = [
      direction: forward, disjoint: TRUE, disjointItems: TRUE, gray: TRUE,
      srcFunc: null, dstFunc: dstFunc, reserved: 0];
    IF window.inTree THEN SpGray[window, box, gray, flags]};

  fifty: ARRAY [0..2) OF CARDINAL ← [125252B, 52525B];

  SpGray: PUBLIC ENTRY PROC [
    window: Handle, box: Window.Box, gray: Display.Brick,
    flags: BitBlt.BitBltFlags,
    context: SpecialDisplay.Special ← SpecialDisplay.defaultContext] = {
    ENABLE UNWIND => NULL;
    abs: WindowOps.ScreenBox = WindowOps.AbsoluteBox[window, box];
    IF gray = Display.fiftyPercent THEN gray ← DESCRIPTOR[fifty];
    flags.gray ← TRUE;
    FOR r: WindowOps.RecList ← WindowOps.DisplayList[window], r.link UNTIL r = NIL
      DO
      left: INTEGER = MAX[r.box.left, abs.left];
      top: INTEGER = MAX[r.box.top, abs.top];
      right: INTEGER = MIN[r.box.right, abs.right];
      bottom: INTEGER = MIN[r.box.bottom, abs.bottom];
      width: INTEGER = right - left;
      height: INTEGER = bottom - top;
      ctx: SpecialDisplay.Special = WindowOps.GetContext[r, context];
      offset, bit, yOffset: INTEGER;
      IF width <= 0 OR height <= 0 THEN LOOP;
      yOffset ← CARDINAL[top - window.place.y] MOD gray.LENGTH;
      [offset, bit] ← WindowOps.DIVMOD16[CARDINAL[left]];
      bbPtr↑ ← [
        dst: [
        word: ctx.bmAddress + WindowOps.SpecialTimesWpl[top, ctx] + offset,
        bit: bit],
        src: [
	  word: gray.BASE + yOffset, bit: CARDINAL[left - window.place.x] MOD 16],
        srcDesc: [gray[BitBlt.GrayParm[
          yOffset: yOffset, widthMinusOne: 0, heightMinusOne: gray.LENGTH - 1]]],
        dstBpl: ctx.bpl, width: width, height: height, flags: flags];
      BitBlt.BITBLT[bbPtr];
      ENDLOOP};

  Trajectory: PUBLIC ENTRY PROC [
    window: Handle, box: Window.Box, proc: Display.TrajectoryProc,
    source: LONG POINTER, bpl: CARDINAL, height: CARDINAL,
    flags: BitBlt.BitBltFlags, missesChildren: BOOLEAN, brick: Display.Brick] = {
    ENABLE UNWIND => NULL;
    dl, temp: WindowOps.RecList;
    IF ~window.inTree THEN RETURN;
    dl ← RecOps.Coalesce[RecOps.Intersect[
      (temp ← IF box = Window.nullBox THEN RecOps.Convert[window] 
        ELSE RecOps.ConvertBox[window, box]),
      WindowOps.DisplayList[window]]];
    RecOps.FreeRecList[temp];
    IF dl = NIL THEN RETURN;
    IF flags.gray AND brick = Display.fiftyPercent THEN brick ← DESCRIPTOR[fifty];
    DO
      ENABLE UNWIND => RecOps.FreeRecList[dl];
      brushOffset, absOffset, absBit: CARDINAL; 
      abs: WindowOps.ScreenBox;
      brushBox: Window.Box;
      [brushBox, brushOffset] ← proc[window];
      IF brushBox.dims.w = 0 THEN EXIT; -- really should be Window.nullBox...
      abs ← WindowOps.AbsoluteBox[window, brushBox];
      [absOffset, absBit] ← WindowOps.Offset[abs.left];
      -- do gray in a separate loop...
      IF flags.gray THEN FOR r: WindowOps.RecList ← dl, r.link UNTIL r = NIL DO
        left: INTEGER = MAX[r.box.left, abs.left];
        top: INTEGER = MAX[r.box.top, abs.top];
        right: INTEGER = MIN[r.box.right, abs.right];
        bottom: INTEGER = MIN[r.box.bottom, abs.bottom];
        width: INTEGER = right - left;
        height: INTEGER = bottom - top;
        ctx: SpecialDisplay.Special = WindowOps.GetContext[
	  r, SpecialDisplay.defaultContext];
        offset, bit, yOffset: INTEGER;
        IF width <= 0 OR height <= 0 THEN LOOP;
        yOffset ← CARDINAL[top - window.place.y] MOD brick.LENGTH;
        [offset, bit] ← WindowOps.DIVMOD16[CARDINAL[left]];
        bbPtr↑ ← [
          dst: [
            word: ctx.bmAddress + WindowOps.SpecialTimesWpl[top, ctx] + offset,
            bit: bit],
          src: [
	    word: brick.BASE + yOffset,
	    bit: CARDINAL[left - window.place.x] MOD 16],
          srcDesc: [gray[BitBlt.GrayParm[
            yOffset: yOffset, widthMinusOne: 0,
	    heightMinusOne: brick.LENGTH - 1]]],
          dstBpl: ctx.bpl, width: width, height: height, flags: flags];
        BitBlt.BITBLT[bbPtr];
        ENDLOOP
      ELSE FOR r: WindowOps.RecList ← dl, r.link UNTIL r = NIL DO
        clipLeft: INTEGER = r.box.left - abs.left;
        clipTop: INTEGER = r.box.top - abs.top;
        clipRight: INTEGER = abs.right - r.box.right;
        clipBottom: INTEGER = abs.bottom - r.box.bottom;
        ctx: SpecialDisplay.Special = WindowOps.GetContext[
	  r, SpecialDisplay.defaultContext];
	offset, bit: CARDINAL;
	[offset, bit] ← WindowOps.DIVMOD16[brushOffset];
	bbPtr↑ ← [
	  dst: [word: ctx.bmAddress + absOffset + 
	    WindowOps.SpecialTimesWpl[abs.top, ctx], bit: absBit],
	  dstBpl: ctx.bpl, flags: flags,
	  height: brushBox.dims.h, width: brushBox.dims.w,
	  src: [word: source + offset, bit: bit], srcDesc: [srcBpl[bpl]]];
	IF clipTop > 0 THEN {
	  bbPtr.src.word ← bbPtr.src.word +
	    Inline.DBITSHIFT[Inline.LongMult[clipTop, bpl], -4];
	  bbPtr.height ← bbPtr.height - clipTop;
	  bbPtr.dst.word ← bbPtr.dst.word + 
	    WindowOps.SpecialTimesWpl[clipTop, ctx]};
	IF clipBottom > 0 THEN bbPtr.height ← bbPtr.height - clipBottom;
	IF clipRight > 0 THEN bbPtr.width ← bbPtr.width - clipRight;
	IF clipLeft > 0 THEN {
	  wordOffset, bitOffset, bit: INTEGER;
	  [wordOffset, bitOffset] ← WindowOps.DIVMOD16[CARDINAL[clipLeft]];
	  bbPtr.src.word ← bbPtr.src.word + wordOffset;
	  bbPtr.dst.word ← bbPtr.dst.word + wordOffset;
	  [wordOffset, bit] ← WindowOps.DIVMOD16[
	    CARDINAL[bbPtr.src.bit + bitOffset]];
	  bbPtr.src ← [word: bbPtr.src.word + wordOffset, bit: bit];
	  [wordOffset, bit] ← WindowOps.DIVMOD16[
	    CARDINAL[bbPtr.dst.bit + bitOffset]];
	  bbPtr.dst ← [word: bbPtr.dst.word + wordOffset, bit: bit];
	  bbPtr.width ← bbPtr.width - clipLeft};
	IF INTEGER[bbPtr.width] <= 0 OR INTEGER[bbPtr.height] <= 0 THEN LOOP;
	BitBlt.BITBLT[bbPtr];
	ENDLOOP;
      ENDLOOP;
    RecOps.FreeRecList[dl]};
      
  -- text

  Character: PUBLIC PROC [
    window: Handle, char: CHARACTER, place: Window.Place, font: WindowFont.Handle,
    flags: BitBlt.BitBltFlags, bounds: Window.BoxHandle] RETURNS [Window.Place] = {
    IF window.inTree THEN
      RETURN SpCharacter[window, char, place, font, flags, bounds]
    ELSE {
      IF font = NIL THEN font ← WindowFont.defaultFont;
      RETURN[[place.x + font.width[char], place.y]]}};

  SpCharacter: PUBLIC ENTRY PROC [
    window: Handle, char: CHARACTER, place: Window.Place, font: WindowFont.Handle,
    flags: BitBlt.BitBltFlags, bounds: Window.BoxHandle,
    context: SpecialDisplay.Special ← SpecialDisplay.defaultContext]
    RETURNS [Window.Place] = {
    ENABLE UNWIND => NULL;
    absBound: WindowOps.ScreenBox =
      IF bounds = NIL THEN WindowOps.Bounds[window]
      ELSE WindowOps.AbsoluteBoxHandle[window, bounds];
    flags.gray ← FALSE;
    IF font = NIL THEN font ← WindowFont.defaultFont;
    FOR r: WindowOps.RecList ← WindowOps.DisplayList[window], r.link UNTIL r = NIL
      DO
      top: INTEGER = place.y + window.place.y;
      left: INTEGER = place.x + window.place.x;
      height: INTEGER ← font.height;
      clipBottom: INTEGER = top + height - MIN[r.box.bottom, absBound.bottom];
      clipTop: INTEGER = MAX[r.box.top, absBound.top] - top;
      clipLeft: INTEGER = MAX[r.box.left, absBound.left];
      clipRight: INTEGER = MIN[r.box.right, absBound.right];
      bits: LONG POINTER ← font.bitmap;
      width: INTEGER ← font.width[char];
      ctx: SpecialDisplay.Special = WindowOps.GetContext[r, context];
      bitmapBase: LONG POINTER ←
        ctx.bmAddress + WindowOps.SpecialTimesWpl[top, ctx];
      clippedPart, charOffset, charBit, bitmapOffset, bitmapBit: INTEGER;
      IF width = 0 THEN {
        char ← font.max.SUCC; width ← font.width[char]};
      IF clipTop > 0 THEN {
        bits ← bits + Inline.LongMult[clipTop, font.raster];
        height ← height - clipTop;
        bitmapBase ← bitmapBase + WindowOps.SpecialTimesWpl[clipTop, ctx]};
      IF clipBottom > 0 THEN height ← height - clipBottom;
      IF height <= 0 THEN LOOP;
      IF (clippedPart ← left + width - clipRight) > 0 THEN {
        width ← width - clippedPart; IF width <= 0 THEN LOOP};
      IF (clippedPart ← clipLeft - left) > 0 THEN {
        width ← width - clippedPart;
        IF width <= 0 THEN LOOP;
        [bitmapOffset, bitmapBit] ← WindowOps.DIVMOD16[CARDINAL[clipLeft]];
        [charOffset, charBit] ← WindowOps.DIVMOD16[
          font.xInSegment[char] + clippedPart]}
      ELSE {
        [bitmapOffset, bitmapBit] ← WindowOps.Offset[left];
        [charOffset, charBit] ← WindowOps.DIVMOD16[font.xInSegment[char]]};
      bbPtr↑ ← [
        dst: [word: bitmapBase + bitmapOffset, bit: bitmapBit],
        src: [word: bits + charOffset, bit: charBit], dstBpl: ctx.bpl,
        height: height, width: width, srcDesc: [srcBpl[font.raster*16]],
        flags: flags];
      BitBlt.BITBLT[bbPtr];
      ENDLOOP;
    RETURN[[place.x + font.width[char], place.y]]};

  Block: PUBLIC PROC [
    window: Handle, block: Environment.Block, lineLength: INTEGER,
    place: Window.Place, font: WindowFont.Handle, flags: BitBlt.BitBltFlags,
    bounds: Window.BoxHandle]
    RETURNS [
      newPlace: Window.Place, positions: CARDINAL, why: Display.BreakReason] = {
    RETURN (
      IF window.inTree THEN
        SpBlock[window, block, lineLength, place, font, flags, bounds]
      ELSE MeasureBlock[window, block, lineLength, place, font])};

  Text: PUBLIC PROC [
    window: Handle, string: LONG STRING, place: Window.Place,
    font: WindowFont.Handle, lineLength: INTEGER, flags: BitBlt.BitBltFlags,
    bounds: Window.BoxHandle] RETURNS [newPlace: Window.Place] = {
    RETURN[(
      IF window.inTree THEN SpBlock[
	window, [LOOPHOLE[@string.text], 0, string.length], lineLength,
	place, font, flags, bounds]
      ELSE MeasureBlock[
        window, [LOOPHOLE[@string.text], 0, string.length], lineLength,
	place, font]).newPlace]};

  SpBlock: PUBLIC ENTRY PROC [
    window: Handle, block: Environment.Block, lineLength: INTEGER,
    place: Window.Place, font: WindowFont.Handle, flags: BitBlt.BitBltFlags,
    bounds: Window.BoxHandle,
    context: SpecialDisplay.Special ← SpecialDisplay.defaultContext]
    RETURNS [
      newPlace: Window.Place, positions: CARDINAL, why: Display.BreakReason] = {
    ENABLE UNWIND => NULL;
    absBound: WindowOps.ScreenBox =
      IF bounds = NIL THEN WindowOps.Bounds[window]
      ELSE WindowOps.AbsoluteBoxHandle[window, bounds];
    displayList: WindowOps.RecList;
    IF font = NIL THEN font ← WindowFont.defaultFont;
    IF lineLength = Display.infinity THEN 
      lineLength ← window.box.dims.w - place.x;
    flags.gray ← FALSE;
    positions ← 0;
    why ← normal;
    newPlace ← place;
    displayList ← WindowOps.DisplayList[window];
    IF displayList = NIL THEN 
      RETURN MeasureBlock[window, block, lineLength, place, font];
    FOR r: WindowOps.RecList ← displayList, r.link UNTIL r = NIL
      DO
      top: INTEGER = place.y + window.place.y;
      left: INTEGER ← place.x + window.place.x;  -- start of character
      x: INTEGER ← left;  -- stop of character
      stop: INTEGER = left + lineLength;
      bits: LONG POINTER ← font.bitmap;
      height: INTEGER ← font.height;
      clipBottom: INTEGER = top + height - MIN[r.box.bottom, absBound.bottom];
      clipTop: INTEGER = MAX[r.box.top, absBound.top] - top;
      clipLeft: INTEGER = MAX[r.box.left, absBound.left];
      clipRight: INTEGER = MIN[r.box.right, absBound.right];
      ctx: SpecialDisplay.Special = WindowOps.GetContext[r, context];
      bitmapBase: LONG POINTER ←
        ctx.bmAddress + WindowOps.SpecialTimesWpl[top, ctx];
      charCount: CARDINAL ← 0;
      IF clipTop > 0 THEN {
        bits ← bits + Inline.LongMult[clipTop, font.raster];
        height ← height - clipTop;
        bitmapBase ← bitmapBase + WindowOps.SpecialTimesWpl[clipTop, ctx]};
      IF clipBottom > 0 THEN height ← height - clipBottom;
      FOR i: CARDINAL IN [block.startIndex..block.stopIndexPlusOne) DO
        char: CHARACTER = LOOPHOLE[block.blockPointer[i]];
        width: INTEGER ← font.width[char];
        clippedPart, charOffset, charBit, bitmapOffset, bitmapBit: INTEGER;
        IF width = 0 THEN {why ← stop; EXIT};
        IF (x ← x + width) > stop THEN {why ← margin; EXIT};
        charCount ← charCount + 1;
        IF height <= 0 THEN {left ← x; LOOP};
        IF (clippedPart ← left + width - clipRight) > 0 THEN {
          width ← width - clippedPart; IF width <= 0 THEN {left ← x; LOOP}};
        IF (clippedPart ← clipLeft - left) > 0 THEN {
          width ← width - clippedPart;
          IF width <= 0 THEN {left ← x; LOOP};
          [bitmapOffset, bitmapBit] ← WindowOps.DIVMOD16[CARDINAL[clipLeft]];
          [charOffset, charBit] ← WindowOps.DIVMOD16[
            font.xInSegment[char] + clippedPart]}
        ELSE {
          [bitmapOffset, bitmapBit] ← WindowOps.Offset[left];
          [charOffset, charBit] ← WindowOps.DIVMOD16[font.xInSegment[char]]};
        bbPtr↑ ← [
          dst: [word: bitmapBase + bitmapOffset, bit: bitmapBit],
          src: [word: bits + charOffset, bit: charBit], dstBpl: ctx.bpl,
          height: height, width: width, srcDesc: [srcBpl[font.raster*16]],
          flags: flags];
        BitBlt.BITBLT[bbPtr];
        left ← x;
        ENDLOOP;
      positions ← MAX[positions, charCount];
      newPlace.x ← left - window.place.x;
      ENDLOOP};

  MeasureBlock: PUBLIC PROC [
    window: Handle, block: Environment.Block, lineLength: INTEGER,
    place: Window.Place, font: WindowFont.Handle]
    RETURNS [
      newPlace: Window.Place, positions: CARDINAL, why: Display.BreakReason] = {
    rightMargin: INTEGER = MIN[Display.infinity, place.x + lineLength];
    chars: LONG POINTER TO PACKED ARRAY OF CHARACTER =
      LOOPHOLE[block.blockPointer];
    pos: CARDINAL;
    IF font = NIL THEN font ← WindowFont.defaultFont;
    newPlace ← place;
    FOR pos IN [block.startIndex..block.stopIndexPlusOne) DO
      charWidth: INTEGER = font.width[chars[pos]];
      newRight: INTEGER = newPlace.x + charWidth;
      SELECT TRUE FROM
        charWidth = 0 => RETURN[newPlace, pos - block.startIndex, stop];
        newRight > rightMargin => RETURN[
	  newPlace, pos - block.startIndex, margin];
        ENDCASE => newPlace.x ← newRight;
      REPEAT
        FINISHED =>
          RETURN[newPlace, block.stopIndexPlusOne - block.startIndex, normal];
      ENDLOOP};

  ResolveBlock: PUBLIC PROC [
    window: Handle, block: Environment.Block,
    offsets: LONG POINTER TO ARRAY CARDINAL [0..0) OF CARDINAL,
    font: WindowFont.Handle]
    RETURNS [positions: CARDINAL ← 0, why: Display.BreakReason] = {
    chars: LONG POINTER TO PACKED ARRAY OF CHARACTER =
      LOOPHOLE[block.blockPointer];
    lastOffset: CARDINAL ← 0;
    pos: CARDINAL;
    IF font = NIL THEN font ← WindowFont.defaultFont;
    FOR pos IN [block.startIndex..block.stopIndexPlusOne) DO
      width: INTEGER = font.width[chars[pos]];
      IF width = 0 THEN RETURN[pos - block.startIndex, stop];
      offsets[pos - block.startIndex] ← lastOffset ← lastOffset + width;
      REPEAT FINISHED => RETURN[
        block.stopIndexPlusOne - block.startIndex, normal];
      ENDLOOP};

  -- bitmaps

  Bitmap: PUBLIC PROC [
    window: Handle, box: Window.Box, address: BitBlt.BitAddress,
    bitmapBitWidth: CARDINAL, flags: BitBlt.BitBltFlags] = {
    IF window.inTree THEN SpBitmap[window, box, address, bitmapBitWidth, flags]};

  SpBitmap: PUBLIC ENTRY PROC [
    window: Handle, box: Window.Box, address: BitBlt.BitAddress,
    bitmapBitWidth: CARDINAL, flags: BitBlt.BitBltFlags,
    context: SpecialDisplay.Special ← SpecialDisplay.defaultContext] = {
    ENABLE UNWIND => NULL;
    abs: WindowOps.ScreenBox = WindowOps.AbsoluteBox[window, box];
    absOffset, absBit: INTEGER;
    flags.gray ← FALSE;
    [absOffset, absBit] ← WindowOps.Offset[abs.left];
    FOR r: WindowOps.RecList ← WindowOps.DisplayList[window], r.link UNTIL r = NIL
      DO
      clipLeft: INTEGER = r.box.left - abs.left;
      clipTop: INTEGER = r.box.top - abs.top;
      clipRight: INTEGER = abs.right - r.box.right;
      clipBottom: INTEGER = abs.bottom - r.box.bottom;
      ctx: SpecialDisplay.Special = WindowOps.GetContext[r, context];
      bbPtr↑ ← [
        dst: [word: ctx.bmAddress + absOffset + WindowOps.SpecialTimesWpl[
          abs.top, ctx], bit: absBit], 
	src: address, dstBpl: ctx.bpl, height: box.dims.h, width: box.dims.w,
        srcDesc: [srcBpl[bitmapBitWidth]], flags: flags];
      IF clipTop > 0 THEN {
        LMOD16: PROC [lc: LONG CARDINAL] RETURNS [CARDINAL[0..16)] = INLINE {
	  RETURN[Inline.LowHalf[lc] MOD 16]};
	bump: LONG CARDINAL = Inline.LongMult[clipTop, bitmapBitWidth];
        word: INTEGER;
	bbPtr.src.word ← bbPtr.src.word + bump/16;
	[word, bbPtr.src.bit] ← WindowOps.DIVMOD16[bbPtr.src.bit + LMOD16[bump]];
	bbPtr.src.word ← bbPtr.src.word + word;
        bbPtr.height ← bbPtr.height - clipTop;
        bbPtr.dst.word ← bbPtr.dst.word + WindowOps.SpecialTimesWpl[
	  clipTop, ctx]};
      IF clipBottom > 0 THEN bbPtr.height ← bbPtr.height - clipBottom;
      IF clipRight > 0 THEN bbPtr.width ← bbPtr.width - clipRight;
      IF clipLeft > 0 THEN {
        wordOffset, bitOffset, bit: INTEGER;
        [wordOffset, bitOffset] ← WindowOps.DIVMOD16[CARDINAL[clipLeft]];
        bbPtr.src.word ← bbPtr.src.word + wordOffset;
        bbPtr.dst.word ← bbPtr.dst.word + wordOffset;
        [wordOffset, bit] ← WindowOps.DIVMOD16[
	  CARDINAL[bbPtr.src.bit + bitOffset]];
        bbPtr.src ← [word: bbPtr.src.word + wordOffset, bit: bit];
        [wordOffset, bit] ← WindowOps.DIVMOD16[
	  CARDINAL[bbPtr.dst.bit + bitOffset]];
        bbPtr.dst ← [word: bbPtr.dst.word + wordOffset, bit: bit];
        bbPtr.width ← bbPtr.width - clipLeft};
      IF INTEGER[bbPtr.width] <= 0 OR INTEGER[bbPtr.height] <= 0 THEN LOOP;
      BitBlt.BITBLT[bbPtr];
      ENDLOOP};

  -- Utility for address calculation

  BitAddressFromPlace: PUBLIC PROC [
    base: BitBlt.BitAddress, x, y: NATURAL, raster: CARDINAL]
    RETURNS [BitBlt.BitAddress] = {
    OPEN Inline;
    LocalBitAddress: TYPE = RECORD [word: LONG POINTER, bit: CARDINAL];
    bitOffset: LongNumber = [
      lc[LongMult[y, raster] + LOOPHOLE[base, LocalBitAddress].bit + x]];
    RETURN[
      LOOPHOLE[LocalBitAddress[
        word: base.word + DBITSHIFT[bitOffset.lu, -4],
        bit: BITAND[bitOffset.lowbits, 15]]]]};

  END.