tcp: Fix 64 bit build with debugging features enabled.
[haiku.git] / src / kits / interface / Shape.cpp
blob909f8e442d9931f0e623e69d17e59760cd6d4564
1 /*
2 * Copyright 2003-2010 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT license.
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
13 #include <Shape.h>
15 #include <Message.h>
16 #include <Point.h>
17 #include <Rect.h>
19 #include <ShapePrivate.h>
21 #include <new>
22 #include <stdlib.h>
23 #include <string.h>
26 // #pragma mark - BShapeIterator
29 BShapeIterator::BShapeIterator()
34 BShapeIterator::~BShapeIterator()
39 status_t
40 BShapeIterator::Iterate(BShape* shape)
42 shape_data* data = (shape_data*)shape->fPrivateData;
43 BPoint* points = data->ptList;
45 for (int32 i = 0; i < data->opCount; i++) {
46 int32 op = data->opList[i] & 0xFF000000;
48 if ((op & OP_MOVETO) != 0) {
49 IterateMoveTo(points);
50 points++;
53 if ((op & OP_LINETO) != 0) {
54 int32 count = data->opList[i] & 0x00FFFFFF;
55 IterateLineTo(count, points);
56 points += count;
59 if ((op & OP_BEZIERTO) != 0) {
60 int32 count = data->opList[i] & 0x00FFFFFF;
61 IterateBezierTo(count / 3, points);
62 points += count;
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;
78 if ((op & OP_CLOSE) != 0)
79 IterateClose();
82 return B_OK;
86 status_t
87 BShapeIterator::IterateMoveTo(BPoint* point)
89 return B_OK;
93 status_t
94 BShapeIterator::IterateLineTo(int32 lineCount, BPoint* linePoints)
96 return B_OK;
100 status_t
101 BShapeIterator::IterateBezierTo(int32 bezierCount, BPoint* bezierPoints)
103 return B_OK;
107 status_t
108 BShapeIterator::IterateClose()
110 return B_OK;
114 status_t
115 BShapeIterator::IterateArcTo(float& rx, float& ry, float& angle, bool largeArc,
116 bool counterClockWise, BPoint& point)
118 return B_OK;
122 // #pragma mark - BShapeIterator FBC padding
125 void BShapeIterator::_ReservedShapeIterator2() {}
126 void BShapeIterator::_ReservedShapeIterator3() {}
127 void BShapeIterator::_ReservedShapeIterator4() {}
130 // #pragma mark - BShape
133 BShape::BShape()
135 InitData();
139 BShape::BShape(const BShape& other)
141 InitData();
142 AddShape(&other);
146 BShape::BShape(BMessage* archive)
148 BArchivable(archive)
150 InitData();
152 shape_data* data = (shape_data*)fPrivateData;
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;
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;
168 archive->GetInfo("pts", &type, &count);
169 if (!AllocatePts(count)) {
170 Clear();
171 return;
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;
183 BShape::~BShape()
185 shape_data* data = (shape_data*)fPrivateData;
187 free(data->opList);
188 free(data->ptList);
190 delete (shape_data*)fPrivateData;
194 status_t
195 BShape::Archive(BMessage* archive, bool deep) const
197 status_t result = BArchivable::Archive(archive, deep);
199 if (result != B_OK)
200 return result;
202 shape_data* data = (shape_data*)fPrivateData;
204 // If no valid shape data, return
205 if (data->opCount == 0 || data->ptCount == 0)
206 return result;
208 // Avoids allocation for each point
209 result = archive->AddData("pts", B_POINT_TYPE, data->ptList,
210 sizeof(BPoint), true, data->ptCount);
211 if (result != B_OK)
212 return result;
214 for (int32 i = 1; i < data->ptCount && result == B_OK; i++)
215 result = archive->AddPoint("pts", data->ptList[i]);
217 // Avoids allocation for each op
218 if (result == B_OK) {
219 result = archive->AddData("ops", B_INT32_TYPE, data->opList,
220 sizeof(int32), true, data->opCount);
223 for (int32 i = 1; i < data->opCount && result == B_OK; i++)
224 result = archive->AddInt32("ops", data->opList[i]);
226 return result;
230 BArchivable*
231 BShape::Instantiate(BMessage* archive)
233 if (validate_instantiation(archive, "BShape"))
234 return new BShape(archive);
235 else
236 return NULL;
240 BShape&
241 BShape::operator=(const BShape& other)
243 if (this != &other) {
244 Clear();
245 AddShape(&other);
248 return *this;
252 bool
253 BShape::operator==(const BShape& other) const
255 if (this == &other)
256 return true;
258 shape_data* data = (shape_data*)fPrivateData;
259 shape_data* otherData = (shape_data*)other.fPrivateData;
261 if (data->opCount != otherData->opCount)
262 return false;
264 if (data->ptCount != otherData->ptCount)
265 return false;
267 return memcmp(data->opList, otherData->opList,
268 data->opCount * sizeof(uint32)) == 0
269 && memcmp(data->ptList, otherData->ptList,
270 data->ptCount * sizeof(BPoint)) == 0;
274 bool
275 BShape::operator!=(const BShape& other) const
277 return !(*this == other);
281 void
282 BShape::Clear()
284 shape_data* data = (shape_data*)fPrivateData;
286 data->opCount = 0;
287 data->opSize = 0;
288 if (data->opList) {
289 free(data->opList);
290 data->opList = NULL;
293 data->ptCount = 0;
294 data->ptSize = 0;
295 if (data->ptList) {
296 free(data->ptList);
297 data->ptList = NULL;
300 fState = 0;
301 fBuildingOp = 0;
305 BRect
306 BShape::Bounds() const
308 shape_data* data = (shape_data*)fPrivateData;
309 BRect bounds;
311 if (data->ptCount == 0)
312 return bounds;
314 // TODO: This implementation doesn't take into account curves at all.
315 bounds.left = data->ptList[0].x;
316 bounds.top = data->ptList[0].y;
317 bounds.right = data->ptList[0].x;
318 bounds.bottom = data->ptList[0].y;
320 for (int32 i = 1; i < data->ptCount; i++) {
321 if (bounds.left > data->ptList[i].x)
322 bounds.left = data->ptList[i].x;
324 if (bounds.top > data->ptList[i].y)
325 bounds.top = data->ptList[i].y;
327 if (bounds.right < data->ptList[i].x)
328 bounds.right = data->ptList[i].x;
330 if (bounds.bottom < data->ptList[i].y)
331 bounds.bottom = data->ptList[i].y;
334 return bounds;
338 BPoint
339 BShape::CurrentPosition() const
341 shape_data* data = (shape_data*)fPrivateData;
343 if (data->ptCount == 0)
344 return B_ORIGIN;
346 return data->ptList[data->ptCount - 1];
350 status_t
351 BShape::AddShape(const BShape* otherShape)
353 shape_data* data = (shape_data*)fPrivateData;
354 shape_data* otherData = (shape_data*)otherShape->fPrivateData;
356 if (!AllocateOps(otherData->opCount) || !AllocatePts(otherData->ptCount))
357 return B_NO_MEMORY;
359 memcpy(data->opList + data->opCount, otherData->opList,
360 otherData->opCount * sizeof(uint32));
361 data->opCount += otherData->opCount;
363 memcpy(data->ptList + data->ptCount, otherData->ptList,
364 otherData->ptCount * sizeof(BPoint));
365 data->ptCount += otherData->ptCount;
367 fBuildingOp = otherShape->fBuildingOp;
369 return B_OK;
373 status_t
374 BShape::MoveTo(BPoint point)
376 shape_data* data = (shape_data*)fPrivateData;
378 // If the last op is MoveTo, replace the point
379 if (fBuildingOp == OP_MOVETO) {
380 data->ptList[data->ptCount - 1] = point;
381 return B_OK;
384 if (!AllocateOps(1) || !AllocatePts(1))
385 return B_NO_MEMORY;
387 fBuildingOp = OP_MOVETO;
389 // Add op
390 data->opList[data->opCount++] = fBuildingOp;
392 // Add point
393 data->ptList[data->ptCount++] = point;
395 return B_OK;
399 status_t
400 BShape::LineTo(BPoint point)
402 if (!AllocatePts(1))
403 return B_NO_MEMORY;
405 shape_data* data = (shape_data*)fPrivateData;
407 // If the last op is MoveTo, replace the op and set the count
408 // If the last op is LineTo increase the count
409 // Otherwise add the op
410 if (fBuildingOp & OP_LINETO || fBuildingOp == OP_MOVETO) {
411 fBuildingOp |= OP_LINETO;
412 fBuildingOp += 1;
413 data->opList[data->opCount - 1] = fBuildingOp;
414 } else {
415 if (!AllocateOps(1))
416 return B_NO_MEMORY;
418 fBuildingOp = OP_LINETO + 1;
419 data->opList[data->opCount++] = fBuildingOp;
422 // Add point
423 data->ptList[data->ptCount++] = point;
425 return B_OK;
429 status_t
430 BShape::BezierTo(BPoint controlPoints[3])
432 return BezierTo(controlPoints[0], controlPoints[1], controlPoints[2]);
436 status_t
437 BShape::BezierTo(const BPoint& control1, const BPoint& control2,
438 const BPoint& endPoint)
440 if (!AllocatePts(3))
441 return B_NO_MEMORY;
443 shape_data* data = (shape_data*)fPrivateData;
445 // If the last op is MoveTo, replace the op and set the count
446 // If the last op is BezierTo increase the count
447 // Otherwise add the op
448 if (fBuildingOp & OP_BEZIERTO || fBuildingOp == OP_MOVETO) {
449 fBuildingOp |= OP_BEZIERTO;
450 fBuildingOp += 3;
451 data->opList[data->opCount - 1] = fBuildingOp;
452 } else {
453 if (!AllocateOps(1))
454 return B_NO_MEMORY;
455 fBuildingOp = OP_BEZIERTO + 3;
456 data->opList[data->opCount++] = fBuildingOp;
459 // Add points
460 data->ptList[data->ptCount++] = control1;
461 data->ptList[data->ptCount++] = control2;
462 data->ptList[data->ptCount++] = endPoint;
464 return B_OK;
468 status_t
469 BShape::ArcTo(float rx, float ry, float angle, bool largeArc,
470 bool counterClockWise, const BPoint& point)
472 if (!AllocatePts(3))
473 return B_NO_MEMORY;
475 shape_data* data = (shape_data*)fPrivateData;
477 uint32 op;
478 if (largeArc) {
479 if (counterClockWise)
480 op = OP_LARGE_ARC_TO_CCW;
481 else
482 op = OP_LARGE_ARC_TO_CW;
483 } else {
484 if (counterClockWise)
485 op = OP_SMALL_ARC_TO_CCW;
486 else
487 op = OP_SMALL_ARC_TO_CW;
490 // If the last op is MoveTo, replace the op and set the count
491 // If the last op is ArcTo increase the count
492 // Otherwise add the op
493 if (fBuildingOp == op || fBuildingOp == (op | OP_MOVETO)) {
494 fBuildingOp |= op;
495 fBuildingOp += 3;
496 data->opList[data->opCount - 1] = fBuildingOp;
497 } else {
498 if (!AllocateOps(1))
499 return B_NO_MEMORY;
501 fBuildingOp = op + 3;
502 data->opList[data->opCount++] = fBuildingOp;
505 // Add points
506 data->ptList[data->ptCount++] = BPoint(rx, ry);
507 data->ptList[data->ptCount++] = BPoint(angle, 0);
508 data->ptList[data->ptCount++] = point;
510 return B_OK;
514 status_t
515 BShape::Close()
517 // If the last op is Close or MoveTo, ignore this
518 if (fBuildingOp == OP_CLOSE || fBuildingOp == OP_MOVETO)
519 return B_OK;
521 if (!AllocateOps(1))
522 return B_NO_MEMORY;
524 shape_data* data = (shape_data*)fPrivateData;
526 // ToDo: Decide about that, it's not BeOS compatible
527 // If there was any op before we can attach the close to it
528 /*if (fBuildingOp) {
529 fBuildingOp |= OP_CLOSE;
530 data->opList[data->opCount - 1] = fBuildingOp;
531 return B_OK;
534 fBuildingOp = OP_CLOSE;
535 data->opList[data->opCount++] = fBuildingOp;
537 return B_OK;
541 // #pragma mark - BShape private methods
544 status_t
545 BShape::Perform(perform_code code, void* data)
547 return BArchivable::Perform(code, data);
551 // #pragma mark - BShape FBC methods
554 void BShape::_ReservedShape1() {}
555 void BShape::_ReservedShape2() {}
556 void BShape::_ReservedShape3() {}
557 void BShape::_ReservedShape4() {}
560 // #pragma mark - BShape private methods
563 void
564 BShape::GetData(int32* opCount, int32* ptCount, uint32** opList,
565 BPoint** ptList)
567 shape_data* data = (shape_data*)fPrivateData;
569 *opCount = data->opCount;
570 *ptCount = data->ptCount;
571 *opList = data->opList;
572 *ptList = data->ptList;
576 void
577 BShape::SetData(int32 opCount, int32 ptCount, const uint32* opList,
578 const BPoint* ptList)
580 Clear();
582 if (opCount == 0)
583 return;
585 shape_data* data = (shape_data*)fPrivateData;
587 if (!AllocateOps(opCount) || !AllocatePts(ptCount))
588 return;
590 memcpy(data->opList, opList, opCount * sizeof(uint32));
591 data->opCount = opCount;
592 fBuildingOp = data->opList[data->opCount - 1];
594 if (ptCount > 0) {
595 memcpy(data->ptList, ptList, ptCount * sizeof(BPoint));
596 data->ptCount = ptCount;
601 void
602 BShape::InitData()
604 fPrivateData = new shape_data;
605 shape_data* data = (shape_data*)fPrivateData;
607 fState = 0;
608 fBuildingOp = 0;
610 data->opList = NULL;
611 data->opCount = 0;
612 data->opSize = 0;
613 data->ptList = NULL;
614 data->ptCount = 0;
615 data->ptSize = 0;
619 inline bool
620 BShape::AllocateOps(int32 count)
622 shape_data* data = (shape_data*)fPrivateData;
624 int32 newSize = (data->opCount + count + 255) / 256 * 256;
625 if (data->opSize >= newSize)
626 return true;
628 uint32* resizedArray = (uint32*)realloc(data->opList, newSize * sizeof(uint32));
629 if (resizedArray) {
630 data->opList = resizedArray;
631 data->opSize = newSize;
632 return true;
634 return false;
638 inline bool
639 BShape::AllocatePts(int32 count)
641 shape_data* data = (shape_data*)fPrivateData;
643 int32 newSize = (data->ptCount + count + 255) / 256 * 256;
644 if (data->ptSize >= newSize)
645 return true;
647 BPoint* resizedArray = (BPoint*)realloc(data->ptList, newSize * sizeof(BPoint));
648 if (resizedArray) {
649 data->ptList = resizedArray;
650 data->ptSize = newSize;
651 return true;
653 return false;
657 // #pragma mark - BShape binary compatibility methods
660 #if __GNUC__ < 3
663 extern "C" BShape*
664 __6BShapeR6BShape(void* self, BShape& copyFrom)
666 return new (self) BShape(copyFrom);
667 // we need to instantiate the object in the provided memory
671 extern "C" BRect
672 Bounds__6BShape(BShape* self)
674 return self->Bounds();
678 extern "C" void
679 _ReservedShapeIterator1__14BShapeIterator(BShapeIterator* self)
684 #else // __GNUC__ < 3
687 extern "C" void
688 _ZN14BShapeIterator23_ReservedShapeIterator1Ev(BShapeIterator* self)
693 #endif // __GNUC__ >= 3