1 /* 2 * Copyright 2001-2007, Haiku. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Marc Flerackers (mflerackers@androme.be) 7 * Stefano Ceccherini (burton666@libero.it) 8 * Marcus Overhagen <marcus@overhagen.de> 9 */ 10 11 12 #include "DrawingEngine.h" 13 #include "ServerBitmap.h" 14 #include "ServerPicture.h" 15 #include "ServerTokenSpace.h" 16 #include "ViewLayer.h" 17 #include "WindowLayer.h" 18 19 #include <LinkReceiver.h> 20 #include <PicturePlayer.h> 21 #include <PictureProtocol.h> 22 #include <ServerProtocol.h> 23 #include <ShapePrivate.h> 24 25 #include <Bitmap.h> 26 #include <Shape.h> 27 28 #include <stdio.h> 29 #include <stack> 30 31 using std::stack; 32 33 class ShapePainter : public BShapeIterator { 34 public: 35 ShapePainter(); 36 virtual ~ShapePainter(); 37 38 status_t Iterate(const BShape *shape); 39 40 virtual status_t IterateMoveTo(BPoint *point); 41 virtual status_t IterateLineTo(int32 lineCount, BPoint *linePts); 42 virtual status_t IterateBezierTo(int32 bezierCount, BPoint *bezierPts); 43 virtual status_t IterateClose(); 44 45 void Draw(ViewLayer *view, BRect frame, bool filled); 46 47 private: 48 stack<uint32> fOpStack; 49 stack<BPoint> fPtStack; 50 }; 51 52 ShapePainter::ShapePainter() 53 : BShapeIterator() 54 { 55 } 56 57 ShapePainter::~ShapePainter() 58 { 59 } 60 61 status_t 62 ShapePainter::Iterate(const BShape *shape) 63 { 64 // this class doesn't modify the shape data 65 return BShapeIterator::Iterate(const_cast<BShape *>(shape)); 66 } 67 68 status_t 69 ShapePainter::IterateMoveTo(BPoint *point) 70 { 71 fOpStack.push(OP_MOVETO); 72 fPtStack.push(*point); 73 74 return B_OK; 75 } 76 77 status_t 78 ShapePainter::IterateLineTo(int32 lineCount, BPoint *linePts) 79 { 80 fOpStack.push(OP_LINETO | lineCount); 81 for(int32 i = 0;i < lineCount;i++) 82 fPtStack.push(linePts[i]); 83 84 return B_OK; 85 } 86 87 status_t 88 ShapePainter::IterateBezierTo(int32 bezierCount, BPoint *bezierPts) 89 { 90 bezierCount *= 3; 91 fOpStack.push(OP_BEZIERTO | bezierCount); 92 for(int32 i = 0;i < bezierCount;i++) 93 fPtStack.push(bezierPts[i]); 94 95 return B_OK; 96 } 97 98 status_t 99 ShapePainter::IterateClose(void) 100 { 101 fOpStack.push(OP_CLOSE); 102 103 return B_OK; 104 } 105 106 void 107 ShapePainter::Draw(ViewLayer *view, BRect frame, bool filled) 108 { 109 // We're going to draw the currently iterated picture. 110 int32 opCount, ptCount; 111 opCount = fOpStack.size(); 112 ptCount = fPtStack.size(); 113 114 uint32 *opList; 115 BPoint *ptList; 116 if(opCount > 0 && ptCount > 0) { 117 int32 i; 118 opList = new uint32[opCount]; 119 ptList = new BPoint[ptCount]; 120 121 for(i = (opCount - 1);i >= 0;i--) { 122 opList[i] = fOpStack.top(); 123 fOpStack.pop(); 124 } 125 126 for(i = (ptCount - 1);i >= 0;i--) { 127 ptList[i] = fPtStack.top(); 128 fPtStack.pop(); 129 } 130 131 view->Window()->GetDrawingEngine()->DrawShape(frame, opCount, opList, ptCount, ptList, 132 view->CurrentState(), filled); 133 } 134 } 135 136 static void 137 get_polygon_frame(const BPoint *points, int32 numPoints, BRect *_frame) 138 { 139 float l, t, r, b; 140 141 ASSERT(numPoints > 0); 142 143 l = r = points->x; 144 t = b = points->y; 145 146 points++; 147 numPoints--; 148 149 while (numPoints--) { 150 if (points->x < l) 151 l = points->x; 152 if (points->x > r) 153 r = points->x; 154 if (points->y < t) 155 t = points->y; 156 if (points->y > b) 157 b = points->y; 158 points++; 159 } 160 161 _frame->Set(l, t, r, b); 162 } 163 164 165 static void 166 nop() 167 { 168 } 169 170 171 static void 172 move_pen_by(ViewLayer *view, BPoint delta) 173 { 174 view->CurrentState()->SetPenLocation(delta - view->CurrentState()->PenLocation()); 175 } 176 177 178 static void 179 stroke_line(ViewLayer *view, BPoint start, BPoint end) 180 { 181 view->ConvertToScreenForDrawing(&start); 182 view->ConvertToScreenForDrawing(&end); 183 view->Window()->GetDrawingEngine()->StrokeLine(start, end, view->CurrentState()); 184 } 185 186 187 static void 188 stroke_rect(ViewLayer *view, BRect rect) 189 { 190 view->ConvertToScreenForDrawing(&rect); 191 view->Window()->GetDrawingEngine()->StrokeRect(rect, view->CurrentState()); 192 } 193 194 195 static void 196 fill_rect(ViewLayer *view, BRect rect) 197 { 198 view->ConvertToScreenForDrawing(&rect); 199 view->Window()->GetDrawingEngine()->FillRect(rect, view->CurrentState()); 200 } 201 202 203 static void 204 stroke_round_rect(ViewLayer *view, BRect rect, BPoint radii) 205 { 206 view->ConvertToScreenForDrawing(&rect); 207 view->Window()->GetDrawingEngine()->DrawRoundRect(rect, radii.x, radii.y, view->CurrentState(), false); 208 } 209 210 211 static void 212 fill_round_rect(ViewLayer *view, BRect rect, BPoint radii) 213 { 214 view->ConvertToScreenForDrawing(&rect); 215 view->Window()->GetDrawingEngine()->DrawRoundRect(rect, radii.x, radii.y, view->CurrentState(), true); 216 } 217 218 219 static void 220 stroke_bezier(ViewLayer *view, const BPoint *viewPoints) 221 { 222 BPoint points[4]; 223 view->ConvertToScreenForDrawing(points, viewPoints, 4); 224 225 view->Window()->GetDrawingEngine()->DrawBezier(points, view->CurrentState(), false); 226 } 227 228 229 static void 230 fill_bezier(ViewLayer *view, const BPoint *viewPoints) 231 { 232 BPoint points[4]; 233 view->ConvertToScreenForDrawing(points, viewPoints, 4); 234 235 view->Window()->GetDrawingEngine()->DrawBezier(points, view->CurrentState(), true); 236 } 237 238 239 static void 240 stroke_arc(ViewLayer *view, BPoint center, BPoint radii, float startTheta, 241 float arcTheta) 242 { 243 BRect rect(center.x - radii.x, center.y - radii.y, center.x + radii.x, 244 center.y + radii.y); 245 view->ConvertToScreenForDrawing(&rect); 246 view->Window()->GetDrawingEngine()->DrawArc(rect, startTheta, arcTheta, view->CurrentState(), false); 247 } 248 249 250 static void 251 fill_arc(ViewLayer *view, BPoint center, BPoint radii, float startTheta, 252 float arcTheta) 253 { 254 BRect rect(center.x - radii.x, center.y - radii.y, center.x + radii.x, 255 center.y + radii.y); 256 view->ConvertToScreenForDrawing(&rect); 257 view->Window()->GetDrawingEngine()->DrawArc(rect, startTheta, arcTheta, view->CurrentState(), true); 258 } 259 260 261 static void 262 stroke_ellipse(ViewLayer *view, BPoint center, BPoint radii) 263 { 264 BRect rect(center.x - radii.x, center.y - radii.y, center.x + radii.x, 265 center.y + radii.y); 266 view->ConvertToScreenForDrawing(&rect); 267 view->Window()->GetDrawingEngine()->DrawEllipse(rect, view->CurrentState(), false); 268 } 269 270 271 static void 272 fill_ellipse(ViewLayer *view, BPoint center, BPoint radii) 273 { 274 BRect rect(center.x - radii.x, center.y - radii.y, center.x + radii.x, 275 center.y + radii.y); 276 view->ConvertToScreenForDrawing(&rect); 277 view->Window()->GetDrawingEngine()->DrawEllipse(rect, view->CurrentState(), true); 278 } 279 280 281 static void 282 stroke_polygon(ViewLayer *view, int32 numPoints, const BPoint *viewPoints, bool isClosed) 283 { 284 if (numPoints <= 0) { 285 return; 286 } else if (numPoints <= 200) { 287 // fast path: no malloc/free, also avoid constructor/destructor calls 288 char data[200 * sizeof(BPoint)]; 289 BPoint *points = (BPoint *)data; 290 291 view->ConvertToScreenForDrawing(points, viewPoints, numPoints); 292 293 BRect polyFrame; 294 get_polygon_frame(points, numPoints, &polyFrame); 295 296 view->Window()->GetDrawingEngine()->DrawPolygon(points, numPoints, polyFrame, 297 view->CurrentState(), false, 298 isClosed && numPoints > 2); 299 } else { 300 // avoid constructor/destructor calls by using malloc instead of new [] 301 BPoint *points = (BPoint *)malloc(numPoints * sizeof(BPoint)); 302 if (!points) 303 return; 304 305 view->ConvertToScreenForDrawing(points, viewPoints, numPoints); 306 307 BRect polyFrame; 308 get_polygon_frame(points, numPoints, &polyFrame); 309 310 view->Window()->GetDrawingEngine()->DrawPolygon(points, numPoints, polyFrame, 311 view->CurrentState(), false, 312 isClosed && numPoints > 2); 313 free(points); 314 } 315 } 316 317 318 static void 319 fill_polygon(ViewLayer *view, int32 numPoints, const BPoint *viewPoints) 320 { 321 if (numPoints <= 0) { 322 return; 323 } else if (numPoints <= 200) { 324 // fast path: no malloc/free, also avoid constructor/destructor calls 325 char data[200 * sizeof(BPoint)]; 326 BPoint *points = (BPoint *)data; 327 328 view->ConvertToScreenForDrawing(points, viewPoints, numPoints); 329 330 BRect polyFrame; 331 get_polygon_frame(points, numPoints, &polyFrame); 332 333 view->Window()->GetDrawingEngine()->DrawPolygon(points, numPoints, polyFrame, 334 view->CurrentState(), true, true); 335 } else { 336 // avoid constructor/destructor calls by using malloc instead of new [] 337 BPoint *points = (BPoint *)malloc(numPoints * sizeof(BPoint)); 338 if (!points) 339 return; 340 341 view->ConvertToScreenForDrawing(points, viewPoints, numPoints); 342 343 BRect polyFrame; 344 get_polygon_frame(points, numPoints, &polyFrame); 345 346 view->Window()->GetDrawingEngine()->DrawPolygon(points, numPoints, polyFrame, 347 view->CurrentState(), true, true); 348 free(points); 349 } 350 } 351 352 353 static void 354 stroke_shape(ViewLayer *view, const BShape *shape) 355 { 356 ShapePainter drawShape; 357 358 drawShape.Iterate(shape); 359 drawShape.Draw(view, shape->Bounds(), false); 360 } 361 362 363 static void 364 fill_shape(ViewLayer *view, const BShape *shape) 365 { 366 ShapePainter drawShape; 367 368 drawShape.Iterate(shape); 369 drawShape.Draw(view, shape->Bounds(), true); 370 } 371 372 373 static void 374 draw_string(ViewLayer *view, const char *string, float deltaSpace, float deltaNonSpace) 375 { 376 BPoint location = view->CurrentState()->PenLocation(); 377 escapement_delta delta = {deltaSpace, deltaNonSpace }; 378 view->ConvertToScreenForDrawing(&location); 379 view->Window()->GetDrawingEngine()->DrawString(string, strlen(string), location, 380 view->CurrentState(), &delta); 381 // TODO: Update pen location ? 382 383 } 384 385 386 static void 387 draw_pixels(ViewLayer *view, BRect src, BRect dest, int32 width, int32 height, 388 int32 bytesPerRow, int32 pixelFormat, int32 flags, const void *data) 389 { 390 // TODO: Review this 391 UtilityBitmap bitmap(BRect(0, 0, width - 1, height - 1), (color_space)pixelFormat, flags, bytesPerRow); 392 393 if (!bitmap.IsValid()) 394 return; 395 396 memcpy(bitmap.Bits(), data, height * bytesPerRow); 397 398 view->ConvertToScreenForDrawing(&dest); 399 400 view->Window()->GetDrawingEngine()->DrawBitmap(&bitmap, src, dest, view->CurrentState()); 401 } 402 403 404 static void 405 set_clipping_rects(ViewLayer *view, const BRect *rects, uint32 numRects) 406 { 407 // TODO: This is too slow, we should copy the rects directly to BRegion's internal data 408 BRegion region; 409 for (uint32 c = 0; c < numRects; c++) 410 region.Include(rects[c]); 411 view->SetUserClipping(®ion); 412 } 413 414 415 static void 416 clip_to_picture(ViewLayer *view, BPicture *picture, BPoint pt, 417 bool clip_to_inverse_picture) 418 { 419 printf("ClipToPicture(picture, BPoint(%.2f, %.2f), %s)\n", pt.x, pt.y, 420 clip_to_inverse_picture ? "inverse" : ""); 421 } 422 423 424 static void 425 push_state(ViewLayer *view) 426 { 427 view->PushState(); 428 } 429 430 431 static void 432 pop_state(ViewLayer *view) 433 { 434 view->PopState(); 435 } 436 437 438 static void 439 enter_state_change(ViewLayer *view) 440 { 441 printf("EnterStateChange\n"); 442 } 443 444 445 static void 446 exit_state_change(ViewLayer *view) 447 { 448 printf("ExitStateChange\n"); 449 } 450 451 452 static void 453 enter_font_state(ViewLayer *view) 454 { 455 printf("EnterFontState\n"); 456 } 457 458 459 static void 460 exit_font_state(ViewLayer *view) 461 { 462 printf("ExitFontState\n"); 463 } 464 465 466 static void 467 set_origin(ViewLayer *view, BPoint pt) 468 { 469 view->CurrentState()->SetOrigin(pt); 470 } 471 472 473 static void 474 set_pen_location(ViewLayer *view, BPoint pt) 475 { 476 view->CurrentState()->SetPenLocation(pt); 477 } 478 479 480 static void 481 set_drawing_mode(ViewLayer *view, drawing_mode mode) 482 { 483 view->CurrentState()->SetDrawingMode(mode); 484 } 485 486 487 static void 488 set_line_mode(ViewLayer *view, cap_mode capMode, join_mode joinMode, float miterLimit) 489 { 490 DrawState *state = view->CurrentState(); 491 state->SetLineCapMode(capMode); 492 state->SetLineJoinMode(joinMode); 493 state->SetMiterLimit(miterLimit); 494 } 495 496 497 static void 498 set_pen_size(ViewLayer *view, float size) 499 { 500 view->CurrentState()->SetPenSize(size); 501 } 502 503 504 static void 505 set_fore_color(ViewLayer *view, rgb_color color) 506 { 507 view->CurrentState()->SetHighColor(RGBColor(color)); 508 } 509 510 511 static void 512 set_back_color(ViewLayer *view, rgb_color color) 513 { 514 view->CurrentState()->SetLowColor(RGBColor(color)); 515 } 516 517 518 static void 519 set_stipple_pattern(ViewLayer *view, pattern p) 520 { 521 printf("SetStipplePattern\n"); 522 } 523 524 525 static void 526 set_scale(ViewLayer *view, float scale) 527 { 528 view->CurrentState()->SetScale(scale); 529 } 530 531 532 static void 533 set_font_family(ViewLayer *view, const char *family) 534 { 535 printf("SetFontFamily(%s)\n", family); 536 } 537 538 539 static void 540 set_font_style(ViewLayer *view, const char *style) 541 { 542 printf("SetFontStyle(%s)\n", style); 543 } 544 545 546 static void 547 set_font_spacing(ViewLayer *view, int32 spacing) 548 { 549 printf("SetFontSpacing(%ld)\n", spacing); 550 } 551 552 553 static void 554 set_font_size(ViewLayer *view, float size) 555 { 556 ServerFont font; 557 font.SetSize(size); 558 view->CurrentState()->SetFont(font, B_FONT_SIZE); 559 } 560 561 562 static void 563 set_font_rotate(ViewLayer *view, float rotation) 564 { 565 printf("SetFontRotate(%.2f)\n", rotation); 566 } 567 568 569 static void 570 set_font_encoding(ViewLayer *view, int32 encoding) 571 { 572 printf("SetFontEncoding(%ld)\n", encoding); 573 } 574 575 576 static void 577 set_font_flags(ViewLayer *view, int32 flags) 578 { 579 printf("SetFontFlags(%ld)\n", flags); 580 } 581 582 583 static void 584 set_font_shear(ViewLayer *view, float shear) 585 { 586 printf("SetFontShear(%.2f)\n", shear); 587 } 588 589 590 static void 591 set_font_face(ViewLayer *view, int32 flags) 592 { 593 printf("SetFontFace(%ld)\n", flags); 594 } 595 596 597 static void 598 set_blending_mode(ViewLayer *view, int16 alphaSrcMode, int16 alphaFncMode) 599 { 600 view->CurrentState()->SetBlendingMode((source_alpha)alphaSrcMode, (alpha_function)alphaFncMode); 601 } 602 603 604 static void 605 reserved() 606 { 607 } 608 609 610 const void *tableEntries[] = { 611 (const void *)nop, 612 (const void *)move_pen_by, 613 (const void *)stroke_line, 614 (const void *)stroke_rect, 615 (const void *)fill_rect, 616 (const void *)stroke_round_rect, 617 (const void *)fill_round_rect, 618 (const void *)stroke_bezier, 619 (const void *)fill_bezier, 620 (const void *)stroke_arc, 621 (const void *)fill_arc, 622 (const void *)stroke_ellipse, 623 (const void *)fill_ellipse, 624 (const void *)stroke_polygon, 625 (const void *)fill_polygon, 626 (const void *)stroke_shape, 627 (const void *)fill_shape, 628 (const void *)draw_string, 629 (const void *)draw_pixels, 630 (const void *)reserved, // TODO: This is probably "draw_picture". Investigate 631 (const void *)set_clipping_rects, 632 (const void *)clip_to_picture, 633 (const void *)push_state, 634 (const void *)pop_state, 635 (const void *)enter_state_change, 636 (const void *)exit_state_change, 637 (const void *)enter_font_state, 638 (const void *)exit_font_state, 639 (const void *)set_origin, 640 (const void *)set_pen_location, 641 (const void *)set_drawing_mode, 642 (const void *)set_line_mode, 643 (const void *)set_pen_size, 644 (const void *)set_fore_color, 645 (const void *)set_back_color, 646 (const void *)set_stipple_pattern, 647 (const void *)set_scale, 648 (const void *)set_font_family, 649 (const void *)set_font_style, 650 (const void *)set_font_spacing, 651 (const void *)set_font_size, 652 (const void *)set_font_rotate, 653 (const void *)set_font_encoding, 654 (const void *)set_font_flags, 655 (const void *)set_font_shear, 656 (const void *)reserved, // TODO: Marc Flerackers calls this "set_font_bpp". Investigate 657 (const void *)set_font_face, // TODO: R5 function table ends here... how is set blending mode implemented there ? 658 (const void *)set_blending_mode 659 }; 660 661 662 // ServerPicture 663 ServerPicture::ServerPicture() 664 :PictureDataWriter(&fData) 665 { 666 fToken = gTokenSpace.NewToken(kPictureToken, this); 667 } 668 669 670 ServerPicture::ServerPicture(const ServerPicture &picture) 671 :PictureDataWriter(&fData) 672 { 673 fToken = gTokenSpace.NewToken(kPictureToken, this); 674 675 fData.Write(picture.Data(), picture.DataLength()); 676 } 677 678 679 ServerPicture::~ServerPicture() 680 { 681 } 682 683 684 void 685 ServerPicture::SyncState(ViewLayer *view) 686 { 687 // TODO: Finish this 688 BeginOp(B_PIC_ENTER_STATE_CHANGE); 689 690 // WriteSetPenLocation(view->CurrentState()->PenLocation()); 691 WriteSetPenSize(view->CurrentState()->PenSize()); 692 WriteSetScale(view->CurrentState()->Scale()); 693 WriteSetLineMode(view->CurrentState()->LineCapMode(), view->CurrentState()->LineJoinMode(), 694 view->CurrentState()->MiterLimit()); 695 696 /* 697 BeginOp(B_PIC_SET_STIPLE_PATTERN); 698 AddData(view->CurrentState()->GetPattern().GetInt8(), sizeof(pattern)); 699 EndOp(); 700 */ 701 WriteSetDrawingMode(view->CurrentState()->GetDrawingMode()); 702 703 /*BeginOp(B_PIC_SET_BLENDING_MODE); 704 AddInt16((int16)view->CurrentState()->AlphaSrcMode()); 705 AddInt16((int16)view->CurrentState()->AlphaFncMode()); 706 EndOp(); 707 */ 708 WriteSetHighColor(view->CurrentState()->HighColor().GetColor32()); 709 WriteSetLowColor(view->CurrentState()->LowColor().GetColor32()); 710 711 EndOp(); 712 713 } 714 715 716 void 717 ServerPicture::Play(ViewLayer *view) 718 { 719 PicturePlayer player(fData.Buffer(), fData.BufferLength(), NULL); 720 player.Play(const_cast<void **>(tableEntries), sizeof(tableEntries) / sizeof(void *), view); 721 } 722 723 724 status_t 725 ServerPicture::ImportData(BPrivate::LinkReceiver &link) 726 { 727 int32 subPicturesCount = 0; 728 link.Read<int32>(&subPicturesCount); 729 for (int32 c = 0; c < subPicturesCount; c++) { 730 // TODO: Support nested pictures 731 } 732 733 int32 size = 0; 734 link.Read<int32>(&size); 735 if (fData.SetSize(size) != B_OK) 736 return B_ERROR; 737 738 // TODO: The best way to do this would be to read the data into 739 // a temporary buffer, and then use the BMallocIO::Write() method, 740 // but this way we avoid an extra copy. Unfortunately BMallocIO::Write() 741 // only accepts a pointer to raw data... 742 link.Read(const_cast<void *>(fData.Buffer()), size); 743 744 return B_OK; 745 } 746