Copyright (C) 1994, Digital Equipment Corp.
by Steve Glassman, Mark Manasse and Greg Nelson
<*PRAGMA LL*>A
ScrnPixmap.T is a handle on a rectangular array of pixels that
is valid for use on a particular screentype, called the {\it owner}
of the handle. Some handles have names; others are anonymous. A
named handle is valid forever; the pixmap referenced by an anonymous
handle will be garbage-collected when all handles to it have been
dropped.
INTERFACEThe raw representation of a pixmap is revealed at the end of this interface.ScrnPixmap ; IMPORT Point, Rect, Word, TrestleComm, Pixmap, BasicCtypes; EXCEPTION Failure; TYPE Raw = Pixmap.Raw;
\subsubsection{Obtaining handles from the oracle}
TYPE
Oracle = Private OBJECT
METHODS
<* LL.sup <= VBT.mu *>
load(READONLY r: Raw; nm: TEXT := NIL): T
RAISES {TrestleComm.Failure};
list(pat: TEXT; maxResults: CARDINAL := 1)
: REF ARRAY OF TEXT RAISES {TrestleComm.Failure};
lookup(name: TEXT): T RAISES {TrestleComm.Failure};
builtIn(pm: Pixmap.Predefined): T;
END;
Private <: ROOT;
For a screentype st, the field st.pixmap is an Oracle that
produces pixmaps owned by st.
The method call st.pixmap.load(r, nm) allocates and returns
a pixmap handle p owned by st whose contents are equal to r. The
depth of r must either be 1 or st.depth, otherwise there is
a checked runtime error. If nm # NIL, p receives the name nm,
and any pixmap handle owned by st that previously had the name
nm becomes anonymous.
The method call st.pixmap.list(pat, maxResults) returns the names
of all pixmaps owned by st that match the pattern pat. The list
of results may be truncated to length maxResults. A * matches
any number of characters and a ? matches any single character.
The method call st.pixmap.lookup(name) return the pixmap with the
given name, or NIL if no pixmap has this name.
The method call st.pixmap.builtIn(pm) returns the screen-dependent
pixmap valid for st that corresponds to the predefined
screen-independent Pixmap.T{pm}.
The locking level for all methods is LL.sup <= VBT.mu.
\subsubsection{The handle object}
TYPE
T <: Public;
Public = OBJECT (*CONST*)
id: INTEGER;
depth: INTEGER;
bounds: Rect.T
METHODS
<* LL.sup <= VBT.mu *>
localize(READONLY rect: Rect.T): Raw
RAISES {TrestleComm.Failure};
unload() RAISES {TrestleComm.Failure};
free() RAISES {TrestleComm.Failure}
END;
If pm is a ScrnPixmap.T, then pm.id is an identifier whose
interpretation depends on the screentype that owns pm. The field
pm.depth is the number of bits in each pixel of pm, and
pm.bounds is the rectangular extent of pm.
The method call pm.localize(rect) returns a raw pixmap equal to
a rectangualr subpixmap of the one on which pm is a handle. The
bounds of the raw pixmap returned by localize is Rect.Meet(rect,
pm.bounds).
The method call pm.unload() causes pm to become anonymous.
Pixmaps consume large amounts of memory. The method call pm.free()
releases the memory associated with the pixmap. You must make sure
that all VBTs using pm have finished painting before you
free it. After a call to free, the pixmap bounds and contents
are arbitrary.
\subsubsection{The raw representation}
A raw pixmap allows the client to directly locate and modify the bits of the pixmap. The following procedure produces a new raw pixmap:
PROCEDURE NewRaw(dpth: INTEGER; READONLY bnds: Rect.T): Raw; <* LL arbitrary *>
Allocate and return a raw pixmap with the given depth and bounds.
The initial contents of the pixmap returned by
NewRaw are undefined.
Here is the representation of a raw pixmap:
REVEAL Pixmap.Raw <: Raw_Public;
TYPE
Raw_Public = OBJECT
depth: INTEGER;
bounds: Rect.T;
pixels: REF ARRAY OF PixWord;
offset: INTEGER;
bitsPerPixel: INTEGER;
wordsPerRow: INTEGER;
pixelOrder: ByteOrder;
westRounded: INTEGER;
METHODS
get(READONLY pt: Point.T): Pixel;
set(READONLY pt: Point.T; pix: Pixel);
sub(READONLY rect: Rect.T): Raw;
END;
PixWord = BasicCtypes.unsigned_int;
Pixel = Word.T;
ByteOrder = {MSBFirst, LSBFirst};
The methods provide the easiest way to operate on a raw pixmap, and
we will explain them first. Let pm be a ScrnPixmap.Raw, then:
The method call
pm.get(pt)
returns the pixel value at the point pt in the pixmap. The result
is undefined if pt is not in pm.bounds.
The method call
pm.set(pt, pix)
sets the pixel value at the point pt of the pixmap pm to the
value pix. It is a noop if pt is not in pm.bounds.
The method call
pm.sub(rect)
returns a pixmap whose bounds are Rect.Meet(rect, pm.bounds) and
whose contents are shared with pm's.
It is also possible to bypass the methods and access the data in the raw pixmap directly. Here is the specification for the internal layout of pixels in a raw pixmap:
A value pm of type Pixmap.Raw is a rectangular subregion of a
larger rectangular pixmap, which we shall call the {\it surround}.
The surround is a word-aligned pixmap, stored in raster-scan order
by rows. Pixels do not cross word boundaries. More precisely, the
westmost pixel in each row of the surround is always a pixel whose
h-coordinate is a multiple of pixelsPerWord (which is equal to
BITSIZE(PixWord) DIV pm.bitsPerPixel). The eastmost pixel in each row
of the surround is always a pixel whose h-coordinate modulo
pixelsPerWord is congruent to pixelsPerWord-1. Hence, the number
of pixels in each row of the surround is a multiple of
pixelsPerWord. The value pm.wordsPerRow is the number of words
that are needed to store one row of the surround.
The value pm.bitsPerPixel might be greater than pm.depth; for
example, a twelve-bit deep pixmap might be stored with
sixteen bits per pixel.
The pixels of the surround are stored in the array pm.pixels. Each
row is represented in pm.wordsPerRow adjacent words; the first
of these words stores the westmost pixelsPerWord pixels of the
row, the following word stores the adjacent pixelsPerWord pixels,
and so on until the last word, which stores the eastmost
pixelsPerWord pixels.
The order in which pixels are packed into words is indicated by
pm.pixelOrder. In this discussion, bit 0 is the least
significant bit and bit BITSIZE(PixWord) - 1 is the most significant bit
of a word.
If pm.pixelOrder = LSBFirst, the bits of the pixels are as follows
(where bpp is pm.bitsPerPixel):
pixel 0: bits 0..bpp-1
pixel 1: bits bpp..2*bpp-1
...
pixel i: bits i*bpp..(i+1)*bpp-1
If pm.pixelOrder = MSBFirst, the pixels are stored in reverse order,
so that pixel i occupies the same bits as pixel pixelsPerWord-i-1
occupies for LSBFirst.
A Word.Extract of the bits indicated above, from the correct word,
gives the pixel's value. If the word size does not contain an
integral number of pixels, the unused bits in the word have
undefined values.
The pixmap pm itself is a rectangular region selected from the surround;
the value pm.bounds, of type Rect.T, specifies the domain of pm. The
value pm.offset specifies where in pm.pixels the words containing the
pixels of pm can be found. In particular, the northwestern-most bit of
pm, the bit with coordinates
h = pm.bounds.west and v = pm.bounds.north,
is stored in word pm.pixels[pm.offset]. The pixel is the
(pm.bounds.west MOD pixelsPerWord)'th pixel of the word.
Its bits can be found by the earlier formulas.
The general formula for the word containing the pixel with position
h, v is
pm.pixels[
(v - pm.bounds.north) * pm.wordsPerRow +
(h - pm.westRounded) DIV pixelsPerWord) + pm.offset].
Here is another useful formula. The surround rectangle must be at
least wide enough to contain the subrectangle pm.bounds, even after
we have rounded the west edge of pm.bounds westward to the next word
boundary and rounded the east edge of pm.bounds eastward to the next
word boundary. As a result, we have the inequality:
pm.wordsPerRow >=
((pm.bounds.east - 1) DIV pixelsPerWord) -
(pm.bounds.west DIV pixelsPerWord) + 1
Finally, the value pm.westRounded is provided for convenience; it
is equal to
bounds.west - (bounds.west MOD pixelsPerWord),
that is, the western boundary moved west to the nearest word boundary.
END ScrnPixmap.