xref: /haiku/src/kits/interface/Shape.cpp (revision b028e77473189065f2baefc6f5e10d451cf591e2)
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 	AllocateOps(count);
134 
135 	int32 i = 0;
136 	const uint32 *opPtr;
137 	while (archive->FindData("ops", B_INT32_TYPE, i++, (const void **)&opPtr, &size) == B_OK)
138 		data->opList[data->opCount++] = *opPtr;
139 
140 	archive->GetInfo("pts", &type, &count);
141 	AllocatePts(count);
142 
143 	i = 0;
144 	const BPoint *ptPtr;
145 	while (archive->FindData("pts", B_POINT_TYPE, i++, (const void **)&ptPtr, &size) == B_OK)
146 		data->ptList[data->ptCount++] = *ptPtr;
147 }
148 
149 
150 BShape::~BShape()
151 {
152 	shape_data *data = (shape_data*)fPrivateData;
153 
154 	free(data->opList);
155 	free(data->ptList);
156 
157 	delete (shape_data*)fPrivateData;
158 }
159 
160 
161 status_t
162 BShape::Archive(BMessage *archive, bool deep) const
163 {
164 	status_t err = BArchivable::Archive(archive, deep);
165 
166 	if (err != B_OK)
167 		return err;
168 
169 	shape_data *data = (shape_data*)fPrivateData;
170 
171 	// If no valid shape data, return
172 	if (data->opCount == 0 || data->ptCount == 0)
173 		return err;
174 
175 	// Avoids allocation for each point
176 	err = archive->AddData("pts", B_POINT_TYPE, data->ptList, sizeof(BPoint), true,
177 		data->ptCount);
178 	if (err != B_OK)
179 		return err;
180 
181 	for (int32 i = 1; i < data->ptCount && err == B_OK; i++)
182 		err = archive->AddPoint("pts", data->ptList[i]);
183 
184 	// Avoids allocation for each op
185 	if (err == B_OK)
186 		err = archive->AddData("ops", B_INT32_TYPE, data->opList, sizeof(int32), true,
187 			data->opCount);
188 
189 	for (int32 i = 1; i < data->opCount && err == B_OK ; i++)
190 		err = archive->AddInt32("ops", data->opList[i]);
191 
192 	return err;
193 }
194 
195 
196 BArchivable*
197 BShape::Instantiate(BMessage *archive)
198 {
199 	if (validate_instantiation(archive, "BShape"))
200 		return new BShape(archive);
201 	else
202 		return NULL;
203 }
204 
205 
206 void
207 BShape::Clear()
208 {
209 	shape_data *data = (shape_data*)fPrivateData;
210 
211 	data->opCount = 0;
212 	data->opSize = 0;
213 	if (data->opList) {
214 		free(data->opList);
215 		data->opList = NULL;
216 	}
217 
218 	data->ptCount = 0;
219 	data->ptSize = 0;
220 	if (data->ptList) {
221 		free(data->ptList);
222 		data->ptList = NULL;
223 	}
224 
225 	fState = 0;
226 	fBuildingOp = 0;
227 }
228 
229 
230 BRect
231 BShape::Bounds() const
232 {
233 	shape_data *data = (shape_data*)fPrivateData;
234 	BRect bounds;
235 
236 	if (data->ptCount == 0)
237 		return bounds;
238 
239 	bounds.left = data->ptList[0].x;
240 	bounds.top = data->ptList[0].y;
241 	bounds.right = data->ptList[0].x;
242 	bounds.bottom = data->ptList[0].y;
243 
244 	for (int32 i = 1; i < data->ptCount; i++)
245 	{
246 		if (bounds.left > data->ptList[i].x)
247 			bounds.left = data->ptList[i].x;
248 		if (bounds.top > data->ptList[i].y)
249 			bounds.top = data->ptList[i].y;
250 		if (bounds.right < data->ptList[i].x)
251 			bounds.right = data->ptList[i].x;
252 		if (bounds.bottom < data->ptList[i].y)
253 			bounds.bottom = data->ptList[i].y;
254 	}
255 
256 	return bounds;
257 }
258 
259 
260 status_t
261 BShape::AddShape(const BShape *otherShape)
262 {
263 	shape_data *data = (shape_data*)fPrivateData;
264 	shape_data *otherData = (shape_data*)otherShape->fPrivateData;
265 
266 	AllocateOps(otherData->opCount);
267 	memcpy(data->opList + data->opCount * sizeof(uint32), otherData->opList,
268 		otherData->opCount * sizeof(uint32));
269 	data->opCount += otherData->opCount;
270 
271 	AllocatePts(otherData->ptCount);
272 	memcpy(data->ptList + data->ptCount * sizeof(BPoint), otherData->ptList,
273 		otherData->ptCount * sizeof(BPoint));
274 	data->ptCount += otherData->ptCount;
275 
276 	fBuildingOp = otherShape->fBuildingOp;
277 
278 	return B_OK;
279 }
280 
281 
282 status_t
283 BShape::MoveTo(BPoint point)
284 {
285 	shape_data *data = (shape_data*)fPrivateData;
286 
287 	// If the last op is MoveTo, replace the point
288 	if (fBuildingOp == OP_MOVETO) {
289 		data->ptList[data->ptCount - 1] = point;
290 		return B_OK;
291 	}
292 
293 	fBuildingOp = OP_MOVETO;
294 
295 	// Add op
296 	AllocateOps(1);
297 	data->opList[data->opCount++] = fBuildingOp;
298 
299 	// Add point
300 	AllocatePts(1);
301 	data->ptList[data->ptCount++] = point;
302 
303 	return B_OK;
304 }
305 
306 
307 status_t
308 BShape::LineTo(BPoint point)
309 {
310 	shape_data *data = (shape_data*)fPrivateData;
311 
312 	// If the last op is MoveTo, replace the op and set the count
313 	// If the last op is LineTo increase the count
314 	// Otherwise add the op
315 	if (fBuildingOp & OP_LINETO || fBuildingOp == OP_MOVETO) {
316 		fBuildingOp |= OP_LINETO;
317 		fBuildingOp += 1;
318 		data->opList[data->opCount - 1] = fBuildingOp;
319 	} else {
320 		fBuildingOp = OP_LINETO + 1;
321 		AllocateOps(1);
322 		data->opList[data->opCount++] = fBuildingOp;
323 	}
324 
325 	// Add point
326 	AllocatePts(1);
327 	data->ptList[data->ptCount++] = point;
328 
329 	return B_OK;
330 }
331 
332 
333 status_t
334 BShape::BezierTo(BPoint controlPoints[3])
335 {
336 	shape_data *data = (shape_data*)fPrivateData;
337 
338 	// If the last op is MoveTo, replace the op and set the count
339 	// If the last op is BezierTo increase the count
340 	// Otherwise add the op
341 	if (fBuildingOp & OP_BEZIERTO || fBuildingOp == OP_MOVETO) {
342 		fBuildingOp |= OP_BEZIERTO;
343 		fBuildingOp += 3;
344 		data->opList[data->opCount - 1] = fBuildingOp;
345 	} else {
346 		fBuildingOp = OP_BEZIERTO + 3;
347 		AllocateOps(1);
348 		data->opList[data->opCount++] = fBuildingOp;
349 	}
350 
351 	// Add points
352 	AllocatePts(3);
353 	data->ptList[data->ptCount++] = controlPoints[0];
354 	data->ptList[data->ptCount++] = controlPoints[1];
355 	data->ptList[data->ptCount++] = controlPoints[2];
356 
357 	return B_OK;
358 }
359 
360 
361 status_t
362 BShape::Close()
363 {
364 	shape_data *data = (shape_data*)fPrivateData;
365 
366 	// If the last op is Close or MoveTo, ignore this
367 	if (fBuildingOp == OP_CLOSE || fBuildingOp == OP_MOVETO)
368 		return B_OK;
369 
370 
371 	// ToDo: Decide about that, it's not BeOS compatible
372 	// If there was any op before we can attach the close to it
373 	/*if (fBuildingOp) {
374 		fBuildingOp |= OP_CLOSE;
375 		data->opList[data->opCount - 1] = fBuildingOp;
376 		return B_OK;
377 	}*/
378 
379 	fBuildingOp = OP_CLOSE;
380 	AllocateOps(1);
381 	data->opList[data->opCount++] = fBuildingOp;
382 
383 	return B_OK;
384 }
385 
386 
387 status_t
388 BShape::Perform(perform_code d, void *arg)
389 {
390 	return BArchivable::Perform(d, arg);
391 }
392 
393 
394 void BShape::_ReservedShape1() {}
395 void BShape::_ReservedShape2() {}
396 void BShape::_ReservedShape3() {}
397 void BShape::_ReservedShape4() {}
398 
399 
400 void
401 BShape::GetData(int32 *opCount, int32 *ptCount, uint32 **opList,
402 					 BPoint **ptList)
403 {
404 	shape_data *data = (shape_data*)fPrivateData;
405 
406 	*opCount = data->opCount;
407 	*ptCount = data->ptCount;
408 	*opList = data->opList;
409 	*ptList = data->ptList;
410 }
411 
412 
413 void
414 BShape::SetData(int32 opCount, int32 ptCount, const uint32 *opList,
415 				const BPoint *ptList)
416 {
417 	Clear();
418 
419 	shape_data *data = (shape_data*)fPrivateData;
420 
421 	AllocateOps(opCount);
422 	memcpy(data->opList, opList, opCount * sizeof(uint32));
423 	data->opCount = opCount;
424 	fBuildingOp = data->opList[data->opCount - 1];
425 
426 	AllocatePts(ptCount);
427 	memcpy(data->ptList, ptList, ptCount * sizeof(BPoint));
428 	data->ptCount = ptCount;
429 }
430 
431 
432 void
433 BShape::InitData()
434 {
435 	fPrivateData = new shape_data;
436 	shape_data *data = (shape_data*)fPrivateData;
437 
438 	fState = 0;
439 	fBuildingOp = 0;
440 
441 	data->opList = NULL;
442 	data->opCount = 0;
443 	data->opSize = 0;
444 	data->opBlockSize = 255;
445 	data->ptList = NULL;
446 	data->ptCount = 0;
447 	data->ptSize = 0;
448 	data->ptBlockSize = 255;
449 }
450 
451 
452 inline void
453 BShape::AllocateOps(int32 count)
454 {
455 	shape_data *data = (shape_data*)fPrivateData;
456 
457 	while (data->opSize < data->opCount + count) {
458 		int32 new_size = ((data->opCount + data->opBlockSize) /
459 			data->opBlockSize) * data->opBlockSize;
460 		data->opList = (uint32*)realloc(data->opList, new_size * sizeof(uint32));
461 		data->opSize = new_size;
462 		count -= data->opBlockSize;
463 	}
464 }
465 
466 
467 inline void
468 BShape::AllocatePts(int32 count)
469 {
470 	shape_data *data = (shape_data*)fPrivateData;
471 
472 	while (data->ptSize < data->ptCount + count) {
473 		int32 new_size = ((data->ptCount + data->ptBlockSize) /
474 			data->ptBlockSize) * data->ptBlockSize;
475 		data->ptList = (BPoint*)realloc(data->ptList, new_size * sizeof(BPoint));
476 		data->ptSize = new_size;
477 		count -= data->ptBlockSize;
478 	}
479 }
480 
481 
482 //	#pragma mark - R4.5 compatibility
483 
484 
485 #if __GNUC__ < 3
486 
487 extern "C" BShape*
488 __6BShapeR6BShape(void* self, BShape& copyFrom)
489 {
490 	return new (self) BShape(copyFrom);
491 		// we need to instantiate the object in the provided memory
492 }
493 
494 
495 extern "C" BRect
496 Bounds__6BShape(BShape *self)
497 {
498 	return self->Bounds();
499 }
500 
501 #endif	// __GNUC__ < 3
502