1 /* 2 * Copyright (c) 2001-2010, Haiku, Inc. 3 * Distributed under the terms of the MIT license. 4 * 5 * Authors: 6 * Marc Flerackers (mflerackers@androme.be) 7 * Stephan Aßmus <superstippi@gmx.de> 8 * Michael Lotz <mmlr@mlotz.ch> 9 * Marcus Overhagen <marcus@overhagen.de> 10 */ 11 12 /*! BShape encapsulates a Postscript-style "path" */ 13 14 #include <Shape.h> 15 16 #include <Message.h> 17 #include <Point.h> 18 #include <Rect.h> 19 20 #include <ShapePrivate.h> 21 22 #include <new> 23 #include <stdlib.h> 24 #include <string.h> 25 26 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) { 49 IterateMoveTo(points); 50 points++; 51 } 52 53 if (op & OP_LINETO) { 54 int32 count = data->opList[i] & 0x00FFFFFF; 55 IterateLineTo(count, points); 56 points += count; 57 } 58 59 if (op & OP_BEZIERTO) { 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) || (op & OP_LARGE_ARC_TO_CCW) 66 || (op & OP_SMALL_ARC_TO_CW) || (op & OP_SMALL_ARC_TO_CCW)) { 67 int32 count = data->opList[i] & 0x00FFFFFF; 68 for (int32 i = 0; i < count / 3; i++) { 69 IterateArcTo(points[0].x, points[0].y, points[1].x, 70 op & (OP_LARGE_ARC_TO_CW | OP_LARGE_ARC_TO_CCW), 71 op & (OP_SMALL_ARC_TO_CCW | OP_LARGE_ARC_TO_CCW), 72 points[2]); 73 points += 3; 74 } 75 } 76 77 if (op & OP_CLOSE) { 78 IterateClose(); 79 } 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 void BShapeIterator::_ReservedShapeIterator2() {} 123 void BShapeIterator::_ReservedShapeIterator3() {} 124 void BShapeIterator::_ReservedShapeIterator4() {} 125 126 127 // #pragma mark - 128 129 130 BShape::BShape() 131 { 132 InitData(); 133 } 134 135 136 BShape::BShape(const BShape ©From) 137 { 138 InitData(); 139 AddShape(©From); 140 } 141 142 143 BShape::BShape(BMessage* archive) 144 : BArchivable(archive) 145 { 146 InitData(); 147 148 shape_data* data = (shape_data*)fPrivateData; 149 150 ssize_t size = 0; 151 int32 count = 0; 152 type_code type = 0; 153 archive->GetInfo("ops", &type, &count); 154 if (!AllocateOps(count)) 155 return; 156 157 int32 i = 0; 158 const uint32* opPtr; 159 while (archive->FindData("ops", B_INT32_TYPE, i++, (const void**)&opPtr, &size) == B_OK) 160 data->opList[data->opCount++] = *opPtr; 161 162 archive->GetInfo("pts", &type, &count); 163 if (!AllocatePts(count)) { 164 Clear(); 165 return; 166 } 167 168 i = 0; 169 const BPoint* ptPtr; 170 while (archive->FindData("pts", B_POINT_TYPE, i++, (const void**)&ptPtr, &size) == B_OK) 171 data->ptList[data->ptCount++] = *ptPtr; 172 } 173 174 175 BShape::~BShape() 176 { 177 shape_data* data = (shape_data*)fPrivateData; 178 179 free(data->opList); 180 free(data->ptList); 181 182 delete (shape_data*)fPrivateData; 183 } 184 185 186 status_t 187 BShape::Archive(BMessage* archive, bool deep) const 188 { 189 status_t err = BArchivable::Archive(archive, deep); 190 191 if (err != B_OK) 192 return err; 193 194 shape_data* data = (shape_data*)fPrivateData; 195 196 // If no valid shape data, return 197 if (data->opCount == 0 || data->ptCount == 0) 198 return err; 199 200 // Avoids allocation for each point 201 err = archive->AddData("pts", B_POINT_TYPE, data->ptList, sizeof(BPoint), true, 202 data->ptCount); 203 if (err != B_OK) 204 return err; 205 206 for (int32 i = 1; i < data->ptCount && err == B_OK; i++) 207 err = archive->AddPoint("pts", data->ptList[i]); 208 209 // Avoids allocation for each op 210 if (err == B_OK) 211 err = archive->AddData("ops", B_INT32_TYPE, data->opList, sizeof(int32), true, 212 data->opCount); 213 214 for (int32 i = 1; i < data->opCount && err == B_OK ; i++) 215 err = archive->AddInt32("ops", data->opList[i]); 216 217 return err; 218 } 219 220 221 BArchivable* 222 BShape::Instantiate(BMessage* archive) 223 { 224 if (validate_instantiation(archive, "BShape")) 225 return new BShape(archive); 226 else 227 return NULL; 228 } 229 230 231 BShape& 232 BShape::operator=(const BShape& other) 233 { 234 if (this != &other) { 235 Clear(); 236 AddShape(&other); 237 } 238 239 return *this; 240 } 241 242 243 bool 244 BShape::operator==(const BShape& other) const 245 { 246 if (this == &other) 247 return true; 248 249 shape_data* data = (shape_data*)fPrivateData; 250 shape_data* otherData = (shape_data*)other.fPrivateData; 251 252 if (data->opCount != otherData->opCount) 253 return false; 254 if (data->ptCount != otherData->ptCount) 255 return false; 256 257 return memcmp(data->opList, otherData->opList, 258 data->opCount * sizeof(uint32)) == 0 259 && memcmp(data->ptList, otherData->ptList, 260 data->ptCount * sizeof(BPoint)) == 0; 261 } 262 263 264 bool 265 BShape::operator!=(const BShape& other) const 266 { 267 return !(*this == other); 268 } 269 270 271 void 272 BShape::Clear() 273 { 274 shape_data* data = (shape_data*)fPrivateData; 275 276 data->opCount = 0; 277 data->opSize = 0; 278 if (data->opList) { 279 free(data->opList); 280 data->opList = NULL; 281 } 282 283 data->ptCount = 0; 284 data->ptSize = 0; 285 if (data->ptList) { 286 free(data->ptList); 287 data->ptList = NULL; 288 } 289 290 fState = 0; 291 fBuildingOp = 0; 292 } 293 294 295 BRect 296 BShape::Bounds() const 297 { 298 shape_data* data = (shape_data*)fPrivateData; 299 BRect bounds; 300 301 if (data->ptCount == 0) 302 return bounds; 303 304 // TODO: This implementation doesn't take into account curves at all. 305 bounds.left = data->ptList[0].x; 306 bounds.top = data->ptList[0].y; 307 bounds.right = data->ptList[0].x; 308 bounds.bottom = data->ptList[0].y; 309 310 for (int32 i = 1; i < data->ptCount; i++) { 311 if (bounds.left > data->ptList[i].x) 312 bounds.left = data->ptList[i].x; 313 if (bounds.top > data->ptList[i].y) 314 bounds.top = data->ptList[i].y; 315 if (bounds.right < data->ptList[i].x) 316 bounds.right = data->ptList[i].x; 317 if (bounds.bottom < data->ptList[i].y) 318 bounds.bottom = data->ptList[i].y; 319 } 320 321 return bounds; 322 } 323 324 325 BPoint 326 BShape::CurrentPosition() const 327 { 328 shape_data* data = (shape_data*)fPrivateData; 329 330 if (data->ptCount == 0) 331 return B_ORIGIN; 332 333 return data->ptList[data->ptCount - 1]; 334 } 335 336 337 status_t 338 BShape::AddShape(const BShape* otherShape) 339 { 340 shape_data* data = (shape_data*)fPrivateData; 341 shape_data* otherData = (shape_data*)otherShape->fPrivateData; 342 343 if (!AllocateOps(otherData->opCount) || !AllocatePts(otherData->ptCount)) 344 return B_NO_MEMORY; 345 346 memcpy(data->opList + data->opCount * sizeof(uint32), otherData->opList, 347 otherData->opCount * sizeof(uint32)); 348 data->opCount += otherData->opCount; 349 350 memcpy(data->ptList + data->ptCount * sizeof(BPoint), otherData->ptList, 351 otherData->ptCount * sizeof(BPoint)); 352 data->ptCount += otherData->ptCount; 353 354 fBuildingOp = otherShape->fBuildingOp; 355 356 return B_OK; 357 } 358 359 360 status_t 361 BShape::MoveTo(BPoint point) 362 { 363 shape_data* data = (shape_data*)fPrivateData; 364 365 // If the last op is MoveTo, replace the point 366 if (fBuildingOp == OP_MOVETO) { 367 data->ptList[data->ptCount - 1] = point; 368 return B_OK; 369 } 370 371 if (!AllocateOps(1) || !AllocatePts(1)) 372 return B_NO_MEMORY; 373 374 fBuildingOp = OP_MOVETO; 375 376 // Add op 377 data->opList[data->opCount++] = fBuildingOp; 378 379 // Add point 380 data->ptList[data->ptCount++] = point; 381 382 return B_OK; 383 } 384 385 386 status_t 387 BShape::LineTo(BPoint point) 388 { 389 if (!AllocatePts(1)) 390 return B_NO_MEMORY; 391 392 shape_data* data = (shape_data*)fPrivateData; 393 394 // If the last op is MoveTo, replace the op and set the count 395 // If the last op is LineTo increase the count 396 // Otherwise add the op 397 if (fBuildingOp & OP_LINETO || fBuildingOp == OP_MOVETO) { 398 fBuildingOp |= OP_LINETO; 399 fBuildingOp += 1; 400 data->opList[data->opCount - 1] = fBuildingOp; 401 } else { 402 if (!AllocateOps(1)) 403 return B_NO_MEMORY; 404 fBuildingOp = OP_LINETO + 1; 405 data->opList[data->opCount++] = fBuildingOp; 406 } 407 408 // Add point 409 data->ptList[data->ptCount++] = point; 410 411 return B_OK; 412 } 413 414 415 status_t 416 BShape::BezierTo(BPoint controlPoints[3]) 417 { 418 return BezierTo(controlPoints[0], controlPoints[1], controlPoints[2]); 419 } 420 421 422 status_t 423 BShape::BezierTo(const BPoint& control1, const BPoint& control2, 424 const BPoint& endPoint) 425 { 426 if (!AllocatePts(3)) 427 return B_NO_MEMORY; 428 429 shape_data* data = (shape_data*)fPrivateData; 430 431 // If the last op is MoveTo, replace the op and set the count 432 // If the last op is BezierTo increase the count 433 // Otherwise add the op 434 if (fBuildingOp & OP_BEZIERTO || fBuildingOp == OP_MOVETO) { 435 fBuildingOp |= OP_BEZIERTO; 436 fBuildingOp += 3; 437 data->opList[data->opCount - 1] = fBuildingOp; 438 } else { 439 if (!AllocateOps(1)) 440 return B_NO_MEMORY; 441 fBuildingOp = OP_BEZIERTO + 3; 442 data->opList[data->opCount++] = fBuildingOp; 443 } 444 445 // Add points 446 data->ptList[data->ptCount++] = control1; 447 data->ptList[data->ptCount++] = control2; 448 data->ptList[data->ptCount++] = endPoint; 449 450 return B_OK; 451 } 452 453 454 status_t 455 BShape::ArcTo(float rx, float ry, float angle, bool largeArc, 456 bool counterClockWise, const BPoint& point) 457 { 458 if (!AllocatePts(3)) 459 return B_NO_MEMORY; 460 461 shape_data* data = (shape_data*)fPrivateData; 462 463 uint32 op; 464 if (largeArc) { 465 if (counterClockWise) 466 op = OP_LARGE_ARC_TO_CCW; 467 else 468 op = OP_LARGE_ARC_TO_CW; 469 } else { 470 if (counterClockWise) 471 op = OP_SMALL_ARC_TO_CCW; 472 else 473 op = OP_SMALL_ARC_TO_CW; 474 } 475 476 // If the last op is MoveTo, replace the op and set the count 477 // If the last op is ArcTo increase the count 478 // Otherwise add the op 479 if (fBuildingOp == op || fBuildingOp == (op | OP_MOVETO)) { 480 fBuildingOp |= op; 481 fBuildingOp += 3; 482 data->opList[data->opCount - 1] = fBuildingOp; 483 } else { 484 if (!AllocateOps(1)) 485 return B_NO_MEMORY; 486 fBuildingOp = op + 3; 487 data->opList[data->opCount++] = fBuildingOp; 488 } 489 490 // Add points 491 data->ptList[data->ptCount++] = BPoint(rx, ry); 492 data->ptList[data->ptCount++] = BPoint(angle, 0); 493 data->ptList[data->ptCount++] = point; 494 495 return B_OK; 496 } 497 498 499 status_t 500 BShape::Close() 501 { 502 // If the last op is Close or MoveTo, ignore this 503 if (fBuildingOp == OP_CLOSE || fBuildingOp == OP_MOVETO) 504 return B_OK; 505 506 if (!AllocateOps(1)) 507 return B_NO_MEMORY; 508 509 shape_data* data = (shape_data*)fPrivateData; 510 511 // ToDo: Decide about that, it's not BeOS compatible 512 // If there was any op before we can attach the close to it 513 /*if (fBuildingOp) { 514 fBuildingOp |= OP_CLOSE; 515 data->opList[data->opCount - 1] = fBuildingOp; 516 return B_OK; 517 }*/ 518 519 fBuildingOp = OP_CLOSE; 520 data->opList[data->opCount++] = fBuildingOp; 521 522 return B_OK; 523 } 524 525 526 status_t 527 BShape::Perform(perform_code d, void* arg) 528 { 529 return BArchivable::Perform(d, arg); 530 } 531 532 533 void BShape::_ReservedShape1() {} 534 void BShape::_ReservedShape2() {} 535 void BShape::_ReservedShape3() {} 536 void BShape::_ReservedShape4() {} 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 578 579 void 580 BShape::InitData() 581 { 582 fPrivateData = new shape_data; 583 shape_data* data = (shape_data*)fPrivateData; 584 585 fState = 0; 586 fBuildingOp = 0; 587 588 data->opList = NULL; 589 data->opCount = 0; 590 data->opSize = 0; 591 data->ptList = NULL; 592 data->ptCount = 0; 593 data->ptSize = 0; 594 } 595 596 597 inline bool 598 BShape::AllocateOps(int32 count) 599 { 600 shape_data* data = (shape_data*)fPrivateData; 601 602 int32 newSize = (data->opCount + count + 255) / 256 * 256; 603 if (data->opSize >= newSize) 604 return true; 605 606 uint32* resizedArray = (uint32*)realloc(data->opList, newSize * sizeof(uint32)); 607 if (resizedArray) { 608 data->opList = resizedArray; 609 data->opSize = newSize; 610 return true; 611 } 612 return false; 613 } 614 615 616 inline bool 617 BShape::AllocatePts(int32 count) 618 { 619 shape_data* data = (shape_data*)fPrivateData; 620 621 int32 newSize = (data->ptCount + count + 255) / 256 * 256; 622 if (data->ptSize >= newSize) 623 return true; 624 625 BPoint* resizedArray = (BPoint*)realloc(data->ptList, newSize * sizeof(BPoint)); 626 if (resizedArray) { 627 data->ptList = resizedArray; 628 data->ptSize = newSize; 629 return true; 630 } 631 return false; 632 } 633 634 635 // #pragma mark - binary compatibility 636 637 638 #if __GNUC__ < 3 639 640 641 extern "C" BShape* 642 __6BShapeR6BShape(void* self, BShape& copyFrom) 643 { 644 return new (self) BShape(copyFrom); 645 // we need to instantiate the object in the provided memory 646 } 647 648 649 extern "C" BRect 650 Bounds__6BShape(BShape* self) 651 { 652 return self->Bounds(); 653 } 654 655 656 extern "C" void 657 _ReservedShapeIterator1__14BShapeIterator(BShapeIterator* self) 658 { 659 } 660 661 662 #else // __GNUC__ < 3 663 664 665 extern "C" void 666 _ZN14BShapeIterator23_ReservedShapeIterator1Ev(BShapeIterator* self) 667 { 668 } 669 670 671 #endif // __GNUC__ >= 3 672