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