<*PRAGMA LL*> INTERFACEAScrnPaintOp ; IMPORT TrestleComm, PaintOp;
ScrnPaintOp.T is a painting operation that is valid for
   some particular screentype.
   If op is a ScrnPaintOp.T valid for screentype st, then op
   maps a source pixel s and destination pixel d to a result pixel
   op(d, s).  It will be used in a painting operation that sets d
   := op(d, s).  Both d and op(d, s) have type st, and s either
   has type st or st.bits.  (The type st.bits is the screentype
   for one-bit deep sources that can be used with st.) For example,
   in a copy operation, s has type st, while in painting a bitmap,
   s has type st.bits.
   A ScrnPaintOp.Oracle is meaningful only as the op field of some
   screentype st.  It provides methods to generate ScreenPaintOp.Ts
   that are valid for st.
   A {\it tint} is a paintop that is independent of s.  If op is
   a tint, we write op(d) instead of op(d, s).  (Even in the case
   of a tint, the type of s must be st.bits; otherwise the result
   of applying the tint is undefined.)  
\subsubsection{Obtaining handles from the oracle}
TYPE
  Pixel = INTEGER;
  Oracle = Private OBJECT
    METHODS
      <* LL.sup <= VBT.mu *>
      opaque(pix: Pixel): T
        RAISES {Failure, TrestleComm.Failure};
      bgfg(bg, fg: T): T
        RAISES {Failure, TrestleComm.Failure};
      swap(p,q: Pixel): T
        RAISES {Failure, TrestleComm.Failure};
      transparent(): T
        RAISES {Failure, TrestleComm.Failure};
      copy(): T
        RAISES {Failure, TrestleComm.Failure};
      builtIn(op: PaintOp.Predefined): T;
    END;
    Private <: ROOT;
EXCEPTION Failure;
 For a screentype st, the field st.op is an Oracle whose methods
   satisfy the following specifications:
The method call
      op := st.op.opaque(pix)
   sets op to a tint such that op(p) = pix for any p. The method call
      op := st.op.bgfg(bg, fg)
   sets op to a tint such that op(p, 0) = bg(p) and op(p, 1)
   = fg(p), for any p, if bg and fg are tints. The method call
      op := st.op.swap(p, q)
   sets op to a tint such that op(p)=q, op(q)=p, and for any
   x, op(op(x))=x. The method call
      op := st.op.transparent()
   sets op to a tint such that op(p) = p for any p. The method call
      op := st.op.copy()
   sets op to a painting operation such that op(p, q) = q for any
   p and q. The method call
      st.op.builtIn(op)
   returns the operation valid for st that corresponds to the
   predefined screen-independent operation PaintOp.T{op}.
   The exception Failure is raised if the screentype cannot provide the
   requested painting operation. For all the methods, LL.sup <= VBT.mu. 
TYPE
  PlaneWiseOracle = Oracle OBJECT
    METHODS <* LL.sup <= VBT.mu *>
      planewise(
          READONLY mask: ARRAY OF BOOLEAN;
          op1, op2: T): T
        RAISES {Failure, TrestleComm.Failure};
  END;
 If a screentype's op oracle is a PlaneWiseOracle (which you can
   test with TYPECASE), then you can use its planewise method to
   define painting operations by their effects on each bit position
   of the destination pixel.  Let p[i] denote bit i of pixel p.
   Assuming NUMBER(mask) = st.depth, the method call
      op := st.op.planewise(mask, bitOps)
sets op so that for d and s of screentype st and i in
[0..st.depth-1],
      IF mask[i] THEN
         op(d, s)[i] = op1(d[i], s[i])
      ELSE
         op(d, s)[i] = op2(d[i], s[i])
      END
The method may raise Failure if it does not support a particular
combination of op1, op2, and mask.
The convenience procedure ConstructPlanewiseOp can be used to construct a painting operation from an array of boolean functions represented by the
enumeration by BitOp: 
TYPE
  BitOp = {
    Zero,           (* 0 *)
    And,            (* dest AND src *)
    NotAnd,         (* (NOT dest) AND src *)
    Src,            (* src *)
    AndNot,         (* dest and (NOT src) *)
    Dest,           (* dest *)
    Xor,            (* dest XOR src *)
    Or,             (* dest OR src *)
    Nor,            (* (NOT dest) AND (NOT src) *)
    Equal,          (* dest XOR (NOT src) *)
    Invert,         (* NOT dest *)
    NotOr,          (* (NOT dest) OR src *)
    NotSrc,         (* NOT src *)
    OrNot,          (* dest OR (NOT src) *)
    Nand,           (* (NOT dest) OR (NOT src) *)
    One};           (* 1 *)
PROCEDURE ConstructPlanewiseOp(
  pwo: PlaneWiseOracle;
  READONLY bitOps: ARRAY OF BitOp): T
RAISES {Failure, TrestleComm.Failure};
<* LL.sup <= VBT.mu *>
Return the painting operation that appliesbitOp[i]to planeiof the source and destination.
If
NUMBER(bitOps) = st.depth then ConstructPlanewiseOp uses pwo to
construct and return an operation op such that for s and
d of screentype st and i in [0 .. st.depth-1],
       op(d, s)[i] = bitOps[i](d[i], s[i])
The procedure may raise Failure if the screentype does not support
a particular array bitOps. 
\subsubsection{The handle object}
TYPE T <: Public; Public = OBJECT id: INTEGER; pix: Pixel := -1 END;If
p is a T, then p.id is an identifier whose interpretation
   depends on the screentype.  If p was created by a call
   st.op.opaque(pix), then p.pix = pix; otherwise p.pix = -1. 
END ScrnPaintOp.