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