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