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