1 /* 2 * Copyright 2006-2009, Haiku Inc. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Stefano Ceccherini (stefano.ceccherini@gmail.com) 7 */ 8 9 #include <PictureDataWriter.h> 10 11 #include <stdio.h> 12 #include <string.h> 13 14 #include <DataIO.h> 15 #include <Point.h> 16 #include <Rect.h> 17 #include <Region.h> 18 19 #include <PictureProtocol.h> 20 21 #define THROW_ERROR(error) throw (status_t)(error) 22 23 // TODO: Review writing of strings. AFAIK in the picture data format 24 // They are not supposed to be NULL terminated 25 // (at least, it's not mandatory) so we should write their size too. 26 PictureDataWriter::PictureDataWriter() 27 : 28 fData(NULL) 29 { 30 } 31 32 33 PictureDataWriter::PictureDataWriter(BPositionIO *data) 34 : 35 fData(data) 36 { 37 } 38 39 40 PictureDataWriter::~PictureDataWriter() 41 { 42 } 43 44 45 status_t 46 PictureDataWriter::SetTo(BPositionIO *data) 47 { 48 if (data == NULL) 49 return B_BAD_VALUE; 50 fData = data; 51 return B_OK; 52 } 53 54 55 status_t 56 PictureDataWriter::WriteSetOrigin(const BPoint &point) 57 { 58 try { 59 BeginOp(B_PIC_SET_ORIGIN); 60 Write<BPoint>(point); 61 EndOp(); 62 } catch (status_t &status) { 63 return status; 64 } 65 return B_OK; 66 } 67 68 69 status_t 70 PictureDataWriter::WriteInvertRect(const BRect &rect) 71 { 72 try { 73 WriteSetDrawingMode(B_OP_INVERT); 74 75 BeginOp(B_PIC_FILL_RECT); 76 Write<BRect>(rect); 77 EndOp(); 78 79 WriteSetDrawingMode(B_OP_COPY); 80 } catch (status_t &status) { 81 return status; 82 } 83 return B_OK; 84 } 85 86 87 status_t 88 PictureDataWriter::WriteSetDrawingMode(const drawing_mode &mode) 89 { 90 try { 91 BeginOp(B_PIC_SET_DRAWING_MODE); 92 Write<int16>((int16)mode); 93 EndOp(); 94 } catch (status_t &status) { 95 return status; 96 } 97 return B_OK; 98 } 99 100 101 status_t 102 PictureDataWriter::WriteSetPenLocation(const BPoint &point) 103 { 104 try { 105 BeginOp(B_PIC_SET_PEN_LOCATION); 106 Write<BPoint>(point); 107 EndOp(); 108 } catch (status_t &status) { 109 return status; 110 } 111 return B_OK; 112 } 113 114 115 status_t 116 PictureDataWriter::WriteSetPenSize(const float &penSize) 117 { 118 try { 119 BeginOp(B_PIC_SET_PEN_SIZE); 120 Write<float>(penSize); 121 EndOp(); 122 } catch (status_t &status) { 123 return status; 124 } 125 return B_OK; 126 } 127 128 129 status_t 130 PictureDataWriter::WriteSetLineMode(const cap_mode &cap, 131 const join_mode &join, const float &miterLimit) 132 { 133 try { 134 BeginOp(B_PIC_SET_LINE_MODE); 135 Write<int16>((int16)cap); 136 Write<int16>((int16)join); 137 Write<float>(miterLimit); 138 EndOp(); 139 } catch (status_t &status) { 140 return status; 141 } 142 return B_OK; 143 } 144 145 146 status_t 147 PictureDataWriter::WriteSetScale(const float &scale) 148 { 149 try { 150 BeginOp(B_PIC_SET_SCALE); 151 Write<float>(scale); 152 EndOp(); 153 } catch (status_t &status) { 154 return status; 155 } 156 return B_OK; 157 } 158 159 160 status_t 161 PictureDataWriter::WriteSetPattern(const pattern &pat) 162 { 163 try { 164 BeginOp(B_PIC_SET_STIPLE_PATTERN); 165 Write<pattern>(pat); 166 EndOp(); 167 } catch (status_t &status) { 168 return status; 169 } 170 return B_OK; 171 } 172 173 174 status_t 175 PictureDataWriter::WriteSetClipping(const BRegion ®ion) 176 { 177 // TODO: I don't know if it's compatible with R5's BPicture version 178 try { 179 const int32 numRects = region.CountRects(); 180 if (numRects > 0 && region.Frame().IsValid()) { 181 BeginOp(B_PIC_SET_CLIPPING_RECTS); 182 Write<uint32>(numRects); 183 for (int32 i = 0; i < numRects; i++) { 184 Write<BRect>(region.RectAt(i)); 185 } 186 EndOp(); 187 } else 188 WriteClearClipping(); 189 } catch (status_t &status) { 190 return status; 191 } 192 193 return B_OK; 194 } 195 196 197 status_t 198 PictureDataWriter::WriteClearClipping() 199 { 200 try { 201 BeginOp(B_PIC_CLEAR_CLIPPING_RECTS); 202 EndOp(); 203 } catch (status_t &status) { 204 return status; 205 } 206 return B_OK; 207 } 208 209 210 status_t 211 PictureDataWriter::WriteSetHighColor(const rgb_color &color) 212 { 213 try { 214 BeginOp(B_PIC_SET_FORE_COLOR); 215 Write<rgb_color>(color); 216 EndOp(); 217 } catch (status_t &status) { 218 return status; 219 } 220 return B_OK; 221 } 222 223 224 status_t 225 PictureDataWriter::WriteSetLowColor(const rgb_color &color) 226 { 227 try { 228 BeginOp(B_PIC_SET_BACK_COLOR); 229 Write<rgb_color>(color); 230 EndOp(); 231 } catch (status_t &status) { 232 return status; 233 } 234 return B_OK; 235 } 236 237 238 status_t 239 PictureDataWriter::WriteDrawRect(const BRect &rect, 240 const bool &fill) 241 { 242 try { 243 BeginOp(fill ? B_PIC_FILL_RECT : B_PIC_STROKE_RECT); 244 Write<BRect>(rect); 245 EndOp(); 246 } catch (status_t &status) { 247 return status; 248 } 249 return B_OK; 250 } 251 252 253 status_t 254 PictureDataWriter::WriteDrawRoundRect(const BRect &rect, 255 const BPoint &radius, const bool &fill) 256 { 257 try { 258 BeginOp(fill ? B_PIC_FILL_ROUND_RECT : B_PIC_STROKE_ROUND_RECT); 259 Write<BRect>(rect); 260 Write<BPoint>(radius); 261 EndOp(); 262 } catch (status_t &status) { 263 return status; 264 } 265 return B_OK; 266 } 267 268 269 status_t 270 PictureDataWriter::WriteDrawEllipse(const BRect &rect, const bool &fill) 271 { 272 try { 273 BeginOp(fill ? B_PIC_FILL_ELLIPSE : B_PIC_STROKE_ELLIPSE); 274 Write<BRect>(rect); 275 EndOp(); 276 } catch (status_t &status) { 277 return status; 278 } 279 return B_OK; 280 } 281 282 283 status_t 284 PictureDataWriter::WriteDrawArc(const BPoint ¢er, 285 const BPoint &radius, const float &startTheta, 286 const float &arcTheta, const bool &fill) 287 { 288 try { 289 BeginOp(fill ? B_PIC_FILL_ARC : B_PIC_STROKE_ARC); 290 Write<BPoint>(center); 291 Write<BPoint>(radius); 292 Write<float>(startTheta); 293 Write<float>(arcTheta); 294 EndOp(); 295 } catch (status_t &status) { 296 return status; 297 } 298 return B_OK; 299 } 300 301 302 status_t 303 PictureDataWriter::WriteDrawPolygon(const int32 &numPoints, 304 BPoint *points, const bool &isClosed, const bool &fill) 305 { 306 try { 307 BeginOp(fill ? B_PIC_FILL_POLYGON : B_PIC_STROKE_POLYGON); 308 Write<int32>(numPoints); 309 for (int32 i = 0; i < numPoints; i++) 310 Write<BPoint>(points[i]); 311 if (!fill) 312 Write<uint8>((uint8)isClosed); 313 EndOp(); 314 } catch (status_t &status) { 315 return status; 316 } 317 return B_OK; 318 } 319 320 321 status_t 322 PictureDataWriter::WriteDrawBezier(const BPoint points[4], 323 const bool &fill) 324 { 325 try { 326 BeginOp(fill ? B_PIC_FILL_BEZIER : B_PIC_STROKE_BEZIER); 327 for (int32 i = 0; i < 4; i++) 328 Write<BPoint>(points[i]); 329 EndOp(); 330 } catch (status_t &status) { 331 return status; 332 } 333 return B_OK; 334 } 335 336 337 status_t 338 PictureDataWriter::WriteStrokeLine(const BPoint &start, 339 const BPoint &end) 340 { 341 try { 342 BeginOp(B_PIC_STROKE_LINE); 343 Write<BPoint>(start); 344 Write<BPoint>(end); 345 EndOp(); 346 } catch (status_t &status) { 347 return status; 348 } 349 return B_OK; 350 } 351 352 353 status_t 354 PictureDataWriter::WriteDrawString(const BPoint &where, 355 const char *string, const int32 &length, 356 const escapement_delta &escapement) 357 { 358 try { 359 BeginOp(B_PIC_SET_PEN_LOCATION); 360 Write<BPoint>(where); 361 EndOp(); 362 363 BeginOp(B_PIC_DRAW_STRING); 364 Write<float>(escapement.space); 365 Write<float>(escapement.nonspace); 366 //WriteData(string, length + 1); 367 // TODO: is string 0 terminated? why is length given? 368 WriteData(string, length); 369 Write<uint8>(0); 370 EndOp(); 371 } catch (status_t &status) { 372 return status; 373 } 374 375 return B_OK; 376 } 377 378 379 status_t 380 PictureDataWriter::WriteDrawShape(const int32 &opCount, 381 const void *opList, const int32 &ptCount, const void *ptList, 382 const bool &fill) 383 { 384 try { 385 BeginOp(fill ? B_PIC_FILL_SHAPE : B_PIC_STROKE_SHAPE); 386 Write<int32>(opCount); 387 Write<int32>(ptCount); 388 WriteData(opList, opCount * sizeof(uint32)); 389 WriteData(ptList, ptCount * sizeof(BPoint)); 390 EndOp(); 391 } catch (status_t &status) { 392 return status; 393 } 394 395 return B_OK; 396 } 397 398 399 status_t 400 PictureDataWriter::WriteDrawBitmap(const BRect &srcRect, 401 const BRect &dstRect, const int32 &width, const int32 &height, 402 const int32 &bytesPerRow, const int32 &colorSpace, 403 const int32 &flags, const void *data, const int32 &length) 404 { 405 if (length != height * bytesPerRow) 406 debugger("PictureDataWriter::WriteDrawBitmap: invalid length"); 407 try { 408 BeginOp(B_PIC_DRAW_PIXELS); 409 Write<BRect>(srcRect); 410 Write<BRect>(dstRect); 411 Write<int32>(width); 412 Write<int32>(height); 413 Write<int32>(bytesPerRow); 414 Write<int32>(colorSpace); 415 Write<int32>(flags); 416 WriteData(data, length); 417 EndOp(); 418 } catch (status_t &status) { 419 return status; 420 } 421 return B_OK; 422 } 423 424 425 status_t 426 PictureDataWriter::WriteDrawPicture(const BPoint &where, 427 const int32 &token) 428 { 429 // TODO: I'm not sure about this function. I think we need 430 // to attach the picture data too. 431 // The token won't be sufficient in many cases (for example, when 432 // we archive/flatten the picture. 433 try { 434 BeginOp(B_PIC_DRAW_PICTURE); 435 Write<BPoint>(where); 436 Write<int32>(token); 437 EndOp(); 438 } catch (status_t &status) { 439 return status; 440 } 441 return B_OK; 442 } 443 444 445 status_t 446 PictureDataWriter::WriteSetFontFamily(const font_family family) 447 { 448 try { 449 BeginOp(B_PIC_SET_FONT_FAMILY); 450 WriteData(family, strlen(family)); 451 Write<uint8>(0); 452 EndOp(); 453 } catch (status_t &status) { 454 return status; 455 } 456 return B_OK; 457 } 458 459 460 status_t 461 PictureDataWriter::WriteSetFontStyle(const font_style style) 462 { 463 try { 464 BeginOp(B_PIC_SET_FONT_STYLE); 465 WriteData(style, strlen(style)); 466 Write<uint8>(0); 467 EndOp(); 468 } catch (status_t &status) { 469 return status; 470 } 471 return B_OK; 472 } 473 474 475 status_t 476 PictureDataWriter::WriteSetFontSpacing(const int32 &spacing) 477 { 478 try { 479 BeginOp(B_PIC_SET_FONT_SPACING); 480 Write<int32>(spacing); 481 EndOp(); 482 } catch (status_t &status) { 483 return status; 484 } 485 return B_OK; 486 } 487 488 489 status_t 490 PictureDataWriter::WriteSetFontSize(const float &size) 491 { 492 try { 493 BeginOp(B_PIC_SET_FONT_SIZE); 494 Write<float>(size); 495 EndOp(); 496 } catch (status_t &status) { 497 return status; 498 } 499 return B_OK; 500 } 501 502 503 status_t 504 PictureDataWriter::WriteSetFontRotation(const float &rotation) 505 { 506 try { 507 BeginOp(B_PIC_SET_FONT_ROTATE); 508 Write<float>(rotation); 509 EndOp(); 510 } catch (status_t &status) { 511 return status; 512 } 513 return B_OK; 514 } 515 516 517 status_t 518 PictureDataWriter::WriteSetFontEncoding(const int32 &encoding) 519 { 520 try { 521 BeginOp(B_PIC_SET_FONT_ENCODING); 522 Write<int32>(encoding); 523 EndOp(); 524 } catch (status_t &status) { 525 return status; 526 } 527 return B_OK; 528 } 529 530 531 status_t 532 PictureDataWriter::WriteSetFontFlags(const int32 &flags) 533 { 534 try { 535 BeginOp(B_PIC_SET_FONT_FLAGS); 536 Write<int32>(flags); 537 EndOp(); 538 } catch (status_t &status) { 539 return status; 540 } 541 return B_OK; 542 } 543 544 545 status_t 546 PictureDataWriter::WriteSetFontShear(const float &shear) 547 { 548 try { 549 BeginOp(B_PIC_SET_FONT_SHEAR); 550 Write<float>(shear); 551 EndOp(); 552 } catch (status_t &status) { 553 return status; 554 } 555 return B_OK; 556 } 557 558 559 status_t 560 PictureDataWriter::WriteSetFontFace(const int32 &face) 561 { 562 try { 563 BeginOp(B_PIC_SET_FONT_FACE); 564 Write<int32>(face); 565 EndOp(); 566 } catch (status_t &status) { 567 return status; 568 } 569 return B_OK; 570 } 571 572 573 status_t 574 PictureDataWriter::WritePushState() 575 { 576 try { 577 BeginOp(B_PIC_PUSH_STATE); 578 EndOp(); 579 } catch (status_t &status) { 580 return status; 581 } 582 return B_OK; 583 } 584 585 586 status_t 587 PictureDataWriter::WritePopState() 588 { 589 try { 590 BeginOp(B_PIC_POP_STATE); 591 EndOp(); 592 } catch (status_t &status) { 593 return status; 594 } 595 return B_OK; 596 } 597 598 599 // private 600 void 601 PictureDataWriter::BeginOp(const int16 &op) 602 { 603 if (fData == NULL) 604 THROW_ERROR(B_NO_INIT); 605 606 fStack.push(fData->Position()); 607 fData->Write(&op, sizeof(op)); 608 609 // Init the size of the opcode block to 0 610 size_t size = 0; 611 fData->Write(&size, sizeof(size)); 612 } 613 614 615 void 616 PictureDataWriter::EndOp() 617 { 618 if (fData == NULL) 619 THROW_ERROR(B_NO_INIT); 620 621 off_t curPos = fData->Position(); 622 off_t stackPos = fStack.top(); 623 fStack.pop(); 624 625 // The size of the op is calculated like this: 626 // current position on the stream minus the position on the stack, 627 // minus the space occupied by the op code itself (int16) 628 // and the space occupied by the size field (size_t) 629 size_t size = curPos - stackPos - sizeof(size_t) - sizeof(int16); 630 631 // Size was set to 0 in BeginOp() 632 // Now we overwrite it with the correct value 633 fData->Seek(stackPos + sizeof(int16), SEEK_SET); 634 fData->Write(&size, sizeof(size)); 635 fData->Seek(curPos, SEEK_SET); 636 } 637 638 639 void 640 PictureDataWriter::WriteData(const void *data, size_t size) 641 { 642 ssize_t result = fData->Write(data, size); 643 if (result < 0) 644 THROW_ERROR(result); 645 if ((size_t)result != size) 646 THROW_ERROR(B_IO_ERROR); 647 } 648