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