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