1 /* 2 * Copyright 2001-2007, Haiku Inc. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Marc Flerackers (mflerackers@androme.be) 7 * Stefano Ceccherini (stefano.ceccherini@gmail.com) 8 * Marcus Overhagen (marcus@overhagen.de) 9 */ 10 11 /** PicturePlayer is used to play picture data. */ 12 13 #include <PicturePlayer.h> 14 15 #include <stdio.h> 16 #include <stdlib.h> 17 #include <string.h> 18 19 #include <AffineTransform.h> 20 #include <PictureProtocol.h> 21 #include <Shape.h> 22 23 24 using BPrivate::PicturePlayer; 25 26 27 struct adapter_context { 28 void* user_data; 29 void** function_table; 30 }; 31 32 33 static void 34 nop() 35 { 36 } 37 38 39 static void 40 move_pen_by(void* _context, const BPoint& delta) 41 { 42 adapter_context* context = reinterpret_cast<adapter_context*>(_context); 43 ((void (*)(void*, BPoint))context->function_table[1])(context->user_data, 44 delta); 45 } 46 47 48 static void 49 stroke_line(void* _context, const BPoint& start, const BPoint& end) 50 { 51 adapter_context* context = reinterpret_cast<adapter_context*>(_context); 52 ((void (*)(void*, BPoint, BPoint))context->function_table[2])( 53 context->user_data, start, end); 54 } 55 56 57 static void 58 draw_rect(void* _context, const BRect& rect, bool fill) 59 { 60 adapter_context* context = reinterpret_cast<adapter_context*>(_context); 61 ((void (*)(void*, BRect))context->function_table[fill ? 4 : 3])( 62 context->user_data, rect); 63 } 64 65 66 static void 67 draw_round_rect(void* _context, const BRect& rect, const BPoint& radii, 68 bool fill) 69 { 70 adapter_context* context = reinterpret_cast<adapter_context*>(_context); 71 ((void (*)(void*, BRect, BPoint))context->function_table[fill ? 6 : 5])( 72 context->user_data, rect, radii); 73 } 74 75 76 static void 77 draw_bezier(void* _context, size_t numPoints, const BPoint _points[], bool fill) 78 { 79 adapter_context* context = reinterpret_cast<adapter_context*>(_context); 80 if (numPoints != 4) 81 return; 82 83 BPoint points[4] = { _points[0], _points[1], _points[2], _points[3] }; 84 ((void (*)(void*, BPoint*))context->function_table[fill ? 8 : 7])( 85 context->user_data, points); 86 } 87 88 89 static void 90 draw_arc(void* _context, const BPoint& center, const BPoint& radii, 91 float startTheta, float arcTheta, bool fill) 92 { 93 adapter_context* context = reinterpret_cast<adapter_context*>(_context); 94 ((void (*)(void*, BPoint, BPoint, float, float)) 95 context->function_table[fill ? 10 : 9])(context->user_data, center, 96 radii, startTheta, arcTheta); 97 } 98 99 100 static void 101 draw_ellipse(void* _context, const BRect& rect, bool fill) 102 { 103 adapter_context* context = reinterpret_cast<adapter_context*>(_context); 104 BPoint radii((rect.Width() + 1) / 2.0f, (rect.Height() + 1) / 2.0f); 105 BPoint center = rect.LeftTop() + radii; 106 ((void (*)(void*, BPoint, BPoint)) 107 context->function_table[fill ? 12 : 11])(context->user_data, center, 108 radii); 109 } 110 111 112 static void 113 draw_polygon(void* _context, size_t numPoints, const BPoint _points[], 114 bool isClosed, bool fill) 115 { 116 adapter_context* context = reinterpret_cast<adapter_context*>(_context); 117 118 // This is rather ugly but works for such a trivial class. 119 const size_t kMaxStackCount = 200; 120 char stackData[kMaxStackCount * sizeof(BPoint)]; 121 BPoint* points = (BPoint*)stackData; 122 if (numPoints > kMaxStackCount) { 123 points = (BPoint*)malloc(numPoints * sizeof(BPoint)); 124 if (points == NULL) 125 return; 126 } 127 128 memcpy(points, _points, numPoints * sizeof(BPoint)); 129 130 ((void (*)(void*, int32, BPoint*, bool)) 131 context->function_table[fill ? 14 : 13])(context->user_data, numPoints, 132 points, isClosed); 133 134 if (numPoints > kMaxStackCount) 135 free(points); 136 } 137 138 139 static void 140 draw_shape(void* _context, const BShape& shape, bool fill) 141 { 142 adapter_context* context = reinterpret_cast<adapter_context*>(_context); 143 ((void (*)(void*, BShape))context->function_table[fill ? 16 : 15])( 144 context->user_data, shape); 145 } 146 147 148 static void 149 draw_string(void* _context, const char* _string, size_t length, 150 float deltaSpace, float deltaNonSpace) 151 { 152 adapter_context* context = reinterpret_cast<adapter_context*>(_context); 153 char* string = strndup(_string, length); 154 155 ((void (*)(void*, char*, float, float)) 156 context->function_table[17])(context->user_data, string, deltaSpace, 157 deltaNonSpace); 158 159 free(string); 160 } 161 162 163 static void 164 draw_pixels(void* _context, const BRect& src, const BRect& dest, uint32 width, 165 uint32 height, size_t bytesPerRow, color_space pixelFormat, uint32 options, 166 const void* _data, size_t length) 167 { 168 adapter_context* context = reinterpret_cast<adapter_context*>(_context); 169 void* data = malloc(length); 170 if (data == NULL) 171 return; 172 173 memcpy(data, _data, length); 174 175 ((void (*)(void*, BRect, BRect, int32, int32, int32, int32, int32, void*)) 176 context->function_table[18])(context->user_data, src, dest, width, 177 height, bytesPerRow, pixelFormat, options, data); 178 179 free(data); 180 } 181 182 183 static void 184 draw_picture(void* _context, const BPoint& where, int32 token) 185 { 186 adapter_context* context = reinterpret_cast<adapter_context*>(_context); 187 ((void (*)(void*, BPoint, int32))context->function_table[19])( 188 context->user_data, where, token); 189 } 190 191 192 static void 193 set_clipping_rects(void* _context, size_t numRects, const BRect _rects[]) 194 { 195 adapter_context* context = reinterpret_cast<adapter_context*>(_context); 196 197 // This is rather ugly but works for such a trivial class. 198 const size_t kMaxStackCount = 100; 199 char stackData[kMaxStackCount * sizeof(BRect)]; 200 BRect* rects = (BRect*)stackData; 201 if (numRects > kMaxStackCount) { 202 rects = (BRect*)malloc(numRects * sizeof(BRect)); 203 if (rects == NULL) 204 return; 205 } 206 207 memcpy(rects, _rects, numRects * sizeof(BRect)); 208 209 ((void (*)(void*, BRect*, uint32))context->function_table[20])( 210 context->user_data, rects, numRects); 211 212 if (numRects > kMaxStackCount) 213 free(rects); 214 } 215 216 217 static void 218 clip_to_picture(void* _context, int32 token, const BPoint& origin, 219 bool clipToInverse) 220 { 221 adapter_context* context = reinterpret_cast<adapter_context*>(_context); 222 ((void (*)(void*, int32, BPoint, bool))context->function_table[21])( 223 context->user_data, token, origin, clipToInverse); 224 } 225 226 227 static void 228 push_state(void* _context) 229 { 230 adapter_context* context = reinterpret_cast<adapter_context*>(_context); 231 ((void (*)(void*))context->function_table[22])(context->user_data); 232 } 233 234 235 static void 236 pop_state(void* _context) 237 { 238 adapter_context* context = reinterpret_cast<adapter_context*>(_context); 239 ((void (*)(void*))context->function_table[23])(context->user_data); 240 } 241 242 243 static void 244 enter_state_change(void* _context) 245 { 246 adapter_context* context = reinterpret_cast<adapter_context*>(_context); 247 ((void (*)(void*))context->function_table[24])(context->user_data); 248 } 249 250 251 static void 252 exit_state_change(void* _context) 253 { 254 adapter_context* context = reinterpret_cast<adapter_context*>(_context); 255 ((void (*)(void*))context->function_table[25])(context->user_data); 256 } 257 258 259 static void 260 enter_font_state(void* _context) 261 { 262 adapter_context* context = reinterpret_cast<adapter_context*>(_context); 263 ((void (*)(void*))context->function_table[26])(context->user_data); 264 } 265 266 267 static void 268 exit_font_state(void* _context) 269 { 270 adapter_context* context = reinterpret_cast<adapter_context*>(_context); 271 ((void (*)(void*))context->function_table[27])(context->user_data); 272 } 273 274 275 static void 276 set_origin(void* _context, const BPoint& origin) 277 { 278 adapter_context* context = reinterpret_cast<adapter_context*>(_context); 279 ((void (*)(void*, BPoint))context->function_table[28])(context->user_data, 280 origin); 281 } 282 283 284 static void 285 set_pen_location(void* _context, const BPoint& penLocation) 286 { 287 adapter_context* context = reinterpret_cast<adapter_context*>(_context); 288 ((void (*)(void*, BPoint))context->function_table[29])(context->user_data, 289 penLocation); 290 } 291 292 293 static void 294 set_drawing_mode(void* _context, drawing_mode mode) 295 { 296 adapter_context* context = reinterpret_cast<adapter_context*>(_context); 297 ((void (*)(void*, drawing_mode))context->function_table[30])( 298 context->user_data, mode); 299 } 300 301 302 static void 303 set_line_mode(void* _context, cap_mode capMode, join_mode joinMode, 304 float miterLimit) 305 { 306 adapter_context* context = reinterpret_cast<adapter_context*>(_context); 307 ((void (*)(void*, cap_mode, join_mode, float))context->function_table[31])( 308 context->user_data, capMode, joinMode, miterLimit); 309 } 310 311 312 static void 313 set_pen_size(void* _context, float size) 314 { 315 adapter_context* context = reinterpret_cast<adapter_context*>(_context); 316 ((void (*)(void*, float))context->function_table[32])(context->user_data, 317 size); 318 } 319 320 321 static void 322 set_fore_color(void* _context, const rgb_color& color) 323 { 324 adapter_context* context = reinterpret_cast<adapter_context*>(_context); 325 ((void (*)(void*, rgb_color))context->function_table[33])( 326 context->user_data, color); 327 } 328 329 330 static void 331 set_back_color(void* _context, const rgb_color& color) 332 { 333 adapter_context* context = reinterpret_cast<adapter_context*>(_context); 334 ((void (*)(void*, rgb_color))context->function_table[34])( 335 context->user_data, color); 336 } 337 338 339 static void 340 set_stipple_pattern(void* _context, const pattern& stipplePattern) 341 { 342 adapter_context* context = reinterpret_cast<adapter_context*>(_context); 343 ((void (*)(void*, pattern))context->function_table[35])(context->user_data, 344 stipplePattern); 345 } 346 347 348 static void 349 set_scale(void* _context, float scale) 350 { 351 adapter_context* context = reinterpret_cast<adapter_context*>(_context); 352 ((void (*)(void*, float))context->function_table[36])(context->user_data, 353 scale); 354 } 355 356 357 static void 358 set_font_family(void* _context, const char* _family, size_t length) 359 { 360 adapter_context* context = reinterpret_cast<adapter_context*>(_context); 361 char* family = strndup(_family, length); 362 363 ((void (*)(void*, char*))context->function_table[37])(context->user_data, 364 family); 365 366 free(family); 367 } 368 369 370 static void 371 set_font_style(void* _context, const char* _style, size_t length) 372 { 373 adapter_context* context = reinterpret_cast<adapter_context*>(_context); 374 char* style = strndup(_style, length); 375 376 ((void (*)(void*, char*))context->function_table[38])(context->user_data, 377 style); 378 379 free(style); 380 } 381 382 383 static void 384 set_font_spacing(void* _context, uint8 spacing) 385 { 386 adapter_context* context = reinterpret_cast<adapter_context*>(_context); 387 ((void (*)(void*, int32))context->function_table[39])(context->user_data, 388 spacing); 389 } 390 391 392 static void 393 set_font_size(void* _context, float size) 394 { 395 adapter_context* context = reinterpret_cast<adapter_context*>(_context); 396 ((void (*)(void*, float))context->function_table[40])(context->user_data, 397 size); 398 } 399 400 401 static void 402 set_font_rotation(void* _context, float rotation) 403 { 404 adapter_context* context = reinterpret_cast<adapter_context*>(_context); 405 ((void (*)(void*, float))context->function_table[41])(context->user_data, 406 rotation); 407 } 408 409 410 static void 411 set_font_encoding(void* _context, uint8 encoding) 412 { 413 adapter_context* context = reinterpret_cast<adapter_context*>(_context); 414 ((void (*)(void*, int32))context->function_table[42])(context->user_data, 415 encoding); 416 } 417 418 419 static void 420 set_font_flags(void* _context, uint32 flags) 421 { 422 adapter_context* context = reinterpret_cast<adapter_context*>(_context); 423 ((void (*)(void*, int32))context->function_table[43])(context->user_data, 424 flags); 425 } 426 427 428 static void 429 set_font_shear(void* _context, float shear) 430 { 431 adapter_context* context = reinterpret_cast<adapter_context*>(_context); 432 ((void (*)(void*, float))context->function_table[44])(context->user_data, 433 shear); 434 } 435 436 437 static void 438 set_font_face(void* _context, uint16 face) 439 { 440 adapter_context* context = reinterpret_cast<adapter_context*>(_context); 441 ((void (*)(void*, int32))context->function_table[46])(context->user_data, 442 face); 443 } 444 445 446 static void 447 set_blending_mode(void* _context, source_alpha alphaSrcMode, 448 alpha_function alphaFncMode) 449 { 450 adapter_context* context = reinterpret_cast<adapter_context*>(_context); 451 ((void (*)(void*, source_alpha, alpha_function)) 452 context->function_table[47])(context->user_data, alphaSrcMode, 453 alphaFncMode); 454 } 455 456 457 #if DEBUG > 1 458 static const char * 459 PictureOpToString(int op) 460 { 461 #define RETURN_STRING(x) case x: return #x 462 463 switch(op) { 464 RETURN_STRING(B_PIC_MOVE_PEN_BY); 465 RETURN_STRING(B_PIC_STROKE_LINE); 466 RETURN_STRING(B_PIC_STROKE_RECT); 467 RETURN_STRING(B_PIC_FILL_RECT); 468 RETURN_STRING(B_PIC_STROKE_ROUND_RECT); 469 RETURN_STRING(B_PIC_FILL_ROUND_RECT); 470 RETURN_STRING(B_PIC_STROKE_BEZIER); 471 RETURN_STRING(B_PIC_FILL_BEZIER); 472 RETURN_STRING(B_PIC_STROKE_POLYGON); 473 RETURN_STRING(B_PIC_FILL_POLYGON); 474 RETURN_STRING(B_PIC_STROKE_SHAPE); 475 RETURN_STRING(B_PIC_FILL_SHAPE); 476 RETURN_STRING(B_PIC_DRAW_STRING); 477 RETURN_STRING(B_PIC_DRAW_PIXELS); 478 RETURN_STRING(B_PIC_DRAW_PICTURE); 479 RETURN_STRING(B_PIC_STROKE_ARC); 480 RETURN_STRING(B_PIC_FILL_ARC); 481 RETURN_STRING(B_PIC_STROKE_ELLIPSE); 482 RETURN_STRING(B_PIC_FILL_ELLIPSE); 483 484 RETURN_STRING(B_PIC_ENTER_STATE_CHANGE); 485 RETURN_STRING(B_PIC_SET_CLIPPING_RECTS); 486 RETURN_STRING(B_PIC_CLIP_TO_PICTURE); 487 RETURN_STRING(B_PIC_PUSH_STATE); 488 RETURN_STRING(B_PIC_POP_STATE); 489 RETURN_STRING(B_PIC_CLEAR_CLIPPING_RECTS); 490 491 RETURN_STRING(B_PIC_SET_ORIGIN); 492 RETURN_STRING(B_PIC_SET_PEN_LOCATION); 493 RETURN_STRING(B_PIC_SET_DRAWING_MODE); 494 RETURN_STRING(B_PIC_SET_LINE_MODE); 495 RETURN_STRING(B_PIC_SET_PEN_SIZE); 496 RETURN_STRING(B_PIC_SET_SCALE); 497 RETURN_STRING(B_PIC_SET_TRANSFORM); 498 RETURN_STRING(B_PIC_SET_FORE_COLOR); 499 RETURN_STRING(B_PIC_SET_BACK_COLOR); 500 RETURN_STRING(B_PIC_SET_STIPLE_PATTERN); 501 RETURN_STRING(B_PIC_ENTER_FONT_STATE); 502 RETURN_STRING(B_PIC_SET_BLENDING_MODE); 503 RETURN_STRING(B_PIC_SET_FONT_FAMILY); 504 RETURN_STRING(B_PIC_SET_FONT_STYLE); 505 RETURN_STRING(B_PIC_SET_FONT_SPACING); 506 RETURN_STRING(B_PIC_SET_FONT_ENCODING); 507 RETURN_STRING(B_PIC_SET_FONT_FLAGS); 508 RETURN_STRING(B_PIC_SET_FONT_SIZE); 509 RETURN_STRING(B_PIC_SET_FONT_ROTATE); 510 RETURN_STRING(B_PIC_SET_FONT_SHEAR); 511 RETURN_STRING(B_PIC_SET_FONT_BPP); 512 RETURN_STRING(B_PIC_SET_FONT_FACE); 513 default: return "Unknown op"; 514 } 515 #undef RETURN_STRING 516 } 517 #endif 518 519 520 PicturePlayer::PicturePlayer(const void *data, size_t size, BList *pictures) 521 : fData(data), 522 fSize(size), 523 fPictures(pictures) 524 { 525 } 526 527 528 PicturePlayer::~PicturePlayer() 529 { 530 } 531 532 533 status_t 534 PicturePlayer::Play(void** callBackTable, int32 tableEntries, void* userData) 535 { 536 const BPrivate::picture_player_callbacks kAdapterCallbacks = { 537 move_pen_by, 538 stroke_line, 539 draw_rect, 540 draw_round_rect, 541 draw_bezier, 542 draw_arc, 543 draw_ellipse, 544 draw_polygon, 545 draw_shape, 546 draw_string, 547 draw_pixels, 548 draw_picture, 549 set_clipping_rects, 550 clip_to_picture, 551 push_state, 552 pop_state, 553 enter_state_change, 554 exit_state_change, 555 enter_font_state, 556 exit_font_state, 557 set_origin, 558 set_pen_location, 559 set_drawing_mode, 560 set_line_mode, 561 set_pen_size, 562 set_fore_color, 563 set_back_color, 564 set_stipple_pattern, 565 set_scale, 566 set_font_family, 567 set_font_style, 568 set_font_spacing, 569 set_font_size, 570 set_font_rotation, 571 set_font_encoding, 572 set_font_flags, 573 set_font_shear, 574 set_font_face, 575 set_blending_mode 576 }; 577 578 // We don't check if the functions in the table are NULL, but we 579 // check the tableEntries to see if the table is big enough. 580 // If an application supplies the wrong size or an invalid pointer, 581 // it's its own fault. 582 583 // If the caller supplied a function table smaller than needed, 584 // we use our dummy table, and copy the supported ops from the supplied one. 585 void *dummyTable[kOpsTableSize]; 586 587 adapter_context adapterContext; 588 adapterContext.user_data = userData; 589 adapterContext.function_table = callBackTable; 590 591 if ((size_t)tableEntries < kOpsTableSize) { 592 memcpy(dummyTable, callBackTable, tableEntries * sizeof(void*)); 593 for (size_t i = (size_t)tableEntries; i < kOpsTableSize; i++) 594 dummyTable[i] = (void*)nop; 595 596 adapterContext.function_table = dummyTable; 597 } 598 599 return _Play(kAdapterCallbacks, &adapterContext, fData, fSize, 0); 600 } 601 602 603 status_t 604 PicturePlayer::Play(const picture_player_callbacks& callbacks, 605 size_t callbacksSize, void* userData) 606 { 607 return _Play(callbacks, userData, fData, fSize, 0); 608 } 609 610 611 class DataReader { 612 public: 613 DataReader(const void* buffer, size_t length) 614 : 615 fBuffer((const uint8*)buffer), 616 fRemaining(length) 617 { 618 } 619 620 size_t 621 Remaining() const 622 { 623 return fRemaining; 624 } 625 626 template<typename T> 627 bool 628 Get(const T*& typed, size_t count = 1) 629 { 630 if (fRemaining < sizeof(T) * count) 631 return false; 632 633 typed = reinterpret_cast<const T *>(fBuffer); 634 fRemaining -= sizeof(T) * count; 635 fBuffer += sizeof(T) * count; 636 return true; 637 } 638 639 template<typename T> 640 bool 641 GetRemaining(const T*& buffer, size_t& size) 642 { 643 if (fRemaining == 0) 644 return false; 645 646 buffer = reinterpret_cast<const T*>(fBuffer); 647 size = fRemaining; 648 fRemaining = 0; 649 return true; 650 } 651 652 private: 653 const uint8* fBuffer; 654 size_t fRemaining; 655 }; 656 657 658 struct picture_data_entry_header { 659 uint16 op; 660 uint32 size; 661 } _PACKED; 662 663 664 status_t 665 PicturePlayer::_Play(const picture_player_callbacks& callbacks, void* userData, 666 const void* buffer, size_t length, uint16 parentOp) 667 { 668 #if DEBUG 669 printf("Start rendering %sBPicture...\n", parentOp != 0 ? "sub " : ""); 670 bigtime_t startTime = system_time(); 671 int32 numOps = 0; 672 #endif 673 674 DataReader pictureReader(buffer, length); 675 676 while (pictureReader.Remaining() > 0) { 677 const picture_data_entry_header* header; 678 const uint8* opData; 679 if (!pictureReader.Get(header) 680 || !pictureReader.Get(opData, header->size)) { 681 return B_BAD_DATA; 682 } 683 684 DataReader reader(opData, header->size); 685 686 // Disallow ops that don't fit the parent. 687 switch (parentOp) { 688 case 0: 689 // No parent op, no restrictions. 690 break; 691 692 case B_PIC_ENTER_STATE_CHANGE: 693 if (header->op <= B_PIC_ENTER_STATE_CHANGE 694 || header->op > B_PIC_SET_TRANSFORM) { 695 return B_BAD_DATA; 696 } 697 break; 698 699 case B_PIC_ENTER_FONT_STATE: 700 if (header->op < B_PIC_SET_FONT_FAMILY 701 || header->op > B_PIC_SET_FONT_FACE) { 702 return B_BAD_DATA; 703 } 704 break; 705 706 default: 707 return B_BAD_DATA; 708 } 709 710 #if DEBUG > 1 711 bigtime_t startOpTime = system_time(); 712 printf("Op %s ", PictureOpToString(header->op)); 713 #endif 714 switch (header->op) { 715 case B_PIC_MOVE_PEN_BY: 716 { 717 const BPoint* where; 718 if (callbacks.move_pen_by == NULL || !reader.Get(where)) 719 break; 720 721 callbacks.move_pen_by(userData, *where); 722 break; 723 } 724 725 case B_PIC_STROKE_LINE: 726 { 727 const BPoint* start; 728 const BPoint* end; 729 if (callbacks.stroke_line == NULL || !reader.Get(start) 730 || !reader.Get(end)) { 731 break; 732 } 733 734 callbacks.stroke_line(userData, *start, *end); 735 break; 736 } 737 738 case B_PIC_STROKE_RECT: 739 case B_PIC_FILL_RECT: 740 { 741 const BRect* rect; 742 if (callbacks.draw_rect == NULL || !reader.Get(rect)) 743 break; 744 745 callbacks.draw_rect(userData, *rect, 746 header->op == B_PIC_FILL_RECT); 747 break; 748 } 749 750 case B_PIC_STROKE_ROUND_RECT: 751 case B_PIC_FILL_ROUND_RECT: 752 { 753 const BRect* rect; 754 const BPoint* radii; 755 if (callbacks.draw_round_rect == NULL || !reader.Get(rect) 756 || !reader.Get(radii)) { 757 break; 758 } 759 760 callbacks.draw_round_rect(userData, *rect, *radii, 761 header->op == B_PIC_FILL_ROUND_RECT); 762 break; 763 } 764 765 case B_PIC_STROKE_BEZIER: 766 case B_PIC_FILL_BEZIER: 767 { 768 const size_t kNumControlPoints = 4; 769 const BPoint* controlPoints; 770 if (callbacks.draw_bezier == NULL 771 || !reader.Get(controlPoints, kNumControlPoints)) { 772 break; 773 } 774 775 callbacks.draw_bezier(userData, kNumControlPoints, 776 controlPoints, header->op == B_PIC_FILL_BEZIER); 777 break; 778 } 779 780 case B_PIC_STROKE_ARC: 781 case B_PIC_FILL_ARC: 782 { 783 const BPoint* center; 784 const BPoint* radii; 785 const float* startTheta; 786 const float* arcTheta; 787 if (callbacks.draw_arc == NULL || !reader.Get(center) 788 || !reader.Get(radii) || !reader.Get(startTheta) 789 || !reader.Get(arcTheta)) { 790 break; 791 } 792 793 callbacks.draw_arc(userData, *center, *radii, *startTheta, 794 *arcTheta, header->op == B_PIC_FILL_ARC); 795 break; 796 } 797 798 case B_PIC_STROKE_ELLIPSE: 799 case B_PIC_FILL_ELLIPSE: 800 { 801 const BRect* rect; 802 if (callbacks.draw_ellipse == NULL || !reader.Get(rect)) 803 break; 804 805 callbacks.draw_ellipse(userData, *rect, 806 header->op == B_PIC_FILL_ELLIPSE); 807 break; 808 } 809 810 case B_PIC_STROKE_POLYGON: 811 case B_PIC_FILL_POLYGON: 812 { 813 const uint32* numPoints; 814 const BPoint* points; 815 if (callbacks.draw_polygon == NULL || !reader.Get(numPoints) 816 || !reader.Get(points, *numPoints)) { 817 break; 818 } 819 820 bool isClosed = true; 821 const bool* closedPointer; 822 if (header->op != B_PIC_FILL_POLYGON) { 823 if (!reader.Get(closedPointer)) 824 break; 825 826 isClosed = *closedPointer; 827 } 828 829 callbacks.draw_polygon(userData, *numPoints, points, isClosed, 830 header->op == B_PIC_FILL_POLYGON); 831 break; 832 } 833 834 case B_PIC_STROKE_SHAPE: 835 case B_PIC_FILL_SHAPE: 836 { 837 const uint32* opCount; 838 const uint32* pointCount; 839 const uint32* opList; 840 const BPoint* pointList; 841 if (callbacks.draw_shape == NULL || !reader.Get(opCount) 842 || !reader.Get(pointCount) || !reader.Get(opList, *opCount) 843 || !reader.Get(pointList, *pointCount)) { 844 break; 845 } 846 847 // TODO: remove BShape data copying 848 BShape shape; 849 shape.SetData(*opCount, *pointCount, opList, pointList); 850 851 callbacks.draw_shape(userData, shape, 852 header->op == B_PIC_FILL_SHAPE); 853 break; 854 } 855 856 case B_PIC_DRAW_STRING: 857 { 858 const float* escapementSpace; 859 const float* escapementNonSpace; 860 const char* string; 861 size_t length; 862 if (callbacks.draw_string == NULL 863 || !reader.Get(escapementSpace) 864 || !reader.Get(escapementNonSpace) 865 || !reader.GetRemaining(string, length)) { 866 break; 867 } 868 869 callbacks.draw_string(userData, string, length, 870 *escapementSpace, *escapementNonSpace); 871 break; 872 } 873 874 case B_PIC_DRAW_PIXELS: 875 { 876 const BRect* sourceRect; 877 const BRect* destinationRect; 878 const uint32* width; 879 const uint32* height; 880 const uint32* bytesPerRow; 881 const uint32* colorSpace; 882 const uint32* flags; 883 const void* data; 884 size_t length; 885 if (callbacks.draw_pixels == NULL || !reader.Get(sourceRect) 886 || !reader.Get(destinationRect) || !reader.Get(width) 887 || !reader.Get(height) || !reader.Get(bytesPerRow) 888 || !reader.Get(colorSpace) || !reader.Get(flags) 889 || !reader.GetRemaining(data, length)) { 890 break; 891 } 892 893 callbacks.draw_pixels(userData, *sourceRect, *destinationRect, 894 *width, *height, *bytesPerRow, (color_space)*colorSpace, 895 *flags, data, length); 896 break; 897 } 898 899 case B_PIC_DRAW_PICTURE: 900 { 901 const BPoint* where; 902 const int32* token; 903 if (callbacks.draw_picture == NULL || !reader.Get(where) 904 || !reader.Get(token)) { 905 break; 906 } 907 908 callbacks.draw_picture(userData, *where, *token); 909 break; 910 } 911 912 case B_PIC_SET_CLIPPING_RECTS: 913 { 914 const uint32* numRects; 915 const BRect* rects; 916 if (callbacks.set_clipping_rects == NULL 917 || !reader.Get(numRects) || !reader.Get(rects, *numRects)) { 918 break; 919 } 920 921 callbacks.set_clipping_rects(userData, *numRects, rects); 922 break; 923 } 924 925 case B_PIC_CLEAR_CLIPPING_RECTS: 926 { 927 if (callbacks.set_clipping_rects == NULL) 928 break; 929 930 callbacks.set_clipping_rects(userData, 0, NULL); 931 break; 932 } 933 934 case B_PIC_CLIP_TO_PICTURE: 935 { 936 const int32* token; 937 const BPoint* where; 938 const bool* inverse; 939 if (callbacks.clip_to_picture == NULL || !reader.Get(token) 940 || !reader.Get(where) || !reader.Get(inverse)) 941 break; 942 943 callbacks.clip_to_picture(userData, *token, *where, *inverse); 944 break; 945 } 946 947 case B_PIC_PUSH_STATE: 948 { 949 if (callbacks.push_state == NULL) 950 break; 951 952 callbacks.push_state(userData); 953 break; 954 } 955 956 case B_PIC_POP_STATE: 957 { 958 if (callbacks.pop_state == NULL) 959 break; 960 961 callbacks.pop_state(userData); 962 break; 963 } 964 965 case B_PIC_ENTER_STATE_CHANGE: 966 case B_PIC_ENTER_FONT_STATE: 967 { 968 const void* data; 969 size_t length; 970 if (!reader.GetRemaining(data, length)) 971 break; 972 973 if (header->op == B_PIC_ENTER_STATE_CHANGE) { 974 if (callbacks.enter_state_change != NULL) 975 callbacks.enter_state_change(userData); 976 } else if (callbacks.enter_font_state != NULL) 977 callbacks.enter_font_state(userData); 978 979 status_t result = _Play(callbacks, userData, data, length, 980 header->op); 981 if (result != B_OK) 982 return result; 983 984 if (header->op == B_PIC_ENTER_STATE_CHANGE) { 985 if (callbacks.exit_state_change != NULL) 986 callbacks.exit_state_change(userData); 987 } else if (callbacks.exit_font_state != NULL) 988 callbacks.exit_font_state(userData); 989 990 break; 991 } 992 993 case B_PIC_SET_ORIGIN: 994 { 995 const BPoint* origin; 996 if (callbacks.set_origin == NULL || !reader.Get(origin)) 997 break; 998 999 callbacks.set_origin(userData, *origin); 1000 break; 1001 } 1002 1003 case B_PIC_SET_PEN_LOCATION: 1004 { 1005 const BPoint* location; 1006 if (callbacks.set_pen_location == NULL || !reader.Get(location)) 1007 break; 1008 1009 callbacks.set_pen_location(userData, *location); 1010 break; 1011 } 1012 1013 case B_PIC_SET_DRAWING_MODE: 1014 { 1015 const uint16* mode; 1016 if (callbacks.set_drawing_mode == NULL || !reader.Get(mode)) 1017 break; 1018 1019 callbacks.set_drawing_mode(userData, (drawing_mode)*mode); 1020 break; 1021 } 1022 1023 case B_PIC_SET_LINE_MODE: 1024 { 1025 const uint16* capMode; 1026 const uint16* joinMode; 1027 const float* miterLimit; 1028 if (callbacks.set_line_mode == NULL || !reader.Get(capMode) 1029 || !reader.Get(joinMode) || !reader.Get(miterLimit)) { 1030 break; 1031 } 1032 1033 callbacks.set_line_mode(userData, (cap_mode)*capMode, 1034 (join_mode)*joinMode, *miterLimit); 1035 break; 1036 } 1037 1038 case B_PIC_SET_PEN_SIZE: 1039 { 1040 const float* penSize; 1041 if (callbacks.set_pen_size == NULL || !reader.Get(penSize)) 1042 break; 1043 1044 callbacks.set_pen_size(userData, *penSize); 1045 break; 1046 } 1047 1048 case B_PIC_SET_FORE_COLOR: 1049 { 1050 const rgb_color* color; 1051 if (callbacks.set_fore_color == NULL || !reader.Get(color)) 1052 break; 1053 1054 callbacks.set_fore_color(userData, *color); 1055 break; 1056 } 1057 1058 case B_PIC_SET_BACK_COLOR: 1059 { 1060 const rgb_color* color; 1061 if (callbacks.set_back_color == NULL || !reader.Get(color)) 1062 break; 1063 1064 callbacks.set_back_color(userData, *color); 1065 break; 1066 } 1067 1068 case B_PIC_SET_STIPLE_PATTERN: 1069 { 1070 const pattern* stipplePattern; 1071 if (callbacks.set_stipple_pattern == NULL 1072 || !reader.Get(stipplePattern)) { 1073 break; 1074 } 1075 1076 callbacks.set_stipple_pattern(userData, *stipplePattern); 1077 break; 1078 } 1079 1080 case B_PIC_SET_SCALE: 1081 { 1082 const float* scale; 1083 if (callbacks.set_scale == NULL || !reader.Get(scale)) 1084 break; 1085 1086 callbacks.set_scale(userData, *scale); 1087 break; 1088 } 1089 1090 case B_PIC_SET_FONT_FAMILY: 1091 { 1092 const char* family; 1093 size_t length; 1094 if (callbacks.set_font_family == NULL 1095 || !reader.GetRemaining(family, length)) { 1096 break; 1097 } 1098 1099 callbacks.set_font_family(userData, family, length); 1100 break; 1101 } 1102 1103 case B_PIC_SET_FONT_STYLE: 1104 { 1105 const char* style; 1106 size_t length; 1107 if (callbacks.set_font_style == NULL 1108 || !reader.GetRemaining(style, length)) { 1109 break; 1110 } 1111 1112 callbacks.set_font_style(userData, style, length); 1113 break; 1114 } 1115 1116 case B_PIC_SET_FONT_SPACING: 1117 { 1118 const uint32* spacing; 1119 if (callbacks.set_font_spacing == NULL || !reader.Get(spacing)) 1120 break; 1121 1122 callbacks.set_font_spacing(userData, *spacing); 1123 break; 1124 } 1125 1126 case B_PIC_SET_FONT_SIZE: 1127 { 1128 const float* size; 1129 if (callbacks.set_font_size == NULL || !reader.Get(size)) 1130 break; 1131 1132 callbacks.set_font_size(userData, *size); 1133 break; 1134 } 1135 1136 case B_PIC_SET_FONT_ROTATE: 1137 { 1138 const float* rotation; 1139 if (callbacks.set_font_rotation == NULL 1140 || !reader.Get(rotation)) { 1141 break; 1142 } 1143 1144 callbacks.set_font_rotation(userData, *rotation); 1145 break; 1146 } 1147 1148 case B_PIC_SET_FONT_ENCODING: 1149 { 1150 const uint32* encoding; 1151 if (callbacks.set_font_encoding == NULL 1152 || !reader.Get(encoding)) { 1153 break; 1154 } 1155 1156 callbacks.set_font_encoding(userData, *encoding); 1157 break; 1158 } 1159 1160 case B_PIC_SET_FONT_FLAGS: 1161 { 1162 const uint32* flags; 1163 if (callbacks.set_font_flags == NULL || !reader.Get(flags)) 1164 break; 1165 1166 callbacks.set_font_flags(userData, *flags); 1167 break; 1168 } 1169 1170 case B_PIC_SET_FONT_SHEAR: 1171 { 1172 const float* shear; 1173 if (callbacks.set_font_shear == NULL || !reader.Get(shear)) 1174 break; 1175 1176 callbacks.set_font_shear(userData, *shear); 1177 break; 1178 } 1179 1180 case B_PIC_SET_FONT_FACE: 1181 { 1182 const uint32* face; 1183 if (callbacks.set_font_face == NULL || !reader.Get(face)) 1184 break; 1185 1186 callbacks.set_font_face(userData, *face); 1187 break; 1188 } 1189 1190 case B_PIC_SET_BLENDING_MODE: 1191 { 1192 const uint16* alphaSourceMode; 1193 const uint16* alphaFunctionMode; 1194 if (callbacks.set_blending_mode == NULL 1195 || !reader.Get(alphaSourceMode) 1196 || !reader.Get(alphaFunctionMode)) { 1197 break; 1198 } 1199 1200 callbacks.set_blending_mode(userData, 1201 (source_alpha)*alphaSourceMode, 1202 (alpha_function)*alphaFunctionMode); 1203 break; 1204 } 1205 1206 case B_PIC_SET_TRANSFORM: 1207 { 1208 const BAffineTransform* transform; 1209 if (callbacks.set_transform == NULL || !reader.Get(transform)) 1210 break; 1211 1212 callbacks.set_transform(userData, *transform); 1213 break; 1214 } 1215 1216 case B_PIC_AFFINE_TRANSLATE: 1217 { 1218 const double* x; 1219 const double* y; 1220 if (callbacks.translate_by == NULL || !reader.Get(x) 1221 || !reader.Get(y)) { 1222 break; 1223 } 1224 1225 callbacks.translate_by(userData, *x, *y); 1226 break; 1227 } 1228 1229 case B_PIC_AFFINE_SCALE: 1230 { 1231 const double* x; 1232 const double* y; 1233 if (callbacks.scale_by == NULL || !reader.Get(x) 1234 || !reader.Get(y)) { 1235 break; 1236 } 1237 1238 callbacks.scale_by(userData, *x, *y); 1239 break; 1240 } 1241 1242 case B_PIC_AFFINE_ROTATE: 1243 { 1244 const double* angleRadians; 1245 if (callbacks.rotate_by == NULL || !reader.Get(angleRadians)) 1246 break; 1247 1248 callbacks.rotate_by(userData, *angleRadians); 1249 break; 1250 } 1251 1252 case B_PIC_BLEND_LAYER: 1253 { 1254 Layer* const* layer; 1255 if (callbacks.blend_layer == NULL || !reader.Get<Layer*>(layer)) 1256 break; 1257 1258 callbacks.blend_layer(userData, *layer); 1259 break; 1260 } 1261 1262 case B_PIC_CLIP_TO_RECT: 1263 { 1264 const bool* inverse; 1265 const BRect* rect; 1266 1267 if (callbacks.clip_to_rect == NULL || !reader.Get(inverse) 1268 || !reader.Get(rect)) { 1269 break; 1270 } 1271 1272 callbacks.clip_to_rect(userData, *rect, *inverse); 1273 break; 1274 } 1275 1276 case B_PIC_CLIP_TO_SHAPE: 1277 { 1278 const bool* inverse; 1279 const uint32* opCount; 1280 const uint32* pointCount; 1281 const uint32* opList; 1282 const BPoint* pointList; 1283 if (callbacks.clip_to_shape == NULL || !reader.Get(inverse) 1284 || !reader.Get(opCount) || !reader.Get(pointCount) 1285 || !reader.Get(opList, *opCount) 1286 || !reader.Get(pointList, *pointCount)) { 1287 break; 1288 } 1289 1290 callbacks.clip_to_shape(userData, *opCount, opList, 1291 *pointCount, pointList, *inverse); 1292 break; 1293 } 1294 1295 default: 1296 break; 1297 } 1298 1299 #if DEBUG 1300 numOps++; 1301 #if DEBUG > 1 1302 printf("executed in %" B_PRId64 " usecs\n", system_time() 1303 - startOpTime); 1304 #endif 1305 #endif 1306 } 1307 1308 #if DEBUG 1309 printf("Done! %" B_PRId32 " ops, rendering completed in %" B_PRId64 1310 " usecs.\n", numOps, system_time() - startTime); 1311 #endif 1312 return B_OK; 1313 } 1314