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 <string.h> 17 18 #include <AffineTransform.h> 19 #include <PictureProtocol.h> 20 #include <Shape.h> 21 22 23 using BPrivate::PicturePlayer; 24 25 26 typedef void (*fnc)(void*); 27 typedef void (*fnc_BPoint)(void*, BPoint); 28 typedef void (*fnc_BPointBPoint)(void*, BPoint, BPoint); 29 typedef void (*fnc_BRect)(void*, BRect); 30 typedef void (*fnc_BRectBPoint)(void*, BRect, BPoint); 31 typedef void (*fnc_PBPoint)(void*, const BPoint*); 32 typedef void (*fnc_i)(void*, int32); 33 typedef void (*fnc_iPBPointb)(void*, int32, const BPoint*, bool); 34 typedef void (*fnc_iPBPoint)(void*, int32, const BPoint*); 35 typedef void (*fnc_Pc)(void*, const char*); 36 typedef void (*fnc_Pcff)(void*, const char*, float, float); 37 typedef void (*fnc_BPointBPointff)(void*, BPoint, BPoint, float, float); 38 typedef void (*fnc_s)(void*, int16); 39 typedef void (*fnc_ssf)(void*, int16, int16, float); 40 typedef void (*fnc_f)(void*, float); 41 typedef void (*fnc_Color)(void*, rgb_color); 42 typedef void (*fnc_Pattern)(void*, pattern); 43 typedef void (*fnc_ss)(void *, int16, int16); 44 typedef void (*fnc_PBRecti)(void*, const BRect*, uint32); 45 typedef void (*fnc_DrawPixels)(void *, BRect, BRect, int32, int32, int32, 46 int32, int32, const void *); 47 typedef void (*fnc_DrawPicture)(void *, BPoint, int32); 48 typedef void (*fnc_BShape)(void*, BShape*); 49 typedef void (*fnc_BAffineTransform)(void*, BAffineTransform); 50 51 52 static void 53 nop() 54 { 55 } 56 57 58 #if DEBUG > 1 59 static const char * 60 PictureOpToString(int op) 61 { 62 #define RETURN_STRING(x) case x: return #x 63 64 switch(op) { 65 RETURN_STRING(B_PIC_MOVE_PEN_BY); 66 RETURN_STRING(B_PIC_STROKE_LINE); 67 RETURN_STRING(B_PIC_STROKE_RECT); 68 RETURN_STRING(B_PIC_FILL_RECT); 69 RETURN_STRING(B_PIC_STROKE_ROUND_RECT); 70 RETURN_STRING(B_PIC_FILL_ROUND_RECT); 71 RETURN_STRING(B_PIC_STROKE_BEZIER); 72 RETURN_STRING(B_PIC_FILL_BEZIER); 73 RETURN_STRING(B_PIC_STROKE_POLYGON); 74 RETURN_STRING(B_PIC_FILL_POLYGON); 75 RETURN_STRING(B_PIC_STROKE_SHAPE); 76 RETURN_STRING(B_PIC_FILL_SHAPE); 77 RETURN_STRING(B_PIC_DRAW_STRING); 78 RETURN_STRING(B_PIC_DRAW_PIXELS); 79 RETURN_STRING(B_PIC_DRAW_PICTURE); 80 RETURN_STRING(B_PIC_STROKE_ARC); 81 RETURN_STRING(B_PIC_FILL_ARC); 82 RETURN_STRING(B_PIC_STROKE_ELLIPSE); 83 RETURN_STRING(B_PIC_FILL_ELLIPSE); 84 85 RETURN_STRING(B_PIC_ENTER_STATE_CHANGE); 86 RETURN_STRING(B_PIC_SET_CLIPPING_RECTS); 87 RETURN_STRING(B_PIC_CLIP_TO_PICTURE); 88 RETURN_STRING(B_PIC_PUSH_STATE); 89 RETURN_STRING(B_PIC_POP_STATE); 90 RETURN_STRING(B_PIC_CLEAR_CLIPPING_RECTS); 91 92 RETURN_STRING(B_PIC_SET_ORIGIN); 93 RETURN_STRING(B_PIC_SET_PEN_LOCATION); 94 RETURN_STRING(B_PIC_SET_DRAWING_MODE); 95 RETURN_STRING(B_PIC_SET_LINE_MODE); 96 RETURN_STRING(B_PIC_SET_PEN_SIZE); 97 RETURN_STRING(B_PIC_SET_SCALE); 98 RETURN_STRING(B_PIC_SET_TRANSFORM); 99 RETURN_STRING(B_PIC_SET_FORE_COLOR); 100 RETURN_STRING(B_PIC_SET_BACK_COLOR); 101 RETURN_STRING(B_PIC_SET_STIPLE_PATTERN); 102 RETURN_STRING(B_PIC_ENTER_FONT_STATE); 103 RETURN_STRING(B_PIC_SET_BLENDING_MODE); 104 RETURN_STRING(B_PIC_SET_FONT_FAMILY); 105 RETURN_STRING(B_PIC_SET_FONT_STYLE); 106 RETURN_STRING(B_PIC_SET_FONT_SPACING); 107 RETURN_STRING(B_PIC_SET_FONT_ENCODING); 108 RETURN_STRING(B_PIC_SET_FONT_FLAGS); 109 RETURN_STRING(B_PIC_SET_FONT_SIZE); 110 RETURN_STRING(B_PIC_SET_FONT_ROTATE); 111 RETURN_STRING(B_PIC_SET_FONT_SHEAR); 112 RETURN_STRING(B_PIC_SET_FONT_BPP); 113 RETURN_STRING(B_PIC_SET_FONT_FACE); 114 default: return "Unknown op"; 115 } 116 #undef RETURN_STRING 117 } 118 #endif 119 120 121 PicturePlayer::PicturePlayer(const void *data, size_t size, BList *pictures) 122 : fData(data), 123 fSize(size), 124 fPictures(pictures) 125 { 126 } 127 128 129 PicturePlayer::~PicturePlayer() 130 { 131 } 132 133 134 status_t 135 PicturePlayer::Play(void **callBackTable, int32 tableEntries, void *userData) 136 { 137 // We don't check if the functions in the table are NULL, but we 138 // check the tableEntries to see if the table is big enough. 139 // If an application supplies the wrong size or an invalid pointer, 140 // it's its own fault. 141 #if DEBUG 142 FILE *file = fopen("/var/log/PicturePlayer.log", "a"); 143 fprintf(file, "Start rendering BPicture...\n"); 144 bigtime_t startTime = system_time(); 145 int32 numOps = 0; 146 #endif 147 // If the caller supplied a function table smaller than needed, 148 // we use our dummy table, and copy the supported ops from the supplied one. 149 void **functionTable = callBackTable; 150 void *dummyTable[kOpsTableSize] = { 151 (void *)nop, (void *)nop, (void *)nop, (void *)nop, 152 (void *)nop, (void *)nop, (void *)nop, (void *)nop, 153 (void *)nop, (void *)nop, (void *)nop, (void *)nop, 154 (void *)nop, (void *)nop, (void *)nop, (void *)nop, 155 (void *)nop, (void *)nop, (void *)nop, (void *)nop, 156 (void *)nop, (void *)nop, (void *)nop, (void *)nop, 157 (void *)nop, (void *)nop, (void *)nop, (void *)nop, 158 (void *)nop, (void *)nop, (void *)nop, (void *)nop, 159 (void *)nop, (void *)nop, (void *)nop, (void *)nop, 160 (void *)nop, (void *)nop, (void *)nop, (void *)nop, 161 (void *)nop, (void *)nop, (void *)nop, (void *)nop, 162 (void *)nop, (void *)nop, (void *)nop, (void *)nop 163 }; 164 165 if ((uint32)tableEntries < kOpsTableSize) { 166 #if DEBUG 167 fprintf(file, "PicturePlayer: A smaller than needed function table was supplied.\n"); 168 #endif 169 functionTable = dummyTable; 170 memcpy(functionTable, callBackTable, tableEntries * sizeof(void *)); 171 } 172 173 const char *data = reinterpret_cast<const char *>(fData); 174 size_t pos = 0; 175 176 int32 fontStateBlockSize = -1; 177 int32 stateBlockSize = -1; 178 179 while ((pos + 6) <= fSize) { 180 int16 op = *reinterpret_cast<const int16 *>(data); 181 int32 size = *reinterpret_cast<const int32 *>(data + 2); 182 pos += 6; 183 data += 6; 184 185 if (pos + size > fSize) 186 debugger("PicturePlayer::Play: buffer overrun\n"); 187 188 #if DEBUG > 1 189 bigtime_t startOpTime = system_time(); 190 fprintf(file, "Op %s ", PictureOpToString(op)); 191 #endif 192 switch (op) { 193 case B_PIC_MOVE_PEN_BY: 194 { 195 ((fnc_BPoint)functionTable[1])(userData, 196 *reinterpret_cast<const BPoint *>(data)); /* where */ 197 break; 198 } 199 200 case B_PIC_STROKE_LINE: 201 { 202 ((fnc_BPointBPoint)functionTable[2])(userData, 203 *reinterpret_cast<const BPoint *>(data), /* start */ 204 *reinterpret_cast<const BPoint *>(data + sizeof(BPoint))); /* end */ 205 break; 206 } 207 208 case B_PIC_STROKE_RECT: 209 { 210 ((fnc_BRect)functionTable[3])(userData, 211 *reinterpret_cast<const BRect *>(data)); /* rect */ 212 break; 213 } 214 215 case B_PIC_FILL_RECT: 216 { 217 ((fnc_BRect)functionTable[4])(userData, 218 *reinterpret_cast<const BRect *>(data)); /* rect */ 219 break; 220 } 221 222 case B_PIC_STROKE_ROUND_RECT: 223 { 224 ((fnc_BRectBPoint)functionTable[5])(userData, 225 *reinterpret_cast<const BRect *>(data), /* rect */ 226 *reinterpret_cast<const BPoint *>(data + sizeof(BRect))); /* radii */ 227 break; 228 } 229 230 case B_PIC_FILL_ROUND_RECT: 231 { 232 ((fnc_BRectBPoint)functionTable[6])(userData, 233 *reinterpret_cast<const BRect *>(data), /* rect */ 234 *reinterpret_cast<const BPoint *>(data + sizeof(BRect))); /* radii */ 235 break; 236 } 237 238 case B_PIC_STROKE_BEZIER: 239 { 240 ((fnc_PBPoint)functionTable[7])(userData, 241 reinterpret_cast<const BPoint *>(data)); 242 break; 243 } 244 245 case B_PIC_FILL_BEZIER: 246 { 247 ((fnc_PBPoint)functionTable[8])(userData, 248 reinterpret_cast<const BPoint *>(data)); 249 break; 250 } 251 252 case B_PIC_STROKE_ARC: 253 { 254 ((fnc_BPointBPointff)functionTable[9])(userData, 255 *reinterpret_cast<const BPoint *>(data), /* center */ 256 *reinterpret_cast<const BPoint *>(data + sizeof(BPoint)), /* radii */ 257 *reinterpret_cast<const float *>(data + 2 * sizeof(BPoint)), /* startTheta */ 258 *reinterpret_cast<const float *>(data + 2 * sizeof(BPoint) + sizeof(float))); /* arcTheta */ 259 break; 260 } 261 262 case B_PIC_FILL_ARC: 263 { 264 ((fnc_BPointBPointff)functionTable[10])(userData, 265 *reinterpret_cast<const BPoint *>(data), /* center */ 266 *reinterpret_cast<const BPoint *>(data + sizeof(BPoint)), /* radii */ 267 *reinterpret_cast<const float *>(data + 2 * sizeof(BPoint)), /* startTheta */ 268 *reinterpret_cast<const float *>(data + 2 * sizeof(BPoint) + sizeof(float))); /* arcTheta */ 269 break; 270 } 271 272 case B_PIC_STROKE_ELLIPSE: 273 { 274 const BRect *rect = reinterpret_cast<const BRect *>(data); 275 BPoint radii((rect->Width() + 1) / 2.0f, (rect->Height() + 1) / 2.0f); 276 BPoint center = rect->LeftTop() + radii; 277 ((fnc_BPointBPoint)functionTable[11])(userData, center, radii); 278 break; 279 } 280 281 case B_PIC_FILL_ELLIPSE: 282 { 283 const BRect *rect = reinterpret_cast<const BRect *>(data); 284 BPoint radii((rect->Width() + 1) / 2.0f, (rect->Height() + 1) / 2.0f); 285 BPoint center = rect->LeftTop() + radii; 286 ((fnc_BPointBPoint)functionTable[12])(userData, center, radii); 287 break; 288 } 289 290 case B_PIC_STROKE_POLYGON: 291 { 292 int32 numPoints = *reinterpret_cast<const int32 *>(data); 293 ((fnc_iPBPointb)functionTable[13])(userData, 294 numPoints, 295 reinterpret_cast<const BPoint *>(data + sizeof(int32)), /* points */ 296 *reinterpret_cast<const uint8 *>(data + sizeof(int32) + numPoints * sizeof(BPoint))); /* is-closed */ 297 break; 298 } 299 300 case B_PIC_FILL_POLYGON: 301 { 302 ((fnc_iPBPoint)functionTable[14])(userData, 303 *reinterpret_cast<const int32 *>(data), /* numPoints */ 304 reinterpret_cast<const BPoint *>(data + sizeof(int32))); /* points */ 305 break; 306 } 307 308 case B_PIC_STROKE_SHAPE: 309 case B_PIC_FILL_SHAPE: 310 { 311 const bool stroke = (op == B_PIC_STROKE_SHAPE); 312 int32 opCount = *reinterpret_cast<const int32 *>(data); 313 int32 ptCount = *reinterpret_cast<const int32 *>(data + sizeof(int32)); 314 const uint32 *opList = reinterpret_cast<const uint32 *>(data + 2 * sizeof(int32)); 315 const BPoint *ptList = reinterpret_cast<const BPoint *>(data + 2 * sizeof(int32) + opCount * sizeof(uint32)); 316 317 // TODO: remove BShape data copying 318 BShape shape; 319 shape.SetData(opCount, ptCount, opList, ptList); 320 321 const int32 tableIndex = stroke ? 15 : 16; 322 ((fnc_BShape)functionTable[tableIndex])(userData, &shape); 323 break; 324 } 325 326 case B_PIC_DRAW_STRING: 327 { 328 ((fnc_Pcff)functionTable[17])(userData, 329 reinterpret_cast<const char *>(data + 2 * sizeof(float)), /* string */ 330 *reinterpret_cast<const float *>(data), /* escapement.space */ 331 *reinterpret_cast<const float *>(data + sizeof(float))); /* escapement.nonspace */ 332 break; 333 } 334 335 case B_PIC_DRAW_PIXELS: 336 { 337 ((fnc_DrawPixels)functionTable[18])(userData, 338 *reinterpret_cast<const BRect *>(data), /* src */ 339 *reinterpret_cast<const BRect *>(data + 1 * sizeof(BRect)), /* dst */ 340 *reinterpret_cast<const int32 *>(data + 2 * sizeof(BRect)), /* width */ 341 *reinterpret_cast<const int32 *>(data + 2 * sizeof(BRect) + 1 * sizeof(int32)), /* height */ 342 *reinterpret_cast<const int32 *>(data + 2 * sizeof(BRect) + 2 * sizeof(int32)), /* bytesPerRow */ 343 *reinterpret_cast<const int32 *>(data + 2 * sizeof(BRect) + 3 * sizeof(int32)), /* pixelFormat */ 344 *reinterpret_cast<const int32 *>(data + 2 * sizeof(BRect) + 4 * sizeof(int32)), /* flags */ 345 reinterpret_cast<const void *>(data + 2 * sizeof(BRect) + 5 * sizeof(int32))); /* data */ 346 break; 347 } 348 349 case B_PIC_DRAW_PICTURE: 350 { 351 ((fnc_DrawPicture)functionTable[19])(userData, 352 *reinterpret_cast<const BPoint *>(data), 353 *reinterpret_cast<const int32 *>(data + sizeof(BPoint))); 354 break; 355 } 356 357 case B_PIC_SET_CLIPPING_RECTS: 358 { 359 // TODO: Not sure if it's compatible with R5's BPicture version 360 const uint32 numRects = *reinterpret_cast<const uint32 *>(data); 361 const BRect *rects = reinterpret_cast<const BRect *>(data + sizeof(uint32)); 362 ((fnc_PBRecti)functionTable[20])(userData, rects, numRects); 363 364 break; 365 } 366 367 case B_PIC_CLEAR_CLIPPING_RECTS: 368 { 369 ((fnc_PBRecti)functionTable[20])(userData, NULL, 0); 370 break; 371 } 372 373 case B_PIC_CLIP_TO_PICTURE: 374 { 375 // TODO: Implement 376 break; 377 } 378 379 case B_PIC_PUSH_STATE: 380 { 381 ((fnc)functionTable[22])(userData); 382 break; 383 } 384 385 case B_PIC_POP_STATE: 386 { 387 ((fnc)functionTable[23])(userData); 388 break; 389 } 390 391 case B_PIC_ENTER_STATE_CHANGE: 392 { 393 ((fnc)functionTable[24])(userData); 394 stateBlockSize = size; 395 break; 396 } 397 398 case B_PIC_ENTER_FONT_STATE: 399 { 400 ((fnc)functionTable[26])(userData); 401 fontStateBlockSize = size; 402 break; 403 } 404 405 case B_PIC_SET_ORIGIN: 406 { 407 ((fnc_BPoint)functionTable[28])(userData, 408 *reinterpret_cast<const BPoint *>(data)); /* origin */ 409 break; 410 } 411 412 case B_PIC_SET_PEN_LOCATION: 413 { 414 ((fnc_BPoint)functionTable[29])(userData, 415 *reinterpret_cast<const BPoint *>(data)); /* location */ 416 break; 417 } 418 419 case B_PIC_SET_DRAWING_MODE: 420 { 421 ((fnc_s)functionTable[30])(userData, 422 *reinterpret_cast<const int16 *>(data)); /* mode */ 423 break; 424 } 425 426 case B_PIC_SET_LINE_MODE: 427 { 428 ((fnc_ssf)functionTable[31])(userData, 429 *reinterpret_cast<const int16 *>(data), /* cap-mode */ 430 *reinterpret_cast<const int16 *>(data + 1 * sizeof(int16)), /* join-mode */ 431 *reinterpret_cast<const float *>(data + 2 * sizeof(int16))); /* miter-limit */ 432 break; 433 } 434 435 case B_PIC_SET_PEN_SIZE: 436 { 437 ((fnc_f)functionTable[32])(userData, 438 *reinterpret_cast<const float *>(data)); /* size */ 439 break; 440 } 441 442 case B_PIC_SET_FORE_COLOR: 443 { 444 ((fnc_Color)functionTable[33])(userData, 445 *reinterpret_cast<const rgb_color *>(data)); /* color */ 446 break; 447 } 448 449 case B_PIC_SET_BACK_COLOR: 450 { 451 ((fnc_Color)functionTable[34])(userData, 452 *reinterpret_cast<const rgb_color *>(data)); /* color */ 453 break; 454 } 455 456 case B_PIC_SET_STIPLE_PATTERN: 457 { 458 ((fnc_Pattern)functionTable[35])(userData, 459 *reinterpret_cast<const pattern *>(data)); /* pattern */ 460 break; 461 } 462 463 case B_PIC_SET_SCALE: 464 { 465 ((fnc_f)functionTable[36])(userData, 466 *reinterpret_cast<const float *>(data)); /* scale */ 467 break; 468 } 469 470 case B_PIC_SET_FONT_FAMILY: 471 { 472 ((fnc_Pc)functionTable[37])(userData, 473 reinterpret_cast<const char *>(data)); /* string */ 474 break; 475 } 476 477 case B_PIC_SET_FONT_STYLE: 478 { 479 ((fnc_Pc)functionTable[38])(userData, 480 reinterpret_cast<const char *>(data)); /* string */ 481 break; 482 } 483 484 case B_PIC_SET_FONT_SPACING: 485 { 486 ((fnc_i)functionTable[39])(userData, 487 *reinterpret_cast<const int32 *>(data)); /* spacing */ 488 break; 489 } 490 491 case B_PIC_SET_FONT_SIZE: 492 { 493 ((fnc_f)functionTable[40])(userData, 494 *reinterpret_cast<const float *>(data)); /* size */ 495 break; 496 } 497 498 case B_PIC_SET_FONT_ROTATE: 499 { 500 ((fnc_f)functionTable[41])(userData, 501 *reinterpret_cast<const float *>(data)); /* rotation */ 502 break; 503 } 504 505 case B_PIC_SET_FONT_ENCODING: 506 { 507 ((fnc_i)functionTable[42])(userData, 508 *reinterpret_cast<const int32 *>(data)); /* encoding */ 509 break; 510 } 511 512 case B_PIC_SET_FONT_FLAGS: 513 { 514 ((fnc_i)functionTable[43])(userData, 515 *reinterpret_cast<const int32 *>(data)); /* flags */ 516 break; 517 } 518 519 case B_PIC_SET_FONT_SHEAR: 520 { 521 ((fnc_f)functionTable[44])(userData, 522 *reinterpret_cast<const float *>(data)); /* shear */ 523 break; 524 } 525 526 case B_PIC_SET_FONT_FACE: 527 { 528 ((fnc_i)functionTable[46])(userData, 529 *reinterpret_cast<const int32 *>(data)); /* flags */ 530 break; 531 } 532 533 case B_PIC_SET_BLENDING_MODE: 534 { 535 ((fnc_ss)functionTable[47])(userData, 536 *reinterpret_cast<const int16 *>(data), /* alphaSrcMode */ 537 *reinterpret_cast<const int16 *>(data + sizeof(int16))); /* alphaFncMode */ 538 break; 539 } 540 541 case B_PIC_SET_TRANSFORM: 542 { 543 ((fnc_BAffineTransform)functionTable[48])(userData, 544 *reinterpret_cast<const BAffineTransform *>(data)); 545 break; 546 } 547 548 default: 549 break; 550 } 551 552 // Skip the already handled block unless it's one of these two, 553 // since they can contain other nested ops. 554 if (op != B_PIC_ENTER_STATE_CHANGE && op != B_PIC_ENTER_FONT_STATE) { 555 pos += size; 556 data += size; 557 if (stateBlockSize > 0) 558 stateBlockSize -= size + 6; 559 if (fontStateBlockSize > 0) 560 fontStateBlockSize -= size + 6; 561 } 562 563 // call the exit_state_change hook if needed 564 if (stateBlockSize == 0) { 565 ((fnc)functionTable[25])(userData); 566 stateBlockSize = -1; 567 } 568 569 // call the exit_font_state hook if needed 570 if (fontStateBlockSize == 0) { 571 ((fnc)functionTable[27])(userData); 572 fontStateBlockSize = -1; 573 } 574 #if DEBUG 575 numOps++; 576 #if DEBUG > 1 577 fprintf(file, "executed in %" B_PRId64 " usecs\n", system_time() 578 - startOpTime); 579 #endif 580 #endif 581 // TODO: what if too much was read, should we return B_ERROR? 582 } 583 584 #if DEBUG 585 fprintf(file, "Done! %" B_PRId32 " ops, rendering completed in %" 586 B_PRId64 " usecs.\n", numOps, system_time() - startTime); 587 fclose(file); 588 #endif 589 return B_OK; 590 } 591