1/*
2 * Copyright 2003-2010 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT license.
4 *
5 * Authors:
6 *		Stephan A��mus, superstippi@gmx.de
7 *		Marc Flerackers, mflerackers@androme.be
8 *		Michael Lotz, mmlr@mlotz.ch
9 *		Marcus Overhagen, marcus@overhagen.de
10 */
11
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//	#pragma mark - BShapeIterator
27
28
29BShapeIterator::BShapeIterator()
30{
31}
32
33
34BShapeIterator::~BShapeIterator()
35{
36}
37
38
39status_t
40BShapeIterator::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) != 0) {
49			IterateMoveTo(points);
50			points++;
51		}
52
53		if ((op & OP_LINETO) != 0) {
54			int32 count = data->opList[i] & 0x00FFFFFF;
55			IterateLineTo(count, points);
56			points += count;
57		}
58
59		if ((op & OP_BEZIERTO) != 0) {
60			int32 count = data->opList[i] & 0x00FFFFFF;
61			IterateBezierTo(count / 3, points);
62			points += count;
63		}
64
65		if ((op & OP_LARGE_ARC_TO_CW) != 0 || (op & OP_LARGE_ARC_TO_CCW) != 0
66			|| (op & OP_SMALL_ARC_TO_CW) != 0
67			|| (op & OP_SMALL_ARC_TO_CCW) != 0) {
68			int32 count = data->opList[i] & 0x00FFFFFF;
69			for (int32 i = 0; i < count / 3; i++) {
70				IterateArcTo(points[0].x, points[0].y, points[1].x,
71					op & (OP_LARGE_ARC_TO_CW | OP_LARGE_ARC_TO_CCW),
72					op & (OP_SMALL_ARC_TO_CCW | OP_LARGE_ARC_TO_CCW),
73					points[2]);
74				points += 3;
75			}
76		}
77
78		if ((op & OP_CLOSE) != 0)
79			IterateClose();
80	}
81
82	return B_OK;
83}
84
85
86status_t
87BShapeIterator::IterateMoveTo(BPoint* point)
88{
89	return B_OK;
90}
91
92
93status_t
94BShapeIterator::IterateLineTo(int32 lineCount, BPoint* linePoints)
95{
96	return B_OK;
97}
98
99
100status_t
101BShapeIterator::IterateBezierTo(int32 bezierCount, BPoint* bezierPoints)
102{
103	return B_OK;
104}
105
106
107status_t
108BShapeIterator::IterateClose()
109{
110	return B_OK;
111}
112
113
114status_t
115BShapeIterator::IterateArcTo(float& rx, float& ry, float& angle, bool largeArc,
116	bool counterClockWise, BPoint& point)
117{
118	return B_OK;
119}
120
121
122// #pragma mark - BShapeIterator FBC padding
123
124
125void BShapeIterator::_ReservedShapeIterator2() {}
126void BShapeIterator::_ReservedShapeIterator3() {}
127void BShapeIterator::_ReservedShapeIterator4() {}
128
129
130// #pragma mark - BShape
131
132
133BShape::BShape()
134{
135	InitData();
136}
137
138
139BShape::BShape(const BShape& other)
140{
141	InitData();
142	AddShape(&other);
143}
144
145
146BShape::BShape(BMessage* archive)
147	:
148	BArchivable(archive)
149{
150	InitData();
151
152	shape_data* data = (shape_data*)fPrivateData;
153
154	ssize_t size = 0;
155	int32 count = 0;
156	type_code type = 0;
157	archive->GetInfo("ops", &type, &count);
158	if (!AllocateOps(count))
159		return;
160
161	int32 i = 0;
162	const uint32* opPtr;
163	while (archive->FindData("ops", B_INT32_TYPE, i++,
164			(const void**)&opPtr, &size) == B_OK) {
165		data->opList[data->opCount++] = *opPtr;
166	}
167
168	archive->GetInfo("pts", &type, &count);
169	if (!AllocatePts(count)) {
170		Clear();
171		return;
172	}
173
174	i = 0;
175	const BPoint* ptPtr;
176	while (archive->FindData("pts", B_POINT_TYPE, i++,
177			(const void**)&ptPtr, &size) == B_OK) {
178		data->ptList[data->ptCount++] = *ptPtr;
179	}
180}
181
182
183BShape::~BShape()
184{
185	shape_data* data = (shape_data*)fPrivateData;
186	if (!data->fOwnsMemory) {
187		free(data->opList);
188		free(data->ptList);
189	}
190
191	data->ReleaseReference();
192}
193
194
195status_t
196BShape::Archive(BMessage* archive, bool deep) const
197{
198	status_t result = BArchivable::Archive(archive, deep);
199
200	if (result != B_OK)
201		return result;
202
203	shape_data* data = (shape_data*)fPrivateData;
204
205	// If no valid shape data, return
206	if (data->opCount == 0 || data->ptCount == 0)
207		return result;
208
209	// Avoids allocation for each point
210	result = archive->AddData("pts", B_POINT_TYPE, data->ptList,
211		sizeof(BPoint), true, data->ptCount);
212	if (result != B_OK)
213		return result;
214
215	for (int32 i = 1; i < data->ptCount && result == B_OK; i++)
216		result = archive->AddPoint("pts", data->ptList[i]);
217
218	// Avoids allocation for each op
219	if (result == B_OK) {
220		result = archive->AddData("ops", B_INT32_TYPE, data->opList,
221			sizeof(int32), true, data->opCount);
222	}
223
224	for (int32 i = 1; i < data->opCount && result == B_OK; i++)
225		result = archive->AddInt32("ops", data->opList[i]);
226
227	return result;
228}
229
230
231BArchivable*
232BShape::Instantiate(BMessage* archive)
233{
234	if (validate_instantiation(archive, "BShape"))
235		return new BShape(archive);
236	else
237		return NULL;
238}
239
240
241BShape&
242BShape::operator=(const BShape& other)
243{
244	if (this != &other) {
245		Clear();
246		AddShape(&other);
247	}
248
249	return *this;
250}
251
252
253bool
254BShape::operator==(const BShape& other) const
255{
256	if (this == &other)
257		return true;
258
259	shape_data* data = (shape_data*)fPrivateData;
260	shape_data* otherData = (shape_data*)other.fPrivateData;
261
262	if (data->opCount != otherData->opCount)
263		return false;
264
265	if (data->ptCount != otherData->ptCount)
266		return false;
267
268	return memcmp(data->opList, otherData->opList,
269			data->opCount * sizeof(uint32)) == 0
270		&& memcmp(data->ptList, otherData->ptList,
271			data->ptCount * sizeof(BPoint)) == 0;
272}
273
274
275bool
276BShape::operator!=(const BShape& other) const
277{
278	return !(*this == other);
279}
280
281
282void
283BShape::Clear()
284{
285	shape_data* data = (shape_data*)fPrivateData;
286
287	data->opCount = 0;
288	data->opSize = 0;
289	if (data->opList) {
290		free(data->opList);
291		data->opList = NULL;
292	}
293
294	data->ptCount = 0;
295	data->ptSize = 0;
296	if (data->ptList) {
297		free(data->ptList);
298		data->ptList = NULL;
299	}
300
301	fState = 0;
302	fBuildingOp = 0;
303}
304
305
306BRect
307BShape::Bounds() const
308{
309	shape_data* data = (shape_data*)fPrivateData;
310	return data->DetermineBoundingBox();
311}
312
313
314BPoint
315BShape::CurrentPosition() const
316{
317	shape_data* data = (shape_data*)fPrivateData;
318
319	if (data->ptCount == 0)
320		return B_ORIGIN;
321
322	return data->ptList[data->ptCount - 1];
323}
324
325
326status_t
327BShape::AddShape(const BShape* otherShape)
328{
329	shape_data* data = (shape_data*)fPrivateData;
330	shape_data* otherData = (shape_data*)otherShape->fPrivateData;
331
332	if (!AllocateOps(otherData->opCount) || !AllocatePts(otherData->ptCount))
333		return B_NO_MEMORY;
334
335	memcpy(data->opList + data->opCount, otherData->opList,
336		otherData->opCount * sizeof(uint32));
337	data->opCount += otherData->opCount;
338
339	memcpy((void*)(data->ptList + data->ptCount), otherData->ptList,
340		otherData->ptCount * sizeof(BPoint));
341	data->ptCount += otherData->ptCount;
342
343	fBuildingOp = otherShape->fBuildingOp;
344
345	return B_OK;
346}
347
348
349status_t
350BShape::MoveTo(BPoint point)
351{
352	shape_data* data = (shape_data*)fPrivateData;
353
354	// If the last op is MoveTo, replace the point
355	if (fBuildingOp == OP_MOVETO) {
356		data->ptList[data->ptCount - 1] = point;
357		return B_OK;
358	}
359
360	if (!AllocateOps(1) || !AllocatePts(1))
361		return B_NO_MEMORY;
362
363	fBuildingOp = OP_MOVETO;
364
365	// Add op
366	data->opList[data->opCount++] = fBuildingOp;
367
368	// Add point
369	data->ptList[data->ptCount++] = point;
370
371	return B_OK;
372}
373
374
375status_t
376BShape::LineTo(BPoint point)
377{
378	if (!AllocatePts(1))
379		return B_NO_MEMORY;
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	// Otherwise add the op
386	if (fBuildingOp & OP_LINETO || fBuildingOp == OP_MOVETO) {
387		fBuildingOp |= OP_LINETO;
388		fBuildingOp += 1;
389		data->opList[data->opCount - 1] = fBuildingOp;
390	} else {
391		if (!AllocateOps(1))
392			return B_NO_MEMORY;
393
394		fBuildingOp = OP_LINETO + 1;
395		data->opList[data->opCount++] = fBuildingOp;
396	}
397
398	// Add point
399	data->ptList[data->ptCount++] = point;
400
401	return B_OK;
402}
403
404
405status_t
406BShape::BezierTo(BPoint controlPoints[3])
407{
408	return BezierTo(controlPoints[0], controlPoints[1], controlPoints[2]);
409}
410
411
412status_t
413BShape::BezierTo(const BPoint& control1, const BPoint& control2,
414	const BPoint& endPoint)
415{
416	if (!AllocatePts(3))
417		return B_NO_MEMORY;
418
419	shape_data* data = (shape_data*)fPrivateData;
420
421	// If the last op is MoveTo, replace the op and set the count
422	// If the last op is BezierTo increase the count
423	// Otherwise add the op
424	if (fBuildingOp & OP_BEZIERTO || fBuildingOp == OP_MOVETO) {
425		fBuildingOp |= OP_BEZIERTO;
426		fBuildingOp += 3;
427		data->opList[data->opCount - 1] = fBuildingOp;
428	} else {
429		if (!AllocateOps(1))
430			return B_NO_MEMORY;
431		fBuildingOp = OP_BEZIERTO + 3;
432		data->opList[data->opCount++] = fBuildingOp;
433	}
434
435	// Add points
436	data->ptList[data->ptCount++] = control1;
437	data->ptList[data->ptCount++] = control2;
438	data->ptList[data->ptCount++] = endPoint;
439
440	return B_OK;
441}
442
443
444status_t
445BShape::ArcTo(float rx, float ry, float angle, bool largeArc,
446	bool counterClockWise, const BPoint& point)
447{
448	if (!AllocatePts(3))
449		return B_NO_MEMORY;
450
451	shape_data* data = (shape_data*)fPrivateData;
452
453	uint32 op;
454	if (largeArc) {
455		if (counterClockWise)
456			op = OP_LARGE_ARC_TO_CCW;
457		else
458			op = OP_LARGE_ARC_TO_CW;
459	} else {
460		if (counterClockWise)
461			op = OP_SMALL_ARC_TO_CCW;
462		else
463			op = OP_SMALL_ARC_TO_CW;
464	}
465
466	// If the last op is MoveTo, replace the op and set the count
467	// If the last op is ArcTo increase the count
468	// Otherwise add the op
469	if (fBuildingOp == op || fBuildingOp == (op | OP_MOVETO)) {
470		fBuildingOp |= op;
471		fBuildingOp += 3;
472		data->opList[data->opCount - 1] = fBuildingOp;
473	} else {
474		if (!AllocateOps(1))
475			return B_NO_MEMORY;
476
477		fBuildingOp = op + 3;
478		data->opList[data->opCount++] = fBuildingOp;
479	}
480
481	// Add points
482	data->ptList[data->ptCount++] = BPoint(rx, ry);
483	data->ptList[data->ptCount++] = BPoint(angle, 0);
484	data->ptList[data->ptCount++] = point;
485
486	return B_OK;
487}
488
489
490status_t
491BShape::Close()
492{
493	// If the last op is Close or MoveTo, ignore this
494	if (fBuildingOp == OP_CLOSE || fBuildingOp == OP_MOVETO)
495		return B_OK;
496
497	if (!AllocateOps(1))
498		return B_NO_MEMORY;
499
500	shape_data* data = (shape_data*)fPrivateData;
501
502	// ToDo: Decide about that, it's not BeOS compatible
503	// If there was any op before we can attach the close to it
504	/*if (fBuildingOp) {
505		fBuildingOp |= OP_CLOSE;
506		data->opList[data->opCount - 1] = fBuildingOp;
507		return B_OK;
508	}*/
509
510	fBuildingOp = OP_CLOSE;
511	data->opList[data->opCount++] = fBuildingOp;
512
513	return B_OK;
514}
515
516
517//	#pragma mark - BShape private methods
518
519
520status_t
521BShape::Perform(perform_code code, void* data)
522{
523	return BArchivable::Perform(code, data);
524}
525
526
527//	#pragma mark - BShape FBC methods
528
529
530void BShape::_ReservedShape1() {}
531void BShape::_ReservedShape2() {}
532void BShape::_ReservedShape3() {}
533void BShape::_ReservedShape4() {}
534
535
536//	#pragma mark - BShape private methods
537
538
539void
540BShape::GetData(int32* opCount, int32* ptCount, uint32** opList,
541	BPoint** ptList)
542{
543	shape_data* data = (shape_data*)fPrivateData;
544
545	*opCount = data->opCount;
546	*ptCount = data->ptCount;
547	*opList = data->opList;
548	*ptList = data->ptList;
549}
550
551
552void
553BShape::SetData(int32 opCount, int32 ptCount, const uint32* opList,
554	const BPoint* ptList)
555{
556	Clear();
557
558	if (opCount == 0)
559		return;
560
561	shape_data* data = (shape_data*)fPrivateData;
562
563	if (!AllocateOps(opCount) || !AllocatePts(ptCount))
564		return;
565
566	memcpy(data->opList, opList, opCount * sizeof(uint32));
567	data->opCount = opCount;
568	fBuildingOp = data->opList[data->opCount - 1];
569
570	if (ptCount > 0) {
571		memcpy((void*)data->ptList, ptList, ptCount * sizeof(BPoint));
572		data->ptCount = ptCount;
573	}
574}
575
576
577void
578BShape::InitData()
579{
580	fPrivateData = new shape_data;
581	shape_data* data = (shape_data*)fPrivateData;
582
583	fState = 0;
584	fBuildingOp = 0;
585
586	data->opList = NULL;
587	data->opCount = 0;
588	data->opSize = 0;
589	data->ptList = NULL;
590	data->ptCount = 0;
591	data->ptSize = 0;
592}
593
594
595inline bool
596BShape::AllocateOps(int32 count)
597{
598	shape_data* data = (shape_data*)fPrivateData;
599
600	int32 newSize = (data->opCount + count + 255) / 256 * 256;
601	if (data->opSize >= newSize)
602		return true;
603
604	uint32* resizedArray = (uint32*)realloc(data->opList, newSize * sizeof(uint32));
605	if (resizedArray) {
606		data->opList = resizedArray;
607		data->opSize = newSize;
608		return true;
609	}
610	return false;
611}
612
613
614inline bool
615BShape::AllocatePts(int32 count)
616{
617	shape_data* data = (shape_data*)fPrivateData;
618
619	int32 newSize = (data->ptCount + count + 255) / 256 * 256;
620	if (data->ptSize >= newSize)
621		return true;
622
623	BPoint* resizedArray = (BPoint*)realloc((void*)data->ptList,
624		newSize * sizeof(BPoint));
625	if (resizedArray) {
626		data->ptList = resizedArray;
627		data->ptSize = newSize;
628		return true;
629	}
630	return false;
631}
632
633
634//	#pragma mark - BShape binary compatibility methods
635
636
637#if __GNUC__ < 3
638
639
640extern "C" BShape*
641__6BShapeR6BShape(void* self, BShape& copyFrom)
642{
643	return new (self) BShape(copyFrom);
644		// we need to instantiate the object in the provided memory
645}
646
647
648extern "C" BRect
649Bounds__6BShape(BShape* self)
650{
651	return self->Bounds();
652}
653
654
655extern "C" void
656_ReservedShapeIterator1__14BShapeIterator(BShapeIterator* self)
657{
658}
659
660
661#else // __GNUC__ < 3
662
663
664extern "C" void
665_ZN14BShapeIterator23_ReservedShapeIterator1Ev(BShapeIterator* self)
666{
667}
668
669
670#endif // __GNUC__ >= 3
671