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