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 29 BShapeIterator::BShapeIterator() 30 { 31 } 32 33 34 BShapeIterator::~BShapeIterator() 35 { 36 } 37 38 39 status_t 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 87 BShapeIterator::IterateMoveTo(BPoint* point) 88 { 89 return B_OK; 90 } 91 92 93 status_t 94 BShapeIterator::IterateLineTo(int32 lineCount, BPoint* linePoints) 95 { 96 return B_OK; 97 } 98 99 100 status_t 101 BShapeIterator::IterateBezierTo(int32 bezierCount, BPoint* bezierPoints) 102 { 103 return B_OK; 104 } 105 106 107 status_t 108 BShapeIterator::IterateClose() 109 { 110 return B_OK; 111 } 112 113 114 status_t 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 125 void BShapeIterator::_ReservedShapeIterator2() {} 126 void BShapeIterator::_ReservedShapeIterator3() {} 127 void BShapeIterator::_ReservedShapeIterator4() {} 128 129 130 // #pragma mark - BShape 131 132 133 BShape::BShape() 134 { 135 InitData(); 136 } 137 138 139 BShape::BShape(const BShape& other) 140 { 141 InitData(); 142 AddShape(&other); 143 } 144 145 146 BShape::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 183 BShape::~BShape() 184 { 185 shape_data* data = (shape_data*)fPrivateData; 186 187 free(data->opList); 188 free(data->ptList); 189 190 delete (shape_data*)fPrivateData; 191 } 192 193 194 status_t 195 BShape::Archive(BMessage* archive, bool deep) const 196 { 197 status_t result = BArchivable::Archive(archive, deep); 198 199 if (result != B_OK) 200 return result; 201 202 shape_data* data = (shape_data*)fPrivateData; 203 204 // If no valid shape data, return 205 if (data->opCount == 0 || data->ptCount == 0) 206 return result; 207 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; 213 214 for (int32 i = 1; i < data->ptCount && result == B_OK; i++) 215 result = archive->AddPoint("pts", data->ptList[i]); 216 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); 221 } 222 223 for (int32 i = 1; i < data->opCount && result == B_OK; i++) 224 result = archive->AddInt32("ops", data->opList[i]); 225 226 return result; 227 } 228 229 230 BArchivable* 231 BShape::Instantiate(BMessage* archive) 232 { 233 if (validate_instantiation(archive, "BShape")) 234 return new BShape(archive); 235 else 236 return NULL; 237 } 238 239 240 BShape& 241 BShape::operator=(const BShape& other) 242 { 243 if (this != &other) { 244 Clear(); 245 AddShape(&other); 246 } 247 248 return *this; 249 } 250 251 252 bool 253 BShape::operator==(const BShape& other) const 254 { 255 if (this == &other) 256 return true; 257 258 shape_data* data = (shape_data*)fPrivateData; 259 shape_data* otherData = (shape_data*)other.fPrivateData; 260 261 if (data->opCount != otherData->opCount) 262 return false; 263 264 if (data->ptCount != otherData->ptCount) 265 return false; 266 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; 271 } 272 273 274 bool 275 BShape::operator!=(const BShape& other) const 276 { 277 return !(*this == other); 278 } 279 280 281 void 282 BShape::Clear() 283 { 284 shape_data* data = (shape_data*)fPrivateData; 285 286 data->opCount = 0; 287 data->opSize = 0; 288 if (data->opList) { 289 free(data->opList); 290 data->opList = NULL; 291 } 292 293 data->ptCount = 0; 294 data->ptSize = 0; 295 if (data->ptList) { 296 free(data->ptList); 297 data->ptList = NULL; 298 } 299 300 fState = 0; 301 fBuildingOp = 0; 302 } 303 304 305 BRect 306 BShape::Bounds() const 307 { 308 shape_data* data = (shape_data*)fPrivateData; 309 BRect bounds; 310 311 if (data->ptCount == 0) 312 return bounds; 313 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; 319 320 for (int32 i = 1; i < data->ptCount; i++) { 321 if (bounds.left > data->ptList[i].x) 322 bounds.left = data->ptList[i].x; 323 324 if (bounds.top > data->ptList[i].y) 325 bounds.top = data->ptList[i].y; 326 327 if (bounds.right < data->ptList[i].x) 328 bounds.right = data->ptList[i].x; 329 330 if (bounds.bottom < data->ptList[i].y) 331 bounds.bottom = data->ptList[i].y; 332 } 333 334 return bounds; 335 } 336 337 338 BPoint 339 BShape::CurrentPosition() const 340 { 341 shape_data* data = (shape_data*)fPrivateData; 342 343 if (data->ptCount == 0) 344 return B_ORIGIN; 345 346 return data->ptList[data->ptCount - 1]; 347 } 348 349 350 status_t 351 BShape::AddShape(const BShape* otherShape) 352 { 353 shape_data* data = (shape_data*)fPrivateData; 354 shape_data* otherData = (shape_data*)otherShape->fPrivateData; 355 356 if (!AllocateOps(otherData->opCount) || !AllocatePts(otherData->ptCount)) 357 return B_NO_MEMORY; 358 359 memcpy(data->opList + data->opCount, otherData->opList, 360 otherData->opCount * sizeof(uint32)); 361 data->opCount += otherData->opCount; 362 363 memcpy(data->ptList + data->ptCount, otherData->ptList, 364 otherData->ptCount * sizeof(BPoint)); 365 data->ptCount += otherData->ptCount; 366 367 fBuildingOp = otherShape->fBuildingOp; 368 369 return B_OK; 370 } 371 372 373 status_t 374 BShape::MoveTo(BPoint point) 375 { 376 shape_data* data = (shape_data*)fPrivateData; 377 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; 382 } 383 384 if (!AllocateOps(1) || !AllocatePts(1)) 385 return B_NO_MEMORY; 386 387 fBuildingOp = OP_MOVETO; 388 389 // Add op 390 data->opList[data->opCount++] = fBuildingOp; 391 392 // Add point 393 data->ptList[data->ptCount++] = point; 394 395 return B_OK; 396 } 397 398 399 status_t 400 BShape::LineTo(BPoint point) 401 { 402 if (!AllocatePts(1)) 403 return B_NO_MEMORY; 404 405 shape_data* data = (shape_data*)fPrivateData; 406 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; 417 418 fBuildingOp = OP_LINETO + 1; 419 data->opList[data->opCount++] = fBuildingOp; 420 } 421 422 // Add point 423 data->ptList[data->ptCount++] = point; 424 425 return B_OK; 426 } 427 428 429 status_t 430 BShape::BezierTo(BPoint controlPoints[3]) 431 { 432 return BezierTo(controlPoints[0], controlPoints[1], controlPoints[2]); 433 } 434 435 436 status_t 437 BShape::BezierTo(const BPoint& control1, const BPoint& control2, 438 const BPoint& endPoint) 439 { 440 if (!AllocatePts(3)) 441 return B_NO_MEMORY; 442 443 shape_data* data = (shape_data*)fPrivateData; 444 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; 457 } 458 459 // Add points 460 data->ptList[data->ptCount++] = control1; 461 data->ptList[data->ptCount++] = control2; 462 data->ptList[data->ptCount++] = endPoint; 463 464 return B_OK; 465 } 466 467 468 status_t 469 BShape::ArcTo(float rx, float ry, float angle, bool largeArc, 470 bool counterClockWise, const BPoint& point) 471 { 472 if (!AllocatePts(3)) 473 return B_NO_MEMORY; 474 475 shape_data* data = (shape_data*)fPrivateData; 476 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; 488 } 489 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; 500 501 fBuildingOp = op + 3; 502 data->opList[data->opCount++] = fBuildingOp; 503 } 504 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; 509 510 return B_OK; 511 } 512 513 514 status_t 515 BShape::Close() 516 { 517 // If the last op is Close or MoveTo, ignore this 518 if (fBuildingOp == OP_CLOSE || fBuildingOp == OP_MOVETO) 519 return B_OK; 520 521 if (!AllocateOps(1)) 522 return B_NO_MEMORY; 523 524 shape_data* data = (shape_data*)fPrivateData; 525 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; 532 }*/ 533 534 fBuildingOp = OP_CLOSE; 535 data->opList[data->opCount++] = fBuildingOp; 536 537 return B_OK; 538 } 539 540 541 // #pragma mark - BShape private methods 542 543 544 status_t 545 BShape::Perform(perform_code code, void* data) 546 { 547 return BArchivable::Perform(code, data); 548 } 549 550 551 // #pragma mark - BShape FBC methods 552 553 554 void BShape::_ReservedShape1() {} 555 void BShape::_ReservedShape2() {} 556 void BShape::_ReservedShape3() {} 557 void BShape::_ReservedShape4() {} 558 559 560 // #pragma mark - BShape private methods 561 562 563 void 564 BShape::GetData(int32* opCount, int32* ptCount, uint32** opList, 565 BPoint** ptList) 566 { 567 shape_data* data = (shape_data*)fPrivateData; 568 569 *opCount = data->opCount; 570 *ptCount = data->ptCount; 571 *opList = data->opList; 572 *ptList = data->ptList; 573 } 574 575 576 void 577 BShape::SetData(int32 opCount, int32 ptCount, const uint32* opList, 578 const BPoint* ptList) 579 { 580 Clear(); 581 582 if (opCount == 0) 583 return; 584 585 shape_data* data = (shape_data*)fPrivateData; 586 587 if (!AllocateOps(opCount) || !AllocatePts(ptCount)) 588 return; 589 590 memcpy(data->opList, opList, opCount * sizeof(uint32)); 591 data->opCount = opCount; 592 fBuildingOp = data->opList[data->opCount - 1]; 593 594 if (ptCount > 0) { 595 memcpy(data->ptList, ptList, ptCount * sizeof(BPoint)); 596 data->ptCount = ptCount; 597 } 598 } 599 600 601 void 602 BShape::InitData() 603 { 604 fPrivateData = new shape_data; 605 shape_data* data = (shape_data*)fPrivateData; 606 607 fState = 0; 608 fBuildingOp = 0; 609 610 data->opList = NULL; 611 data->opCount = 0; 612 data->opSize = 0; 613 data->ptList = NULL; 614 data->ptCount = 0; 615 data->ptSize = 0; 616 } 617 618 619 inline bool 620 BShape::AllocateOps(int32 count) 621 { 622 shape_data* data = (shape_data*)fPrivateData; 623 624 int32 newSize = (data->opCount + count + 255) / 256 * 256; 625 if (data->opSize >= newSize) 626 return true; 627 628 uint32* resizedArray = (uint32*)realloc(data->opList, newSize * sizeof(uint32)); 629 if (resizedArray) { 630 data->opList = resizedArray; 631 data->opSize = newSize; 632 return true; 633 } 634 return false; 635 } 636 637 638 inline bool 639 BShape::AllocatePts(int32 count) 640 { 641 shape_data* data = (shape_data*)fPrivateData; 642 643 int32 newSize = (data->ptCount + count + 255) / 256 * 256; 644 if (data->ptSize >= newSize) 645 return true; 646 647 BPoint* resizedArray = (BPoint*)realloc(data->ptList, newSize * sizeof(BPoint)); 648 if (resizedArray) { 649 data->ptList = resizedArray; 650 data->ptSize = newSize; 651 return true; 652 } 653 return false; 654 } 655 656 657 // #pragma mark - BShape binary compatibility methods 658 659 660 #if __GNUC__ < 3 661 662 663 extern "C" BShape* 664 __6BShapeR6BShape(void* self, BShape& copyFrom) 665 { 666 return new (self) BShape(copyFrom); 667 // we need to instantiate the object in the provided memory 668 } 669 670 671 extern "C" BRect 672 Bounds__6BShape(BShape* self) 673 { 674 return self->Bounds(); 675 } 676 677 678 extern "C" void 679 _ReservedShapeIterator1__14BShapeIterator(BShapeIterator* self) 680 { 681 } 682 683 684 #else // __GNUC__ < 3 685 686 687 extern "C" void 688 _ZN14BShapeIterator23_ReservedShapeIterator1Ev(BShapeIterator* self) 689 { 690 } 691 692 693 #endif // __GNUC__ >= 3 694