mirror of
https://github.com/microsoft/Microsoft-3D-Movie-Maker.git
synced 2024-11-25 11:42:35 +01:00
1436 lines
35 KiB
C++
1436 lines
35 KiB
C++
/* Copyright (c) Microsoft Corporation.
|
|
Licensed under the MIT License. */
|
|
|
|
/***************************************************************************
|
|
Author: ShonK
|
|
Project: Kauai
|
|
Reviewed:
|
|
Copyright (c) Microsoft Corporation
|
|
|
|
Mac specific graphics routines.
|
|
|
|
***************************************************************************/
|
|
#include "frame.h"
|
|
ASSERTNAME
|
|
|
|
|
|
HCLT GPT::_hcltDef;
|
|
bool GPT::_fForcePalOnSys;
|
|
|
|
#ifdef SYMC
|
|
ACR kacrBlack(0, 0, 0);
|
|
ACR kacrDkGray(0x3F, 0x3F, 0x3F);
|
|
ACR kacrGray(0x7F, 0x7F, 0x7F);
|
|
ACR kacrLtGray(0xBF, 0xBF, 0xBF);
|
|
ACR kacrWhite(kbMax, kbMax, kbMax);
|
|
ACR kacrRed(kbMax, 0, 0);
|
|
ACR kacrGreen(0, kbMax, 0);
|
|
ACR kacrBlue(0, 0, kbMax);
|
|
ACR kacrYellow(kbMax, kbMax, 0);
|
|
ACR kacrCyan(0, kbMax, kbMax);
|
|
ACR kacrMagenta(kbMax, 0, kbMax);
|
|
ACR kacrClear(fTrue, fTrue);
|
|
ACR kacrInvert(fFalse, fFalse);
|
|
#endif //SYMC
|
|
|
|
/***************************************************************************
|
|
Set the color as the current foreground color.
|
|
***************************************************************************/
|
|
void ACR::_SetFore(void)
|
|
{
|
|
AssertThis(facrRgb | facrIndex);
|
|
SCR scr;
|
|
byte b;
|
|
|
|
if (B3Lw(_lu) == kbIndexAcr)
|
|
PmForeColor(B0Lw(_lu));
|
|
else
|
|
{
|
|
b = B2Lw(_lu);
|
|
scr.red = SwHighLow(b, b);
|
|
b = B1Lw(_lu);
|
|
scr.green = SwHighLow(b, b);
|
|
b = B0Lw(_lu);
|
|
scr.blue = SwHighLow(b, b);
|
|
RGBForeColor(&scr);
|
|
}
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Set the color as the current background color.
|
|
***************************************************************************/
|
|
void ACR::_SetBack(void)
|
|
{
|
|
AssertThis(facrRgb | facrIndex);
|
|
SCR scr;
|
|
byte b;
|
|
|
|
if (B3Lw(_lu) == kbIndexAcr)
|
|
PmBackColor(B0Lw(_lu));
|
|
else
|
|
{
|
|
b = B2Lw(_lu);
|
|
scr.red = SwHighLow(b, b);
|
|
b = B1Lw(_lu);
|
|
scr.green = SwHighLow(b, b);
|
|
b = B0Lw(_lu);
|
|
scr.blue = SwHighLow(b, b);
|
|
RGBBackColor(&scr);
|
|
}
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Static method to flush any pending graphics operations.
|
|
***************************************************************************/
|
|
void GPT::Flush(void)
|
|
{
|
|
// does nothing on Mac.
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Static method to set the current color table.
|
|
While using fpalIdentity the following cautions apply:
|
|
|
|
1) The following indexes are reserved by the system, so shouldn't be used:
|
|
{ 0, 1, 3, 15, 255 } (Mac)
|
|
{ 0 - 9; 246 - 255 } (Win).
|
|
2) While we're in the background, RGB values may get mapped to
|
|
the wrong indexes, so the colors will change when we move
|
|
to the foreground. The solution is to always use indexed
|
|
based color while using fForceOnSystem.
|
|
3) This should only be called when we are the foreground app.
|
|
|
|
REVIEW shonk: Mac: implement fpalInitAnim and fpalAnimate.
|
|
***************************************************************************/
|
|
void GPT::SetActiveColors(PGL pglclr, ulong grfpal)
|
|
{
|
|
AssertNilOrPo(pglclr, 0);
|
|
long cclr, iclr, iv;
|
|
HPAL hpal, hpalOld;
|
|
SCR scr;
|
|
CLR clr;
|
|
HCLT hclt;
|
|
HWND hwnd;
|
|
|
|
if (hNil == (hclt = GetCTable(72)))
|
|
goto LFail;
|
|
(*hclt)->ctSeed = GetCTSeed();
|
|
|
|
//REVIEW shonk: Mac: does it work to call SetPalette with a nil palette?
|
|
if (pvNil != pglclr && 0 < (cclr = LwMin(256, pglclr->IvMac())))
|
|
{
|
|
if (hNil == (hpal = NewPalette((short)cclr, hNil,
|
|
(grfpal & fpalIdentity) ? pmTolerant | pmExplicit : pmTolerant, 0)))
|
|
{
|
|
DisposeHandle((HN)hclt);
|
|
LFail:
|
|
PushErc(ercGfxCantSetPalette);
|
|
return;
|
|
}
|
|
for (iclr = 0; iclr < cclr; iclr++)
|
|
{
|
|
pglclr->Get(iclr, &clr);
|
|
scr.red = SwHighLow(clr.bRed, clr.bRed);
|
|
scr.green = SwHighLow(clr.bGreen, clr.bGreen);
|
|
scr.blue = SwHighLow(clr.bBlue, clr.bBlue);
|
|
SetEntryColor(hpal, (short)iclr, &scr);
|
|
(*hclt)->ctTable[iclr].rgb = scr;
|
|
}
|
|
if (grfpal & fpalIdentity)
|
|
{
|
|
//set the first entry to white (with just pmExplicit)
|
|
scr.red = scr.green = scr.blue = (ushort)-1;
|
|
SetEntryColor(hpal, 0, &scr);
|
|
SetEntryUsage(hpal, 0, pmExplicit, -1);
|
|
(*hclt)->ctTable[0].rgb = scr;
|
|
|
|
//set all possible ending entries to black (with just pmExplicit)
|
|
scr.red = scr.green = scr.blue = 0;
|
|
for (iv = 1; iv <= 8; iv <<= 1)
|
|
{
|
|
iclr = (1 << iv) - 1;
|
|
if (iclr < cclr)
|
|
{
|
|
SetEntryColor(hpal, (short)iclr, &scr);
|
|
SetEntryUsage(hpal, (short)iclr, pmExplicit, -1);
|
|
}
|
|
(*hclt)->ctTable[iclr].rgb = scr;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
hpal = hNil;
|
|
|
|
hpalOld = GetPalette(PPRT(-1));
|
|
SetPalette(PPRT(-1), hpal, fFalse);
|
|
|
|
//activate the palette
|
|
if (hNil != (hwnd = (HWND)FrontWindow()))
|
|
ActivatePalette((PPRT)hwnd);
|
|
else
|
|
{
|
|
//to activate the palette, create a window offscreen and then destroy it
|
|
RCS rcs;
|
|
|
|
rcs = qd.screenBits.bounds;
|
|
rcs.top = qd.screenBits.bounds.top + GetMBarHeight() / 2;
|
|
rcs.left = (qd.screenBits.bounds.left + qd.screenBits.bounds.right) / 2;
|
|
rcs.bottom = rcs.top + 1;
|
|
rcs.right = rcs.left + 1;
|
|
hwnd = (HWND)NewCWindow(pvNil, &rcs, (byte *)"\p", fTrue, plainDBox,
|
|
GrafPtr(-1), fTrue, 0);
|
|
if (hNil != hwnd)
|
|
DisposeWindow((PPRT)hwnd);
|
|
}
|
|
|
|
if (hNil != hpalOld)
|
|
DisposePalette(hpalOld);
|
|
if (hNil != _hcltDef)
|
|
DisposeHandle((HN)_hcltDef);
|
|
_hcltDef = hclt;
|
|
_fForcePalOnSys = FPure(grfpal & fpalIdentity);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Static method to determine if the main screen supports this depth
|
|
and color status.
|
|
***************************************************************************/
|
|
bool GPT::FCanScreen(long cbitPixel, bool fColor)
|
|
{
|
|
if (cbitPixel == 24)
|
|
cbitPixel = 32;
|
|
|
|
//assert that cbitPixel is in {1,2,4,8,16,32}
|
|
AssertIn(cbitPixel, 1, 33);
|
|
AssertVar((cbitPixel & (cbitPixel - 1)) == 0, "bad cbitPixel value", &cbitPixel);
|
|
HGD hgd;
|
|
|
|
if (hNil == (hgd = GetMainDevice()))
|
|
return fFalse;
|
|
return HasDepth(hgd, (short)cbitPixel, 1, fColor ? 1 : 0) != 0;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Static method to attempt to set the depth and/or color status of the
|
|
main screen (the one with the menu bar).
|
|
***************************************************************************/
|
|
bool GPT::FSetScreenState(long cbitPixel, bool tColor)
|
|
{
|
|
if (cbitPixel == 24)
|
|
cbitPixel = 32;
|
|
|
|
//assert that cbitPixel is in {0,1,2,4,8,16,32}
|
|
AssertIn(cbitPixel, 0, 33);
|
|
AssertVar((cbitPixel & (cbitPixel - 1)) == 0, "bad cbitPixel value", &cbitPixel);
|
|
AssertT(tColor);
|
|
HGD hgd;
|
|
short swT;
|
|
|
|
if (hNil == (hgd = GetMainDevice()))
|
|
return fFalse;
|
|
if (0 == cbitPixel)
|
|
cbitPixel = (*(*hgd)->gdPMap)->pixelSize;
|
|
swT = (tColor == tYes ||
|
|
tColor == tMaybe && TestDeviceAttribute(hgd, gdDevType)) ? 1 : 0;
|
|
if (0 == HasDepth(hgd, (short)cbitPixel, 1, swT))
|
|
return fFalse;
|
|
return (noErr == SetDepth(hgd, (short)cbitPixel, 1, swT));
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Static method to get the state of the main screen.
|
|
***************************************************************************/
|
|
void GPT::GetScreenState(long *pcbitPixel, bool *pfColor)
|
|
{
|
|
AssertVarMem(pcbitPixel);
|
|
AssertVarMem(pfColor);
|
|
HGD hgd;
|
|
|
|
if (hNil == (hgd = GetMainDevice()))
|
|
{
|
|
*pcbitPixel = 0;
|
|
*pfColor = fFalse;
|
|
}
|
|
else
|
|
{
|
|
*pcbitPixel = (*(*hgd)->gdPMap)->pixelSize;
|
|
*pfColor = FPure(TestDeviceAttribute(hgd, gdDevType));
|
|
}
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Static method to create a new GPT.
|
|
***************************************************************************/
|
|
PGPT GPT::PgptNew(PPRT pprt, HGD hgd)
|
|
{
|
|
AssertVarMem(pprt);
|
|
AssertNilOrVarMem(hgd);
|
|
PGPT pgpt;
|
|
|
|
if (pvNil == (pgpt = NewObj GPT))
|
|
return pvNil;
|
|
|
|
pgpt->_pprt = pprt;
|
|
pgpt->_hgd = hgd;
|
|
AssertThis(0);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Destructor for a port.
|
|
***************************************************************************/
|
|
GPT::~GPT(void)
|
|
{
|
|
if (_fOffscreen)
|
|
{
|
|
Assert(_cactLock == 0, "pixels are still locked for GWorld being freed");
|
|
if (hNil != _hpic)
|
|
{
|
|
Set(pvNil);
|
|
ClosePicture();
|
|
Restore();
|
|
KillPicture(_hpic);
|
|
_hpic = hNil;
|
|
}
|
|
DisposeGWorld((PGWR)_pprt);
|
|
}
|
|
ReleasePpo(&_pregnClip);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Return the clut that should be used for off-screen GPT's.
|
|
***************************************************************************/
|
|
HCLT GPT::_HcltUse(long cbitPixel)
|
|
{
|
|
HGD hgd;
|
|
HCLT hclt;
|
|
|
|
if (cbitPixel > 8)
|
|
return hNil;
|
|
|
|
if (_fForcePalOnSys)
|
|
{
|
|
if (hNil == (hgd = GetMainDevice()) ||
|
|
hNil == (hclt = (*(*hgd)->gdPMap)->pmTable))
|
|
{
|
|
Warn("Can't get Main Device's color table");
|
|
}
|
|
else if ((*hclt)->ctSize + 1 >= (1 << cbitPixel))
|
|
return hclt;
|
|
}
|
|
return _hcltDef;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Static method to create an offscreen port.
|
|
***************************************************************************/
|
|
PGPT GPT::PgptNewOffscreen(RC *prc, long cbitPixel)
|
|
{
|
|
AssertVarMem(prc);
|
|
Assert(!prc->FEmpty(), "empty rc for offscreen");
|
|
PGWR pgwr;
|
|
RCS rcs;
|
|
PGPT pgpt;
|
|
|
|
if (cbitPixel == 24)
|
|
cbitPixel = 32;
|
|
|
|
//assert that cbitPixel is in {1,2,4,8,16,32}
|
|
AssertIn(cbitPixel, 1, 33);
|
|
AssertVar((cbitPixel & (cbitPixel - 1)) == 0, "bad cbitPixel value", &cbitPixel);
|
|
|
|
rcs = *prc;
|
|
if (noErr != NewGWorld(&pgwr, (short)cbitPixel, &rcs, _HcltUse(cbitPixel), hNil, 0))
|
|
return pvNil;
|
|
|
|
if (pvNil == (pgpt = PgptNew((PPRT)pgwr)))
|
|
DisposeGWorld(pgwr);
|
|
else
|
|
{
|
|
pgpt->_fOffscreen = fTrue;
|
|
pgpt->_rcOff = *prc;
|
|
pgpt->_cbitPixel = (short)cbitPixel;
|
|
}
|
|
|
|
return pgpt;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
If this is an offscreen bitmap, return the pointer to the pixels and
|
|
optionally get the bounds. Must balance with a call to Unlock().
|
|
***************************************************************************/
|
|
byte *GPT::PrgbLockPixels(RC *prc)
|
|
{
|
|
AssertThis(0);
|
|
AssertNilOrVarMem(prc);
|
|
HPIX hpix;
|
|
|
|
if (!_fOffscreen)
|
|
return pvNil;
|
|
|
|
Lock();
|
|
hpix = _Hpix();
|
|
if (pvNil != prc)
|
|
*prc = _rcOff;
|
|
|
|
return (byte *)(*hpix)->baseAddr;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
If this is an offscreen bitmap, return the number of bytes per row.
|
|
***************************************************************************/
|
|
long GPT::CbRow(void)
|
|
{
|
|
AssertThis(0);
|
|
HPIX hpix;
|
|
|
|
if (!_fOffscreen)
|
|
return 0;
|
|
hpix = _Hpix();
|
|
return (*hpix)->rowBytes & 0x7FFF;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
If this is an offscreen bitmap, return the number of bits per pixel.
|
|
***************************************************************************/
|
|
long GPT::CbitPixel(void)
|
|
{
|
|
AssertThis(0);
|
|
|
|
if (!_fOffscreen)
|
|
return 0;
|
|
return _cbitPixel;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Static method to create a PICT and its an associated GPT.
|
|
This should be balanced with a call to PpicRelease().
|
|
***************************************************************************/
|
|
PGPT GPT::PgptNewPic(RC *prc)
|
|
{
|
|
AssertVarMem(prc);
|
|
Assert(!prc->FEmpty(), "empty rectangle for metafile GPT");
|
|
PGPT pgpt;
|
|
RCS rcs;
|
|
RC rc(0, 0, 1, 1);
|
|
|
|
if (pvNil == (pgpt = PgptNewOffscreen(&rc, 8)))
|
|
return pvNil;
|
|
|
|
rcs = RCS(*prc);
|
|
pgpt->Set(&rcs);
|
|
pgpt->_rcOff = *prc;
|
|
pgpt->_hpic = OpenPicture(&rcs);
|
|
pgpt->Restore();
|
|
if (hNil == pgpt->_hpic)
|
|
{
|
|
ReleasePpo(&pgpt);
|
|
return pvNil;
|
|
}
|
|
return pgpt;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Closes a metafile based GPT and returns the picture produced from
|
|
drawing into the GPT.
|
|
***************************************************************************/
|
|
PPIC GPT::PpicRelease(void)
|
|
{
|
|
AssertThis(0);
|
|
PPIC ppic;
|
|
RCS rcs;
|
|
|
|
if (hNil == _hpic)
|
|
{
|
|
Bug("not a Pict GPT");
|
|
goto LRelease;
|
|
}
|
|
|
|
Set(pvNil);
|
|
ClosePicture();
|
|
Restore();
|
|
rcs = (*_hpic)->picFrame;
|
|
if (EmptyRect(&rcs) || pvNil == (ppic = PIC::PpicNew(_hpic, &_rcOff)))
|
|
{
|
|
KillPicture(_hpic);
|
|
_hpic = hNil;
|
|
LRelease:
|
|
Release();
|
|
return pvNil;
|
|
}
|
|
_hpic = hNil;
|
|
Release();
|
|
return ppic;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Fill or frame a rectangle.
|
|
***************************************************************************/
|
|
void GPT::DrawRcs(RCS *prcs, GDD *pgdd)
|
|
{
|
|
AssertThis(0);
|
|
AssertVarMem(prcs);
|
|
AssertVarMem(pgdd);
|
|
PFNDRW pfn;
|
|
|
|
pfn = (pgdd->grfgdd & fgddFrame) ? (PFNDRW)_FrameRcs : (PFNDRW)_FillRcs;
|
|
_Fill(prcs, pgdd, pfn);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Callback (PFNDRW) to fill a rectangle.
|
|
***************************************************************************/
|
|
void GPT::_FillRcs(RCS *prcs)
|
|
{
|
|
AssertVarMem(prcs);
|
|
PaintRect(prcs);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Callback (PFNDRW) to frame a rectangle.
|
|
***************************************************************************/
|
|
void GPT::_FrameRcs(RCS *prcs)
|
|
{
|
|
AssertVarMem(prcs);
|
|
FrameRect(prcs);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Hilite the rectangle by reversing white and the system hilite color.
|
|
***************************************************************************/
|
|
void GPT::HiliteRcs(RCS *prcs, GDD *pgdd)
|
|
{
|
|
AssertThis(0);
|
|
AssertVarMem(prcs);
|
|
AssertVarMem(pgdd);
|
|
|
|
Set(pgdd->prcsClip);
|
|
ForeColor(blackColor);
|
|
pgdd->acrBack._SetBack();
|
|
*(byte *) 0x938 &= 0x7f; /* use color highlighting */
|
|
InvertRect(prcs);
|
|
Restore();
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Fill or frame an oval.
|
|
***************************************************************************/
|
|
void GPT::DrawOval(RCS *prcs, GDD *pgdd)
|
|
{
|
|
AssertThis(0);
|
|
AssertVarMem(prcs);
|
|
AssertVarMem(pgdd);
|
|
PFNDRW pfn;
|
|
|
|
pfn = (pgdd->grfgdd & fgddFrame) ? (PFNDRW)_FrameOval : (PFNDRW)_FillOval;
|
|
_Fill(prcs, pgdd, pfn);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Callback (PFNDRW) to fill an oval.
|
|
***************************************************************************/
|
|
void GPT::_FillOval(RCS *prcs)
|
|
{
|
|
AssertVarMem(prcs);
|
|
PaintOval(prcs);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Callback (PFNDRW) to frame an oval.
|
|
***************************************************************************/
|
|
void GPT::_FrameOval(RCS *prcs)
|
|
{
|
|
AssertVarMem(prcs);
|
|
FrameOval(prcs);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Fill or frame a polygon.
|
|
***************************************************************************/
|
|
void GPT::DrawPoly(HQ hqoly, GDD *pgdd)
|
|
{
|
|
AssertThis(0);
|
|
AssertHq(hqoly);
|
|
AssertVarMem(pgdd);
|
|
PFNDRW pfn;
|
|
|
|
pfn = (pgdd->grfgdd & fgddFrame) ? (PFNDRW)_FramePoly : (PFNDRW)_FillPoly;
|
|
_Fill(&hqoly, pgdd, pfn);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Callback (PFNDRW) to fill a polygon.
|
|
***************************************************************************/
|
|
void GPT::_FillPoly(HQ *phqoly)
|
|
{
|
|
AssertVarMem(phqoly);
|
|
AssertHq(*phqoly);
|
|
PaintPoly((PolyHandle)*phqoly);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Callback (PFNDRW) to frame a polygon.
|
|
***************************************************************************/
|
|
void GPT::_FramePoly(HQ *phqoly)
|
|
{
|
|
AssertVarMem(phqoly);
|
|
AssertHq(*phqoly);
|
|
FramePoly((PolyHandle)*phqoly);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Draw a line.
|
|
***************************************************************************/
|
|
void GPT::DrawLine(PTS *ppts1, PTS *ppts2, GDD *pgdd)
|
|
{
|
|
AssertThis(0);
|
|
AssertVarMem(ppts1);
|
|
AssertVarMem(ppts2);
|
|
AssertVarMem(pgdd);
|
|
PTS rgpts[2];
|
|
|
|
rgpts[0] = *ppts1;
|
|
rgpts[1] = *ppts2;
|
|
_Fill(rgpts, pgdd, (PFNDRW)_DrawLine);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Callback (PFNDRW) to draw a line.
|
|
***************************************************************************/
|
|
void GPT::_DrawLine(PTS *prgpts)
|
|
{
|
|
AssertPvCb(prgpts, 2 * size(PTS));
|
|
MoveTo(prgpts[0].h, prgpts[0].v);
|
|
LineTo(prgpts[1].h, prgpts[1].v);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Low level routine to fill/frame a shape.
|
|
***************************************************************************/
|
|
void GPT::_Fill(void *pv, GDD *pgdd, PFNDRW pfn)
|
|
{
|
|
ACR acrFore = pgdd->acrFore;
|
|
|
|
Set(pgdd->prcsClip);
|
|
if (pgdd->grfgdd & fgddFrame)
|
|
PenSize((short)pgdd->dxpPen, (short)pgdd->dypPen);
|
|
if (pgdd->grfgdd & fgddPattern)
|
|
{
|
|
//pattern fill
|
|
APT apt = pgdd->apt;
|
|
ACR acrBack = pgdd->acrBack;
|
|
|
|
//check for a solid pattern
|
|
if (apt.FSolidFore() || acrFore == acrBack)
|
|
goto LSolid;
|
|
if (apt.FSolidBack())
|
|
{
|
|
acrFore = acrBack;
|
|
goto LSolid;
|
|
}
|
|
|
|
Assert(acrFore != acrBack, "fore and back colors still equal!");
|
|
// Make sure we have one of these forms:
|
|
// (*, *)
|
|
// (clear, *)
|
|
// (invert, *)
|
|
// (invert, clear)
|
|
if (acrBack == kacrInvert || acrBack == kacrClear && acrFore != kacrInvert)
|
|
{
|
|
// swap them and invert the pattern
|
|
acrFore = acrBack;
|
|
acrBack = pgdd->acrFore;
|
|
apt.Invert();
|
|
}
|
|
|
|
PenPat((Pattern *)apt.rgb);
|
|
if (acrFore == kacrInvert)
|
|
{
|
|
// do (invert, clear)
|
|
PenMode(patXor);
|
|
ForeColor(blackColor);
|
|
(this->*pfn)(pv);
|
|
if (acrBack != kacrClear)
|
|
{
|
|
// need (invert, *), have already done (invert, clear)
|
|
// so still need to do (clear, *)
|
|
goto LClear;
|
|
}
|
|
}
|
|
else if (acrFore == kacrClear)
|
|
{
|
|
LClear:
|
|
// do (clear, *)
|
|
PenMode(notPatOr);
|
|
acrBack._SetFore();
|
|
(this->*pfn)(pv);
|
|
}
|
|
else
|
|
{
|
|
// do (*, *)
|
|
PenMode(patCopy);
|
|
acrFore._SetFore();
|
|
acrBack._SetBack();
|
|
(this->*pfn)(pv);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//solid color
|
|
LSolid:
|
|
if (acrFore == kacrClear)
|
|
goto LDone; //nothing to do
|
|
|
|
PenPat(&qd.black);
|
|
if (acrFore == kacrInvert)
|
|
{
|
|
PenMode(patXor);
|
|
ForeColor(blackColor);
|
|
}
|
|
else
|
|
{
|
|
PenMode(patCopy);
|
|
acrFore._SetFore();
|
|
}
|
|
(this->*pfn)(pv);
|
|
}
|
|
|
|
LDone:
|
|
Restore();
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Scroll the given rectangle.
|
|
***************************************************************************/
|
|
void GPT::ScrollRcs(RCS *prcs, long dxp, long dyp, GDD *pgdd)
|
|
{
|
|
AssertThis(0);
|
|
AssertVarMem(prcs);
|
|
AssertVarMem(pgdd);
|
|
HRGN hrgn;
|
|
|
|
Set(pgdd->prcsClip);
|
|
if (hNil == (hrgn = NewRgn()))
|
|
PushErc(ercGfxCantDraw);
|
|
else
|
|
{
|
|
ScrollRect(prcs, (short)dxp, (short)dyp, hrgn);
|
|
DisposeRgn(hrgn);
|
|
}
|
|
Restore();
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Draw the text.
|
|
***************************************************************************/
|
|
void GPT::DrawRgch(achar *prgch, long cch, PTS pts, GDD *pgdd, DSF *pdsf)
|
|
{
|
|
AssertThis(0);
|
|
AssertIn(cch, 0, kcbMax);
|
|
AssertPvCb(prgch, cch);
|
|
AssertVarMem(pgdd);
|
|
AssertPo(pdsf, 0);
|
|
|
|
ACR acrFore, acrBack;
|
|
RCS rcs;
|
|
RCS *prcs = pvNil;
|
|
|
|
if (pdsf->grfont & fontBoxed)
|
|
prcs = &rcs;
|
|
Set(pgdd->prcsClip);
|
|
_GetRcsFromRgch(prcs, prgch, (short)cch, &pts, pdsf);
|
|
acrFore = pgdd->acrFore;
|
|
acrBack = pgdd->acrBack;
|
|
|
|
ForeColor(blackColor);
|
|
BackColor(whiteColor);
|
|
if (acrFore == kacrInvert)
|
|
{
|
|
//do (invert, clear)
|
|
TextMode(srcXor);
|
|
MoveTo(pts.h, pts.v);
|
|
DrawText(prgch, 0, (short)cch);
|
|
}
|
|
else if (acrFore != kacrClear)
|
|
{
|
|
acrFore._SetFore();
|
|
if (acrBack != kacrClear && acrBack != kacrInvert)
|
|
{
|
|
TextMode(srcCopy);
|
|
acrBack._SetBack();
|
|
goto LDraw;
|
|
}
|
|
TextMode(srcOr);
|
|
MoveTo(pts.h, pts.v);
|
|
DrawText(prgch, 0, (short)cch);
|
|
ForeColor(blackColor);
|
|
}
|
|
|
|
if (acrBack == kacrInvert)
|
|
{
|
|
TextMode(notSrcXor);
|
|
goto LDraw;
|
|
}
|
|
else if (acrBack != kacrClear)
|
|
{
|
|
TextMode(notSrcCopy);
|
|
acrBack._SetFore();
|
|
LDraw:
|
|
MoveTo(pts.h, pts.v);
|
|
DrawText(prgch, 0, (short)cch);
|
|
}
|
|
|
|
if (pdsf->grfont & fontBoxed)
|
|
{
|
|
GDD gdd = *pgdd;
|
|
|
|
gdd.dxpPen = gdd.dypPen = 1;
|
|
gdd.grfgdd = fgddFrame | fgddPattern;
|
|
gdd.apt = vaptGray;
|
|
gdd.apt.MoveOrigin(-_ptBase.xp, -_ptBase.yp);
|
|
gdd.acrBack = kacrClear;
|
|
DrawRcs(&rcs, &gdd);
|
|
}
|
|
Restore();
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Get the bounding text rectangle (in port coordinates).
|
|
***************************************************************************/
|
|
void GPT::GetRcsFromRgch(RCS *prcs, achar *prgch, long cch, PTS pts, DSF *pdsf)
|
|
{
|
|
Set(pvNil);
|
|
_GetRcsFromRgch(prcs, prgch, (short)cch, &pts, pdsf);
|
|
Restore();
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Set the text properties in the current port and get the bounding
|
|
rectangle for the text.
|
|
|
|
-- On input:
|
|
-- ppts : Text origin, relative position is determined by tah and tav.
|
|
-- On output:
|
|
-- ppts : Text origin, relative to (left, baseline).
|
|
-- prcs : Bounding box.
|
|
|
|
prcs may be nil (saves a call to TextWidth if tah is tahLeft).
|
|
***************************************************************************/
|
|
void GPT::_GetRcsFromRgch(RCS *prcs, achar *prgch, short cch, PTS *ppts, DSF *pdsf)
|
|
{
|
|
AssertNilOrVarMem(prcs);
|
|
AssertIn(cch, 0, kcbMax);
|
|
AssertPvCb(prgch, cch);
|
|
AssertVarMem(ppts);
|
|
AssertPo(pdsf, 0);
|
|
|
|
FontInfo fin;
|
|
short xpLeft, ypTop;
|
|
short dyp;
|
|
short dxp;
|
|
short ftc;
|
|
|
|
//REVIEW shonk: avoid small font sizes (the OS will crash) - is this true
|
|
//on newer machines (020 and better)?
|
|
ftc = vntl.FtcFromOnn(pdsf->onn);
|
|
TextFont(ftc);
|
|
TextFace((short)pdsf->grfont);
|
|
TextSize((short)pdsf->dyp);
|
|
|
|
dxp = (pvNil == prcs && pdsf->tah == tahLeft) ?
|
|
0 : TextWidth(prgch, 0, cch);
|
|
|
|
xpLeft = ppts->h;
|
|
ypTop = ppts->v;
|
|
switch (pdsf->tah)
|
|
{
|
|
case tahCenter:
|
|
xpLeft -= dxp / 2;
|
|
break;
|
|
|
|
case tahRight:
|
|
xpLeft -= dxp;
|
|
break;
|
|
}
|
|
|
|
GetFontInfo(&fin);
|
|
dyp = fin.ascent + fin.descent;
|
|
switch (pdsf->tav)
|
|
{
|
|
case tavBaseline:
|
|
ypTop -= fin.ascent;
|
|
break;
|
|
|
|
case tavCenter:
|
|
ypTop -= dyp / 2;
|
|
break;
|
|
|
|
case tavBottom:
|
|
ypTop -= dyp;
|
|
break;
|
|
}
|
|
|
|
if (pvNil != prcs)
|
|
{
|
|
prcs->left = xpLeft;
|
|
prcs->top = ypTop;
|
|
prcs->right = xpLeft + dxp;
|
|
prcs->bottom = ypTop + dyp;
|
|
}
|
|
ppts->h = xpLeft;
|
|
ppts->v = ypTop + fin.ascent;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Lock the pixels for the port if this is an offscreen PixMap.
|
|
Must be balanced by a call to Unlock.
|
|
***************************************************************************/
|
|
void GPT::Lock(void)
|
|
{
|
|
if (_fOffscreen && 0 == _cactLock++)
|
|
{
|
|
AssertDo(LockPixels(GetGWorldPixMap((PGWR)_pprt)),
|
|
"couldn't lock gworld pixmap pixels");
|
|
}
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Unlock the pixels for the port if this is an offscreen PixMap.
|
|
***************************************************************************/
|
|
void GPT::Unlock(void)
|
|
{
|
|
if (_fOffscreen && 0 >= --_cactLock)
|
|
{
|
|
Assert(0 == _cactLock, "Unmatched Unlock call");
|
|
UnlockPixels(GetGWorldPixMap((PGWR)_pprt));
|
|
_cactLock = 0;
|
|
}
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Select our graf-port and device. Must be balanced by a call to
|
|
Restore. Set/Restore combinations are nestable for distinct ports
|
|
(but not for the same port). If this is a picture GPT, intersect
|
|
the clipping with _rcOff.
|
|
***************************************************************************/
|
|
void GPT::Set(RCS *prcsClip)
|
|
{
|
|
HCLT hclt;
|
|
RC rc, rcT;
|
|
RCS rcs;
|
|
HRGN hrgn = hNil;
|
|
|
|
Assert(!_fSet, "this port is already set");
|
|
Lock();
|
|
GetGWorld((PGWR *)&_pprtSav, &_hgdSav);
|
|
SetGWorld((PGWR)_pprt, _hgd);
|
|
|
|
if (pvNil == prcsClip)
|
|
rc.Max();
|
|
else
|
|
rc = RC(*prcsClip);
|
|
|
|
if (hNil != _hpic)
|
|
{
|
|
//in a picture GPT, clip to the bounding rectangle
|
|
rc.FIntersect(&_rcOff);
|
|
}
|
|
|
|
if (_fNewClip || rc != _rcClip)
|
|
{
|
|
//have to set the clipping
|
|
if (pvNil == _pregnClip)
|
|
rcT = rc;
|
|
else
|
|
{
|
|
if (!_pregnClip->FIsRc(&rcT) &&
|
|
hNil == (hrgn = _pregnClip->HrgnEnsure()))
|
|
{
|
|
Warn("clipping to region failed");
|
|
}
|
|
rcT.FIntersect(&rc);
|
|
}
|
|
|
|
rcs = RCS(rcT);
|
|
ClipRect(&rcs);
|
|
if (hNil != hrgn)
|
|
{
|
|
HRGN hrgnClip = qd.thePort->clipRgn;
|
|
SectRgn(hrgnClip, hrgn, hrgnClip);
|
|
}
|
|
_fNewClip = fFalse;
|
|
_rcClip = rc;
|
|
}
|
|
|
|
if (_fOffscreen && hNil != (hclt = _HcltUse(_cbitPixel)))
|
|
{
|
|
HPIX hpix = ((PCPRT)qd.thePort)->portPixMap;
|
|
if ((*(*hpix)->pmTable)->ctSeed != (*hclt)->ctSeed)
|
|
{
|
|
//change the color table without doing any color mapping
|
|
//REVIEW shonk: not sure we want to use UpdateGWorld - it does pixel mapping
|
|
//REVIEW shonk: does UpdateGWorld just copy the color table or does it do
|
|
//other stuff, including changing the seed?
|
|
NewCode();
|
|
long lw;
|
|
RCS rcs = _rcOff;
|
|
|
|
//REVIEW shonk: check for errors
|
|
lw = UpdateGWorld((PGWR *)&_pprt, _cbitPixel, &rcs, hclt, hNil, keepLocal);
|
|
}
|
|
}
|
|
_fSet = fTrue;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Restores the saved port and device (from a call to Set).
|
|
***************************************************************************/
|
|
void GPT::Restore(void)
|
|
{
|
|
if (!_fSet)
|
|
{
|
|
Bug("Unmatched restore");
|
|
return;
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
PPRT pprt;
|
|
HGD hgd;
|
|
|
|
GetGWorld((PGWR *)&pprt, &hgd);
|
|
Assert(pprt == _pprt, "why aren't we set - someone didn't restore");
|
|
Assert(hgd == _hgd || _hgd == hNil, "gdevice set wrong");
|
|
#endif //DEBUG
|
|
|
|
SetGWorld((PGWR)_pprtSav, _hgdSav);
|
|
Unlock();
|
|
_fSet = fFalse;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Return the PixMapHandle for the given port.
|
|
***************************************************************************/
|
|
HPIX GPT::_Hpix(void)
|
|
{
|
|
if (_fOffscreen)
|
|
return GetGWorldPixMap((PGWR)_pprt);
|
|
return ((PCPRT)_pprt)->portPixMap;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Copy bits from pgptSrc to this GPT.
|
|
***************************************************************************/
|
|
void GPT::CopyPixels(PGPT pgptSrc, RCS *prcsSrc, RCS *prcsDst, GDD *pgdd)
|
|
{
|
|
Set(pgdd->prcsClip);
|
|
ForeColor(blackColor);
|
|
BackColor(whiteColor);
|
|
pgptSrc->Lock();
|
|
CopyBits((PBMP)*pgptSrc->_Hpix(), (PBMP)*_Hpix(), prcsSrc, prcsDst, srcCopy, hNil);
|
|
pgptSrc->Unlock();
|
|
Restore();
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Draw the picture in the given rectangle.
|
|
***************************************************************************/
|
|
void GPT::DrawPic(PPIC ppic, RCS *prcs, GDD *pgdd)
|
|
{
|
|
AssertThis(0);
|
|
AssertPo(ppic, 0);
|
|
AssertVarMem(prcs);
|
|
AssertVarMem(pgdd);
|
|
|
|
Set(pgdd->prcsClip);
|
|
DrawPicture(ppic->Hpic(), prcs);
|
|
Restore();
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Draw the masked bitmap in the given rectangle with reference point
|
|
*ppts. pgdd->prcsClip is the clipping rectangle.
|
|
***************************************************************************/
|
|
void GPT::DrawMbmp(PMBMP pmbmp, RCS *prcs, GDD *pgdd)
|
|
{
|
|
AssertThis(0);
|
|
AssertPo(pmbmp, 0);
|
|
AssertVarMem(prcs);
|
|
AssertVarMem(pgdd);
|
|
RC rc, rcT;
|
|
HPIX hpix;
|
|
|
|
//REVIEW shonk: fix DrawMbmp to use the rcs.
|
|
|
|
pmbmp->GetRc(&rc);
|
|
rc.Offset(prcs->left, prcs->top);
|
|
if (pvNil != pgdd->prcsClip)
|
|
{
|
|
rcT = *pgdd->prcsClip;
|
|
if (!rc.FIntersect(&rcT))
|
|
return;
|
|
}
|
|
|
|
if (_cbitPixel == 8)
|
|
{
|
|
rcT = _rcOff;
|
|
Assert(rcT.xpLeft == 0 && rcT.ypTop == 0, "bad _rcOff");
|
|
if (!rc.FIntersect(&rcT))
|
|
return;
|
|
|
|
Lock();
|
|
hpix = _Hpix();
|
|
pmbmp->Draw((byte *)(*hpix)->baseAddr, (*hpix)->rowBytes & 0x7FFF, rcT.Dyp(),
|
|
prcs->left, prcs->top, &rc, _pregnClip);
|
|
Unlock();
|
|
}
|
|
else
|
|
{
|
|
//need to create a temporary offscreen GPT for the Mask, set the Mask
|
|
//area to white in this GPT, then create an offscreen GPT for the
|
|
//actual MBMP graphic, then blt these to this GPT.
|
|
PT ptDst;
|
|
PGPT pgpt;
|
|
RCS rcsDst;
|
|
RCS rcsSrc;
|
|
|
|
ptDst = rc.PtTopLeft();
|
|
rcsDst = RCS(rc);
|
|
rc.OffsetToOrigin();
|
|
if (pvNil == (pgpt = GPT::PgptNewOffscreen(&rc, 1)))
|
|
{
|
|
Warn("Drawing MBMP failed");
|
|
return;
|
|
}
|
|
Assert(pgpt->_rcOff == rc, 0);
|
|
pgpt->Lock();
|
|
hpix = pgpt->_Hpix();
|
|
pmbmp->DrawMask((byte *)(*hpix)->baseAddr, (*hpix)->rowBytes & 0x7FFF,
|
|
rc.Dyp(), prcs->left - ptDst.xp, prcs->top - ptDst.yp);
|
|
|
|
//set the mask bits to black
|
|
Set(pgdd->prcsClip);
|
|
ForeColor(blackColor);
|
|
BackColor(whiteColor);
|
|
rcsSrc = RCS(rc);
|
|
CopyBits((PBMP)*hpix, (PBMP)*_Hpix(), &rcsSrc, &rcsDst, srcBic, hNil);
|
|
Restore();
|
|
pgpt->Unlock();
|
|
ReleasePpo(&pgpt);
|
|
|
|
if (pvNil == (pgpt = GPT::PgptNewOffscreen(&rc, 8)))
|
|
{
|
|
Warn("Drawing MBMP failed");
|
|
return;
|
|
}
|
|
pgpt->Set(pvNil);
|
|
EraseRect(&rcsSrc);
|
|
pgpt->Restore();
|
|
|
|
if (pvNil != _pregnClip)
|
|
_pregnClip->Offset(-ptDst.xp, -ptDst.yp);
|
|
pgpt->Lock();
|
|
hpix = pgpt->_Hpix();
|
|
pmbmp->Draw((byte *)(*hpix)->baseAddr, (*hpix)->rowBytes & 0x7FFF, rc.Dyp(),
|
|
prcs->left - ptDst.xp, prcs->top - ptDst.yp, &rc, _pregnClip);
|
|
if (pvNil != _pregnClip)
|
|
_pregnClip->Offset(ptDst.xp, ptDst.yp);
|
|
|
|
Set(pgdd->prcsClip);
|
|
ForeColor(blackColor);
|
|
BackColor(whiteColor);
|
|
CopyBits((PBMP)*hpix, (PBMP)*_Hpix(), &rcsSrc, &rcsDst, srcOr, hNil);
|
|
Restore();
|
|
pgpt->Unlock();
|
|
ReleasePpo(&pgpt);
|
|
}
|
|
}
|
|
|
|
|
|
#ifdef DEBUG
|
|
/***************************************************************************
|
|
Test the validity of the port.
|
|
***************************************************************************/
|
|
void GPT::AssertValid(ulong grf)
|
|
{
|
|
GPT_PAR::AssertValid(0);
|
|
AssertIn(_cactRef, 1, kcbMax);
|
|
AssertVarMem(_pprt);
|
|
AssertNilOrVarMem(_hgd);
|
|
AssertNilOrVarMem(_pprtSav);
|
|
AssertNilOrVarMem(_hgdSav);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Static method to mark static GPT memory.
|
|
***************************************************************************/
|
|
void GPT::MarkStaticMem(void)
|
|
{
|
|
}
|
|
#endif //DEBUG
|
|
|
|
|
|
/***************************************************************************
|
|
Initialize the font table.
|
|
***************************************************************************/
|
|
bool NTL::FInit(void)
|
|
{
|
|
MenuHandle hmenu;
|
|
achar st[kcbMaxSt];
|
|
short ftc;
|
|
long ftcT;
|
|
long cstz, istz;
|
|
|
|
hmenu = NewMenu(1001, (byte *)"\pFont");
|
|
AddResMenu(hmenu, 'FONT');
|
|
cstz = CountMItems(hmenu);
|
|
if ((_pgst = GST::PgstNew(size(long), cstz + 1, (cstz + 1) * 15)) == pvNil)
|
|
goto LFail;
|
|
|
|
for (istz = 0; istz < cstz; istz++)
|
|
{
|
|
GetItem(hmenu, istz + 1, (byte *)st);
|
|
GetFNum((byte *)st, &ftc);
|
|
ftcT = ftc;
|
|
AssertDo(!_pgst->FFindSt(st, &istz, fgstUserSorted),
|
|
"font already found!");
|
|
if (!_pgst->FInsertSt(istz, st, &ftcT))
|
|
goto LFail;
|
|
}
|
|
|
|
//add the system font
|
|
GetFontName(0, (byte *)st);
|
|
ftcT = 0;
|
|
if (!_pgst->FFindSt(st, &_onnSystem, fgstUserSorted) &&
|
|
!_pgst->FInsertSt(_onnSystem, st, &ftcT))
|
|
{
|
|
LFail:
|
|
PushErc(ercGfxNoFontList);
|
|
return fFalse;
|
|
}
|
|
|
|
_pgst->FEnsureSpace(0, 0, fgrpShrink);
|
|
AssertThis(0);
|
|
return fTrue;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Return the system font code for this font number.
|
|
***************************************************************************/
|
|
short NTL::FtcFromOnn(long onn)
|
|
{
|
|
AssertThis(0);
|
|
long ftc;
|
|
|
|
_pgst->GetExtra(onn, &ftc);
|
|
return (short)ftc;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Return true iff the font is a fixed pitch font.
|
|
***************************************************************************/
|
|
bool NTL::FFixedPitch(long onn)
|
|
{
|
|
#ifdef REVIEW //shonk: implement FFixedPitch on Mac
|
|
AssertThis(0);
|
|
Assert(FValidOnn(onn), "bad onn");
|
|
LOGFONT lgf;
|
|
|
|
_pgst->GetExtra(onn, &lgf);
|
|
return (lgf.lfPitchAndFamily & 0x03) == FIXED_PITCH;
|
|
#else
|
|
return fFalse;
|
|
#endif
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Create a new rectangular region. If prc is nil, the region will be
|
|
empty.
|
|
***************************************************************************/
|
|
bool FCreateRgn(HRGN *phrgn, RC *prc)
|
|
{
|
|
AssertVarMem(phrgn);
|
|
AssertNilOrVarMem(prc);
|
|
|
|
if (pvNil == (*phrgn = NewRgn()))
|
|
return fFalse;
|
|
if (pvNil != prc && !prc->FEmpty())
|
|
{
|
|
RCS rcs = *prc;
|
|
RectRgn(*phrgn, &rcs);
|
|
}
|
|
return fTrue;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Free the region and set *phrgn to nil.
|
|
***************************************************************************/
|
|
void FreePhrgn(HRGN *phrgn)
|
|
{
|
|
AssertVarMem(phrgn);
|
|
|
|
if (*phrgn != hNil)
|
|
{
|
|
DisposeRgn(*phrgn);
|
|
*phrgn = hNil;
|
|
}
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Make the region rectangular. If prc is nil, the region will be empty.
|
|
If *phrgn is hNil, creates the region. *phrgn may change even if
|
|
*phrgn is not nil.
|
|
***************************************************************************/
|
|
bool FSetRectRgn(HRGN *phrgn, RC *prc)
|
|
{
|
|
AssertVarMem(phrgn);
|
|
AssertNilOrVarMem(prc);
|
|
|
|
if (hNil == *phrgn)
|
|
return FCreateRgn(phrgn, prc);
|
|
|
|
if (pvNil == prc)
|
|
SetEmptyRgn(*phrgn);
|
|
else
|
|
{
|
|
RCS rcs = *prc;
|
|
RectRgn(*phrgn, &rcs);
|
|
}
|
|
return fTrue;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Put the union of hrgnSrc1 and hrgnSrc2 into hrgnDst. The parameters
|
|
need not be distinct. Returns success/failure.
|
|
***************************************************************************/
|
|
bool FUnionRgn(HRGN hrgnDst, HRGN hrgnSrc1, HRGN hrgnSrc2)
|
|
{
|
|
Assert(hNil != hrgnDst, "null dst");
|
|
Assert(hNil != hrgnSrc1, "null src1");
|
|
Assert(hNil != hrgnSrc2, "null src2");
|
|
UnionRgn(hrgnSrc1, hrgnSrc2, hrgnDst);
|
|
return QDError() == noErr;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Put the intersection of hrgnSrc1 and hrgnSrc2 into hrgnDst. The parameters
|
|
need not be distinct. Returns success/failure.
|
|
***************************************************************************/
|
|
bool FIntersectRgn(HRGN hrgnDst, HRGN hrgnSrc1, HRGN hrgnSrc2, bool *pfEmpty)
|
|
{
|
|
Assert(hNil != hrgnDst, "null dst");
|
|
Assert(hNil != hrgnSrc1, "null src1");
|
|
Assert(hNil != hrgnSrc2, "null src2");
|
|
SectRgn(hrgnSrc1, hrgnSrc2, hrgnDst);
|
|
if (pvNil != pfEmpty)
|
|
*pfEmpty = EmptyRgn(hrgnDst);
|
|
return QDError() == noErr;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Put hrgnSrc - hrgnSrcSub into hrgnDst. The parameters need not be
|
|
distinct. Returns success/failure.
|
|
***************************************************************************/
|
|
bool FDiffRgn(HRGN hrgnDst, HRGN hrgnSrc, HRGN hrgnSrcSub)
|
|
{
|
|
Assert(hNil != hrgnDst, "null dst");
|
|
Assert(hNil != hrgnSrc, "null src");
|
|
Assert(hNil != hrgnSrcSub, "null srcSub");
|
|
DiffRgn(hrgnSrc, hrgnSrcSub, hrgnDst);
|
|
return QDError() == noErr;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Determine if the region is rectangular and put the bounding rectangle
|
|
in *prc (if not nil).
|
|
***************************************************************************/
|
|
bool FRectRgn(HRGN hrgn, RC *prc)
|
|
{
|
|
Assert(hNil != hrgn, "null rgn");
|
|
Assert((*hrgn)->rgnSize >= 10, "bad region");
|
|
|
|
if (pvNil != prc)
|
|
{
|
|
RCS rcs = (*hrgn)->rgnBBox;
|
|
*prc = rcs;
|
|
}
|
|
return (*hrgn)->rgnSize == 10;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Return true iff the region is empty.
|
|
***************************************************************************/
|
|
bool FEmptyRgn(HRGN hrgn, RC *prc)
|
|
{
|
|
Assert(hNil != hrgn, "null rgn");
|
|
|
|
if (pvNil != prc)
|
|
{
|
|
RCS rcs = (*hrgn)->rgnBBox;
|
|
*prc = rcs;
|
|
}
|
|
return EmptyRgn(hrgn);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Return true iff the two regions are equal.
|
|
***************************************************************************/
|
|
bool FEqualRgn(HRGN hrgn1, HRGN hrgn2)
|
|
{
|
|
Assert(hNil != hrgn1, "null rgn1");
|
|
Assert(hNil != hrgn2, "null rgn2");
|
|
return EqualRgn(hrgn1, hrgn2);
|
|
}
|
|
|
|
|