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