1 /* 2 * Copyright (c) 2001-2007, 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_CLOSE) { 66 IterateClose(); 67 } 68 } 69 70 return B_OK; 71 } 72 73 74 status_t 75 BShapeIterator::IterateBezierTo(int32 bezierCount, 76 BPoint *bezierPoints) 77 { 78 return B_OK; 79 } 80 81 82 status_t 83 BShapeIterator::IterateClose() 84 { 85 return B_OK; 86 } 87 88 89 status_t 90 BShapeIterator::IterateLineTo(int32 lineCount, BPoint *linePoints) 91 { 92 return B_OK; 93 } 94 95 96 status_t 97 BShapeIterator::IterateMoveTo ( BPoint *point ) 98 { 99 return B_OK; 100 } 101 102 103 void BShapeIterator::_ReservedShapeIterator1() {} 104 void BShapeIterator::_ReservedShapeIterator2() {} 105 void BShapeIterator::_ReservedShapeIterator3() {} 106 void BShapeIterator::_ReservedShapeIterator4() {} 107 108 109 BShape::BShape() 110 { 111 InitData(); 112 } 113 114 115 BShape::BShape(const BShape ©From) 116 { 117 InitData(); 118 AddShape(©From); 119 } 120 121 122 BShape::BShape(BMessage *archive) 123 : BArchivable(archive) 124 { 125 InitData(); 126 127 shape_data *data = (shape_data*)fPrivateData; 128 129 ssize_t size = 0; 130 int32 count = 0; 131 type_code type = 0; 132 archive->GetInfo("ops", &type, &count); 133 if (!AllocateOps(count)) 134 return; 135 136 int32 i = 0; 137 const uint32 *opPtr; 138 while (archive->FindData("ops", B_INT32_TYPE, i++, (const void **)&opPtr, &size) == B_OK) 139 data->opList[data->opCount++] = *opPtr; 140 141 archive->GetInfo("pts", &type, &count); 142 if (!AllocatePts(count)) { 143 Clear(); 144 return; 145 } 146 147 i = 0; 148 const BPoint *ptPtr; 149 while (archive->FindData("pts", B_POINT_TYPE, i++, (const void **)&ptPtr, &size) == B_OK) 150 data->ptList[data->ptCount++] = *ptPtr; 151 } 152 153 154 BShape::~BShape() 155 { 156 shape_data *data = (shape_data*)fPrivateData; 157 158 free(data->opList); 159 free(data->ptList); 160 161 delete (shape_data*)fPrivateData; 162 } 163 164 165 status_t 166 BShape::Archive(BMessage *archive, bool deep) const 167 { 168 status_t err = BArchivable::Archive(archive, deep); 169 170 if (err != B_OK) 171 return err; 172 173 shape_data *data = (shape_data*)fPrivateData; 174 175 // If no valid shape data, return 176 if (data->opCount == 0 || data->ptCount == 0) 177 return err; 178 179 // Avoids allocation for each point 180 err = archive->AddData("pts", B_POINT_TYPE, data->ptList, sizeof(BPoint), true, 181 data->ptCount); 182 if (err != B_OK) 183 return err; 184 185 for (int32 i = 1; i < data->ptCount && err == B_OK; i++) 186 err = archive->AddPoint("pts", data->ptList[i]); 187 188 // Avoids allocation for each op 189 if (err == B_OK) 190 err = archive->AddData("ops", B_INT32_TYPE, data->opList, sizeof(int32), true, 191 data->opCount); 192 193 for (int32 i = 1; i < data->opCount && err == B_OK ; i++) 194 err = archive->AddInt32("ops", data->opList[i]); 195 196 return err; 197 } 198 199 200 BArchivable* 201 BShape::Instantiate(BMessage *archive) 202 { 203 if (validate_instantiation(archive, "BShape")) 204 return new BShape(archive); 205 else 206 return NULL; 207 } 208 209 210 void 211 BShape::Clear() 212 { 213 shape_data *data = (shape_data*)fPrivateData; 214 215 data->opCount = 0; 216 data->opSize = 0; 217 if (data->opList) { 218 free(data->opList); 219 data->opList = NULL; 220 } 221 222 data->ptCount = 0; 223 data->ptSize = 0; 224 if (data->ptList) { 225 free(data->ptList); 226 data->ptList = NULL; 227 } 228 229 fState = 0; 230 fBuildingOp = 0; 231 } 232 233 234 BRect 235 BShape::Bounds() const 236 { 237 shape_data *data = (shape_data*)fPrivateData; 238 BRect bounds; 239 240 if (data->ptCount == 0) 241 return bounds; 242 243 bounds.left = data->ptList[0].x; 244 bounds.top = data->ptList[0].y; 245 bounds.right = data->ptList[0].x; 246 bounds.bottom = data->ptList[0].y; 247 248 for (int32 i = 1; i < data->ptCount; i++) 249 { 250 if (bounds.left > data->ptList[i].x) 251 bounds.left = data->ptList[i].x; 252 if (bounds.top > data->ptList[i].y) 253 bounds.top = data->ptList[i].y; 254 if (bounds.right < data->ptList[i].x) 255 bounds.right = data->ptList[i].x; 256 if (bounds.bottom < data->ptList[i].y) 257 bounds.bottom = data->ptList[i].y; 258 } 259 260 return bounds; 261 } 262 263 264 status_t 265 BShape::AddShape(const BShape *otherShape) 266 { 267 shape_data *data = (shape_data*)fPrivateData; 268 shape_data *otherData = (shape_data*)otherShape->fPrivateData; 269 270 if (!AllocateOps(otherData->opCount) || !AllocatePts(otherData->ptCount)) 271 return B_NO_MEMORY; 272 273 memcpy(data->opList + data->opCount * sizeof(uint32), otherData->opList, 274 otherData->opCount * sizeof(uint32)); 275 data->opCount += otherData->opCount; 276 277 memcpy(data->ptList + data->ptCount * sizeof(BPoint), otherData->ptList, 278 otherData->ptCount * sizeof(BPoint)); 279 data->ptCount += otherData->ptCount; 280 281 fBuildingOp = otherShape->fBuildingOp; 282 283 return B_OK; 284 } 285 286 287 status_t 288 BShape::MoveTo(BPoint point) 289 { 290 shape_data *data = (shape_data*)fPrivateData; 291 292 // If the last op is MoveTo, replace the point 293 if (fBuildingOp == OP_MOVETO) { 294 data->ptList[data->ptCount - 1] = point; 295 return B_OK; 296 } 297 298 if (!AllocateOps(1) || !AllocatePts(1)) 299 return B_NO_MEMORY; 300 301 fBuildingOp = OP_MOVETO; 302 303 // Add op 304 data->opList[data->opCount++] = fBuildingOp; 305 306 // Add point 307 data->ptList[data->ptCount++] = point; 308 309 return B_OK; 310 } 311 312 313 status_t 314 BShape::LineTo(BPoint point) 315 { 316 if (!AllocatePts(1)) 317 return B_NO_MEMORY; 318 319 shape_data *data = (shape_data*)fPrivateData; 320 321 // If the last op is MoveTo, replace the op and set the count 322 // If the last op is LineTo increase the count 323 // Otherwise add the op 324 if (fBuildingOp & OP_LINETO || fBuildingOp == OP_MOVETO) { 325 fBuildingOp |= OP_LINETO; 326 fBuildingOp += 1; 327 data->opList[data->opCount - 1] = fBuildingOp; 328 } else { 329 if (!AllocateOps(1)) 330 return B_NO_MEMORY; 331 fBuildingOp = OP_LINETO + 1; 332 data->opList[data->opCount++] = fBuildingOp; 333 } 334 335 // Add point 336 data->ptList[data->ptCount++] = point; 337 338 return B_OK; 339 } 340 341 342 status_t 343 BShape::BezierTo(BPoint controlPoints[3]) 344 { 345 if (!AllocatePts(3)) 346 return B_NO_MEMORY; 347 348 shape_data *data = (shape_data*)fPrivateData; 349 350 // If the last op is MoveTo, replace the op and set the count 351 // If the last op is BezierTo increase the count 352 // Otherwise add the op 353 if (fBuildingOp & OP_BEZIERTO || fBuildingOp == OP_MOVETO) { 354 fBuildingOp |= OP_BEZIERTO; 355 fBuildingOp += 3; 356 data->opList[data->opCount - 1] = fBuildingOp; 357 } else { 358 if (!AllocateOps(1)) 359 return B_NO_MEMORY; 360 fBuildingOp = OP_BEZIERTO + 3; 361 data->opList[data->opCount++] = fBuildingOp; 362 } 363 364 // Add points 365 data->ptList[data->ptCount++] = controlPoints[0]; 366 data->ptList[data->ptCount++] = controlPoints[1]; 367 data->ptList[data->ptCount++] = controlPoints[2]; 368 369 return B_OK; 370 } 371 372 373 status_t 374 BShape::Close() 375 { 376 // If the last op is Close or MoveTo, ignore this 377 if (fBuildingOp == OP_CLOSE || fBuildingOp == OP_MOVETO) 378 return B_OK; 379 380 if (!AllocateOps(1)) 381 return B_NO_MEMORY; 382 383 shape_data *data = (shape_data*)fPrivateData; 384 385 // ToDo: Decide about that, it's not BeOS compatible 386 // If there was any op before we can attach the close to it 387 /*if (fBuildingOp) { 388 fBuildingOp |= OP_CLOSE; 389 data->opList[data->opCount - 1] = fBuildingOp; 390 return B_OK; 391 }*/ 392 393 fBuildingOp = OP_CLOSE; 394 data->opList[data->opCount++] = fBuildingOp; 395 396 return B_OK; 397 } 398 399 400 status_t 401 BShape::Perform(perform_code d, void *arg) 402 { 403 return BArchivable::Perform(d, arg); 404 } 405 406 407 void BShape::_ReservedShape1() {} 408 void BShape::_ReservedShape2() {} 409 void BShape::_ReservedShape3() {} 410 void BShape::_ReservedShape4() {} 411 412 413 void 414 BShape::GetData(int32 *opCount, int32 *ptCount, uint32 **opList, 415 BPoint **ptList) 416 { 417 shape_data *data = (shape_data*)fPrivateData; 418 419 *opCount = data->opCount; 420 *ptCount = data->ptCount; 421 *opList = data->opList; 422 *ptList = data->ptList; 423 } 424 425 426 void 427 BShape::SetData(int32 opCount, int32 ptCount, const uint32 *opList, 428 const BPoint *ptList) 429 { 430 Clear(); 431 432 if (opCount == 0) 433 return; 434 435 shape_data *data = (shape_data*)fPrivateData; 436 437 if (!AllocateOps(opCount) || !AllocatePts(ptCount)) 438 return; 439 440 memcpy(data->opList, opList, opCount * sizeof(uint32)); 441 data->opCount = opCount; 442 fBuildingOp = data->opList[data->opCount - 1]; 443 444 if (ptCount > 0) { 445 memcpy(data->ptList, ptList, ptCount * sizeof(BPoint)); 446 data->ptCount = ptCount; 447 } 448 } 449 450 451 452 453 void 454 BShape::InitData() 455 { 456 fPrivateData = new shape_data; 457 shape_data *data = (shape_data*)fPrivateData; 458 459 fState = 0; 460 fBuildingOp = 0; 461 462 data->opList = NULL; 463 data->opCount = 0; 464 data->opSize = 0; 465 data->ptList = NULL; 466 data->ptCount = 0; 467 data->ptSize = 0; 468 } 469 470 471 inline bool 472 BShape::AllocateOps(int32 count) 473 { 474 shape_data *data = (shape_data*)fPrivateData; 475 476 int32 newSize = (data->opCount + count + 255) / 256 * 256; 477 if (data->opSize >= newSize) 478 return true; 479 480 uint32* resizedArray = (uint32*)realloc(data->opList, newSize * sizeof(uint32)); 481 if (resizedArray) { 482 data->opList = resizedArray; 483 data->opSize = newSize; 484 return true; 485 } 486 return false; 487 } 488 489 490 inline bool 491 BShape::AllocatePts(int32 count) 492 { 493 shape_data *data = (shape_data*)fPrivateData; 494 495 int32 newSize = (data->ptCount + count + 255) / 256 * 256; 496 if (data->ptSize >= newSize) 497 return true; 498 499 BPoint* resizedArray = (BPoint*)realloc(data->ptList, newSize * sizeof(BPoint)); 500 if (resizedArray) { 501 data->ptList = resizedArray; 502 data->ptSize = newSize; 503 return true; 504 } 505 return false; 506 } 507 508 509 // #pragma mark - R4.5 compatibility 510 511 512 #if __GNUC__ < 3 513 514 extern "C" BShape* 515 __6BShapeR6BShape(void* self, BShape& copyFrom) 516 { 517 return new (self) BShape(copyFrom); 518 // we need to instantiate the object in the provided memory 519 } 520 521 522 extern "C" BRect 523 Bounds__6BShape(BShape *self) 524 { 525 return self->Bounds(); 526 } 527 528 #endif // __GNUC__ < 3 529