netscape-revival
lib/mac/VText/V_PowerPlant_Mods/URegions.cp
// ===========================================================================
// URegions.cp ©1994 Metrowerks Inc. All rights reserved.
// ===========================================================================
#ifdef PowerPlant_PCH
#include PowerPlant_PCH
#endif
#include <URegions.h>
#include <PP_Messages.h>
#include <UDrawingState.h>
#include <UDrawingUtils.h>
#ifndef __ERRORS__
#include <Errors.h>
#endif
// ===========================================================================
// StRegion
// ===========================================================================
//
// Class for a temporary region that exists only during the execution of a
// block of C++ code.
//
// When the StRegion variable goes out of scope (exceptions included), the
// associated region will be disposed.
StRegion::StRegion()
{
mRgn = URegions::sRgnPool.Get();
ThrowIfNULL_(mRgn);
}
StRegion::StRegion(const Rect &inRect)
{
mRgn = URegions::sRgnPool.Get();
ThrowIfNULL_(mRgn);
RectRgn(mRgn, &((Rect &)inRect));
ThrowIfOSErr_(QDError());
}
StRegion::StRegion(const RgnHandle inRegion)
/*
This constructor was semantically changed on 950304...
This constructor now takes a copy of the passed region! This is
more useful than the previous policy of simply claiming the
passed region. Unfortunately, it is incompatible with
previous code!
Previous code that used the previous RgnHandle constructor semantic
must be rewritten...
*/
{
mRgn = URegions::sRgnPool.Get();
ThrowIfNULL_(mRgn);
if (inRegion) {
CopyRgn(inRegion, mRgn);
ThrowIfOSErr_(QDError());
}
}
StRegion::StRegion(const StRegion &inStRegion)
{
mRgn = URegions::sRgnPool.Get();
ThrowIfNULL_(mRgn);
CopyRgn(inStRegion.mRgn, mRgn);
ThrowIfOSErr_(QDError());
}
StRegion::~StRegion()
{
if (mRgn)
URegions::sRgnPool.Return(mRgn);
mRgn = NULL;
}
Boolean StRegion::operator==(const StRegion &inRhs) const
{
if (this == &inRhs)
return true;
return EqualRgn(mRgn, inRhs.mRgn);
}
StRegion & StRegion::operator=(const StRegion &inRhs)
{
if (this != &inRhs) {
ThrowIfNULL_(mRgn);
CopyRgn(inRhs.mRgn, mRgn);
}
return *this;
}
// ===========================================================================
// StRegionBuilder
// ===========================================================================
//
// Class to "open" a region for the scope of a given block.
//
// When the StRegionBuilder variable goes out of scope (exceptions included),
// the region will be closed.
StRegionBuilder::StRegionBuilder(RgnHandle ioRgn)
{
mRgn = NULL;
ThrowIfNULL_(ioRgn);
if (UQDGlobals::GetQDGlobals()->thePort->rgnSave != NULL)
Throw_(paramErr); // Can't nest open regions
OpenRgn();
ThrowIfOSErr_(QDError());
mRgn = ioRgn;
}
StRegionBuilder::~StRegionBuilder()
{
if (mRgn) {
CloseRgn(mRgn);
ThrowIfOSErr_(QDError());
}
}
// ===========================================================================
// StVisRgn
// ===========================================================================
//
// Class providing a stack scoped vis region change.
//
// When the StVisRgn variable goes out of scope (exceptions included), the
// original port visRgn will be restored.
//
// The (inPort) constructor will make the visRgn empty.
StVisRgn::StVisRgn(GrafPtr inPort, const Rect &inRect)
{
ThrowIfNULL_(inPort);
mPort = inPort;
mSavedVisRgn = mPort->visRgn;
RectRgn(mTempRgn.mRgn, &inRect);
mPort->visRgn = mTempRgn.mRgn;
mOldTopLeft = topLeft((**(mPort->visRgn)).rgnBBox);
}
StVisRgn::StVisRgn(GrafPtr inPort)
{
ThrowIfNULL_(inPort);
mPort = inPort;
mSavedVisRgn = mPort->visRgn;
mPort->visRgn = mTempRgn.mRgn;
}
StVisRgn::~StVisRgn()
{
// Origin might have moved since constructor saved the
// visRgn. The distance to the current topLeft indicates
// the amount that the origin shifted. We shift the
// saved visRgn by this amount to keep it in synch with
// the new origin position.
Point offset = topLeft((**(mPort->visRgn)).rgnBBox);
offset.h -= mOldTopLeft.h;
offset.v -= mOldTopLeft.v;
URegions::Translate(mSavedVisRgn, offset);
mPort->visRgn = mSavedVisRgn;
}
// ===========================================================================
// LRegionPool
// ===========================================================================
//
// Pool class to speed up StRegions. "Free" regions are kept in an internal
// list with region allocations & returns be sent through the free region
// list. Get and Return are optimized for St operation (ie. they favor
// the end of the list).
#include <LList.h>
LRegionPool::LRegionPool()
: LList(sizeof(RgnHandle))
{
}
LRegionPool::~LRegionPool()
{
RgnHandle rgn = NULL;
for (Int32 i = GetCount(); i > 0; i--) {
FetchItemAt(i, &rgn);
DisposeRgn(rgn);
RemoveItemsAt(1, i);
}
Assert_(GetCount() == 0);
}
// Get
//
// Get an existing regions from the list (much faster than
// allocating a new one) or calls NewRgn if no free region exists.
//
// To have pooled free regions disposed of attach to an LGrowZone broadcaster
// with:
//
// LGrowZone::GetGrowZone()->AddListerner(URegions::sRgnPool);
//
// For poor, non-pooled performance turn this conditional off.
#if 1
RgnHandle LRegionPool::Get(void)
{
RgnHandle rval = NULL;
Int32 count = GetCount();
if (count == 0) {
rval = NewRgn();
} else {
FetchItemAt(count, &rval);
RemoveItemsAt(1, count);
}
return rval;
}
void LRegionPool::Return(RgnHandle inRegion)
{
Try_ {
InsertItemsAt(1, max_Int32, &inRegion);
} Catch_(inErr) {
DisposeRgn(inRegion);
if (inErr != memFullErr)
Throw_(inErr);
} EndCatch_;
}
#else
RgnHandle LRegionPool::Get(void)
{
RgnHandle rval = NewRgn();
ThrowIfNULL_(rval);
return rval;
}
void LRegionPool::Return(RgnHandle inRegion)
{
DisposeRgn(inRegion);
}
#endif
void LRegionPool::ListenToMessage(MessageT inMessage, void *ioParam)
{
switch (inMessage) {
case msg_GrowZone:
{
Int32 requested = *((Int32 *)ioParam);
Int32 freedBytes = 0;
RgnHandle rgn = NULL;
for (Int32 i = GetCount(); i > 0; i--) {
if (freedBytes > requested)
break;
FetchItemAt(i, &rgn);
freedBytes += GetHandleSize((Handle)rgn);
DisposeRgn(rgn);
}
*((Int32 *)ioParam) = freedBytes;
break;
}
}
}
// ===========================================================================
// URegion
// ===========================================================================
//
// Exception aware utility functions for Regions.
LRegionPool URegions::sRgnPool;
void URegions::MakeEmpty(RgnHandle ioRegion)
{
Rect r = {0, 0, 0, 0};
RectRgn(ioRegion, &r);
ThrowIfOSErr_(QDError());
}
void URegions::DrawAt(RgnHandle inRegion, Point inWhere, ConstPatternParam inPat)
{
ThrowIfNULL_(inRegion);
Point negWhere;
negWhere.h = -inWhere.h;
negWhere.v = -inWhere.v;
Translate(inRegion, inWhere);
Try_{
FillRgn(inRegion, inPat);
ThrowIfOSErr_(QDError());
Translate(inRegion, negWhere);
} Catch_(inErr) {
Translate(inRegion, negWhere);
} EndCatch_;
}
void URegions::FrameAt(RgnHandle inRegion, Point inWhere)
{
ThrowIfNULL_(inRegion);
Point negWhere;
negWhere.h = -inWhere.h;
negWhere.v = -inWhere.v;
Translate(inRegion, inWhere);
Try_{
FrameRgn(inRegion);
ThrowIfOSErr_(QDError());
Translate(inRegion, negWhere);
} Catch_(inErr) {
Translate(inRegion, negWhere);
} EndCatch_;
}
void URegions::Hilite(RgnHandle inRegion)
{
StColorPenState savePen;
PenPat(&UQDGlobals::GetQDGlobals()->black);
PenMode(srcXor);
UDrawingUtils::SetHiliteModeOn();
InvertRgn(inRegion);
}
void URegions::Translate(RgnHandle ioRegion, Point inVector)
{
ThrowIfNULL_(ioRegion);
OffsetRgn(ioRegion, inVector.h, inVector.v);
}
void URegions::MakeRegionOutline(RgnHandle inRegion, RgnHandle *ioRgn)
{
OSErr err = noErr;
Boolean createdRgn = false;
ThrowIfNULL_(ioRgn);
ThrowIfNULL_(inRegion);
if (inRegion == *ioRgn) {
StRegion tempRgn(inRegion);
InsetRgn(tempRgn, 1, 1);
ThrowIfOSErr_(QDError());
DiffRgn(inRegion, tempRgn, *ioRgn); // of course, inRegion & *ioRgn are the same!
ThrowIfOSErr_(QDError());
} else {
if (*ioRgn == NULL) {
*ioRgn = NewRgn();
createdRgn = true;
}
ThrowIfNULL_(*ioRgn);
Try_ {
// Get outline
CopyRgn(inRegion, *ioRgn);
ThrowIfOSErr_(QDError());
InsetRgn(*ioRgn, 1, 1);
ThrowIfOSErr_(QDError());
DiffRgn(inRegion, *ioRgn, *ioRgn);
ThrowIfOSErr_(QDError());
} Catch_(inErr) {
if (createdRgn && *ioRgn) {
DisposeRgn(*ioRgn);
*ioRgn = NULL;
}
Throw_(inErr);
} EndCatch_;
}
}