1 /* 2 * Copyright (c) 2001-2005, 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 * 9 * Description: 10 * BShape encapsulates a Postscript-style "path" 11 */ 12 13 #include <stdlib.h> 14 15 16 #include <Shape.h> 17 #include <Point.h> 18 #include <Rect.h> 19 #include <Errors.h> 20 #include <Message.h> 21 22 23 // NOTE: changing these defines will break Painter, 24 // currently located in src/servers/app/drawing/Painter/Painter.cpp 25 #define OP_LINETO 0x10000000 26 #define OP_BEZIERTO 0x20000000 27 #define OP_CLOSE 0x40000000 28 #define OP_MOVETO 0x80000000 29 30 31 struct shape_data { 32 uint32 *opList; 33 int32 opCount; 34 int32 opSize; 35 int32 opBlockSize; 36 BPoint *ptList; 37 int32 ptCount; 38 int32 ptSize; 39 int32 ptBlockSize; 40 }; 41 42 43 BShapeIterator::BShapeIterator() 44 { 45 } 46 47 48 BShapeIterator::~BShapeIterator() 49 { 50 } 51 52 53 status_t 54 BShapeIterator::Iterate(BShape *shape) 55 { 56 shape_data *data = (shape_data*)shape->fPrivateData; 57 BPoint *points = data->ptList; 58 59 for (int32 i = 0; i < data->opCount; i++) { 60 switch (data->opList[i] & 0xFF000000) { 61 case OP_LINETO: { 62 int32 count = data->opList[i] & 0x00FFFFFF; 63 IterateLineTo(count, points); 64 points += count; 65 break; 66 } 67 case (OP_MOVETO | OP_LINETO): { 68 int32 count = data->opList[i] & 0x00FFFFFF; 69 IterateMoveTo(points); 70 points++; 71 IterateLineTo(count, points); 72 points += count; 73 break; 74 } 75 case OP_BEZIERTO: { 76 int32 count = data->opList[i] & 0x00FFFFFF; 77 IterateBezierTo(count, points); 78 points += count; 79 break; 80 } 81 case (OP_MOVETO | OP_BEZIERTO): { 82 int32 count = data->opList[i] & 0x00FFFFFF; 83 IterateMoveTo(points); 84 points++; 85 IterateBezierTo(count, points); 86 points += count; 87 break; 88 } 89 case OP_CLOSE: 90 case OP_CLOSE | OP_LINETO | OP_BEZIERTO: { 91 IterateClose(); 92 break; 93 } 94 } 95 } 96 97 return B_OK; 98 } 99 100 101 status_t 102 BShapeIterator::IterateBezierTo(int32 bezierCount, 103 BPoint *bezierPoints) 104 { 105 return B_OK; 106 } 107 108 109 status_t 110 BShapeIterator::IterateClose() 111 { 112 return B_OK; 113 } 114 115 116 status_t 117 BShapeIterator::IterateLineTo(int32 lineCount, BPoint *linePoints) 118 { 119 return B_OK; 120 } 121 122 123 status_t 124 BShapeIterator::IterateMoveTo ( BPoint *point ) 125 { 126 return B_OK; 127 } 128 129 130 void BShapeIterator::_ReservedShapeIterator1() {} 131 void BShapeIterator::_ReservedShapeIterator2() {} 132 void BShapeIterator::_ReservedShapeIterator3() {} 133 void BShapeIterator::_ReservedShapeIterator4() {} 134 135 136 BShape::BShape() 137 { 138 InitData(); 139 } 140 141 142 BShape::BShape(const BShape ©From) 143 { 144 InitData(); 145 AddShape(©From); 146 } 147 148 149 BShape::BShape(BMessage *archive) 150 : BArchivable(archive) 151 { 152 InitData(); 153 154 shape_data *data = (shape_data*)fPrivateData; 155 ssize_t size; 156 int32 i = 0; 157 158 const uint32 *opPtr; 159 160 while (archive->FindData("ops", B_INT32_TYPE, i++, (const void**)&opPtr, &size) == B_OK) { 161 if (data->opSize < data->opCount + 1) { 162 int32 new_size = ((data->opCount + data->opBlockSize) / 163 data->opBlockSize) * data->opBlockSize; 164 data->opList = (uint32*)realloc(data->opList, new_size * sizeof(uint32)); 165 data->opSize = new_size; 166 } 167 168 data->opList[data->opCount++] = *opPtr; 169 } 170 171 const BPoint *ptPtr; 172 173 while (archive->FindData("pts", B_POINT_TYPE, i++, (const void**)&ptPtr, &size) == B_OK) { 174 if (data->ptSize < data->ptCount + 1) { 175 int32 new_size = ((data->ptCount + data->ptBlockSize) / 176 data->ptBlockSize) * data->ptBlockSize; 177 data->ptList = (BPoint*)realloc(data->ptList, 178 new_size * sizeof(BPoint)); 179 data->ptSize = new_size; 180 } 181 182 data->ptList[data->ptCount++] = *ptPtr; 183 } 184 } 185 186 187 BShape::~BShape() 188 { 189 shape_data *data = (shape_data*)fPrivateData; 190 191 free(data->opList); 192 free(data->ptList); 193 194 delete (shape_data*)fPrivateData; 195 } 196 197 198 status_t 199 BShape::Archive(BMessage *archive, bool deep) const 200 { 201 status_t err = BArchivable::Archive(archive, deep); 202 int32 i; 203 204 if (err != B_OK) 205 return err; 206 207 shape_data *data = (shape_data*)fPrivateData; 208 209 // If no valid shape data, return 210 if (data->opCount == 0 || data->ptCount == 0) 211 return err; 212 213 // Avoids allocation for each point 214 archive->AddData("pts", B_POINT_TYPE, data->ptList, sizeof(BPoint), true, 215 data->ptCount); 216 217 for (i = 1; i < data->ptCount; i++) 218 archive->AddPoint("pts", data->ptList[i]); 219 220 // Avoids allocation for each op 221 archive->AddData("ops", B_INT32_TYPE, data->opList, sizeof(int32), true, 222 data->opCount); 223 224 for (i = 1; i < data->opCount; i++) 225 archive->AddInt32("ops", data->opList[i]); 226 227 archive->AddInt32("ops", fBuildingOp); 228 229 return err; 230 } 231 232 233 BArchivable* 234 BShape::Instantiate(BMessage *archive) 235 { 236 if (validate_instantiation(archive, "BShape")) 237 return new BShape(archive); 238 else 239 return NULL; 240 } 241 242 243 void 244 BShape::Clear() 245 { 246 shape_data *data = (shape_data*)fPrivateData; 247 248 if (data->opList) { 249 free(data->opList); 250 data->opList = NULL; 251 data->opCount = 0; 252 data->opSize = 0; 253 } 254 255 if (data->ptList) { 256 free(data->ptList); 257 data->ptList = NULL; 258 data->ptCount = 0; 259 data->ptSize = 0; 260 } 261 262 fState = 0; 263 fBuildingOp = 0; 264 } 265 266 267 BRect 268 BShape::Bounds() const 269 { 270 shape_data *data = (shape_data*)fPrivateData; 271 BRect bounds; 272 273 if (data->ptCount == 0) 274 return bounds; 275 276 bounds.left = data->ptList[0].x; 277 bounds.top = data->ptList[0].y; 278 bounds.right = data->ptList[0].x; 279 bounds.bottom = data->ptList[0].y; 280 281 for (int32 i = 1; i < data->ptCount; i++) 282 { 283 if (bounds.left > data->ptList[0].x) 284 bounds.left = data->ptList[0].x; 285 if (bounds.top > data->ptList[0].y) 286 bounds.top = data->ptList[0].y; 287 if (bounds.right < data->ptList[0].x) 288 bounds.right = data->ptList[0].x; 289 if (bounds.bottom < data->ptList[0].y) 290 bounds.bottom = data->ptList[0].y; 291 } 292 293 return bounds; 294 } 295 296 297 status_t 298 BShape::AddShape(const BShape *otherShape) 299 { 300 shape_data *data = (shape_data*)fPrivateData; 301 shape_data *otherData = (shape_data*)otherShape->fPrivateData; 302 303 if (data->opSize < data->opCount + otherData->opCount) 304 { 305 int32 new_size = ((data->opCount + otherData->opBlockSize) / 306 data->opBlockSize) * data->opBlockSize; 307 data->opList = (uint32*)realloc(data->opList, new_size * sizeof(uint32)); 308 data->opSize = new_size; 309 } 310 311 memcpy(data->opList + data->opCount * sizeof(uint32), otherData->opList, 312 otherData->opCount * sizeof(uint32)); 313 data->opCount += otherData->opCount; 314 315 if (data->ptSize < data->ptCount + otherData->ptCount) 316 { 317 int32 new_size = ((data->ptCount + otherData->ptBlockSize) / 318 data->ptBlockSize) * data->ptBlockSize; 319 data->ptList = (BPoint*)realloc(data->ptList, new_size * sizeof(uint32)); 320 data->ptSize = new_size; 321 } 322 323 memcpy(data->ptList + data->ptCount * sizeof(BPoint), otherData->ptList, 324 otherData->ptCount * sizeof(BPoint)); 325 data->ptCount += otherData->ptCount; 326 327 fBuildingOp = otherShape->fBuildingOp; 328 329 return B_OK; 330 } 331 332 333 status_t 334 BShape::MoveTo(BPoint point) 335 { 336 shape_data *data = (shape_data*)fPrivateData; 337 338 // If the last op is MoveTo, replace the point 339 // If there was a previous op, add the op 340 if (fBuildingOp == OP_MOVETO) { 341 data->ptList[data->ptCount - 1] = point; 342 343 return B_OK; 344 } 345 346 // BuildingOp is MoveTo 347 fBuildingOp = OP_MOVETO; 348 349 // Add point 350 if (data->ptSize < data->ptCount + 1) { 351 int32 new_size = ((data->ptCount + data->ptBlockSize) / 352 data->ptBlockSize) * data->ptBlockSize; 353 data->ptList = (BPoint*)realloc(data->ptList, new_size * sizeof(BPoint)); 354 data->ptSize = new_size; 355 } 356 357 data->ptList[data->ptCount++] = point; 358 359 return B_OK; 360 } 361 362 363 status_t 364 BShape::LineTo(BPoint point) 365 { 366 shape_data *data = (shape_data*)fPrivateData; 367 368 // If the last op is MoveTo, replace the op and set the count 369 // If the last op is LineTo increase the count 370 // If there was a previous op, add the op 371 bool newOp = true; 372 if (fBuildingOp == OP_MOVETO) { 373 fBuildingOp = OP_LINETO | OP_MOVETO; 374 } else if (fBuildingOp & OP_LINETO) { 375 newOp = false; 376 } else { 377 fBuildingOp = OP_LINETO; 378 } 379 fBuildingOp++; 380 381 if (newOp) { 382 if (data->opSize < data->opCount + 1) { 383 int32 new_size = ((data->opCount + data->opBlockSize) / 384 data->opBlockSize) * data->opBlockSize; 385 data->opList = (uint32*)realloc(data->opList, new_size * sizeof(uint32)); 386 data->opSize = new_size; 387 } 388 data->opCount++; 389 } 390 data->opList[data->opCount - 1] = fBuildingOp; 391 392 // Add point 393 if (data->ptSize < data->ptCount + 1) { 394 int32 new_size = ((data->ptCount + data->ptBlockSize) / 395 data->ptBlockSize) * data->ptBlockSize; 396 data->ptList = (BPoint*)realloc(data->ptList, new_size * sizeof(BPoint)); 397 data->ptSize = new_size; 398 } 399 400 data->ptList[data->ptCount++] = point; 401 402 return B_OK; 403 } 404 405 406 status_t 407 BShape::BezierTo(BPoint controlPoints[3]) 408 { 409 shape_data *data = (shape_data*)fPrivateData; 410 411 // If the last op is MoveTo, replace the op and set the count 412 // If the last op is BezierTo increase the count 413 // If there was a previous op, add the op 414 bool newOp = true; 415 if (fBuildingOp == OP_MOVETO) { 416 fBuildingOp = OP_BEZIERTO | OP_MOVETO; 417 } else if (fBuildingOp & OP_BEZIERTO) { 418 newOp = false; 419 } else { 420 fBuildingOp = OP_BEZIERTO; 421 } 422 fBuildingOp += 3; 423 424 if (newOp) { 425 if (data->opSize < data->opCount + 1) { 426 int32 new_size = ((data->opCount + data->opBlockSize) / 427 data->opBlockSize) * data->opBlockSize; 428 data->opList = (uint32*)realloc(data->opList, new_size * sizeof(uint32)); 429 data->opSize = new_size; 430 } 431 data->opCount++; 432 } 433 data->opList[data->opCount - 1] = fBuildingOp; 434 435 436 // Add points 437 if (data->ptSize < data->ptCount + 3) 438 { 439 int32 new_size = ((data->ptCount + data->ptBlockSize) / 440 data->ptBlockSize) * data->ptBlockSize; 441 data->ptList = (BPoint*)realloc(data->ptList, new_size * sizeof(BPoint)); 442 data->ptSize = new_size; 443 } 444 445 data->ptList[data->ptCount++] = controlPoints[0]; 446 data->ptList[data->ptCount++] = controlPoints[1]; 447 data->ptList[data->ptCount++] = controlPoints[2]; 448 449 return B_OK; 450 } 451 452 453 status_t 454 BShape::Close() 455 { 456 shape_data *data = (shape_data*)fPrivateData; 457 458 // If there was a previous line/bezier op, add the op 459 if (fBuildingOp & (OP_LINETO | OP_BEZIERTO)) { 460 if (data->opSize < data->opCount + 1) { 461 int32 new_size = ((data->opCount + data->opBlockSize) / 462 data->opBlockSize) * data->opBlockSize; 463 data->opList = (uint32*)realloc(data->opList, new_size * sizeof(uint32)); 464 data->opSize = new_size; 465 } 466 467 data->opList[data->opCount++] = fBuildingOp; 468 fBuildingOp = OP_CLOSE; 469 } 470 471 return B_OK; 472 } 473 474 475 status_t 476 BShape::Perform(perform_code d, void *arg) 477 { 478 return BArchivable::Perform(d, arg); 479 } 480 481 482 void BShape::_ReservedShape1() {} 483 void BShape::_ReservedShape2() {} 484 void BShape::_ReservedShape3() {} 485 void BShape::_ReservedShape4() {} 486 487 488 void 489 BShape::GetData(int32 *opCount, int32 *ptCount, uint32 **opList, 490 BPoint **ptList) 491 { 492 shape_data *data = (shape_data*)fPrivateData; 493 494 *opCount = data->opCount; 495 *ptCount = data->ptCount; 496 *opList = data->opList; 497 *ptList = data->ptList; 498 } 499 500 501 void 502 BShape::SetData(int32 opCount, int32 ptCount, uint32 *opList, 503 BPoint *ptList) 504 { 505 shape_data *data = (shape_data*)fPrivateData; 506 507 if (data->opSize < opCount) { 508 int32 new_size = ((opCount + data->opBlockSize) / 509 data->opBlockSize) * data->opBlockSize; 510 511 data->opList = (uint32*)realloc(data->opList, new_size * sizeof(uint32)); 512 data->opSize = new_size; 513 } 514 515 memcpy(data->opList, opList, opCount * sizeof(uint32)); 516 data->opCount = opCount; 517 518 if (data->ptSize < ptCount) { 519 int32 new_size = ((ptCount + data->ptBlockSize) / 520 data->ptBlockSize) * data->ptBlockSize; 521 522 data->ptList = (BPoint*)realloc(data->ptList, new_size * sizeof(BPoint)); 523 data->ptSize = new_size; 524 } 525 526 memcpy(data->ptList, ptList, ptCount * sizeof(BPoint)); 527 data->ptCount = ptCount; 528 } 529 530 531 void 532 BShape::InitData() 533 { 534 fPrivateData = new shape_data; 535 shape_data *data = (shape_data*)fPrivateData; 536 537 fState = 0; 538 fBuildingOp = 0; 539 540 data->opList = NULL; 541 data->opCount = 0; 542 data->opSize = 0; 543 data->opBlockSize = 255; 544 data->ptList = NULL; 545 data->ptCount = 0; 546 data->ptSize = 0; 547 data->ptBlockSize = 255; 548 } 549 550 551 // #pragma mark - 552 // R4.5 compatibility 553 554 555 #if __GNUC__ < 3 556 557 extern "C" BRect 558 Bounds__6BShape(BShape *self) 559 { 560 return self->Bounds(); 561 } 562 563 // ToDo: Add those: 564 // BShape(BShape ©From); 565 // status_t AddShape(BShape *other); 566 567 #endif // __GNUC__ < 3 568