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 29BShapeIterator::BShapeIterator() 30{ 31} 32 33 34BShapeIterator::~BShapeIterator() 35{ 36} 37 38 39status_t 40BShapeIterator::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 86status_t 87BShapeIterator::IterateMoveTo(BPoint* point) 88{ 89 return B_OK; 90} 91 92 93status_t 94BShapeIterator::IterateLineTo(int32 lineCount, BPoint* linePoints) 95{ 96 return B_OK; 97} 98 99 100status_t 101BShapeIterator::IterateBezierTo(int32 bezierCount, BPoint* bezierPoints) 102{ 103 return B_OK; 104} 105 106 107status_t 108BShapeIterator::IterateClose() 109{ 110 return B_OK; 111} 112 113 114status_t 115BShapeIterator::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 125void BShapeIterator::_ReservedShapeIterator2() {} 126void BShapeIterator::_ReservedShapeIterator3() {} 127void BShapeIterator::_ReservedShapeIterator4() {} 128 129 130// #pragma mark - BShape 131 132 133BShape::BShape() 134{ 135 InitData(); 136} 137 138 139BShape::BShape(const BShape& other) 140{ 141 InitData(); 142 AddShape(&other); 143} 144 145 146BShape::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 183BShape::~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 195status_t 196BShape::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 231BArchivable* 232BShape::Instantiate(BMessage* archive) 233{ 234 if (validate_instantiation(archive, "BShape")) 235 return new BShape(archive); 236 else 237 return NULL; 238} 239 240 241BShape& 242BShape::operator=(const BShape& other) 243{ 244 if (this != &other) { 245 Clear(); 246 AddShape(&other); 247 } 248 249 return *this; 250} 251 252 253bool 254BShape::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 275bool 276BShape::operator!=(const BShape& other) const 277{ 278 return !(*this == other); 279} 280 281 282void 283BShape::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 306BRect 307BShape::Bounds() const 308{ 309 shape_data* data = (shape_data*)fPrivateData; 310 return data->DetermineBoundingBox(); 311} 312 313 314BPoint 315BShape::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 326status_t 327BShape::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((void*)(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 349status_t 350BShape::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 375status_t 376BShape::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 405status_t 406BShape::BezierTo(BPoint controlPoints[3]) 407{ 408 return BezierTo(controlPoints[0], controlPoints[1], controlPoints[2]); 409} 410 411 412status_t 413BShape::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 444status_t 445BShape::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 490status_t 491BShape::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 520status_t 521BShape::Perform(perform_code code, void* data) 522{ 523 return BArchivable::Perform(code, data); 524} 525 526 527// #pragma mark - BShape FBC methods 528 529 530void BShape::_ReservedShape1() {} 531void BShape::_ReservedShape2() {} 532void BShape::_ReservedShape3() {} 533void BShape::_ReservedShape4() {} 534 535 536// #pragma mark - BShape private methods 537 538 539void 540BShape::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 552void 553BShape::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((void*)data->ptList, ptList, ptCount * sizeof(BPoint)); 572 data->ptCount = ptCount; 573 } 574} 575 576 577void 578BShape::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 595inline bool 596BShape::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 614inline bool 615BShape::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((void*)data->ptList, 624 newSize * sizeof(BPoint)); 625 if (resizedArray) { 626 data->ptList = resizedArray; 627 data->ptSize = newSize; 628 return true; 629 } 630 return false; 631} 632 633 634// #pragma mark - BShape binary compatibility methods 635 636 637#if __GNUC__ < 3 638 639 640extern "C" BShape* 641__6BShapeR6BShape(void* self, BShape& copyFrom) 642{ 643 return new (self) BShape(copyFrom); 644 // we need to instantiate the object in the provided memory 645} 646 647 648extern "C" BRect 649Bounds__6BShape(BShape* self) 650{ 651 return self->Bounds(); 652} 653 654 655extern "C" void 656_ReservedShapeIterator1__14BShapeIterator(BShapeIterator* self) 657{ 658} 659 660 661#else // __GNUC__ < 3 662 663 664extern "C" void 665_ZN14BShapeIterator23_ReservedShapeIterator1Ev(BShapeIterator* self) 666{ 667} 668 669 670#endif // __GNUC__ >= 3 671