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