xref: /haiku/src/kits/interface/Shape.cpp (revision b55a57da7173b9af0432bd3e148d03f06161d036)
1 /*
2  * Copyright (c) 2001-2007, Haiku, Inc.
3  * Distributed under the terms of the MIT license.
4  *
5  * Authors:
6  *		Marc Flerackers (mflerackers@androme.be)
7  *		Stephan Aßmus <superstippi@gmx.de>
8  *		Michael Lotz <mmlr@mlotz.ch>
9  *		Marcus Overhagen <marcus@overhagen.de>
10  */
11 
12 /*! BShape encapsulates a Postscript-style "path" */
13 
14 #include <Shape.h>
15 
16 #include <Message.h>
17 #include <Point.h>
18 #include <Rect.h>
19 
20 #include <ShapePrivate.h>
21 
22 #include <new>
23 #include <stdlib.h>
24 #include <string.h>
25 
26 
27 
28 
29 BShapeIterator::BShapeIterator()
30 {
31 }
32 
33 
34 BShapeIterator::~BShapeIterator()
35 {
36 }
37 
38 
39 status_t
40 BShapeIterator::Iterate(BShape *shape)
41 {
42 	shape_data *data = (shape_data*)shape->fPrivateData;
43 	BPoint *points = data->ptList;
44 
45 	for (int32 i = 0; i < data->opCount; i++) {
46 		int32 op = data->opList[i] & 0xFF000000;
47 
48 		if (op & OP_MOVETO) {
49 			IterateMoveTo(points);
50 			points++;
51 		}
52 
53 		if (op & OP_LINETO) {
54 			int32 count = data->opList[i] & 0x00FFFFFF;
55 			IterateLineTo(count, points);
56 			points += count;
57 		}
58 
59 		if (op & OP_BEZIERTO) {
60 			int32 count = data->opList[i] & 0x00FFFFFF;
61 			IterateBezierTo(count / 3, points);
62 			points += count;
63 		}
64 
65 		if (op & OP_CLOSE) {
66 			IterateClose();
67 		}
68 	}
69 
70 	return B_OK;
71 }
72 
73 
74 status_t
75 BShapeIterator::IterateBezierTo(int32 bezierCount,
76 										 BPoint *bezierPoints)
77 {
78 	return B_OK;
79 }
80 
81 
82 status_t
83 BShapeIterator::IterateClose()
84 {
85 	return B_OK;
86 }
87 
88 
89 status_t
90 BShapeIterator::IterateLineTo(int32 lineCount, BPoint *linePoints)
91 {
92 	return B_OK;
93 }
94 
95 
96 status_t
97 BShapeIterator::IterateMoveTo ( BPoint *point )
98 {
99 	return B_OK;
100 }
101 
102 
103 void BShapeIterator::_ReservedShapeIterator1() {}
104 void BShapeIterator::_ReservedShapeIterator2() {}
105 void BShapeIterator::_ReservedShapeIterator3() {}
106 void BShapeIterator::_ReservedShapeIterator4() {}
107 
108 
109 BShape::BShape()
110 {
111 	InitData();
112 }
113 
114 
115 BShape::BShape(const BShape &copyFrom)
116 {
117 	InitData();
118 	AddShape(&copyFrom);
119 }
120 
121 
122 BShape::BShape(BMessage *archive)
123 	:	BArchivable(archive)
124 {
125 	InitData();
126 
127 	shape_data *data = (shape_data*)fPrivateData;
128 
129 	ssize_t size = 0;
130 	int32 count = 0;
131 	type_code type = 0;
132 	archive->GetInfo("ops", &type, &count);
133 	if (!AllocateOps(count))
134 		return;
135 
136 	int32 i = 0;
137 	const uint32 *opPtr;
138 	while (archive->FindData("ops", B_INT32_TYPE, i++, (const void **)&opPtr, &size) == B_OK)
139 		data->opList[data->opCount++] = *opPtr;
140 
141 	archive->GetInfo("pts", &type, &count);
142 	if (!AllocatePts(count)) {
143 		Clear();
144 		return;
145 	}
146 
147 	i = 0;
148 	const BPoint *ptPtr;
149 	while (archive->FindData("pts", B_POINT_TYPE, i++, (const void **)&ptPtr, &size) == B_OK)
150 		data->ptList[data->ptCount++] = *ptPtr;
151 }
152 
153 
154 BShape::~BShape()
155 {
156 	shape_data *data = (shape_data*)fPrivateData;
157 
158 	free(data->opList);
159 	free(data->ptList);
160 
161 	delete (shape_data*)fPrivateData;
162 }
163 
164 
165 status_t
166 BShape::Archive(BMessage *archive, bool deep) const
167 {
168 	status_t err = BArchivable::Archive(archive, deep);
169 
170 	if (err != B_OK)
171 		return err;
172 
173 	shape_data *data = (shape_data*)fPrivateData;
174 
175 	// If no valid shape data, return
176 	if (data->opCount == 0 || data->ptCount == 0)
177 		return err;
178 
179 	// Avoids allocation for each point
180 	err = archive->AddData("pts", B_POINT_TYPE, data->ptList, sizeof(BPoint), true,
181 		data->ptCount);
182 	if (err != B_OK)
183 		return err;
184 
185 	for (int32 i = 1; i < data->ptCount && err == B_OK; i++)
186 		err = archive->AddPoint("pts", data->ptList[i]);
187 
188 	// Avoids allocation for each op
189 	if (err == B_OK)
190 		err = archive->AddData("ops", B_INT32_TYPE, data->opList, sizeof(int32), true,
191 			data->opCount);
192 
193 	for (int32 i = 1; i < data->opCount && err == B_OK ; i++)
194 		err = archive->AddInt32("ops", data->opList[i]);
195 
196 	return err;
197 }
198 
199 
200 BArchivable*
201 BShape::Instantiate(BMessage *archive)
202 {
203 	if (validate_instantiation(archive, "BShape"))
204 		return new BShape(archive);
205 	else
206 		return NULL;
207 }
208 
209 
210 void
211 BShape::Clear()
212 {
213 	shape_data *data = (shape_data*)fPrivateData;
214 
215 	data->opCount = 0;
216 	data->opSize = 0;
217 	if (data->opList) {
218 		free(data->opList);
219 		data->opList = NULL;
220 	}
221 
222 	data->ptCount = 0;
223 	data->ptSize = 0;
224 	if (data->ptList) {
225 		free(data->ptList);
226 		data->ptList = NULL;
227 	}
228 
229 	fState = 0;
230 	fBuildingOp = 0;
231 }
232 
233 
234 BRect
235 BShape::Bounds() const
236 {
237 	shape_data *data = (shape_data*)fPrivateData;
238 	BRect bounds;
239 
240 	if (data->ptCount == 0)
241 		return bounds;
242 
243 	bounds.left = data->ptList[0].x;
244 	bounds.top = data->ptList[0].y;
245 	bounds.right = data->ptList[0].x;
246 	bounds.bottom = data->ptList[0].y;
247 
248 	for (int32 i = 1; i < data->ptCount; i++)
249 	{
250 		if (bounds.left > data->ptList[i].x)
251 			bounds.left = data->ptList[i].x;
252 		if (bounds.top > data->ptList[i].y)
253 			bounds.top = data->ptList[i].y;
254 		if (bounds.right < data->ptList[i].x)
255 			bounds.right = data->ptList[i].x;
256 		if (bounds.bottom < data->ptList[i].y)
257 			bounds.bottom = data->ptList[i].y;
258 	}
259 
260 	return bounds;
261 }
262 
263 
264 status_t
265 BShape::AddShape(const BShape *otherShape)
266 {
267 	shape_data *data = (shape_data*)fPrivateData;
268 	shape_data *otherData = (shape_data*)otherShape->fPrivateData;
269 
270 	if (!AllocateOps(otherData->opCount) || !AllocatePts(otherData->ptCount))
271 		return B_NO_MEMORY;
272 
273 	memcpy(data->opList + data->opCount * sizeof(uint32), otherData->opList,
274 		otherData->opCount * sizeof(uint32));
275 	data->opCount += otherData->opCount;
276 
277 	memcpy(data->ptList + data->ptCount * sizeof(BPoint), otherData->ptList,
278 		otherData->ptCount * sizeof(BPoint));
279 	data->ptCount += otherData->ptCount;
280 
281 	fBuildingOp = otherShape->fBuildingOp;
282 
283 	return B_OK;
284 }
285 
286 
287 status_t
288 BShape::MoveTo(BPoint point)
289 {
290 	shape_data *data = (shape_data*)fPrivateData;
291 
292 	// If the last op is MoveTo, replace the point
293 	if (fBuildingOp == OP_MOVETO) {
294 		data->ptList[data->ptCount - 1] = point;
295 		return B_OK;
296 	}
297 
298 	if (!AllocateOps(1) || !AllocatePts(1))
299 		return B_NO_MEMORY;
300 
301 	fBuildingOp = OP_MOVETO;
302 
303 	// Add op
304 	data->opList[data->opCount++] = fBuildingOp;
305 
306 	// Add point
307 	data->ptList[data->ptCount++] = point;
308 
309 	return B_OK;
310 }
311 
312 
313 status_t
314 BShape::LineTo(BPoint point)
315 {
316 	if (!AllocatePts(1))
317 		return B_NO_MEMORY;
318 
319 	shape_data *data = (shape_data*)fPrivateData;
320 
321 	// If the last op is MoveTo, replace the op and set the count
322 	// If the last op is LineTo increase the count
323 	// Otherwise add the op
324 	if (fBuildingOp & OP_LINETO || fBuildingOp == OP_MOVETO) {
325 		fBuildingOp |= OP_LINETO;
326 		fBuildingOp += 1;
327 		data->opList[data->opCount - 1] = fBuildingOp;
328 	} else {
329 		if (!AllocateOps(1))
330 			return B_NO_MEMORY;
331 		fBuildingOp = OP_LINETO + 1;
332 		data->opList[data->opCount++] = fBuildingOp;
333 	}
334 
335 	// Add point
336 	data->ptList[data->ptCount++] = point;
337 
338 	return B_OK;
339 }
340 
341 
342 status_t
343 BShape::BezierTo(BPoint controlPoints[3])
344 {
345 	if (!AllocatePts(3))
346 		return B_NO_MEMORY;
347 
348 	shape_data *data = (shape_data*)fPrivateData;
349 
350 	// If the last op is MoveTo, replace the op and set the count
351 	// If the last op is BezierTo increase the count
352 	// Otherwise add the op
353 	if (fBuildingOp & OP_BEZIERTO || fBuildingOp == OP_MOVETO) {
354 		fBuildingOp |= OP_BEZIERTO;
355 		fBuildingOp += 3;
356 		data->opList[data->opCount - 1] = fBuildingOp;
357 	} else {
358 		if (!AllocateOps(1))
359 			return B_NO_MEMORY;
360 		fBuildingOp = OP_BEZIERTO + 3;
361 		data->opList[data->opCount++] = fBuildingOp;
362 	}
363 
364 	// Add points
365 	data->ptList[data->ptCount++] = controlPoints[0];
366 	data->ptList[data->ptCount++] = controlPoints[1];
367 	data->ptList[data->ptCount++] = controlPoints[2];
368 
369 	return B_OK;
370 }
371 
372 
373 status_t
374 BShape::Close()
375 {
376 	// If the last op is Close or MoveTo, ignore this
377 	if (fBuildingOp == OP_CLOSE || fBuildingOp == OP_MOVETO)
378 		return B_OK;
379 
380 	if (!AllocateOps(1))
381 		return B_NO_MEMORY;
382 
383 	shape_data *data = (shape_data*)fPrivateData;
384 
385 	// ToDo: Decide about that, it's not BeOS compatible
386 	// If there was any op before we can attach the close to it
387 	/*if (fBuildingOp) {
388 		fBuildingOp |= OP_CLOSE;
389 		data->opList[data->opCount - 1] = fBuildingOp;
390 		return B_OK;
391 	}*/
392 
393 	fBuildingOp = OP_CLOSE;
394 	data->opList[data->opCount++] = fBuildingOp;
395 
396 	return B_OK;
397 }
398 
399 
400 status_t
401 BShape::Perform(perform_code d, void *arg)
402 {
403 	return BArchivable::Perform(d, arg);
404 }
405 
406 
407 void BShape::_ReservedShape1() {}
408 void BShape::_ReservedShape2() {}
409 void BShape::_ReservedShape3() {}
410 void BShape::_ReservedShape4() {}
411 
412 
413 void
414 BShape::GetData(int32 *opCount, int32 *ptCount, uint32 **opList,
415 					 BPoint **ptList)
416 {
417 	shape_data *data = (shape_data*)fPrivateData;
418 
419 	*opCount = data->opCount;
420 	*ptCount = data->ptCount;
421 	*opList = data->opList;
422 	*ptList = data->ptList;
423 }
424 
425 
426 void
427 BShape::SetData(int32 opCount, int32 ptCount, const uint32 *opList,
428 				const BPoint *ptList)
429 {
430 	Clear();
431 
432 	if (opCount == 0)
433 		return;
434 
435 	shape_data *data = (shape_data*)fPrivateData;
436 
437 	if (!AllocateOps(opCount) || !AllocatePts(ptCount))
438 		return;
439 
440 	memcpy(data->opList, opList, opCount * sizeof(uint32));
441 	data->opCount = opCount;
442 	fBuildingOp = data->opList[data->opCount - 1];
443 
444 	if (ptCount > 0) {
445 		memcpy(data->ptList, ptList, ptCount * sizeof(BPoint));
446 		data->ptCount = ptCount;
447 	}
448 }
449 
450 
451 
452 
453 void
454 BShape::InitData()
455 {
456 	fPrivateData = new shape_data;
457 	shape_data *data = (shape_data*)fPrivateData;
458 
459 	fState = 0;
460 	fBuildingOp = 0;
461 
462 	data->opList = NULL;
463 	data->opCount = 0;
464 	data->opSize = 0;
465 	data->ptList = NULL;
466 	data->ptCount = 0;
467 	data->ptSize = 0;
468 }
469 
470 
471 inline bool
472 BShape::AllocateOps(int32 count)
473 {
474 	shape_data *data = (shape_data*)fPrivateData;
475 
476 	int32 newSize = (data->opCount + count + 255) / 256 * 256;
477 	if (data->opSize >= newSize)
478 		return true;
479 
480 	uint32* resizedArray = (uint32*)realloc(data->opList, newSize * sizeof(uint32));
481 	if (resizedArray) {
482 		data->opList = resizedArray;
483 		data->opSize = newSize;
484 		return true;
485 	}
486 	return false;
487 }
488 
489 
490 inline bool
491 BShape::AllocatePts(int32 count)
492 {
493 	shape_data *data = (shape_data*)fPrivateData;
494 
495 	int32 newSize = (data->ptCount + count + 255) / 256 * 256;
496 	if (data->ptSize >= newSize)
497 		return true;
498 
499 	BPoint* resizedArray = (BPoint*)realloc(data->ptList, newSize * sizeof(BPoint));
500 	if (resizedArray) {
501 		data->ptList = resizedArray;
502 		data->ptSize = newSize;
503 		return true;
504 	}
505 	return false;
506 }
507 
508 
509 //	#pragma mark - R4.5 compatibility
510 
511 
512 #if __GNUC__ < 3
513 
514 extern "C" BShape*
515 __6BShapeR6BShape(void* self, BShape& copyFrom)
516 {
517 	return new (self) BShape(copyFrom);
518 		// we need to instantiate the object in the provided memory
519 }
520 
521 
522 extern "C" BRect
523 Bounds__6BShape(BShape *self)
524 {
525 	return self->Bounds();
526 }
527 
528 #endif	// __GNUC__ < 3
529