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