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 return data->DetermineBoundingBox(); 310 } 311 312 313 BPoint 314 BShape::CurrentPosition() const 315 { 316 shape_data* data = (shape_data*)fPrivateData; 317 318 if (data->ptCount == 0) 319 return B_ORIGIN; 320 321 return data->ptList[data->ptCount - 1]; 322 } 323 324 325 status_t 326 BShape::AddShape(const BShape* otherShape) 327 { 328 shape_data* data = (shape_data*)fPrivateData; 329 shape_data* otherData = (shape_data*)otherShape->fPrivateData; 330 331 if (!AllocateOps(otherData->opCount) || !AllocatePts(otherData->ptCount)) 332 return B_NO_MEMORY; 333 334 memcpy(data->opList + data->opCount, otherData->opList, 335 otherData->opCount * sizeof(uint32)); 336 data->opCount += otherData->opCount; 337 338 memcpy(data->ptList + data->ptCount, otherData->ptList, 339 otherData->ptCount * sizeof(BPoint)); 340 data->ptCount += otherData->ptCount; 341 342 fBuildingOp = otherShape->fBuildingOp; 343 344 return B_OK; 345 } 346 347 348 status_t 349 BShape::MoveTo(BPoint point) 350 { 351 shape_data* data = (shape_data*)fPrivateData; 352 353 // If the last op is MoveTo, replace the point 354 if (fBuildingOp == OP_MOVETO) { 355 data->ptList[data->ptCount - 1] = point; 356 return B_OK; 357 } 358 359 if (!AllocateOps(1) || !AllocatePts(1)) 360 return B_NO_MEMORY; 361 362 fBuildingOp = OP_MOVETO; 363 364 // Add op 365 data->opList[data->opCount++] = fBuildingOp; 366 367 // Add point 368 data->ptList[data->ptCount++] = point; 369 370 return B_OK; 371 } 372 373 374 status_t 375 BShape::LineTo(BPoint point) 376 { 377 if (!AllocatePts(1)) 378 return B_NO_MEMORY; 379 380 shape_data* data = (shape_data*)fPrivateData; 381 382 // If the last op is MoveTo, replace the op and set the count 383 // If the last op is LineTo increase the count 384 // Otherwise add the op 385 if (fBuildingOp & OP_LINETO || fBuildingOp == OP_MOVETO) { 386 fBuildingOp |= OP_LINETO; 387 fBuildingOp += 1; 388 data->opList[data->opCount - 1] = fBuildingOp; 389 } else { 390 if (!AllocateOps(1)) 391 return B_NO_MEMORY; 392 393 fBuildingOp = OP_LINETO + 1; 394 data->opList[data->opCount++] = fBuildingOp; 395 } 396 397 // Add point 398 data->ptList[data->ptCount++] = point; 399 400 return B_OK; 401 } 402 403 404 status_t 405 BShape::BezierTo(BPoint controlPoints[3]) 406 { 407 return BezierTo(controlPoints[0], controlPoints[1], controlPoints[2]); 408 } 409 410 411 status_t 412 BShape::BezierTo(const BPoint& control1, const BPoint& control2, 413 const BPoint& endPoint) 414 { 415 if (!AllocatePts(3)) 416 return B_NO_MEMORY; 417 418 shape_data* data = (shape_data*)fPrivateData; 419 420 // If the last op is MoveTo, replace the op and set the count 421 // If the last op is BezierTo increase the count 422 // Otherwise add the op 423 if (fBuildingOp & OP_BEZIERTO || fBuildingOp == OP_MOVETO) { 424 fBuildingOp |= OP_BEZIERTO; 425 fBuildingOp += 3; 426 data->opList[data->opCount - 1] = fBuildingOp; 427 } else { 428 if (!AllocateOps(1)) 429 return B_NO_MEMORY; 430 fBuildingOp = OP_BEZIERTO + 3; 431 data->opList[data->opCount++] = fBuildingOp; 432 } 433 434 // Add points 435 data->ptList[data->ptCount++] = control1; 436 data->ptList[data->ptCount++] = control2; 437 data->ptList[data->ptCount++] = endPoint; 438 439 return B_OK; 440 } 441 442 443 status_t 444 BShape::ArcTo(float rx, float ry, float angle, bool largeArc, 445 bool counterClockWise, const BPoint& point) 446 { 447 if (!AllocatePts(3)) 448 return B_NO_MEMORY; 449 450 shape_data* data = (shape_data*)fPrivateData; 451 452 uint32 op; 453 if (largeArc) { 454 if (counterClockWise) 455 op = OP_LARGE_ARC_TO_CCW; 456 else 457 op = OP_LARGE_ARC_TO_CW; 458 } else { 459 if (counterClockWise) 460 op = OP_SMALL_ARC_TO_CCW; 461 else 462 op = OP_SMALL_ARC_TO_CW; 463 } 464 465 // If the last op is MoveTo, replace the op and set the count 466 // If the last op is ArcTo increase the count 467 // Otherwise add the op 468 if (fBuildingOp == op || fBuildingOp == (op | OP_MOVETO)) { 469 fBuildingOp |= op; 470 fBuildingOp += 3; 471 data->opList[data->opCount - 1] = fBuildingOp; 472 } else { 473 if (!AllocateOps(1)) 474 return B_NO_MEMORY; 475 476 fBuildingOp = op + 3; 477 data->opList[data->opCount++] = fBuildingOp; 478 } 479 480 // Add points 481 data->ptList[data->ptCount++] = BPoint(rx, ry); 482 data->ptList[data->ptCount++] = BPoint(angle, 0); 483 data->ptList[data->ptCount++] = point; 484 485 return B_OK; 486 } 487 488 489 status_t 490 BShape::Close() 491 { 492 // If the last op is Close or MoveTo, ignore this 493 if (fBuildingOp == OP_CLOSE || fBuildingOp == OP_MOVETO) 494 return B_OK; 495 496 if (!AllocateOps(1)) 497 return B_NO_MEMORY; 498 499 shape_data* data = (shape_data*)fPrivateData; 500 501 // ToDo: Decide about that, it's not BeOS compatible 502 // If there was any op before we can attach the close to it 503 /*if (fBuildingOp) { 504 fBuildingOp |= OP_CLOSE; 505 data->opList[data->opCount - 1] = fBuildingOp; 506 return B_OK; 507 }*/ 508 509 fBuildingOp = OP_CLOSE; 510 data->opList[data->opCount++] = fBuildingOp; 511 512 return B_OK; 513 } 514 515 516 // #pragma mark - BShape private methods 517 518 519 status_t 520 BShape::Perform(perform_code code, void* data) 521 { 522 return BArchivable::Perform(code, data); 523 } 524 525 526 // #pragma mark - BShape FBC methods 527 528 529 void BShape::_ReservedShape1() {} 530 void BShape::_ReservedShape2() {} 531 void BShape::_ReservedShape3() {} 532 void BShape::_ReservedShape4() {} 533 534 535 // #pragma mark - BShape private methods 536 537 538 void 539 BShape::GetData(int32* opCount, int32* ptCount, uint32** opList, 540 BPoint** ptList) 541 { 542 shape_data* data = (shape_data*)fPrivateData; 543 544 *opCount = data->opCount; 545 *ptCount = data->ptCount; 546 *opList = data->opList; 547 *ptList = data->ptList; 548 } 549 550 551 void 552 BShape::SetData(int32 opCount, int32 ptCount, const uint32* opList, 553 const BPoint* ptList) 554 { 555 Clear(); 556 557 if (opCount == 0) 558 return; 559 560 shape_data* data = (shape_data*)fPrivateData; 561 562 if (!AllocateOps(opCount) || !AllocatePts(ptCount)) 563 return; 564 565 memcpy(data->opList, opList, opCount * sizeof(uint32)); 566 data->opCount = opCount; 567 fBuildingOp = data->opList[data->opCount - 1]; 568 569 if (ptCount > 0) { 570 memcpy(data->ptList, ptList, ptCount * sizeof(BPoint)); 571 data->ptCount = ptCount; 572 } 573 } 574 575 576 void 577 BShape::InitData() 578 { 579 fPrivateData = new shape_data; 580 shape_data* data = (shape_data*)fPrivateData; 581 582 fState = 0; 583 fBuildingOp = 0; 584 585 data->opList = NULL; 586 data->opCount = 0; 587 data->opSize = 0; 588 data->ptList = NULL; 589 data->ptCount = 0; 590 data->ptSize = 0; 591 } 592 593 594 inline bool 595 BShape::AllocateOps(int32 count) 596 { 597 shape_data* data = (shape_data*)fPrivateData; 598 599 int32 newSize = (data->opCount + count + 255) / 256 * 256; 600 if (data->opSize >= newSize) 601 return true; 602 603 uint32* resizedArray = (uint32*)realloc(data->opList, newSize * sizeof(uint32)); 604 if (resizedArray) { 605 data->opList = resizedArray; 606 data->opSize = newSize; 607 return true; 608 } 609 return false; 610 } 611 612 613 inline bool 614 BShape::AllocatePts(int32 count) 615 { 616 shape_data* data = (shape_data*)fPrivateData; 617 618 int32 newSize = (data->ptCount + count + 255) / 256 * 256; 619 if (data->ptSize >= newSize) 620 return true; 621 622 BPoint* resizedArray = (BPoint*)realloc(data->ptList, newSize * sizeof(BPoint)); 623 if (resizedArray) { 624 data->ptList = resizedArray; 625 data->ptSize = newSize; 626 return true; 627 } 628 return false; 629 } 630 631 632 // #pragma mark - BShape binary compatibility methods 633 634 635 #if __GNUC__ < 3 636 637 638 extern "C" BShape* 639 __6BShapeR6BShape(void* self, BShape& copyFrom) 640 { 641 return new (self) BShape(copyFrom); 642 // we need to instantiate the object in the provided memory 643 } 644 645 646 extern "C" BRect 647 Bounds__6BShape(BShape* self) 648 { 649 return self->Bounds(); 650 } 651 652 653 extern "C" void 654 _ReservedShapeIterator1__14BShapeIterator(BShapeIterator* self) 655 { 656 } 657 658 659 #else // __GNUC__ < 3 660 661 662 extern "C" void 663 _ZN14BShapeIterator23_ReservedShapeIterator1Ev(BShapeIterator* self) 664 { 665 } 666 667 668 #endif // __GNUC__ >= 3 669