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