BufferedRefreshImpl.mesa
Copyright © 1986 by Xerox Corporation. All rights reserved.
Last edited by Bier on February 3, 1987
Contents: Builds up an abstraction of transparent layers onto which shapes can be drawn. Each layer may have a backing pixel map, in which case it need not be redrawn when other layers change. This scheme is used by Gargoyle and Solidviews.
DIRECTORY
BufferedRefresh, Imager, ImagerBackdoor, ImagerBitmapContext, ImagerSample, Real;
BufferedRefreshImpl: CEDAR PROGRAM
IMPORTS Imager, ImagerBackdoor, ImagerBitmapContext, ImagerSample, Real
EXPORTS BufferedRefresh =
BEGIN
RefreshProc: TYPE = BufferedRefresh.RefreshProc;
Layer: TYPE = BufferedRefresh.Layer;
Sandwich: TYPE = REF SandwichObj;
SandwichObj: TYPE = BufferedRefresh.SandwichObj;
LayerData: TYPE = REF LayerDataObj;
LayerDataObj: TYPE = BufferedRefresh.LayerDataObj;
StartLayerDataList: PUBLIC PROC [] RETURNS [entityList, ptr: LIST OF LayerData] = {
ptr ← entityList ← NIL;
};
AddLayerData: PUBLIC PROC [entity: LayerData, entityList, ptr: LIST OF LayerData] RETURNS [newList, newPtr: LIST OF LayerData] = {
IF ptr = NIL THEN {
IF NOT entityList = NIL THEN ERROR;
newPtr ← newList ← CONS[entity, NIL];
RETURN;
}
ELSE {
newList ← entityList;
ptr.rest ← CONS[entity, NIL];
newPtr ← ptr.rest;
};
};
CreateSandwich: PUBLIC PROC [layers: LIST OF Layer] RETURNS [sandwich: Sandwich] = {
Layers should be specified in back to front order.
layerData: LayerData;
ptr: LIST OF LayerData;
sandwich ← NEW[SandwichObj];
[sandwich.layers, ptr] ← StartLayerDataList[];
FOR list: LIST OF Layer ← layers, list.rest UNTIL list = NIL DO
layerData ← NEW[LayerDataObj ← [name: list.first.name, refreshProc: list.first.refreshProc, hasMap: list.first.backingMap]];
[sandwich.layers, ptr] ← AddLayerData[layerData, sandwich.layers, ptr];
ENDLOOP;
};
FitSandwichToScreen: PUBLIC PROC [sandwich: Sandwich, cw, ch: INTEGER, clientToViewer: Imager.Transformation ← NIL] = {
layer: LayerData;
rect: Imager.Rectangle;
Construct the chunking map.
bitmap ← sandwich.chunkingBitmap ← ImagerBackdoor.NewBitmap[cw, ch];
pmRef ← NEW[ImagerPixelMap.PixelMapRep ← [
ref: bitmap.ref, pointer: bitmap.base, words: LONG[bitmap.wordsPerLine]*bitmap.height,
lgBitsPerPixel: 0, rast: bitmap.wordsPerLine, lines: bitmap.height
]];
pm ← [
sOrigin: 0, fOrigin: 0, sMin: 0, fMin: 0,
sSize: bitmap.height, fSize: bitmap.width, refRep: pmRef
];
sandwich.chunkingContext ← ImagerFastShow.Create[pm, 72, TRUE];
sandwich.chunkingBitmap ← ImagerSample.NewSampleMap[[max: [ch, cw]]];
sandwich.chunkingContext ← ImagerBitmapContext.Create[[ch, cw], [down, right], [72.0, 72.0], TRUE];
ImagerBitmapContext.SetBitmap[sandwich.chunkingContext, sandwich.chunkingBitmap];
IF clientToViewer # NIL THEN Imager.ConcatT[sandwich.chunkingContext, clientToViewer];
Construct the layer backing maps.
FOR list: LIST OF LayerData ← sandwich.layers, list.rest UNTIL list = NIL DO
layer ← list.first;
layer.backingMap ← ImagerSample.NewSampleMap[[max: [ch, cw]]];
layer.backingContext ← ImagerBitmapContext.Create[[ch, cw], [down, right], [72.0, 72.0], TRUE];
ImagerBitmapContext.SetBitmap[layer.backingContext, layer.backingMap];
IF clientToViewer # NIL THEN Imager.ConcatT[layer.backingContext, clientToViewer];
Initialize the context to white.
rect ← ImagerBackdoor.GetBounds[layer.backingContext];
Imager.SetColor[layer.backingContext, Imager.white];
Imager.MaskRectangle[layer.backingContext, rect];
ENDLOOP;
};
DrawSandwich: PUBLIC PROC [sandwich: Sandwich, screen: Imager.Context, boundRect: Imager.Rectangle, viewerToClient: Imager.Transformation, clientData: REF ANY, ignoreBackingMap: BOOLFALSE] = {
Draw the picture, derivable from the sandwich, on the screen. For backed layers that are OK, this will just dump the backing map on the screen. For backed layers that are not OK, this will remake the backing map by calling the refreshProc and dump the backing map on the screen. For unbacked layers, this will call the RefreshProc for that layer. Layers will be drawn in back-to-front order. If ignoreBackingMap is TRUE, all layers will be drawn by calling their refresh proc. Since, we currently use 1 bit per pixel backing maps, this must be done to show colors. All layers are initially NOT OK.
chunking: Imager.Context ← sandwich.chunkingContext;
layer: LayerData;
IF ignoreBackingMap THEN {
Imager.SetColor[screen, Imager.white];
Imager.MaskRectangle[screen, boundRect];
}
ELSE {
Imager.SetColor[chunking, Imager.white];
Imager.MaskRectangle[chunking, boundRect];
};
FOR list: LIST OF LayerData ← sandwich.layers, list.rest UNTIL list = NIL DO
layer ← list.first;
IF ignoreBackingMap THEN {
layer.refreshProc[screen, boundRect, clientData]
}
ELSE {
IF NOT layer.hasMap THEN layer.refreshProc[chunking, boundRect, clientData]
ELSE {
IF NOT layer.mapOK THEN {
UpdateBackingMap: PROC = {
rect: Imager.Rectangle;
rect ← ImagerBackdoor.GetBounds[layer.backingContext];
Imager.SetColor[layer.backingContext, Imager.white];
Imager.MaskRectangle[layer.backingContext, rect];
layer.refreshProc[layer.backingContext, boundRect, clientData];
};
Imager.DoSaveAll[layer.backingContext, UpdateBackingMap];
layer.mapOK ← TRUE;
};
LayerToChunking[layer, chunking, viewerToClient];
};
};
ENDLOOP;
IF NOT ignoreBackingMap THEN ChunkingToScreen[sandwich, screen, viewerToClient];
};
ViewerToClientFromBiScrollers: PROC [dc: Imager.Context, gargoyleData: GargoyleData] RETURNS [viewerToClient: Imager.Transformation] = {
style: BiScrollers.BiScrollerStyle ← BiScrollers.GetStyle[];
viewerToClient ← style.GetTransforms[BiScrollers.QuaBiScroller[gargoyleData.actionArea]].viewerToClient;
};
ChunkingToScreen: PROC [sandwich: Sandwich, screen: Imager.Context, viewerToClient: Imager.Transformation ← NIL] = {
ChunkingToScreenAux: PROC = {
rect: Imager.Rectangle;
rect ← ImagerBackdoor.GetBounds[sandwich.chunkingContext];
IF viewerToClient # NIL THEN Imager.ConcatT[screen, viewerToClient];
Imager.DrawBitmap[screen, chunkingBitmap, [Real.Fix[rect.h], 0]];
ImagerBackdoor.DrawBits[screen, chunkingBitmap.base, chunkingBitmap.wordsPerLine, 0, 0, chunkingBitmap.height, chunkingBitmap.width, 0, chunkingBitmap.height];
};
chunkingBitmap: Imager.SampleMap ← sandwich.chunkingBitmap;
Imager.DoSaveAll[screen, ChunkingToScreenAux];
};
LayerToChunking: PROC [layer: LayerData, chunking: Imager.Context, viewerToClient: Imager.Transformation ← NIL] = {
UpdateBackingMap: PROC = {
rect: Imager.Rectangle;
rect ← ImagerBackdoor.GetBounds[layer.backingContext];
IF viewerToClient # NIL THEN Imager.ConcatT[chunking, viewerToClient];
Imager.SetColor[chunking, Imager.black];
Imager.MaskBitmap[chunking, backingMap, [Real.Fix[rect.h], 0]];
Imager.MaskBits[chunking, backingMap.base, backingMap.wordsPerLine, 0, 0, backingMap.height, backingMap.width, 0, backingMap.height];
};
backingMap: Imager.SampleMap ← layer.backingMap;
Imager.DoSaveAll[chunking, UpdateBackingMap];
};
SetLayerOK: PUBLIC PROC [sandwich: Sandwich, layerName: ATOM, ok: BOOL] = {
layer: LayerData ← FindLayer[sandwich, layerName];
layer.mapOK ← ok;
};
GetLayerOK: PUBLIC PROC [sandwich: Sandwich, layerName: ATOM] RETURNS [ok: BOOL] = {
layer: LayerData ← FindLayer[sandwich, layerName];
ok ← layer.mapOK;
};
GetLayerContext: PUBLIC PROC [sandwich: Sandwich, layerName: ATOM] RETURNS [backingContext: Imager.Context] = {
layer: LayerData ← FindLayer[sandwich, layerName];
backingContext ← layer.backingContext;
};
FindLayer: PROC [sandwich: Sandwich, layerName: ATOM] RETURNS [layer: LayerData] = {
FOR list: LIST OF LayerData ← sandwich.layers, list.rest UNTIL list = NIL DO
IF list.first.name = layerName THEN RETURN[list.first];
ENDLOOP;
ERROR;
};
END.