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