windows-nt/Source/XPSP1/NT/com/ole32/olecnv32/cache.c
2020-09-26 16:20:57 +08:00

1162 lines
35 KiB
C

/****************************************************************************
Unit Cache; Implementation
*****************************************************************************
Module Prefix: Ca
****************************************************************************/
#include "headers.c"
#pragma hdrstop
#include "cache.h" /* own interface */
/*********************** Exported Data **************************************/
/*********************** Private Data ***************************************/
/*--- Gdi cache ---*/
typedef struct
{
HPEN handle;
LOGPEN logPen;
Boolean stockObject;
} Pen, far * PenLPtr;
typedef struct
{
HBRUSH handle;
LOGBRUSH logBrush;
Boolean stockObject;
} Brush, far * BrushLPtr;
typedef struct
{
Handle metafile; // metafile handle
Rect prevClipRect; // last cliprect before SaveDC()
Rect curClipRect; // last clipping rectangle
Boolean forceNewClipRect; // always emit new clipping rectangle?
HPEN nulPen; // frequently used pens
HPEN whitePen;
HPEN blackPen;
HBRUSH nulBrush; // frequently used brushes
HBRUSH whiteBrush;
HBRUSH blackBrush;
Boolean stockFont; // current font selection
HFONT curFont;
LOGFONT curLogFont;
Brush curBrush; // current pen and brush selections
Pen curPen;
Pen nextPen; // cached frame(pen)
CaPrimitive nextPrim; // cached primitive
Boolean samePrim;
Handle polyHandle;
Integer numPoints;
Integer maxPoints;
Point far * pointList;
Word iniROP2; // initial value for ROP2 mode
Word iniTextAlign; // initial value for text alignment
Word iniBkMode;
RGBColor iniTxColor;
RGBColor iniBkColor;
Word curROP2; // current ROP codes setting
Word curBkMode; // current background mode
RGBColor curBkColor; // current background color
Word curStretchMode; // current stretchblt mode
RGBColor curTextColor; // last text color
Word curTextAlign; // last text alignment value
short curCharExtra; // last char extra value
Fixed spExtra; // last space extra value
Point txNumer; // last text scaling
Point txDenom; // factors
Boolean restorePen; // do any attribs need to be re-issued
Boolean restoreBrush; // after RestoreDC() call?
Boolean restoreFont;
Boolean restoreCharExtra;
Boolean restoreStretchMode;
} GdiCache;
private GdiCache gdiCache;
/*********************** Private Function Definitions ***********************/
#define /* void */ NewPolygon( /* void */ ) \
/* start a new polygon definition */ \
gdiCache.numPoints = 0
private void AddPolyPt( Point pt );
/* Add a point to the polygon buffer */
private void SelectCachedPen( void );
/* select the currently cached Pen into the metafile */
/*********************** Function Implementation ****************************/
void CaInit( Handle metafile )
/*=========*/
/* initialize the gdi cache module */
{
/* save off the metafile handle into global structure */
gdiCache.metafile = metafile;
/* make sure that text and background colors will be set */
gdiCache.curTextColor =
gdiCache.curBkColor = RGB( 12, 34, 56 );
/* get handles to some stock pen objects */
gdiCache.nulPen = GetStockObject( NULL_PEN );
gdiCache.whitePen = CreatePen( PS_INSIDEFRAME, 1, RGB( 255, 255, 255 ) );
gdiCache.blackPen = CreatePen( PS_INSIDEFRAME, 1, RGB( 0, 0, 0 ) );
/* get handles to some stock brush objects */
gdiCache.nulBrush = GetStockObject( NULL_BRUSH );
gdiCache.whiteBrush = GetStockObject( WHITE_BRUSH );
gdiCache.blackBrush = GetStockObject( BLACK_BRUSH );
/* allocate space for the polygon buffer */
gdiCache.numPoints = 0;
gdiCache.maxPoints = 16;
gdiCache.polyHandle = GlobalAlloc( GHND, gdiCache.maxPoints * sizeof( Point ) );
if (gdiCache.polyHandle == NULL)
{
ErSetGlobalError( ErMemoryFull);
}
else
{
/* get a pointer address for the memory block */
gdiCache.pointList = (Point far *)GlobalLock( gdiCache.polyHandle );
}
/* mark the primitive cache as empty */
gdiCache.nextPrim.type = CaEmpty;
/* the current primitive isn't being repeated */
gdiCache.samePrim = FALSE;
/* turn off forcing of a new clipping rectangle */
gdiCache.forceNewClipRect = FALSE;
} /* CaInit */
void CaFini( void )
/*=========*/
/* close down the cache module */
{
/* delete the current font selection if non-NULL and non-stock */
if ((gdiCache.curFont != NULL) && !gdiCache.stockFont)
{
/* free the font object */
DeleteObject( gdiCache.curFont );
}
/* remove the current brush selection if non-NULL and not a stock brush */
if ((gdiCache.curBrush.handle != NULL) && !gdiCache.curBrush.stockObject)
{
/* see if the current brush has a DIB - if so, delete it */
if (gdiCache.curBrush.logBrush.lbStyle == BS_DIBPATTERN)
{
/* free the DIB memory used for brush */
GlobalFree( (HANDLE) gdiCache.curBrush.logBrush.lbHatch );
}
/* delte the brush object */
DeleteObject( gdiCache.curBrush.handle );
}
/* remove the current pen selection if non-NULL and not a stock pen */
if ((gdiCache.curPen.handle != NULL) && !gdiCache.curPen.stockObject)
{
DeleteObject( gdiCache.curPen.handle );
}
/* Remove other pens created at initialization time */
DeleteObject( gdiCache.whitePen );
DeleteObject( gdiCache.blackPen );
/* deallocate the polygon buffer */
GlobalUnlock( gdiCache.polyHandle );
GlobalFree( gdiCache.polyHandle );
} /* CaFini */
void CaSetMetafileDefaults( void )
/*========================*/
/* Set up any defaults that will be used throughout the metafile context */
{
/* set up some metafile defaults */
gdiCache.iniTextAlign = TA_LEFT | TA_BASELINE | TA_NOUPDATECP;
gdiCache.iniROP2 = R2_COPYPEN;
gdiCache.iniBkMode = TRANSPARENT;
gdiCache.iniTxColor = RGB( 0, 0, 0 );
gdiCache.iniBkColor = RGB( 255, 255, 255 );
/* Put the records into the metafile */
CaSetROP2( gdiCache.iniROP2 );
CaSetTextAlign( gdiCache.iniTextAlign );
CaSetBkMode( gdiCache.iniBkMode );
CaSetTextColor( gdiCache.iniTxColor );
CaSetBkColor( gdiCache.iniBkColor );
} /* CaSetMetafileDefaults */
void CaSamePrimitive( Boolean same )
/*==================*/
/* indicate whether next primitive is the same or new */
{
gdiCache.samePrim = same;
} /* CaSamePrimitive */
void CaMergePen( Word verb )
/*=============*/
/* indicate that next pen should be merged with previous logical pen */
{
if (gdiCache.nextPen.handle != NULL)
{
/* check to see if this is a NULL pen - the merge can happen */
if (gdiCache.samePrim && verb == GdiFrame &&
gdiCache.nextPen.handle == gdiCache.nulPen)
{
/* remove the cached pen - don't delte the pen object */
gdiCache.nextPen.handle = NULL;
}
else
{
/* if not removing a null pen, then flush the cache. This will most
often result in a line segment being flushed. */
CaFlushCache();
}
}
} /* CaMergePen */
Word CaGetCachedPrimitive( void )
/*=======================*/
/* return the current cached primitive type */
{
return gdiCache.nextPrim.type;
} /* CaGetCachedPrimitive */
void CaCachePrimitive( CaPrimitiveLPtr primLPtr )
/*===================*/
/* Cache the primitive passed down. This includes the current pen and brush. */
{
/* not another line segment and/or not continuous - flush cache */
CaFlushCache();
/* save off the new primitive */
gdiCache.nextPrim = *primLPtr;
/* check if we need to copy over the polygon list, also */
if ((gdiCache.nextPrim.type == CaPolygon) ||
(gdiCache.nextPrim.type == CaPolyLine))
{
/* create new polygon */
NewPolygon();
/* add the polygon to the polygon buffer */
while (gdiCache.nextPrim.a.poly.numPoints--)
{
AddPolyPt( *gdiCache.nextPrim.a.poly.pointList++);
}
}
} /* CaCachePrimitive */
void CaFlushCache( void )
/*===============*/
/* Flush the current primitive stored in the cache */
{
/* if the cache is empty, then just return - nothing to do */
if (gdiCache.nextPrim.type == CaEmpty)
{
return;
}
/* select all cached attributes */
CaFlushAttributes();
/* emit any cached primitive, if necessary */
switch (gdiCache.nextPrim.type)
{
case CaLine:
{
Rect clip;
Point delta;
Point offset;
/* determine the length in both directions */
delta.x = gdiCache.nextPrim.a.line.end.x - gdiCache.nextPrim.a.line.start.x;
delta.y = gdiCache.nextPrim.a.line.end.y - gdiCache.nextPrim.a.line.start.y;
/* set clipRect extents based upon current point position */
clip.left = min( gdiCache.nextPrim.a.line.start.x, gdiCache.nextPrim.a.line.end.x );
clip.top = min( gdiCache.nextPrim.a.line.start.y, gdiCache.nextPrim.a.line.end.y );
clip.right = max( gdiCache.nextPrim.a.line.start.x, gdiCache.nextPrim.a.line.end.x );
clip.bottom = max( gdiCache.nextPrim.a.line.start.y, gdiCache.nextPrim.a.line.end.y );
/* extend clip rectangle for down-right pen stylus hang */
clip.right += gdiCache.nextPrim.a.line.pnSize.x;
clip.bottom += gdiCache.nextPrim.a.line.pnSize.y;
/* determine the new starting and ending points */
gdiCache.nextPrim.a.line.start.x -= delta.x;
gdiCache.nextPrim.a.line.start.y -= delta.y;
gdiCache.nextPrim.a.line.end.x += delta.x;
gdiCache.nextPrim.a.line.end.y += delta.y;
/* ajust the clipping rect for vertical line penSize roundoff? */
if (delta.x == 0)
{
/* vertical line - expand clip in x dimension */
clip.left--;
}
/* are we are adjusting pen by 1/2 metafile unit - roundoff error? */
else if (gdiCache.nextPrim.a.line.pnSize.x & 0x01)
{
/* adjust clipping rectangle to clip the rounding error */
clip.right--;
}
/* ajust the clipping rect for horizontal line penSize roundoff? */
if (delta.y == 0)
{
/* horizontal line - extend clip in y dimension */
clip.top--;
}
/* are we are adjusting pen by 1/2 metafile unit - roundoff error? */
else if (gdiCache.nextPrim.a.line.pnSize.y & 0x01)
{
/* adjust clipping rectangle to clip the rounding error */
clip.bottom--;
}
/* cut the size of the pen dimensions in half for offsets */
offset.x = gdiCache.nextPrim.a.line.pnSize.x / 2;
offset.y = gdiCache.nextPrim.a.line.pnSize.y / 2;
/* set the new clipping rectangle */
SaveDC( gdiCache.metafile );
IntersectClipRect( gdiCache.metafile,
clip.left, clip.top, clip.right, clip.bottom );
/* move to the first point and draw to second (with padding) */
// MoveTo is replaced by MoveToEx in win32
#ifdef WIN32
MoveToEx( gdiCache.metafile,
gdiCache.nextPrim.a.line.start.x + offset.x,
gdiCache.nextPrim.a.line.start.y + offset.y, NULL );
#else
MoveTo( gdiCache.metafile,
gdiCache.nextPrim.a.line.start.x + offset.x,
gdiCache.nextPrim.a.line.start.y + offset.y );
#endif
LineTo( gdiCache.metafile,
gdiCache.nextPrim.a.line.end.x + offset.x,
gdiCache.nextPrim.a.line.end.y + offset.y );
/* restore the previous clipping rectangle */
RestoreDC( gdiCache.metafile, -1 );
break;
}
case CaRectangle:
{
if (gdiCache.curPen.handle == gdiCache.nulPen)
{
Point poly[5];
/* set up the bounding coodinates */
poly[0].x = poly[3].x = gdiCache.nextPrim.a.rect.bbox.left;
poly[0].y = poly[1].y = gdiCache.nextPrim.a.rect.bbox.top;
poly[1].x = poly[2].x = gdiCache.nextPrim.a.rect.bbox.right;
poly[2].y = poly[3].y = gdiCache.nextPrim.a.rect.bbox.bottom;
poly[4] = poly[0];
/* perform call to render rectangle */
Polygon( gdiCache.metafile, poly, 5 );
}
else
{
Rectangle( gdiCache.metafile,
gdiCache.nextPrim.a.rect.bbox.left, gdiCache.nextPrim.a.rect.bbox.top,
gdiCache.nextPrim.a.rect.bbox.right, gdiCache.nextPrim.a.rect.bbox.bottom );
}
break;
}
case CaRoundRect:
{
RoundRect( gdiCache.metafile,
gdiCache.nextPrim.a.rect.bbox.left, gdiCache.nextPrim.a.rect.bbox.top,
gdiCache.nextPrim.a.rect.bbox.right, gdiCache.nextPrim.a.rect.bbox.bottom,
gdiCache.nextPrim.a.rect.oval.x, gdiCache.nextPrim.a.rect.oval.y );
break;
}
case CaEllipse:
{
Ellipse( gdiCache.metafile,
gdiCache.nextPrim.a.rect.bbox.left, gdiCache.nextPrim.a.rect.bbox.top,
gdiCache.nextPrim.a.rect.bbox.right, gdiCache.nextPrim.a.rect.bbox.bottom );
break;
}
case CaArc:
{
Arc( gdiCache.metafile,
gdiCache.nextPrim.a.arc.bbox.left, gdiCache.nextPrim.a.arc.bbox.top,
gdiCache.nextPrim.a.arc.bbox.right, gdiCache.nextPrim.a.arc.bbox.bottom,
gdiCache.nextPrim.a.arc.start.x, gdiCache.nextPrim.a.arc.start.y,
gdiCache.nextPrim.a.arc.end.x, gdiCache.nextPrim.a.arc.end.y );
break;
}
case CaPie:
{
Pie( gdiCache.metafile,
gdiCache.nextPrim.a.arc.bbox.left, gdiCache.nextPrim.a.arc.bbox.top,
gdiCache.nextPrim.a.arc.bbox.right, gdiCache.nextPrim.a.arc.bbox.bottom,
gdiCache.nextPrim.a.arc.start.x, gdiCache.nextPrim.a.arc.start.y,
gdiCache.nextPrim.a.arc.end.x, gdiCache.nextPrim.a.arc.end.y );
break;
}
case CaPolygon:
case CaPolyLine:
{
Point offset;
Integer i;
/* see if centering of the pen is required */
if (gdiCache.curPen.handle == gdiCache.nulPen)
{
/* no - just filling the object without frame */
offset.x = offset.y = 0;
}
else
{
/* transform all points to correct for down-right pen
rendering in QuickDraw and make for a GDI centered pen */
offset.x = gdiCache.nextPrim.a.poly.pnSize.x / 2;
offset.y = gdiCache.nextPrim.a.poly.pnSize.y / 2;
}
/* transform end point for all points in the polygon */
for (i = 0; i < gdiCache.numPoints; i++)
{
/* increment each coordinate pair off half of the pen size */
gdiCache.pointList[i].x += offset.x;
gdiCache.pointList[i].y += offset.y;
}
/* call the appropriate GDI routine based upon the type */
if (gdiCache.nextPrim.type == CaPolygon)
{
Polygon( gdiCache.metafile,
gdiCache.pointList,
gdiCache.numPoints );
}
else
{
Polyline( gdiCache.metafile,
gdiCache.pointList,
gdiCache.numPoints );
}
break;
}
}
/* mark the primitive cache as empty */
gdiCache.nextPrim.type = CaEmpty;
} /* CaFlushCache */
void CaFlushAttributes( void )
/*====================*/
/* flush any pending attribute elements */
{
/* select the cached pen - the routine will determine if one exits */
SelectCachedPen();
} /* CaFlushAttributes */
void CaCreatePenIndirect( LOGPEN far * newLogPen )
/*======================*/
/* create a new pen */
{
PenLPtr compare;
Boolean different;
/* determine which pen to compare against */
compare = (gdiCache.nextPen.handle != NULL) ? &gdiCache.nextPen :
&gdiCache.curPen;
/* compare the two pens */
different = ((newLogPen->lopnStyle != compare->logPen.lopnStyle) ||
(newLogPen->lopnColor != compare->logPen.lopnColor) ||
(newLogPen->lopnWidth.x != compare->logPen.lopnWidth.x));
/* if the pens are different ... */
if (different)
{
/* if there is a cached pen ... */
if (gdiCache.nextPen.handle != NULL)
{
/* flush the cached primitive - there is a change of pens */
CaFlushCache();
/* check to see if the new pen is changed by next selection */
different = ((newLogPen->lopnStyle != gdiCache.curPen.logPen.lopnStyle) ||
(newLogPen->lopnColor != gdiCache.curPen.logPen.lopnColor) ||
(newLogPen->lopnWidth.x != gdiCache.curPen.logPen.lopnWidth.x));
}
}
/* if the pen has changed from the current setting, cache the next pen */
if (different || gdiCache.curPen.handle == NULL)
{
/* if there is a pending line or polyline, the flush the cache */
if (gdiCache.nextPrim.type == CaLine || gdiCache.nextPrim.type == CaPolyLine)
{
CaFlushCache();
}
/* assign the new pen attributes */
gdiCache.nextPen.logPen = *newLogPen;
/* currently not using a stock pen object */
gdiCache.nextPen.stockObject = FALSE;
/* check for any pre-defined pen objects */
if (gdiCache.nextPen.logPen.lopnStyle == PS_NULL)
{
/* and use them if possible */
gdiCache.nextPen.handle = gdiCache.nulPen;
gdiCache.nextPen.stockObject = TRUE;
}
else if (gdiCache.nextPen.logPen.lopnWidth.x == 1)
{
if (newLogPen->lopnColor == RGB( 0, 0, 0 ))
{
gdiCache.nextPen.handle = gdiCache.blackPen;
gdiCache.nextPen.stockObject = TRUE;
}
else if (gdiCache.nextPen.logPen.lopnColor == RGB( 255, 255, 255 ))
{
gdiCache.nextPen.handle = gdiCache.whitePen;
gdiCache.nextPen.stockObject = TRUE;
}
}
if (!gdiCache.nextPen.stockObject)
{
/* otherwise, create a new pen */
gdiCache.nextPen.handle = CreatePenIndirect( &gdiCache.nextPen.logPen );
}
}
else
{
/* copy the current setting back into the next pen setting */
gdiCache.nextPen = gdiCache.curPen;
}
/* check if cache was invalidated */
if (gdiCache.restorePen && (gdiCache.curPen.handle != NULL))
{
/* if pen was invalidated by RestoreDC(), reselect it */
SelectObject( gdiCache.metafile, gdiCache.curPen.handle );
}
/* all is ok with cache now */
gdiCache.restorePen = FALSE;
} /* CaCreatePenIndirect */
void CaCreateBrushIndirect( LOGBRUSH far * newLogBrush )
/*========================*/
/* Create a new logical brush using structure passed in */
{
/* assume that the DIB patterns are different */
Boolean differentDIB = TRUE;
/* check if we are comparing two DIB patterned brushes */
if ((newLogBrush->lbStyle == BS_DIBPATTERN) &&
(gdiCache.curBrush.logBrush.lbStyle == BS_DIBPATTERN))
{
Word nextSize = (Word)GlobalSize( (HANDLE) newLogBrush->lbHatch ) / 2;
Word currSize = (Word)GlobalSize( (HANDLE) gdiCache.curBrush.logBrush.lbHatch ) / 2;
/* make sure that the sizes are the same */
if (nextSize == currSize)
{
Word far * nextDIBPattern = (Word far *)GlobalLock( (HANDLE) newLogBrush->lbHatch );
Word far * currDIBPattern = (Word far *)GlobalLock( (HANDLE) gdiCache.curBrush.logBrush.lbHatch );
/* assume that the DIBs are the same so far */
differentDIB = FALSE;
/* compare all the bytes in the two brush patterns */
while (currSize--)
{
/* are they the same ? */
if (*nextDIBPattern++ != *currDIBPattern++)
{
/* if not, flag the difference and break from the loop */
differentDIB = TRUE;
break;
}
}
/* Unlock the data blocks */
GlobalUnlock( (HANDLE) newLogBrush->lbHatch );
GlobalUnlock( (HANDLE) gdiCache.curBrush.logBrush.lbHatch );
/* see if these did compare exactly */
if (!differentDIB)
{
/* if so, free the new DIB brush - it's no longer needed */
GlobalFree( (HANDLE) newLogBrush->lbHatch );
}
}
}
/* see if we are requesting a new brush */
if (differentDIB &&
(newLogBrush->lbStyle != gdiCache.curBrush.logBrush.lbStyle ||
newLogBrush->lbColor != gdiCache.curBrush.logBrush.lbColor ||
newLogBrush->lbHatch != gdiCache.curBrush.logBrush.lbHatch ||
gdiCache.curBrush.handle == NULL))
{
HBRUSH brushHandle;
Boolean stockBrush;
/* flush the primitive cache if changing brush selection */
CaFlushCache();
/* if current brush has a DIB, make sure to free memory */
if (gdiCache.curBrush.logBrush.lbStyle == BS_DIBPATTERN)
{
/* free the memory */
GlobalFree( (HANDLE) gdiCache.curBrush.logBrush.lbHatch );
}
/* copy over the new structure */
gdiCache.curBrush.logBrush = *newLogBrush;
/* We currently aren't using a stock brush */
stockBrush = FALSE;
/* use stock objects if possible */
if (gdiCache.curBrush.logBrush.lbStyle == BS_HOLLOW)
{
/* use null (hollow) brush */
brushHandle = gdiCache.nulBrush;
stockBrush = TRUE;
}
/* check for some standard solid colored brushes */
else if (gdiCache.curBrush.logBrush.lbStyle == BS_SOLID)
{
if (gdiCache.curBrush.logBrush.lbColor == RGB( 0, 0, 0) )
{
/* use solid black brush */
brushHandle = gdiCache.blackBrush;
stockBrush = TRUE;
}
else if (gdiCache.curBrush.logBrush.lbColor == RGB( 255, 255, 255 ))
{
/* use solid white brush */
brushHandle = gdiCache.whiteBrush;
stockBrush = TRUE;
}
}
/* if unable to find a stock brush, then create a new one */
if (!stockBrush)
{
/* otherwise, create new brush using logbrush structure */
brushHandle = CreateBrushIndirect( &gdiCache.curBrush.logBrush );
}
/* select the new brush */
SelectObject( gdiCache.metafile, brushHandle );
/* if this isn't the first brush selection and not a stock brush */
if (gdiCache.curBrush.handle != NULL && !gdiCache.curBrush.stockObject)
{
/* delete the previous brush object */
DeleteObject( gdiCache.curBrush.handle );
}
/* save brush handle in current cache variable */
gdiCache.curBrush.handle = brushHandle;
gdiCache.curBrush.stockObject = stockBrush;
}
else if (gdiCache.restoreBrush)
{
/* if brush was invalidated by RestoreDC(), reselect it */
SelectObject( gdiCache.metafile, gdiCache.curBrush.handle );
}
/* all is ok with cache now */
gdiCache.restoreBrush = FALSE;
} /* CaCreateBrushIndirect */
void CaCreateFontIndirect( LOGFONT far * newLogFont )
/*=======================*/
/* create the logical font passed as paramter */
{
/* make sure we are requesting a new font */
if (newLogFont->lfHeight != gdiCache.curLogFont.lfHeight ||
newLogFont->lfWeight != gdiCache.curLogFont.lfWeight ||
newLogFont->lfEscapement != gdiCache.curLogFont.lfEscapement ||
newLogFont->lfOrientation != gdiCache.curLogFont.lfOrientation ||
newLogFont->lfItalic != gdiCache.curLogFont.lfItalic ||
newLogFont->lfUnderline != gdiCache.curLogFont.lfUnderline ||
newLogFont->lfPitchAndFamily != gdiCache.curLogFont.lfPitchAndFamily ||
lstrcmp( newLogFont->lfFaceName, gdiCache.curLogFont.lfFaceName ) != 0 ||
gdiCache.curFont == NULL)
{
HFONT fontHandle;
Boolean stockFont;
/* flush the primitive cache if changing font attributes */
CaFlushCache();
/* assign the new pen attributes */
gdiCache.curLogFont = *newLogFont;
/* currently not using a stock font object */
stockFont = FALSE;
/* check for any pre-defined pen objects */
if (newLogFont->lfFaceName == NULL)
{
fontHandle = GetStockObject( SYSTEM_FONT );
stockFont = TRUE;
}
else
{
/* otherwise, create a new pen */
fontHandle = CreateFontIndirect( &gdiCache.curLogFont );
}
/* select the new font */
SelectObject( gdiCache.metafile, fontHandle );
/* if this isn't the first font selection and not a stock font */
if (gdiCache.curFont != NULL && !gdiCache.stockFont)
{
/* delete the previous font object */
DeleteObject( gdiCache.curFont );
}
/* save font handle in current cache variable */
gdiCache.curFont = fontHandle;
gdiCache.stockFont = stockFont;
}
else if (gdiCache.restoreFont)
{
/* if pen was invalidated by RestoreDC(), reselect it */
SelectObject( gdiCache.metafile, gdiCache.curFont );
}
/* all is ok with cache now */
gdiCache.restoreFont = FALSE;
} /* CaCreateFontIndirect */
void CaSetBkMode( Word mode )
/*==============*/
/* set the backgound transfer mode */
{
if (gdiCache.curBkMode != mode)
{
/* flush the primitive cache if changing mode */
CaFlushCache();
/* set the background mode and save in global cache */
SetBkMode( gdiCache.metafile, mode );
gdiCache.curBkMode = mode;
}
/* no need to worry about restoring BkMode, since this is set
before the initial SaveDC() is issued and is restored after each
RestoreDC() call back to the metafile default. */
} /* CaSetBkMode */
void CaSetROP2( Word ROP2Code )
/*============*/
/* set the transfer ROP mode according to ROP2Code */
{
/* check for change in ROP code */
if (gdiCache.curROP2 != ROP2Code)
{
/* flush the primitive cache if changing ROP mode */
CaFlushCache();
/* set the ROP code and save in global cache variable */
SetROP2( gdiCache.metafile, ROP2Code );
gdiCache.curROP2 = ROP2Code;
}
/* no need to worry about restoring ROP code, since this is set
before the initial SaveDC() is issued and is restored after each
RestoreDC() call back to the metafile default. */
} /* CaSetROP2 */
void CaSetStretchBltMode( Word mode )
/*======================*/
/* stretch blt mode - how to preserve scanlines using StretchDIBits() */
{
if (gdiCache.curStretchMode != mode)
{
/* flush the primitive cache if changing mode */
CaFlushCache();
/* set the stretch blt mode and save in global cache variable */
SetStretchBltMode( gdiCache.metafile, mode );
gdiCache.curStretchMode = mode;
}
else if (gdiCache.restoreStretchMode)
{
/* if stretch blt mode was invalidated by RestoreDC(), re-issue */
SetStretchBltMode( gdiCache.metafile, gdiCache.curStretchMode );
}
/* all is ok with cache now */
gdiCache.restoreStretchMode = FALSE;
} /* CaSetStretchBltMode */
void CaSetTextAlign( Word txtAlign )
/*=================*/
/* set text alignment according to parameter */
{
if (gdiCache.curTextAlign != txtAlign)
{
/* flush the primitive cache if changing text alignment */
CaFlushCache();
/* Set the text color and save in cache */
SetTextAlign( gdiCache.metafile, txtAlign );
gdiCache.curTextAlign = txtAlign;
}
/* no need to worry about restoring text align, since this is set
before the initial SaveDC() is issued and is restored after each
RestoreDC() call back to the metafile default. */
} /* CaSetTextAlign */
void CaSetTextColor( RGBColor txtColor )
/*=================*/
/* set the text color if different from current setting */
{
if (gdiCache.curTextColor != txtColor)
{
/* flush the primitive cache if changing text color */
CaFlushCache();
/* Set the text color and save in cache */
SetTextColor( gdiCache.metafile, txtColor );
gdiCache.curTextColor = txtColor;
}
/* no need to worry about restoring text color, since this is set
before the initial SaveDC() is issued and is restored after each
RestoreDC() call back to the metafile default. */
} /* CaSetTextColor */
void CaSetTextCharacterExtra( Integer chExtra )
/*==========================*/
/* set the character extra spacing */
{
if (gdiCache.curCharExtra != chExtra)
{
/* flush the primitive cache if changing text char extra */
CaFlushCache();
/* set the char extra and same state in the cache */
SetTextCharacterExtra( gdiCache.metafile, chExtra );
gdiCache.curCharExtra = (WORD) chExtra;
}
else if (gdiCache.restoreCharExtra)
{
/* if text char extra was invalidated by RestoreDC(), re-issue */
SetTextCharacterExtra( gdiCache.metafile, gdiCache.curCharExtra );
}
/* all is ok with cache now */
gdiCache.restoreCharExtra = FALSE;
} /* CaSetTextCharacterExtra */
void CaSetBkColor( RGBColor bkColor )
/*===============*/
/* set background color if different from current setting */
{
if (gdiCache.curBkColor != bkColor)
{
/* flush the primitive cache if changing background color */
CaFlushCache();
/* Set the background color and save in cache */
SetBkColor( gdiCache.metafile, bkColor );
gdiCache.curBkColor = bkColor;
}
/* no need to worry about restoring background color, since this is set
before the initial SaveDC() is issued and is restored after each
RestoreDC() call back to the metafile default. */
} /* CaSetBkColor */
Boolean CaIntersectClipRect( Rect rect )
/*=========================*/
/* Create new clipping rectangle - return FALSE if drawing is disabled */
{
Rect combinedRect;
/* See if the clipping rectangle is empty, indicating that no drawing
should occur into the metafile */
if (Height( rect ) == 0 || Width( rect ) == 0)
{
/* indicate that drawing is disabled */
return FALSE;
}
/* don't do anything if rectangle hasn't changed */
if (!EqualRect( &rect, &gdiCache.curClipRect ) || gdiCache.forceNewClipRect)
{
/* flush the primitive cache if changing clip region */
CaFlushCache();
/* is new clip rect is completely enclosed by current cliprect? */
IntersectRect( &combinedRect, &rect, &gdiCache.curClipRect );
/* check for equality of intersection and new cliprect */
if (!EqualRect( &combinedRect, &rect ) || gdiCache.forceNewClipRect)
{
/* must be called just to be able to change clipping rectangle */
CaRestoreDC();
CaSaveDC();
}
/* set the new clipping rectangle */
IntersectClipRect( gdiCache.metafile,
rect.left, rect.top, rect.right, rect.bottom );
/* save the current clip rectangle, since it has changed */
gdiCache.curClipRect = rect;
/* turn off forcing of the clipping rectangle */
gdiCache.forceNewClipRect = FALSE;
}
/* return TRUE - drawing is enabled */
return TRUE;
} /* GdiIntersectClipRect */
void CaSetClipRect( Rect rect )
/*================*/
/* set the current cliprectangle to be equal to rect */
{
gdiCache.curClipRect = rect;
} /* CaSetClipRect */
Rect far * CaGetClipRect( void )
/*=====================*/
/* get the current cliprectangle */
{
return &gdiCache.curClipRect;
} /* CaGetClipRect */
void CaNonRectangularClip( void )
/*=======================*/
/* notify cache that a non-rectangular clipping region was set */
{
gdiCache.forceNewClipRect = TRUE;
} /* CaNonRectangularClip */
void CaSaveDC( void )
/*===========*/
/* save the current device context - used to set up clipping rects */
{
/* the previous clipping rectangle is saved off */
gdiCache.prevClipRect = gdiCache.curClipRect;
/* issue call to GDI */
SaveDC( gdiCache.metafile );
}
void CaRestoreDC( void )
/*==============*/
/* restore the device context and invalidate cached attributes */
{
/* restore previous clipping rectangle */
gdiCache.curClipRect = gdiCache.prevClipRect;
/* invalidate all of the cached attributes and objects */
gdiCache.restorePen =
gdiCache.restoreBrush =
gdiCache.restoreFont =
gdiCache.restoreCharExtra = TRUE;
/* reset metafile defaults */
gdiCache.curROP2 = gdiCache.iniROP2;
gdiCache.curTextAlign = gdiCache.iniTextAlign;
gdiCache.curBkMode = gdiCache.iniBkMode;
gdiCache.curTextColor = gdiCache.iniTxColor;
gdiCache.curBkColor = gdiCache.iniBkColor;
/* issue call to GDI */
RestoreDC( gdiCache.metafile, -1 );
}
/******************************* Private Routines ***************************/
private void AddPolyPt( Point pt )
/*--------------------*/
/* Add a point to the polygon buffer */
{
/* make sure that we haven't reached maximum size */
if ((gdiCache.numPoints + 1) >= gdiCache.maxPoints)
{
/* expand the number of points that can be cached by 10 */
gdiCache.maxPoints += 16;
/* unlock to prepare for re-allocation */
GlobalUnlock( gdiCache.polyHandle);
/* re-allocate the memory handle by the given amount */
gdiCache.polyHandle = GlobalReAlloc(
gdiCache.polyHandle,
gdiCache.maxPoints * sizeof( Point ),
GMEM_MOVEABLE);
/* make sure that the re-allocation succeeded */
if (gdiCache.polyHandle == NULL)
{
/* if not, flag global error and exit from here */
ErSetGlobalError( ErMemoryFull );
return;
}
/* lock the memory handle to get a pointer address */
gdiCache.pointList = (Point far *)GlobalLock( gdiCache.polyHandle );
}
/* insert the new point and increment the number of points in the buffer */
gdiCache.pointList[gdiCache.numPoints++] = pt;
} /* AddPolyPt */
private void SelectCachedPen( void )
/*--------------------------*/
/* select the currently cached Pen into the metafile */
{
/* make sure that there is some new pen to select */
if (gdiCache.nextPen.handle != NULL)
{
/* make sure that the pens are different */
if (gdiCache.nextPen.handle != gdiCache.curPen.handle)
{
/* select the new pen */
SelectObject( gdiCache.metafile, gdiCache.nextPen.handle);
/* if this isn't the first pen selection and not a stock pen */
if (gdiCache.curPen.handle != NULL && !gdiCache.curPen.stockObject)
{
/* delete the previous pen selection */
DeleteObject( gdiCache.curPen.handle );
}
/* save pen handle in current cache variable */
gdiCache.curPen = gdiCache.nextPen;
}
/* reset the cache pen to indicate no pre-existing cached pen */
gdiCache.nextPen.handle = NULL;
}
} /* SelectCachedPen */