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 #if defined(__cplusplus) && __cplusplus >= 201103L 147 BShape::BShape(BShape&& other) 148 { 149 InitData(); 150 MoveFrom(other); 151 } 152 #endif 153 154 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 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 205 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* 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& 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& 264 BShape::operator=(BShape&& other) 265 { 266 MoveFrom(other); 267 268 return *this; 269 } 270 #endif 271 272 273 bool 274 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 296 BShape::operator!=(const BShape& other) const 297 { 298 return !(*this == other); 299 } 300 301 302 void 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 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 341 BShape::Bounds() const 342 { 343 shape_data* data = (shape_data*)fPrivateData; 344 return data->DetermineBoundingBox(); 345 } 346 347 348 BPoint 349 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 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 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 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 440 BShape::BezierTo(BPoint controlPoints[3]) 441 { 442 return BezierTo(controlPoints[0], controlPoints[1], controlPoints[2]); 443 } 444 445 446 status_t 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 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 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 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 564 void BShape::_ReservedShape1() {} 565 void BShape::_ReservedShape2() {} 566 void BShape::_ReservedShape3() {} 567 void BShape::_ReservedShape4() {} 568 569 570 // #pragma mark - BShape private methods 571 572 573 void 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 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 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 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 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* 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 683 Bounds__6BShape(BShape* self) 684 { 685 return self->Bounds(); 686 } 687 688 689 extern "C" void 690 _ReservedShapeIterator1__14BShapeIterator(BShapeIterator* self) 691 { 692 } 693 694 695 #else // __GNUC__ < 3 696 697 698 extern "C" void 699 _ZN14BShapeIterator23_ReservedShapeIterator1Ev(BShapeIterator* self) 700 { 701 } 702 703 704 #endif // __GNUC__ >= 3 705