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::WriteSetTransform(BAffineTransform transform) 162 { 163 try { 164 BeginOp(B_PIC_SET_TRANSFORM); 165 Write<BAffineTransform>(transform); 166 EndOp(); 167 } catch (status_t &status) { 168 return status; 169 } 170 return B_OK; 171 } 172 173 174 status_t 175 PictureDataWriter::WriteSetPattern(const pattern &pat) 176 { 177 try { 178 BeginOp(B_PIC_SET_STIPLE_PATTERN); 179 Write<pattern>(pat); 180 EndOp(); 181 } catch (status_t &status) { 182 return status; 183 } 184 return B_OK; 185 } 186 187 188 status_t 189 PictureDataWriter::WriteSetClipping(const BRegion ®ion) 190 { 191 // TODO: I don't know if it's compatible with R5's BPicture version 192 try { 193 const int32 numRects = region.CountRects(); 194 if (numRects > 0 && region.Frame().IsValid()) { 195 BeginOp(B_PIC_SET_CLIPPING_RECTS); 196 Write<uint32>(numRects); 197 for (int32 i = 0; i < numRects; i++) { 198 Write<BRect>(region.RectAt(i)); 199 } 200 EndOp(); 201 } else 202 WriteClearClipping(); 203 } catch (status_t &status) { 204 return status; 205 } 206 207 return B_OK; 208 } 209 210 211 status_t 212 PictureDataWriter::WriteClearClipping() 213 { 214 try { 215 BeginOp(B_PIC_CLEAR_CLIPPING_RECTS); 216 EndOp(); 217 } catch (status_t &status) { 218 return status; 219 } 220 return B_OK; 221 } 222 223 224 status_t 225 PictureDataWriter::WriteSetHighColor(const rgb_color &color) 226 { 227 try { 228 BeginOp(B_PIC_SET_FORE_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::WriteSetLowColor(const rgb_color &color) 240 { 241 try { 242 BeginOp(B_PIC_SET_BACK_COLOR); 243 Write<rgb_color>(color); 244 EndOp(); 245 } catch (status_t &status) { 246 return status; 247 } 248 return B_OK; 249 } 250 251 252 status_t 253 PictureDataWriter::WriteDrawRect(const BRect &rect, 254 const bool &fill) 255 { 256 try { 257 BeginOp(fill ? B_PIC_FILL_RECT : B_PIC_STROKE_RECT); 258 Write<BRect>(rect); 259 EndOp(); 260 } catch (status_t &status) { 261 return status; 262 } 263 return B_OK; 264 } 265 266 267 status_t 268 PictureDataWriter::WriteDrawRoundRect(const BRect &rect, 269 const BPoint &radius, const bool &fill) 270 { 271 try { 272 BeginOp(fill ? B_PIC_FILL_ROUND_RECT : B_PIC_STROKE_ROUND_RECT); 273 Write<BRect>(rect); 274 Write<BPoint>(radius); 275 EndOp(); 276 } catch (status_t &status) { 277 return status; 278 } 279 return B_OK; 280 } 281 282 283 status_t 284 PictureDataWriter::WriteDrawEllipse(const BRect &rect, const bool &fill) 285 { 286 try { 287 BeginOp(fill ? B_PIC_FILL_ELLIPSE : B_PIC_STROKE_ELLIPSE); 288 Write<BRect>(rect); 289 EndOp(); 290 } catch (status_t &status) { 291 return status; 292 } 293 return B_OK; 294 } 295 296 297 status_t 298 PictureDataWriter::WriteDrawArc(const BPoint ¢er, 299 const BPoint &radius, const float &startTheta, 300 const float &arcTheta, const bool &fill) 301 { 302 try { 303 BeginOp(fill ? B_PIC_FILL_ARC : B_PIC_STROKE_ARC); 304 Write<BPoint>(center); 305 Write<BPoint>(radius); 306 Write<float>(startTheta); 307 Write<float>(arcTheta); 308 EndOp(); 309 } catch (status_t &status) { 310 return status; 311 } 312 return B_OK; 313 } 314 315 316 status_t 317 PictureDataWriter::WriteDrawPolygon(const int32 &numPoints, 318 BPoint *points, const bool &isClosed, const bool &fill) 319 { 320 try { 321 BeginOp(fill ? B_PIC_FILL_POLYGON : B_PIC_STROKE_POLYGON); 322 Write<int32>(numPoints); 323 for (int32 i = 0; i < numPoints; i++) 324 Write<BPoint>(points[i]); 325 if (!fill) 326 Write<uint8>((uint8)isClosed); 327 EndOp(); 328 } catch (status_t &status) { 329 return status; 330 } 331 return B_OK; 332 } 333 334 335 status_t 336 PictureDataWriter::WriteDrawBezier(const BPoint points[4], 337 const bool &fill) 338 { 339 try { 340 BeginOp(fill ? B_PIC_FILL_BEZIER : B_PIC_STROKE_BEZIER); 341 for (int32 i = 0; i < 4; i++) 342 Write<BPoint>(points[i]); 343 EndOp(); 344 } catch (status_t &status) { 345 return status; 346 } 347 return B_OK; 348 } 349 350 351 status_t 352 PictureDataWriter::WriteStrokeLine(const BPoint &start, 353 const BPoint &end) 354 { 355 try { 356 BeginOp(B_PIC_STROKE_LINE); 357 Write<BPoint>(start); 358 Write<BPoint>(end); 359 EndOp(); 360 } catch (status_t &status) { 361 return status; 362 } 363 return B_OK; 364 } 365 366 367 status_t 368 PictureDataWriter::WriteDrawString(const BPoint &where, 369 const char *string, const int32 &length, 370 const escapement_delta &escapement) 371 { 372 try { 373 BeginOp(B_PIC_SET_PEN_LOCATION); 374 Write<BPoint>(where); 375 EndOp(); 376 377 BeginOp(B_PIC_DRAW_STRING); 378 Write<float>(escapement.space); 379 Write<float>(escapement.nonspace); 380 //WriteData(string, length + 1); 381 // TODO: is string 0 terminated? why is length given? 382 WriteData(string, length); 383 Write<uint8>(0); 384 EndOp(); 385 } catch (status_t &status) { 386 return status; 387 } 388 389 return B_OK; 390 } 391 392 393 status_t 394 PictureDataWriter::WriteDrawShape(const int32 &opCount, 395 const void *opList, const int32 &ptCount, const void *ptList, 396 const bool &fill) 397 { 398 try { 399 BeginOp(fill ? B_PIC_FILL_SHAPE : B_PIC_STROKE_SHAPE); 400 Write<int32>(opCount); 401 Write<int32>(ptCount); 402 WriteData(opList, opCount * sizeof(uint32)); 403 WriteData(ptList, ptCount * sizeof(BPoint)); 404 EndOp(); 405 } catch (status_t &status) { 406 return status; 407 } 408 409 return B_OK; 410 } 411 412 413 status_t 414 PictureDataWriter::WriteDrawBitmap(const BRect &srcRect, 415 const BRect &dstRect, const int32 &width, const int32 &height, 416 const int32 &bytesPerRow, const int32 &colorSpace, 417 const int32 &flags, const void *data, const int32 &length) 418 { 419 if (length != height * bytesPerRow) 420 debugger("PictureDataWriter::WriteDrawBitmap: invalid length"); 421 try { 422 BeginOp(B_PIC_DRAW_PIXELS); 423 Write<BRect>(srcRect); 424 Write<BRect>(dstRect); 425 Write<int32>(width); 426 Write<int32>(height); 427 Write<int32>(bytesPerRow); 428 Write<int32>(colorSpace); 429 Write<int32>(flags); 430 WriteData(data, length); 431 EndOp(); 432 } catch (status_t &status) { 433 return status; 434 } 435 return B_OK; 436 } 437 438 439 status_t 440 PictureDataWriter::WriteDrawPicture(const BPoint &where, 441 const int32 &token) 442 { 443 // TODO: I'm not sure about this function. I think we need 444 // to attach the picture data too. 445 // The token won't be sufficient in many cases (for example, when 446 // we archive/flatten the picture. 447 try { 448 BeginOp(B_PIC_DRAW_PICTURE); 449 Write<BPoint>(where); 450 Write<int32>(token); 451 EndOp(); 452 } catch (status_t &status) { 453 return status; 454 } 455 return B_OK; 456 } 457 458 459 status_t 460 PictureDataWriter::WriteSetFontFamily(const font_family family) 461 { 462 try { 463 BeginOp(B_PIC_SET_FONT_FAMILY); 464 WriteData(family, strlen(family)); 465 Write<uint8>(0); 466 EndOp(); 467 } catch (status_t &status) { 468 return status; 469 } 470 return B_OK; 471 } 472 473 474 status_t 475 PictureDataWriter::WriteSetFontStyle(const font_style style) 476 { 477 try { 478 BeginOp(B_PIC_SET_FONT_STYLE); 479 WriteData(style, strlen(style)); 480 Write<uint8>(0); 481 EndOp(); 482 } catch (status_t &status) { 483 return status; 484 } 485 return B_OK; 486 } 487 488 489 status_t 490 PictureDataWriter::WriteSetFontSpacing(const int32 &spacing) 491 { 492 try { 493 BeginOp(B_PIC_SET_FONT_SPACING); 494 Write<int32>(spacing); 495 EndOp(); 496 } catch (status_t &status) { 497 return status; 498 } 499 return B_OK; 500 } 501 502 503 status_t 504 PictureDataWriter::WriteSetFontSize(const float &size) 505 { 506 try { 507 BeginOp(B_PIC_SET_FONT_SIZE); 508 Write<float>(size); 509 EndOp(); 510 } catch (status_t &status) { 511 return status; 512 } 513 return B_OK; 514 } 515 516 517 status_t 518 PictureDataWriter::WriteSetFontRotation(const float &rotation) 519 { 520 try { 521 BeginOp(B_PIC_SET_FONT_ROTATE); 522 Write<float>(rotation); 523 EndOp(); 524 } catch (status_t &status) { 525 return status; 526 } 527 return B_OK; 528 } 529 530 531 status_t 532 PictureDataWriter::WriteSetFontEncoding(const int32 &encoding) 533 { 534 try { 535 BeginOp(B_PIC_SET_FONT_ENCODING); 536 Write<int32>(encoding); 537 EndOp(); 538 } catch (status_t &status) { 539 return status; 540 } 541 return B_OK; 542 } 543 544 545 status_t 546 PictureDataWriter::WriteSetFontFlags(const int32 &flags) 547 { 548 try { 549 BeginOp(B_PIC_SET_FONT_FLAGS); 550 Write<int32>(flags); 551 EndOp(); 552 } catch (status_t &status) { 553 return status; 554 } 555 return B_OK; 556 } 557 558 559 status_t 560 PictureDataWriter::WriteSetFontShear(const float &shear) 561 { 562 try { 563 BeginOp(B_PIC_SET_FONT_SHEAR); 564 Write<float>(shear); 565 EndOp(); 566 } catch (status_t &status) { 567 return status; 568 } 569 return B_OK; 570 } 571 572 573 status_t 574 PictureDataWriter::WriteSetFontFace(const int32 &face) 575 { 576 try { 577 BeginOp(B_PIC_SET_FONT_FACE); 578 Write<int32>(face); 579 EndOp(); 580 } catch (status_t &status) { 581 return status; 582 } 583 return B_OK; 584 } 585 586 587 status_t 588 PictureDataWriter::WritePushState() 589 { 590 try { 591 BeginOp(B_PIC_PUSH_STATE); 592 EndOp(); 593 } catch (status_t &status) { 594 return status; 595 } 596 return B_OK; 597 } 598 599 600 status_t 601 PictureDataWriter::WritePopState() 602 { 603 try { 604 BeginOp(B_PIC_POP_STATE); 605 EndOp(); 606 } catch (status_t &status) { 607 return status; 608 } 609 return B_OK; 610 } 611 612 613 // private 614 void 615 PictureDataWriter::BeginOp(const int16 &op) 616 { 617 if (fData == NULL) 618 THROW_ERROR(B_NO_INIT); 619 620 fStack.push(fData->Position()); 621 fData->Write(&op, sizeof(op)); 622 623 // Init the size of the opcode block to 0 624 int32 size = 0; 625 fData->Write(&size, sizeof(size)); 626 } 627 628 629 void 630 PictureDataWriter::EndOp() 631 { 632 if (fData == NULL) 633 THROW_ERROR(B_NO_INIT); 634 635 off_t curPos = fData->Position(); 636 off_t stackPos = fStack.top(); 637 fStack.pop(); 638 639 // The size of the op is calculated like this: 640 // current position on the stream minus the position on the stack, 641 // minus the space occupied by the op code itself (int16) 642 // and the space occupied by the size field (int32) 643 int32 size = curPos - stackPos - sizeof(int32) - sizeof(int16); 644 645 // Size was set to 0 in BeginOp() 646 // Now we overwrite it with the correct value 647 fData->Seek(stackPos + sizeof(int16), SEEK_SET); 648 fData->Write(&size, sizeof(size)); 649 fData->Seek(curPos, SEEK_SET); 650 } 651 652 653 void 654 PictureDataWriter::WriteData(const void *data, size_t size) 655 { 656 ssize_t result = fData->Write(data, size); 657 if (result < 0) 658 THROW_ERROR(result); 659 if ((size_t)result != size) 660 THROW_ERROR(B_IO_ERROR); 661 } 662