vfs: check userland buffers before reading them.
[haiku.git] / src / kits / interface / Shape.cpp
blobd6e195da7834ff4709caa99483d63ad7e2ff6487
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;
186 if (!data->fOwnsMemory) {
187 free(data->opList);
188 free(data->ptList);
191 data->ReleaseReference();
195 status_t
196 BShape::Archive(BMessage* archive, bool deep) const
198 status_t result = BArchivable::Archive(archive, deep);
200 if (result != B_OK)
201 return result;
203 shape_data* data = (shape_data*)fPrivateData;
205 // If no valid shape data, return
206 if (data->opCount == 0 || data->ptCount == 0)
207 return result;
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;
215 for (int32 i = 1; i < data->ptCount && result == B_OK; i++)
216 result = archive->AddPoint("pts", data->ptList[i]);
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);
224 for (int32 i = 1; i < data->opCount && result == B_OK; i++)
225 result = archive->AddInt32("ops", data->opList[i]);
227 return result;
231 BArchivable*
232 BShape::Instantiate(BMessage* archive)
234 if (validate_instantiation(archive, "BShape"))
235 return new BShape(archive);
236 else
237 return NULL;
241 BShape&
242 BShape::operator=(const BShape& other)
244 if (this != &other) {
245 Clear();
246 AddShape(&other);
249 return *this;
253 bool
254 BShape::operator==(const BShape& other) const
256 if (this == &other)
257 return true;
259 shape_data* data = (shape_data*)fPrivateData;
260 shape_data* otherData = (shape_data*)other.fPrivateData;
262 if (data->opCount != otherData->opCount)
263 return false;
265 if (data->ptCount != otherData->ptCount)
266 return false;
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;
275 bool
276 BShape::operator!=(const BShape& other) const
278 return !(*this == other);
282 void
283 BShape::Clear()
285 shape_data* data = (shape_data*)fPrivateData;
287 data->opCount = 0;
288 data->opSize = 0;
289 if (data->opList) {
290 free(data->opList);
291 data->opList = NULL;
294 data->ptCount = 0;
295 data->ptSize = 0;
296 if (data->ptList) {
297 free(data->ptList);
298 data->ptList = NULL;
301 fState = 0;
302 fBuildingOp = 0;
306 BRect
307 BShape::Bounds() const
309 shape_data* data = (shape_data*)fPrivateData;
310 return data->DetermineBoundingBox();
314 BPoint
315 BShape::CurrentPosition() const
317 shape_data* data = (shape_data*)fPrivateData;
319 if (data->ptCount == 0)
320 return B_ORIGIN;
322 return data->ptList[data->ptCount - 1];
326 status_t
327 BShape::AddShape(const BShape* otherShape)
329 shape_data* data = (shape_data*)fPrivateData;
330 shape_data* otherData = (shape_data*)otherShape->fPrivateData;
332 if (!AllocateOps(otherData->opCount) || !AllocatePts(otherData->ptCount))
333 return B_NO_MEMORY;
335 memcpy(data->opList + data->opCount, otherData->opList,
336 otherData->opCount * sizeof(uint32));
337 data->opCount += otherData->opCount;
339 memcpy(data->ptList + data->ptCount, otherData->ptList,
340 otherData->ptCount * sizeof(BPoint));
341 data->ptCount += otherData->ptCount;
343 fBuildingOp = otherShape->fBuildingOp;
345 return B_OK;
349 status_t
350 BShape::MoveTo(BPoint point)
352 shape_data* data = (shape_data*)fPrivateData;
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;
360 if (!AllocateOps(1) || !AllocatePts(1))
361 return B_NO_MEMORY;
363 fBuildingOp = OP_MOVETO;
365 // Add op
366 data->opList[data->opCount++] = fBuildingOp;
368 // Add point
369 data->ptList[data->ptCount++] = point;
371 return B_OK;
375 status_t
376 BShape::LineTo(BPoint point)
378 if (!AllocatePts(1))
379 return B_NO_MEMORY;
381 shape_data* data = (shape_data*)fPrivateData;
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;
394 fBuildingOp = OP_LINETO + 1;
395 data->opList[data->opCount++] = fBuildingOp;
398 // Add point
399 data->ptList[data->ptCount++] = point;
401 return B_OK;
405 status_t
406 BShape::BezierTo(BPoint controlPoints[3])
408 return BezierTo(controlPoints[0], controlPoints[1], controlPoints[2]);
412 status_t
413 BShape::BezierTo(const BPoint& control1, const BPoint& control2,
414 const BPoint& endPoint)
416 if (!AllocatePts(3))
417 return B_NO_MEMORY;
419 shape_data* data = (shape_data*)fPrivateData;
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;
435 // Add points
436 data->ptList[data->ptCount++] = control1;
437 data->ptList[data->ptCount++] = control2;
438 data->ptList[data->ptCount++] = endPoint;
440 return B_OK;
444 status_t
445 BShape::ArcTo(float rx, float ry, float angle, bool largeArc,
446 bool counterClockWise, const BPoint& point)
448 if (!AllocatePts(3))
449 return B_NO_MEMORY;
451 shape_data* data = (shape_data*)fPrivateData;
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;
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;
477 fBuildingOp = op + 3;
478 data->opList[data->opCount++] = fBuildingOp;
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;
486 return B_OK;
490 status_t
491 BShape::Close()
493 // If the last op is Close or MoveTo, ignore this
494 if (fBuildingOp == OP_CLOSE || fBuildingOp == OP_MOVETO)
495 return B_OK;
497 if (!AllocateOps(1))
498 return B_NO_MEMORY;
500 shape_data* data = (shape_data*)fPrivateData;
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;
510 fBuildingOp = OP_CLOSE;
511 data->opList[data->opCount++] = fBuildingOp;
513 return B_OK;
517 // #pragma mark - BShape private methods
520 status_t
521 BShape::Perform(perform_code code, void* data)
523 return BArchivable::Perform(code, data);
527 // #pragma mark - BShape FBC methods
530 void BShape::_ReservedShape1() {}
531 void BShape::_ReservedShape2() {}
532 void BShape::_ReservedShape3() {}
533 void BShape::_ReservedShape4() {}
536 // #pragma mark - BShape private methods
539 void
540 BShape::GetData(int32* opCount, int32* ptCount, uint32** opList,
541 BPoint** ptList)
543 shape_data* data = (shape_data*)fPrivateData;
545 *opCount = data->opCount;
546 *ptCount = data->ptCount;
547 *opList = data->opList;
548 *ptList = data->ptList;
552 void
553 BShape::SetData(int32 opCount, int32 ptCount, const uint32* opList,
554 const BPoint* ptList)
556 Clear();
558 if (opCount == 0)
559 return;
561 shape_data* data = (shape_data*)fPrivateData;
563 if (!AllocateOps(opCount) || !AllocatePts(ptCount))
564 return;
566 memcpy(data->opList, opList, opCount * sizeof(uint32));
567 data->opCount = opCount;
568 fBuildingOp = data->opList[data->opCount - 1];
570 if (ptCount > 0) {
571 memcpy(data->ptList, ptList, ptCount * sizeof(BPoint));
572 data->ptCount = ptCount;
577 void
578 BShape::InitData()
580 fPrivateData = new shape_data;
581 shape_data* data = (shape_data*)fPrivateData;
583 fState = 0;
584 fBuildingOp = 0;
586 data->opList = NULL;
587 data->opCount = 0;
588 data->opSize = 0;
589 data->ptList = NULL;
590 data->ptCount = 0;
591 data->ptSize = 0;
595 inline bool
596 BShape::AllocateOps(int32 count)
598 shape_data* data = (shape_data*)fPrivateData;
600 int32 newSize = (data->opCount + count + 255) / 256 * 256;
601 if (data->opSize >= newSize)
602 return true;
604 uint32* resizedArray = (uint32*)realloc(data->opList, newSize * sizeof(uint32));
605 if (resizedArray) {
606 data->opList = resizedArray;
607 data->opSize = newSize;
608 return true;
610 return false;
614 inline bool
615 BShape::AllocatePts(int32 count)
617 shape_data* data = (shape_data*)fPrivateData;
619 int32 newSize = (data->ptCount + count + 255) / 256 * 256;
620 if (data->ptSize >= newSize)
621 return true;
623 BPoint* resizedArray = (BPoint*)realloc(data->ptList, newSize * sizeof(BPoint));
624 if (resizedArray) {
625 data->ptList = resizedArray;
626 data->ptSize = newSize;
627 return true;
629 return false;
633 // #pragma mark - BShape binary compatibility methods
636 #if __GNUC__ < 3
639 extern "C" BShape*
640 __6BShapeR6BShape(void* self, BShape& copyFrom)
642 return new (self) BShape(copyFrom);
643 // we need to instantiate the object in the provided memory
647 extern "C" BRect
648 Bounds__6BShape(BShape* self)
650 return self->Bounds();
654 extern "C" void
655 _ReservedShapeIterator1__14BShapeIterator(BShapeIterator* self)
660 #else // __GNUC__ < 3
663 extern "C" void
664 _ZN14BShapeIterator23_ReservedShapeIterator1Ev(BShapeIterator* self)
669 #endif // __GNUC__ >= 3