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 if (!data->fOwnsMemory) { 187 free(data->opList); 188 free(data->ptList); 189 } 190 191 data->ReleaseReference(); 192 } 193 194 195 status_t 196 BShape::Archive(BMessage* archive, bool deep) const 197 { 198 status_t result = BArchivable::Archive(archive, deep); 199 200 if (result != B_OK) 201 return result; 202 203 shape_data* data = (shape_data*)fPrivateData; 204 205 // If no valid shape data, return 206 if (data->opCount == 0 || data->ptCount == 0) 207 return result; 208 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; 214 215 for (int32 i = 1; i < data->ptCount && result == B_OK; i++) 216 result = archive->AddPoint("pts", data->ptList[i]); 217 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); 222 } 223 224 for (int32 i = 1; i < data->opCount && result == B_OK; i++) 225 result = archive->AddInt32("ops", data->opList[i]); 226 227 return result; 228 } 229 230 231 BArchivable* 232 BShape::Instantiate(BMessage* archive) 233 { 234 if (validate_instantiation(archive, "BShape")) 235 return new BShape(archive); 236 else 237 return NULL; 238 } 239 240 241 BShape& 242 BShape::operator=(const BShape& other) 243 { 244 if (this != &other) { 245 Clear(); 246 AddShape(&other); 247 } 248 249 return *this; 250 } 251 252 253 bool 254 BShape::operator==(const BShape& other) const 255 { 256 if (this == &other) 257 return true; 258 259 shape_data* data = (shape_data*)fPrivateData; 260 shape_data* otherData = (shape_data*)other.fPrivateData; 261 262 if (data->opCount != otherData->opCount) 263 return false; 264 265 if (data->ptCount != otherData->ptCount) 266 return false; 267 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; 272 } 273 274 275 bool 276 BShape::operator!=(const BShape& other) const 277 { 278 return !(*this == other); 279 } 280 281 282 void 283 BShape::Clear() 284 { 285 shape_data* data = (shape_data*)fPrivateData; 286 287 data->opCount = 0; 288 data->opSize = 0; 289 if (data->opList) { 290 free(data->opList); 291 data->opList = NULL; 292 } 293 294 data->ptCount = 0; 295 data->ptSize = 0; 296 if (data->ptList) { 297 free(data->ptList); 298 data->ptList = NULL; 299 } 300 301 fState = 0; 302 fBuildingOp = 0; 303 } 304 305 306 BRect 307 BShape::Bounds() const 308 { 309 shape_data* data = (shape_data*)fPrivateData; 310 return data->DetermineBoundingBox(); 311 } 312 313 314 BPoint 315 BShape::CurrentPosition() const 316 { 317 shape_data* data = (shape_data*)fPrivateData; 318 319 if (data->ptCount == 0) 320 return B_ORIGIN; 321 322 return data->ptList[data->ptCount - 1]; 323 } 324 325 326 status_t 327 BShape::AddShape(const BShape* otherShape) 328 { 329 shape_data* data = (shape_data*)fPrivateData; 330 shape_data* otherData = (shape_data*)otherShape->fPrivateData; 331 332 if (!AllocateOps(otherData->opCount) || !AllocatePts(otherData->ptCount)) 333 return B_NO_MEMORY; 334 335 memcpy(data->opList + data->opCount, otherData->opList, 336 otherData->opCount * sizeof(uint32)); 337 data->opCount += otherData->opCount; 338 339 memcpy(data->ptList + data->ptCount, otherData->ptList, 340 otherData->ptCount * sizeof(BPoint)); 341 data->ptCount += otherData->ptCount; 342 343 fBuildingOp = otherShape->fBuildingOp; 344 345 return B_OK; 346 } 347 348 349 status_t 350 BShape::MoveTo(BPoint point) 351 { 352 shape_data* data = (shape_data*)fPrivateData; 353 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; 358 } 359 360 if (!AllocateOps(1) || !AllocatePts(1)) 361 return B_NO_MEMORY; 362 363 fBuildingOp = OP_MOVETO; 364 365 // Add op 366 data->opList[data->opCount++] = fBuildingOp; 367 368 // Add point 369 data->ptList[data->ptCount++] = point; 370 371 return B_OK; 372 } 373 374 375 status_t 376 BShape::LineTo(BPoint point) 377 { 378 if (!AllocatePts(1)) 379 return B_NO_MEMORY; 380 381 shape_data* data = (shape_data*)fPrivateData; 382 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; 393 394 fBuildingOp = OP_LINETO + 1; 395 data->opList[data->opCount++] = fBuildingOp; 396 } 397 398 // Add point 399 data->ptList[data->ptCount++] = point; 400 401 return B_OK; 402 } 403 404 405 status_t 406 BShape::BezierTo(BPoint controlPoints[3]) 407 { 408 return BezierTo(controlPoints[0], controlPoints[1], controlPoints[2]); 409 } 410 411 412 status_t 413 BShape::BezierTo(const BPoint& control1, const BPoint& control2, 414 const BPoint& endPoint) 415 { 416 if (!AllocatePts(3)) 417 return B_NO_MEMORY; 418 419 shape_data* data = (shape_data*)fPrivateData; 420 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; 433 } 434 435 // Add points 436 data->ptList[data->ptCount++] = control1; 437 data->ptList[data->ptCount++] = control2; 438 data->ptList[data->ptCount++] = endPoint; 439 440 return B_OK; 441 } 442 443 444 status_t 445 BShape::ArcTo(float rx, float ry, float angle, bool largeArc, 446 bool counterClockWise, const BPoint& point) 447 { 448 if (!AllocatePts(3)) 449 return B_NO_MEMORY; 450 451 shape_data* data = (shape_data*)fPrivateData; 452 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; 464 } 465 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; 476 477 fBuildingOp = op + 3; 478 data->opList[data->opCount++] = fBuildingOp; 479 } 480 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; 485 486 return B_OK; 487 } 488 489 490 status_t 491 BShape::Close() 492 { 493 // If the last op is Close or MoveTo, ignore this 494 if (fBuildingOp == OP_CLOSE || fBuildingOp == OP_MOVETO) 495 return B_OK; 496 497 if (!AllocateOps(1)) 498 return B_NO_MEMORY; 499 500 shape_data* data = (shape_data*)fPrivateData; 501 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; 508 }*/ 509 510 fBuildingOp = OP_CLOSE; 511 data->opList[data->opCount++] = fBuildingOp; 512 513 return B_OK; 514 } 515 516 517 // #pragma mark - BShape private methods 518 519 520 status_t 521 BShape::Perform(perform_code code, void* data) 522 { 523 return BArchivable::Perform(code, data); 524 } 525 526 527 // #pragma mark - BShape FBC methods 528 529 530 void BShape::_ReservedShape1() {} 531 void BShape::_ReservedShape2() {} 532 void BShape::_ReservedShape3() {} 533 void BShape::_ReservedShape4() {} 534 535 536 // #pragma mark - BShape private methods 537 538 539 void 540 BShape::GetData(int32* opCount, int32* ptCount, uint32** opList, 541 BPoint** ptList) 542 { 543 shape_data* data = (shape_data*)fPrivateData; 544 545 *opCount = data->opCount; 546 *ptCount = data->ptCount; 547 *opList = data->opList; 548 *ptList = data->ptList; 549 } 550 551 552 void 553 BShape::SetData(int32 opCount, int32 ptCount, const uint32* opList, 554 const BPoint* ptList) 555 { 556 Clear(); 557 558 if (opCount == 0) 559 return; 560 561 shape_data* data = (shape_data*)fPrivateData; 562 563 if (!AllocateOps(opCount) || !AllocatePts(ptCount)) 564 return; 565 566 memcpy(data->opList, opList, opCount * sizeof(uint32)); 567 data->opCount = opCount; 568 fBuildingOp = data->opList[data->opCount - 1]; 569 570 if (ptCount > 0) { 571 memcpy(data->ptList, ptList, ptCount * sizeof(BPoint)); 572 data->ptCount = ptCount; 573 } 574 } 575 576 577 void 578 BShape::InitData() 579 { 580 fPrivateData = new shape_data; 581 shape_data* data = (shape_data*)fPrivateData; 582 583 fState = 0; 584 fBuildingOp = 0; 585 586 data->opList = NULL; 587 data->opCount = 0; 588 data->opSize = 0; 589 data->ptList = NULL; 590 data->ptCount = 0; 591 data->ptSize = 0; 592 } 593 594 595 inline bool 596 BShape::AllocateOps(int32 count) 597 { 598 shape_data* data = (shape_data*)fPrivateData; 599 600 int32 newSize = (data->opCount + count + 255) / 256 * 256; 601 if (data->opSize >= newSize) 602 return true; 603 604 uint32* resizedArray = (uint32*)realloc(data->opList, newSize * sizeof(uint32)); 605 if (resizedArray) { 606 data->opList = resizedArray; 607 data->opSize = newSize; 608 return true; 609 } 610 return false; 611 } 612 613 614 inline bool 615 BShape::AllocatePts(int32 count) 616 { 617 shape_data* data = (shape_data*)fPrivateData; 618 619 int32 newSize = (data->ptCount + count + 255) / 256 * 256; 620 if (data->ptSize >= newSize) 621 return true; 622 623 BPoint* resizedArray = (BPoint*)realloc(data->ptList, newSize * sizeof(BPoint)); 624 if (resizedArray) { 625 data->ptList = resizedArray; 626 data->ptSize = newSize; 627 return true; 628 } 629 return false; 630 } 631 632 633 // #pragma mark - BShape binary compatibility methods 634 635 636 #if __GNUC__ < 3 637 638 639 extern "C" BShape* 640 __6BShapeR6BShape(void* self, BShape& copyFrom) 641 { 642 return new (self) BShape(copyFrom); 643 // we need to instantiate the object in the provided memory 644 } 645 646 647 extern "C" BRect 648 Bounds__6BShape(BShape* self) 649 { 650 return self->Bounds(); 651 } 652 653 654 extern "C" void 655 _ReservedShapeIterator1__14BShapeIterator(BShapeIterator* self) 656 { 657 } 658 659 660 #else // __GNUC__ < 3 661 662 663 extern "C" void 664 _ZN14BShapeIterator23_ReservedShapeIterator1Ev(BShapeIterator* self) 665 { 666 } 667 668 669 #endif // __GNUC__ >= 3 670