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