aboutsummaryrefslogtreecommitdiff
path: root/SrcShared/EmRegion.h
blob: da73139fa996ceb7b2a85ae44c0c6704e0590ee1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
/* -*- mode: C++; tab-width: 4 -*- */
/* ===================================================================== *\
	Copyright (c) 2000-2001 Palm, Inc. or its subsidiaries.
	All rights reserved.

	This file is part of the Palm OS Emulator.

	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.
\* ===================================================================== */

#ifndef EmRegion_h
#define EmRegion_h

/*
	EmRegion is a cross-platform region class. It provides for the following needs:

		- A common API that can be used on both Mac and Windows

		- An internal 32-bit representation so that regions can be calculated
		  in a 32-bit coordinate plane.

		- Automatic management of heap structures so that you don't have to
		  remember to call DisposeRgn or DeleteObject.

	Use regions as you would something like EmRect. Create them on the stack,
	declare them as data members, pass them by reference, etc. For instance,
	ScriptViewCore uses regions as follows to determine the highlight area:

	{
		EmRegion	scratch;
		EmRect		aRect;

		// The selection's bounding rectangle
		aRect = ...;	// Calculate full bounds
		highlight = aRect;

		// ... minus beginning of the first line
		aRect = ...;	// Calculate leading area to subtract
		scratch = aRect;
		highlight.Subtract(scratch);

		// ... and the end of the last line
		aRect = ...;	// Calculate trailing area to subtract
		scratch = aRect;
		highlight.Subtract(scratch);
	}

	If you need to decompose the region into a series of rectangles, you can use
	the EmRegionRectIterator class for this. It can be used as follows:

		EmRegionRectIterator	iter(*this);
		EmRect					r;
		while (iter.Next(r))
		{
			// ...do something with the rect...
		}
	
	This region class is based on the region class from ET++ 3.2.2, used by
	permission from AndrŽ Weinand:

			Regions: yes sure, just use the code and send me the bugs!

			--andre
			P.S.: my official life-long mail address is weinand@acm.org
*/

#include "EmPoint.h"			// EmPoint
#include "EmRect.h"				// EmRect
#include "EmRefCounted.h"


class EmRegion
{
	public:
								EmRegion	(void);
			// Creates a region spanning {0, 0, 0, 0}.

								EmRegion	(const EmRect& r);
			// Creates a region spanning the given rectangle.

								EmRegion	(const EmRegion& r);
			// Copy constructor. The internal data is copied via an internal
			// reference counted object, so cloning regions is quick.

								~EmRegion	(void);

		EmRegion&				operator=	(const EmRegion& r);
		EmRegion&				operator=	(const EmRect& r);
			// Assignment operator. Similar to copy constructor. There is also
			// a version that takes an EmRect as an r-value.

		void					BeEmpty		(void);
			// Quickly empty out a region so that you don't have to do anything
			// goofy like assigning a NULL rectangle to it.

		const EmRect&			Bounds		(void) const;
			// Returns an EmRect containing the bounds of the region.

		long					GetRects	(EmRect* r) const;
			// Decompose the region into a set of rectangles, returning the
			// number of rectangles. You pass in a pointer to a buffer that
			// will receive the rectangles. If you pass in NULL, no rectangles
			// will be returned, but you'll still get the rectangle count.
			// You should probably use a region iterator instead of this method
			// if you want to mess with the rectangles.

		Bool					IsEmpty		(void) const;
			// Returns whether or not the region encompases any area.

		Bool					IsEqual		(const EmRegion& r2) const;
			// Compares two regions, returning whether or not they encompass
			// the same area (set of pixels).

		Bool					Contains	(const EmPoint& p) const;
			// Returns whether or not the given point is in the interior of
			// the area described by the region. Testing is performed on the
			// normal half-open interval.

		friend inline Bool		operator==	(const EmRegion& r1, const EmRegion& r2);
		friend inline Bool		operator!=	(const EmRegion& r1, const EmRegion& r2);
			// Shortcuts for the IsEqual method

		void					Offset		(const EmPoint&);
		void					Offset		(EmCoord dx, EmCoord dy);
			// Offset the region by the given deltas. Positive deltas move
			// the region down and to the right.

		void					Inset		(const EmPoint&);
		void					Inset		(EmCoord dx, EmCoord dy);
			// Inset the region by the given deltas. Positive deltas move
			// the region inward.

		EmRegion&				UnionWith	(const EmRegion&);
		EmRegion&				IntersectWith(const EmRegion&);
		EmRegion&				Subtract	(const EmRegion&);
		EmRegion&				XorWith		(const EmRegion&);
			// Modify the region in place. Note that XorWith is synthesized from
			// the other operations, so it's not quite as effiecient as it
			// could be.

		friend inline EmRegion	Union		(const EmRegion& r1, const EmRegion& r2);
		friend inline EmRegion	Intersection(const EmRegion& r1, const EmRegion& r2);
		friend inline EmRegion	Difference	(const EmRegion& r1, const EmRegion& r2);
		friend inline EmRegion	Xor			(const EmRegion& r1, const EmRegion& r2);
			// Versions of the previous four operations, with the difference
			// being that neither of the given regions are modified. Instead,
			// a new region containing the result is returned.

	private:
		enum EOpcode
		{
			eUnion           = 0,
			eDifference      = 1,
			eRevDifference   = 2,
			eIntersection    = 3
		};

								EmRegion	(const EmCoord* s, long len);
		EmCoord*				GetBuf		(void) const;
		long					Length		(void) const;

		static EmRegion			RegionOp	(EOpcode code, const EmRegion& r1, const EmRegion& r2);

		friend class EmRegionRectIterator;

		class EmRegionImpl : public EmRefCounted
		{
			public:
										EmRegionImpl	(void);
										EmRegionImpl	(const EmCoord* s, long len);
										EmRegionImpl	(const EmRect& r);
										EmRegionImpl	(const EmRegion& r);
										~EmRegionImpl	(void);
		
				Bool					operator==		(const EmRegionImpl& other) const;

				long					GetRects		(EmRect* r) const;
				Bool					IsEqual			(const EmRegionImpl&) const;
				Bool					Contains		(const EmPoint& p) const;
		
				void					Offset			(EmCoord dx, EmCoord dy);
		
			protected:
				void					CalcBounds		(void);
		
			protected:
				friend class EmRegion;
		
				EmRect					fBounds;
				long					fCapacity;
				EmCoord*				fBuf;
				EmCoord					fRectBuf[7];
		};

		EmRefCounter<EmRegionImpl>	fImpl;
};

class EmRegionRectIterator
{
	public:
								EmRegionRectIterator	(const EmRegion& r);

		void					Reset					(void);
		Bool					Next					(EmRect& r);

	private:
		EmRegion				fRegion;
		EmCoord*				fBufPtr;
		long					fNext;
};


#endif	// EmRegion_h