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