xref: /haiku/src/kits/interface/Shape.cpp (revision d5cd5d63ff0ad395989db6cf4841a64d5b545d1d)
1 //------------------------------------------------------------------------------
2 //	Copyright (c) 2001-2002, OpenBeOS
3 //
4 //	Permission is hereby granted, free of charge, to any person obtaining a
5 //	copy of this software and associated documentation files (the "Software"),
6 //	to deal in the Software without restriction, including without limitation
7 //	the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 //	and/or sell copies of the Software, and to permit persons to whom the
9 //	Software is furnished to do so, subject to the following conditions:
10 //
11 //	The above copyright notice and this permission notice shall be included in
12 //	all copies or substantial portions of the Software.
13 //
14 //	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 //	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 //	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 //	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 //	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 //	FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 //	DEALINGS IN THE SOFTWARE.
21 //
22 //	File Name:		Shape.cpp
23 //	Author:			Marc Flerackers (mflerackers@androme.be)
24 //	Description:	BShape encapsulates a Postscript-style "path"
25 //------------------------------------------------------------------------------
26 
27 // Standard Includes -----------------------------------------------------------
28 #include <stdlib.h>
29 
30 // System Includes -------------------------------------------------------------
31 #include <Shape.h>
32 #include <Point.h>
33 #include <Rect.h>
34 #include <Errors.h>
35 #include <Message.h>
36 
37 // Project Includes ------------------------------------------------------------
38 
39 // Local Includes --------------------------------------------------------------
40 
41 // Local Defines ---------------------------------------------------------------
42 #define OP_LINETO		0x10000000
43 #define OP_BEZIERTO		0x20000000
44 #define OP_CLOSE		0x40000000
45 #define OP_MOVETO		0x80000000
46 
47 struct shape_data {
48 	uint32	*opList;
49 	int32	opCount;
50 	int32	opSize;
51 	int32	opBlockSize;
52 	BPoint	*ptList;
53 	int32	ptCount;
54 	int32	ptSize;
55 	int32	ptBlockSize;
56 };
57 
58 // Globals ---------------------------------------------------------------------
59 
60 //------------------------------------------------------------------------------
61 BShapeIterator::BShapeIterator()
62 {
63 }
64 //------------------------------------------------------------------------------
65 BShapeIterator::~BShapeIterator()
66 {
67 }
68 //------------------------------------------------------------------------------
69 status_t BShapeIterator::Iterate(BShape *shape)
70 {
71 	shape_data *data = (shape_data*)shape->fPrivateData;
72 	BPoint *points = data->ptList;
73 
74 	for (int32 i = 0; i < data->opCount; i++)
75 	{
76 		switch (data->opList[i] & 0xFF000000)
77 		{
78 			case OP_LINETO:
79 			{
80 				int32 count = data->opList[i] & 0x00FFFFFF;
81 				IterateLineTo(count, points);
82 				points += count;
83 				break;
84 			}
85 			case (OP_MOVETO | OP_LINETO):
86 			{
87 				int32 count = data->opList[i] & 0x00FFFFFF;
88 				IterateMoveTo(points);
89 				points++;
90 				IterateLineTo(count, points);
91 				points += count;
92 				break;
93 			}
94 			case OP_BEZIERTO:
95 			{
96 				int32 count = data->opList[i] & 0x00FFFFFF;
97 				IterateBezierTo(count, points);
98 				points += count;
99 				break;
100 			}
101 			case (OP_MOVETO | OP_BEZIERTO):
102 			{
103 				int32 count = data->opList[i] & 0x00FFFFFF;
104 				IterateMoveTo(points);
105 				points++;
106 				IterateBezierTo(count, points);
107 				points += count;
108 				break;
109 			}
110 			case OP_CLOSE:
111 			case OP_CLOSE | OP_LINETO | OP_BEZIERTO:
112 			{
113 				IterateClose();
114 				break;
115 			}
116 		}
117 	}
118 
119 	return B_OK;
120 }
121 //------------------------------------------------------------------------------
122 status_t BShapeIterator::IterateBezierTo(int32 bezierCount,
123 										 BPoint *bezierPoints)
124 {
125 	return B_OK;
126 }
127 //------------------------------------------------------------------------------
128 status_t BShapeIterator::IterateClose()
129 {
130 	return B_OK;
131 }
132 //------------------------------------------------------------------------------
133 status_t BShapeIterator::IterateLineTo(int32 lineCount, BPoint *linePoints)
134 {
135 	return B_OK;
136 }
137 //------------------------------------------------------------------------------
138 status_t BShapeIterator::IterateMoveTo ( BPoint *point )
139 {
140 	return B_OK;
141 }
142 //------------------------------------------------------------------------------
143 void BShapeIterator::_ReservedShapeIterator1() {}
144 void BShapeIterator::_ReservedShapeIterator2() {}
145 void BShapeIterator::_ReservedShapeIterator3() {}
146 void BShapeIterator::_ReservedShapeIterator4() {}
147 //------------------------------------------------------------------------------
148 
149 //------------------------------------------------------------------------------
150 BShape::BShape()
151 {
152 	InitData();
153 }
154 //------------------------------------------------------------------------------
155 BShape::BShape(const BShape &copyFrom)
156 {
157 	InitData();
158 	AddShape(&copyFrom);
159 }
160 //------------------------------------------------------------------------------
161 BShape::BShape(BMessage *archive)
162 	:	BArchivable(archive)
163 {
164 	InitData();
165 
166 	shape_data *data = (shape_data*)fPrivateData;
167 	ssize_t size;
168 	int32 i = 0;
169 
170 	const uint32 *opPtr;
171 
172 	while (archive->FindData("ops", B_INT32_TYPE, i++, (const void**)&opPtr, &size) == B_OK)
173 	{
174 		if (data->opSize < data->opCount + 1)
175 		{
176 			int32 new_size = ((data->opCount + data->opBlockSize) /
177 				data->opBlockSize) * data->opBlockSize;
178 			data->opList = (uint32*)realloc(data->opList, new_size * sizeof(uint32));
179 			data->opSize = new_size;
180 		}
181 
182 		data->opList[data->opCount++] = *opPtr;
183 	}
184 
185 	const BPoint *ptPtr;
186 
187 	while (archive->FindData("pts", B_POINT_TYPE, i++, (const void**)&ptPtr, &size) == B_OK)
188 	{
189 		if (data->ptSize < data->ptCount + 1)
190 		{
191 			int32 new_size = ((data->ptCount + data->ptBlockSize) /
192 				data->ptBlockSize) * data->ptBlockSize;
193 			data->ptList = (BPoint*)realloc(data->ptList,
194 				new_size * sizeof(BPoint));
195 			data->ptSize = new_size;
196 		}
197 
198 		data->ptList[data->ptCount++] = *ptPtr;
199 	}
200 }
201 //------------------------------------------------------------------------------
202 BShape::~BShape()
203 {
204 	shape_data *data = (shape_data*)fPrivateData;
205 
206 	free(data->opList);
207 	free(data->ptList);
208 
209 	delete (shape_data*)fPrivateData;
210 }
211 //------------------------------------------------------------------------------
212 status_t BShape::Archive(BMessage *archive, bool deep) const
213 {
214 	status_t err = BArchivable::Archive(archive, deep);
215 	int32 i;
216 
217 	if (err != B_OK)
218 		return err;
219 
220 	shape_data *data = (shape_data*)fPrivateData;
221 
222 	// If no valid shape data, return
223 	if (data->opCount == 0 || data->ptCount == 0)
224 		return err;
225 
226 	// Avoids allocation for each point
227 	archive->AddData("pts", B_POINT_TYPE, data->ptList, sizeof(BPoint), true,
228 		data->ptCount);
229 
230 	for (i = 1; i < data->ptCount; i++)
231 		archive->AddPoint("pts", data->ptList[i]);
232 
233 	// Avoids allocation for each op
234 	archive->AddData("ops", B_INT32_TYPE, data->opList, sizeof(int32), true,
235 			data->opCount);
236 
237 	for (i = 1; i < data->opCount; i++)
238 		archive->AddInt32("ops", data->opList[i]);
239 
240 	archive->AddInt32("ops", fBuildingOp);
241 
242 	return err;
243 }
244 //------------------------------------------------------------------------------
245 BArchivable *BShape::Instantiate(BMessage *archive)
246 {
247 	if (validate_instantiation(archive, "BShape"))
248 		return new BShape(archive);
249 	else
250 		return NULL;
251 }
252 //------------------------------------------------------------------------------
253 void BShape::Clear()
254 {
255 	shape_data *data = (shape_data*)fPrivateData;
256 
257 	if (data->opList)
258 	{
259 		free(data->opList);
260 		data->opList = NULL;
261 		data->opCount = 0;
262 	}
263 
264 	if (data->ptList)
265 	{
266 		free(data->ptList);
267 		data->ptList = NULL;
268 		data->ptCount = 0;
269 	}
270 
271 	fState = 0;
272 	fBuildingOp = 0;
273 }
274 //------------------------------------------------------------------------------
275 BRect BShape::Bounds() const
276 {
277 	shape_data *data = (shape_data*)fPrivateData;
278 	BRect bounds;
279 
280 	if (data->ptCount == 0)
281 		return bounds;
282 
283 	bounds.left = data->ptList[0].x;
284 	bounds.top = data->ptList[0].y;
285 	bounds.right = data->ptList[0].x;
286 	bounds.bottom = data->ptList[0].y;
287 
288 	for (int32 i = 1; i < data->ptCount; i++)
289 	{
290 		if (bounds.left > data->ptList[0].x)
291 			bounds.left = data->ptList[0].x;
292 		if (bounds.top > data->ptList[0].y)
293 			bounds.top = data->ptList[0].y;
294 		if (bounds.right < data->ptList[0].x)
295 			bounds.right = data->ptList[0].x;
296 		if (bounds.bottom < data->ptList[0].y)
297 			bounds.bottom = data->ptList[0].y;
298 	}
299 
300 	return bounds;
301 }
302 //------------------------------------------------------------------------------
303 status_t BShape::AddShape(const BShape *otherShape)
304 {
305 	shape_data *data = (shape_data*)fPrivateData;
306 	shape_data *otherData = (shape_data*)otherShape->fPrivateData;
307 
308 	if (data->opSize < data->opCount + otherData->opCount)
309 	{
310 		int32 new_size = ((data->opCount + otherData->opBlockSize) /
311 			data->opBlockSize) * data->opBlockSize;
312 		data->opList = (uint32*)realloc(data->opList, new_size * sizeof(uint32));
313 		data->opSize = new_size;
314 	}
315 
316 	memcpy(data->opList + data->opCount * sizeof(uint32), otherData->opList,
317 		otherData->opCount * sizeof(uint32));
318 	data->opCount += otherData->opCount;
319 
320 	if (data->ptSize < data->ptCount + otherData->ptCount)
321 	{
322 		int32 new_size = ((data->ptCount + otherData->ptBlockSize) /
323 			data->ptBlockSize) * data->ptBlockSize;
324 		data->ptList = (BPoint*)realloc(data->ptList, new_size * sizeof(uint32));
325 		data->ptSize = new_size;
326 	}
327 
328 	memcpy(data->ptList + data->ptCount * sizeof(BPoint), otherData->ptList,
329 		otherData->ptCount * sizeof(BPoint));
330 	data->ptCount += otherData->ptCount;
331 
332 	fBuildingOp = otherShape->fBuildingOp;
333 
334 	return B_OK;
335 }
336 //------------------------------------------------------------------------------
337 status_t BShape::MoveTo(BPoint point)
338 {
339 	shape_data *data = (shape_data*)fPrivateData;
340 
341 	// If the last op is MoveTo, replace the point
342 	// If there was a previous op, add the op
343 	if (fBuildingOp == OP_MOVETO)
344 	{
345 		data->ptList[data->ptCount - 1] = point;
346 
347 		return B_OK;
348 	}
349 	else if (fBuildingOp != 0)
350 	{
351 		if (data->opSize < data->opCount + 1)
352 		{
353 			int32 new_size = ((data->opCount + data->opBlockSize) /
354 				data->opBlockSize) * data->opBlockSize;
355 			data->opList = (uint32*)realloc(data->opList, new_size * sizeof(uint32));
356 			data->opSize = new_size;
357 		}
358 
359 		data->opList[data->opCount++] = fBuildingOp;
360 	}
361 
362 	// BuildingOp is MoveTo
363 	fBuildingOp = OP_MOVETO;
364 
365 	// Add point
366 	if (data->ptSize < data->ptCount + 1)
367 	{
368 		int32 new_size = ((data->ptCount + data->ptBlockSize) /
369 			data->ptBlockSize) * data->ptBlockSize;
370 		data->ptList = (BPoint*)realloc(data->ptList, new_size * sizeof(BPoint));
371 		data->ptSize = new_size;
372 	}
373 
374 	data->ptList[data->ptCount++] = point;
375 
376 	return B_OK;
377 }
378 //------------------------------------------------------------------------------
379 status_t BShape::LineTo(BPoint point)
380 {
381 	shape_data *data = (shape_data*)fPrivateData;
382 
383 	// If the last op is MoveTo, replace the op and set the count
384 	// If the last op is LineTo increase the count
385 	// If there was a previous op, add the op
386 	if (fBuildingOp == OP_MOVETO)
387 	{
388 		fBuildingOp = OP_LINETO | OP_MOVETO | 0x01;
389 	}
390 	else if (fBuildingOp & OP_LINETO)
391 	{
392 		fBuildingOp++;
393 	}
394 	else
395 	{
396 		if (fBuildingOp != 0)
397 		{
398 			if (data->opSize < data->opCount + 1)
399 			{
400 				int32 new_size = ((data->opCount + data->opBlockSize) /
401 					data->opBlockSize) * data->opBlockSize;
402 				data->opList = (uint32*)realloc(data->opList, new_size * sizeof(uint32));
403 				data->opSize = new_size;
404 			}
405 
406 			data->opList[data->opCount++] = fBuildingOp;
407 		}
408 
409 		fBuildingOp = OP_LINETO | 0x01;
410 	}
411 
412 	// Add point
413 	if (data->ptSize < data->ptCount + 1)
414 	{
415 		int32 new_size = ((data->ptCount + data->ptBlockSize) /
416 			data->ptBlockSize) * data->ptBlockSize;
417 		data->ptList = (BPoint*)realloc(data->ptList, new_size * sizeof(BPoint));
418 		data->ptSize = new_size;
419 	}
420 
421 	data->ptList[data->ptCount++] = point;
422 
423 	return B_OK;
424 }
425 //------------------------------------------------------------------------------
426 status_t BShape::BezierTo(BPoint controlPoints[3])
427 {
428 	shape_data *data = (shape_data*)fPrivateData;
429 
430 	// If the last op is MoveTo, replace the op and set the count
431 	// If the last op is BezierTo increase the count
432 	// If there was a previous op, add the op
433 	if (fBuildingOp == OP_MOVETO)
434 	{
435 		fBuildingOp = OP_BEZIERTO | OP_MOVETO | 0x03;
436 	}
437 	else if (fBuildingOp & OP_BEZIERTO)
438 	{
439 		fBuildingOp += 3;
440 	}
441 	else
442 	{
443 		if (fBuildingOp != 0)
444 		{
445 			if (data->opSize < data->opCount + 1)
446 			{
447 				int32 new_size = ((data->opCount + data->opBlockSize) /
448 					data->opBlockSize) * data->opBlockSize;
449 				data->opList = (uint32*)realloc(data->opList, new_size * sizeof(uint32));
450 				data->opSize = new_size;
451 			}
452 
453 			data->opList[data->opCount++] = fBuildingOp;
454 		}
455 
456 		fBuildingOp = OP_BEZIERTO | 0x03;
457 	}
458 
459 	// Add points
460 	if (data->ptSize < data->ptCount + 3)
461 	{
462 		int32 new_size = ((data->ptCount + data->ptBlockSize) /
463 			data->ptBlockSize) * data->ptBlockSize;
464 		data->ptList = (BPoint*)realloc(data->ptList, new_size * sizeof(BPoint));
465 		data->ptSize = new_size;
466 	}
467 
468 	data->ptList[data->ptCount++] = controlPoints[0];
469 	data->ptList[data->ptCount++] = controlPoints[1];
470 	data->ptList[data->ptCount++] = controlPoints[2];
471 
472 	return B_OK;
473 }
474 //------------------------------------------------------------------------------
475 status_t BShape::Close()
476 {
477 	shape_data *data = (shape_data*)fPrivateData;
478 
479 	// If there was a previous line/bezier op, add the op
480 	if (fBuildingOp & (OP_LINETO | OP_BEZIERTO))
481 	{
482 		if (data->opSize < data->opCount + 1)
483 		{
484 			int32 new_size = ((data->opCount + data->opBlockSize) /
485 				data->opBlockSize) * data->opBlockSize;
486 			data->opList = (uint32*)realloc(data->opList, new_size * sizeof(uint32));
487 			data->opSize = new_size;
488 		}
489 
490 		data->opList[data->opCount++] = fBuildingOp;
491 		fBuildingOp = OP_CLOSE;
492 	}
493 
494 	return B_OK;
495 }
496 //------------------------------------------------------------------------------
497 status_t BShape::Perform(perform_code d, void *arg)
498 {
499 	return BArchivable::Perform(d, arg);
500 }
501 //------------------------------------------------------------------------------
502 void BShape::_ReservedShape1() {}
503 void BShape::_ReservedShape2() {}
504 void BShape::_ReservedShape3() {}
505 void BShape::_ReservedShape4() {}
506 //------------------------------------------------------------------------------
507 void BShape::GetData(int32 *opCount, int32 *ptCount, uint32 **opList,
508 					 BPoint **ptList)
509 {
510 	shape_data *data = (shape_data*)fPrivateData;
511 
512 	*opCount = data->opCount;
513 	*ptCount = data->ptCount;
514 	*opList = data->opList;
515 	*ptList =data->ptList;
516 }
517 //------------------------------------------------------------------------------
518 void BShape::SetData(int32 opCount, int32 ptCount, uint32 *opList,
519 					 BPoint *ptList)
520 {
521 	shape_data *data = (shape_data*)fPrivateData;
522 
523 	if (data->opSize < opCount)
524 	{
525 		int32 new_size = ((opCount + data->opBlockSize) /
526 			data->opBlockSize) * data->opBlockSize;
527 
528 		data->opList = (uint32*)realloc(data->opList, new_size * sizeof(uint32));
529 		data->opSize = new_size;
530 	}
531 
532 	memcpy(data->opList, opList, opCount * sizeof(uint32));
533 	data->opCount = opCount;
534 
535 	if (data->ptSize < ptCount)
536 	{
537 		int32 new_size = ((ptCount + data->ptBlockSize) /
538 			data->ptBlockSize) * data->ptBlockSize;
539 
540 		data->ptList = (BPoint*)realloc(data->ptList, new_size * sizeof(BPoint));
541 		data->ptSize = new_size;
542 	}
543 
544 	memcpy(data->ptList, ptList, ptCount * sizeof(BPoint));
545 	data->ptCount = ptCount;
546 }
547 //------------------------------------------------------------------------------
548 void BShape::InitData()
549 {
550 	fPrivateData = new shape_data;
551 	shape_data *data = (shape_data*)fPrivateData;
552 
553 	fState = 0;
554 	fBuildingOp = 0;
555 
556 	data->opList = NULL;
557 	data->opCount = 0;
558 	data->opSize = 0;
559 	data->opBlockSize = 255;
560 	data->ptList = NULL;
561 	data->ptCount = 0;
562 	data->ptSize = 0;
563 	data->ptBlockSize = 255;
564 }
565 //------------------------------------------------------------------------------
566