1 /* 2 * Copyright 2001-2010, Haiku. 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 #include "ServerPicture.h" 12 13 #include <new> 14 #include <stdio.h> 15 #include <stack> 16 17 #include "DrawingEngine.h" 18 #include "DrawState.h" 19 #include "FontManager.h" 20 #include "ServerApp.h" 21 #include "ServerBitmap.h" 22 #include "ServerFont.h" 23 #include "ServerTokenSpace.h" 24 #include "View.h" 25 #include "Window.h" 26 27 #include <LinkReceiver.h> 28 #include <OffsetFile.h> 29 #include <ObjectListPrivate.h> 30 #include <PicturePlayer.h> 31 #include <PictureProtocol.h> 32 #include <PortLink.h> 33 #include <ServerProtocol.h> 34 #include <ShapePrivate.h> 35 36 #include <Bitmap.h> 37 #include <Debug.h> 38 #include <List.h> 39 #include <Shape.h> 40 41 42 using std::stack; 43 44 45 class ShapePainter : public BShapeIterator { 46 public: 47 ShapePainter(View* view); 48 virtual ~ShapePainter(); 49 50 status_t Iterate(const BShape* shape); 51 52 virtual status_t IterateMoveTo(BPoint* point); 53 virtual status_t IterateLineTo(int32 lineCount, BPoint* linePts); 54 virtual status_t IterateBezierTo(int32 bezierCount, BPoint* bezierPts); 55 virtual status_t IterateClose(); 56 virtual status_t IterateArcTo(float& rx, float& ry, 57 float& angle, bool largeArc, bool counterClockWise, BPoint& point); 58 59 void Draw(BRect frame, bool filled); 60 61 private: 62 View* fView; 63 stack<uint32> fOpStack; 64 stack<BPoint> fPtStack; 65 }; 66 67 68 ShapePainter::ShapePainter(View* view) 69 : 70 fView(view) 71 { 72 } 73 74 75 ShapePainter::~ShapePainter() 76 { 77 } 78 79 80 status_t 81 ShapePainter::Iterate(const BShape* shape) 82 { 83 // this class doesn't modify the shape data 84 return BShapeIterator::Iterate(const_cast<BShape*>(shape)); 85 } 86 87 88 status_t 89 ShapePainter::IterateMoveTo(BPoint* point) 90 { 91 try { 92 fOpStack.push(OP_MOVETO); 93 fPtStack.push(*point); 94 } catch (std::bad_alloc) { 95 return B_NO_MEMORY; 96 } 97 98 return B_OK; 99 } 100 101 102 status_t 103 ShapePainter::IterateLineTo(int32 lineCount, BPoint* linePts) 104 { 105 try { 106 fOpStack.push(OP_LINETO | lineCount); 107 for (int32 i = 0; i < lineCount; i++) 108 fPtStack.push(linePts[i]); 109 } catch (std::bad_alloc) { 110 return B_NO_MEMORY; 111 } 112 113 return B_OK; 114 } 115 116 117 status_t 118 ShapePainter::IterateBezierTo(int32 bezierCount, BPoint* bezierPts) 119 { 120 bezierCount *= 3; 121 try { 122 fOpStack.push(OP_BEZIERTO | bezierCount); 123 for (int32 i = 0; i < bezierCount; i++) 124 fPtStack.push(bezierPts[i]); 125 } catch (std::bad_alloc) { 126 return B_NO_MEMORY; 127 } 128 129 return B_OK; 130 } 131 132 133 status_t 134 ShapePainter::IterateArcTo(float& rx, float& ry, 135 float& angle, bool largeArc, bool counterClockWise, BPoint& point) 136 { 137 uint32 op; 138 if (largeArc) { 139 if (counterClockWise) 140 op = OP_LARGE_ARC_TO_CCW; 141 else 142 op = OP_LARGE_ARC_TO_CW; 143 } else { 144 if (counterClockWise) 145 op = OP_SMALL_ARC_TO_CCW; 146 else 147 op = OP_SMALL_ARC_TO_CW; 148 } 149 150 try { 151 fOpStack.push(op | 3); 152 fPtStack.push(BPoint(rx, ry)); 153 fPtStack.push(BPoint(angle, 0)); 154 fPtStack.push(point); 155 } catch (std::bad_alloc) { 156 return B_NO_MEMORY; 157 } 158 159 return B_OK; 160 } 161 162 163 status_t 164 ShapePainter::IterateClose() 165 { 166 try { 167 fOpStack.push(OP_CLOSE); 168 } catch (std::bad_alloc) { 169 return B_NO_MEMORY; 170 } 171 172 return B_OK; 173 } 174 175 176 void 177 ShapePainter::Draw(BRect frame, bool filled) 178 { 179 // We're going to draw the currently iterated shape. 180 // TODO: This can be more efficient by skipping the conversion. 181 int32 opCount = fOpStack.size(); 182 int32 ptCount = fPtStack.size(); 183 184 if (opCount > 0 && ptCount > 0) { 185 int32 i; 186 uint32* opList = new(std::nothrow) uint32[opCount]; 187 if (opList == NULL) 188 return; 189 190 BPoint* ptList = new(std::nothrow) BPoint[ptCount]; 191 if (ptList == NULL) { 192 delete[] opList; 193 return; 194 } 195 196 for (i = opCount - 1; i >= 0; i--) { 197 opList[i] = fOpStack.top(); 198 fOpStack.pop(); 199 } 200 201 for (i = ptCount - 1; i >= 0; i--) { 202 ptList[i] = fPtStack.top(); 203 fPtStack.pop(); 204 } 205 206 BPoint offset(fView->CurrentState()->PenLocation()); 207 fView->ConvertToScreenForDrawing(&offset); 208 fView->Window()->GetDrawingEngine()->DrawShape(frame, opCount, 209 opList, ptCount, ptList, filled, offset, fView->Scale()); 210 211 delete[] opList; 212 delete[] ptList; 213 } 214 } 215 216 217 // #pragma mark - drawing functions 218 219 220 static void 221 get_polygon_frame(const BPoint* points, int32 numPoints, BRect* _frame) 222 { 223 ASSERT(numPoints > 0); 224 225 float left = points->x; 226 float top = points->y; 227 float right = left; 228 float bottom = top; 229 230 points++; 231 numPoints--; 232 233 while (numPoints--) { 234 if (points->x < left) 235 left = points->x; 236 if (points->x > right) 237 right = points->x; 238 if (points->y < top) 239 top = points->y; 240 if (points->y > bottom) 241 bottom = points->y; 242 points++; 243 } 244 245 _frame->Set(left, top, right, bottom); 246 } 247 248 249 static void 250 nop() 251 { 252 } 253 254 255 static void 256 move_pen_by(View* view, BPoint delta) 257 { 258 view->CurrentState()->SetPenLocation( 259 view->CurrentState()->PenLocation() + delta); 260 } 261 262 263 static void 264 stroke_line(View* view, BPoint start, BPoint end) 265 { 266 BPoint penPos = end; 267 268 view->ConvertToScreenForDrawing(&start); 269 view->ConvertToScreenForDrawing(&end); 270 view->Window()->GetDrawingEngine()->StrokeLine(start, end); 271 272 view->CurrentState()->SetPenLocation(penPos); 273 // the DrawingEngine/Painter does not need to be updated, since this 274 // effects only the view->screen coord conversion, which is handled 275 // by the view only 276 } 277 278 279 static void 280 stroke_rect(View* view, BRect rect) 281 { 282 view->ConvertToScreenForDrawing(&rect); 283 view->Window()->GetDrawingEngine()->StrokeRect(rect); 284 } 285 286 287 static void 288 fill_rect(View* view, BRect rect) 289 { 290 view->ConvertToScreenForDrawing(&rect); 291 view->Window()->GetDrawingEngine()->FillRect(rect); 292 } 293 294 295 static void 296 stroke_round_rect(View* view, BRect rect, BPoint radii) 297 { 298 view->ConvertToScreenForDrawing(&rect); 299 view->Window()->GetDrawingEngine()->DrawRoundRect(rect, radii.x, 300 radii.y, false); 301 } 302 303 304 static void 305 fill_round_rect(View* view, BRect rect, BPoint radii) 306 { 307 view->ConvertToScreenForDrawing(&rect); 308 view->Window()->GetDrawingEngine()->DrawRoundRect(rect, radii.x, 309 radii.y, true); 310 } 311 312 313 static void 314 stroke_bezier(View* view, const BPoint* viewPoints) 315 { 316 BPoint points[4]; 317 view->ConvertToScreenForDrawing(points, viewPoints, 4); 318 319 view->Window()->GetDrawingEngine()->DrawBezier(points, false); 320 } 321 322 323 static void 324 fill_bezier(View* view, const BPoint* viewPoints) 325 { 326 BPoint points[4]; 327 view->ConvertToScreenForDrawing(points, viewPoints, 4); 328 329 view->Window()->GetDrawingEngine()->DrawBezier(points, true); 330 } 331 332 333 static void 334 stroke_arc(View* view, BPoint center, BPoint radii, float startTheta, 335 float arcTheta) 336 { 337 BRect rect(center.x - radii.x, center.y - radii.y, 338 center.x + radii.x - 1, center.y + radii.y - 1); 339 view->ConvertToScreenForDrawing(&rect); 340 view->Window()->GetDrawingEngine()->DrawArc(rect, startTheta, 341 arcTheta, false); 342 } 343 344 345 static void 346 fill_arc(View* view, BPoint center, BPoint radii, float startTheta, 347 float arcTheta) 348 { 349 BRect rect(center.x - radii.x, center.y - radii.y, 350 center.x + radii.x - 1, center.y + radii.y - 1); 351 view->ConvertToScreenForDrawing(&rect); 352 view->Window()->GetDrawingEngine()->DrawArc(rect, startTheta, 353 arcTheta, true); 354 } 355 356 357 static void 358 stroke_ellipse(View* view, BPoint center, BPoint radii) 359 { 360 BRect rect(center.x - radii.x, center.y - radii.y, 361 center.x + radii.x - 1, center.y + radii.y - 1); 362 view->ConvertToScreenForDrawing(&rect); 363 view->Window()->GetDrawingEngine()->DrawEllipse(rect, false); 364 } 365 366 367 static void 368 fill_ellipse(View* view, BPoint center, BPoint radii) 369 { 370 BRect rect(center.x - radii.x, center.y - radii.y, 371 center.x + radii.x - 1, center.y + radii.y - 1); 372 view->ConvertToScreenForDrawing(&rect); 373 view->Window()->GetDrawingEngine()->DrawEllipse(rect, true); 374 } 375 376 377 static void 378 stroke_polygon(View* view, int32 numPoints, const BPoint* viewPoints, 379 bool isClosed) 380 { 381 if (numPoints <= 0) 382 return; 383 384 if (numPoints <= 200) { 385 // fast path: no malloc/free, also avoid 386 // constructor/destructor calls 387 char data[200 * sizeof(BPoint)]; 388 BPoint* points = (BPoint*)data; 389 390 view->ConvertToScreenForDrawing(points, viewPoints, numPoints); 391 392 BRect polyFrame; 393 get_polygon_frame(points, numPoints, &polyFrame); 394 395 view->Window()->GetDrawingEngine()->DrawPolygon(points, 396 numPoints, polyFrame, false, isClosed && numPoints > 2); 397 } else { 398 // avoid constructor/destructor calls by 399 // using malloc instead of new [] 400 BPoint* points = (BPoint*)malloc(numPoints * sizeof(BPoint)); 401 if (points == NULL) 402 return; 403 404 view->ConvertToScreenForDrawing(points, viewPoints, numPoints); 405 406 BRect polyFrame; 407 get_polygon_frame(points, numPoints, &polyFrame); 408 409 view->Window()->GetDrawingEngine()->DrawPolygon(points, 410 numPoints, polyFrame, false, isClosed && numPoints > 2); 411 free(points); 412 } 413 } 414 415 416 static void 417 fill_polygon(View* view, int32 numPoints, const BPoint* viewPoints) 418 { 419 if (numPoints <= 0) 420 return; 421 422 if (numPoints <= 200) { 423 // fast path: no malloc/free, also avoid 424 // constructor/destructor calls 425 char data[200 * sizeof(BPoint)]; 426 BPoint* points = (BPoint*)data; 427 428 view->ConvertToScreenForDrawing(points, viewPoints, numPoints); 429 430 BRect polyFrame; 431 get_polygon_frame(points, numPoints, &polyFrame); 432 433 view->Window()->GetDrawingEngine()->DrawPolygon(points, 434 numPoints, polyFrame, true, true); 435 } else { 436 // avoid constructor/destructor calls by 437 // using malloc instead of new [] 438 BPoint* points = (BPoint*)malloc(numPoints * sizeof(BPoint)); 439 if (points == NULL) 440 return; 441 442 view->ConvertToScreenForDrawing(points, viewPoints, numPoints); 443 444 BRect polyFrame; 445 get_polygon_frame(points, numPoints, &polyFrame); 446 447 view->Window()->GetDrawingEngine()->DrawPolygon(points, 448 numPoints, polyFrame, true, true); 449 free(points); 450 } 451 } 452 453 454 static void 455 stroke_shape(View* view, const BShape* shape) 456 { 457 ShapePainter drawShape(view); 458 459 drawShape.Iterate(shape); 460 drawShape.Draw(shape->Bounds(), false); 461 } 462 463 464 static void 465 fill_shape(View* view, const BShape* shape) 466 { 467 ShapePainter drawShape(view); 468 469 drawShape.Iterate(shape); 470 drawShape.Draw(shape->Bounds(), true); 471 } 472 473 474 static void 475 draw_string(View* view, const char* string, float deltaSpace, 476 float deltaNonSpace) 477 { 478 // NOTE: the picture data was recorded with a "set pen location" 479 // command inserted before the "draw string" command, so we can 480 // use PenLocation() 481 BPoint location = view->CurrentState()->PenLocation(); 482 483 escapement_delta delta = {deltaSpace, deltaNonSpace }; 484 view->ConvertToScreenForDrawing(&location); 485 view->Window()->GetDrawingEngine()->DrawString(string, 486 strlen(string), location, &delta); 487 488 view->ConvertFromScreenForDrawing(&location); 489 view->CurrentState()->SetPenLocation(location); 490 // the DrawingEngine/Painter does not need to be updated, since this 491 // effects only the view->screen coord conversion, which is handled 492 // by the view only 493 } 494 495 496 static void 497 draw_pixels(View* view, BRect src, BRect dest, int32 width, 498 int32 height, int32 bytesPerRow, int32 pixelFormat, int32 options, 499 const void* data) 500 { 501 UtilityBitmap bitmap(BRect(0, 0, width - 1, height - 1), 502 (color_space)pixelFormat, 0, bytesPerRow); 503 504 if (!bitmap.IsValid()) 505 return; 506 507 memcpy(bitmap.Bits(), data, height * bytesPerRow); 508 509 view->ConvertToScreenForDrawing(&dest); 510 view->Window()->GetDrawingEngine()->DrawBitmap(&bitmap, src, dest, options); 511 } 512 513 514 static void 515 draw_picture(View* view, BPoint where, int32 token) 516 { 517 ServerPicture* picture 518 = view->Window()->ServerWindow()->App()->GetPicture(token); 519 if (picture != NULL) { 520 view->PushState(); 521 view->SetDrawingOrigin(where); 522 523 view->PushState(); 524 picture->Play(view); 525 view->PopState(); 526 527 view->PopState(); 528 picture->ReleaseReference(); 529 } 530 } 531 532 533 static void 534 set_clipping_rects(View* view, const BRect* rects, uint32 numRects) 535 { 536 // TODO: This might be too slow, we should copy the rects 537 // directly to BRegion's internal data 538 BRegion region; 539 for (uint32 c = 0; c < numRects; c++) 540 region.Include(rects[c]); 541 view->SetUserClipping(®ion); 542 view->Window()->ServerWindow()->UpdateCurrentDrawingRegion(); 543 } 544 545 546 static void 547 clip_to_picture(View* view, BPicture* picture, BPoint pt, bool clipToInverse) 548 { 549 printf("ClipToPicture(picture, BPoint(%.2f, %.2f), %s)\n", 550 pt.x, pt.y, clipToInverse ? "inverse" : ""); 551 } 552 553 554 static void 555 push_state(View* view) 556 { 557 view->PushState(); 558 } 559 560 561 static void 562 pop_state(View* view) 563 { 564 view->PopState(); 565 566 BPoint p(0, 0); 567 view->ConvertToScreenForDrawing(&p); 568 view->Window()->GetDrawingEngine()->SetDrawState( 569 view->CurrentState(), (int32)p.x, (int32)p.y); 570 } 571 572 573 // TODO: Be smart and actually take advantage of these methods: 574 // only apply state changes when they are called 575 static void 576 enter_state_change(View* view) 577 { 578 } 579 580 581 static void 582 exit_state_change(View* view) 583 { 584 view->Window()->ServerWindow()->ResyncDrawState(); 585 } 586 587 588 static void 589 enter_font_state(View* view) 590 { 591 } 592 593 594 static void 595 exit_font_state(View* view) 596 { 597 view->Window()->GetDrawingEngine()->SetFont( 598 view->CurrentState()->Font()); 599 } 600 601 602 static void 603 set_origin(View* view, BPoint pt) 604 { 605 view->CurrentState()->SetOrigin(pt); 606 } 607 608 609 static void 610 set_pen_location(View* view, BPoint pt) 611 { 612 view->CurrentState()->SetPenLocation(pt); 613 // the DrawingEngine/Painter does not need to be updated, since this 614 // effects only the view->screen coord conversion, which is handled 615 // by the view only 616 } 617 618 619 static void 620 set_drawing_mode(View* view, drawing_mode mode) 621 { 622 view->CurrentState()->SetDrawingMode(mode); 623 view->Window()->GetDrawingEngine()->SetDrawingMode(mode); 624 } 625 626 627 static void 628 set_line_mode(View* view, cap_mode capMode, join_mode joinMode, 629 float miterLimit) 630 { 631 DrawState* state = view->CurrentState(); 632 state->SetLineCapMode(capMode); 633 state->SetLineJoinMode(joinMode); 634 state->SetMiterLimit(miterLimit); 635 view->Window()->GetDrawingEngine()->SetStrokeMode(capMode, joinMode, 636 miterLimit); 637 } 638 639 640 static void 641 set_pen_size(View* view, float size) 642 { 643 view->CurrentState()->SetPenSize(size); 644 view->Window()->GetDrawingEngine()->SetPenSize( 645 view->CurrentState()->PenSize()); 646 // DrawState::PenSize() returns the scaled pen size, so we 647 // need to use that value to set the drawing engine pen size. 648 } 649 650 651 static void 652 set_fore_color(View* view, rgb_color color) 653 { 654 view->CurrentState()->SetHighColor(color); 655 view->Window()->GetDrawingEngine()->SetHighColor(color); 656 } 657 658 659 static void 660 set_back_color(View* view, rgb_color color) 661 { 662 view->CurrentState()->SetLowColor(color); 663 view->Window()->GetDrawingEngine()->SetLowColor(color); 664 } 665 666 667 static void 668 set_stipple_pattern(View* view, pattern p) 669 { 670 view->CurrentState()->SetPattern(Pattern(p)); 671 view->Window()->GetDrawingEngine()->SetPattern(p); 672 } 673 674 675 static void 676 set_scale(View* view, float scale) 677 { 678 view->CurrentState()->SetScale(scale); 679 view->Window()->ServerWindow()->ResyncDrawState(); 680 681 // Update the drawing engine draw state, since some stuff 682 // (for example the pen size) needs to be recalculated. 683 } 684 685 686 static void 687 set_font_family(View* view, const char* family) 688 { 689 FontStyle* fontStyle = gFontManager->GetStyleByIndex(family, 0); 690 ServerFont font; 691 font.SetStyle(fontStyle); 692 view->CurrentState()->SetFont(font, B_FONT_FAMILY_AND_STYLE); 693 } 694 695 696 static void 697 set_font_style(View* view, const char* style) 698 { 699 ServerFont font(view->CurrentState()->Font()); 700 701 FontStyle* fontStyle = gFontManager->GetStyle(font.Family(), style); 702 703 font.SetStyle(fontStyle); 704 view->CurrentState()->SetFont(font, B_FONT_FAMILY_AND_STYLE); 705 } 706 707 708 static void 709 set_font_spacing(View* view, int32 spacing) 710 { 711 ServerFont font; 712 font.SetSpacing(spacing); 713 view->CurrentState()->SetFont(font, B_FONT_SPACING); 714 } 715 716 717 static void 718 set_font_size(View* view, float size) 719 { 720 ServerFont font; 721 font.SetSize(size); 722 view->CurrentState()->SetFont(font, B_FONT_SIZE); 723 } 724 725 726 static void 727 set_font_rotate(View* view, float rotation) 728 { 729 ServerFont font; 730 font.SetRotation(rotation); 731 view->CurrentState()->SetFont(font, B_FONT_ROTATION); 732 } 733 734 735 static void 736 set_font_encoding(View* view, int32 encoding) 737 { 738 ServerFont font; 739 font.SetEncoding(encoding); 740 view->CurrentState()->SetFont(font, B_FONT_ENCODING); 741 } 742 743 744 static void 745 set_font_flags(View* view, int32 flags) 746 { 747 ServerFont font; 748 font.SetFlags(flags); 749 view->CurrentState()->SetFont(font, B_FONT_FLAGS); 750 } 751 752 753 static void 754 set_font_shear(View* view, float shear) 755 { 756 ServerFont font; 757 font.SetShear(shear); 758 view->CurrentState()->SetFont(font, B_FONT_SHEAR); 759 } 760 761 762 static void 763 set_font_face(View* view, int32 face) 764 { 765 ServerFont font; 766 font.SetFace(face); 767 view->CurrentState()->SetFont(font, B_FONT_FACE); 768 } 769 770 771 static void 772 set_blending_mode(View* view, int16 alphaSrcMode, int16 alphaFncMode) 773 { 774 view->CurrentState()->SetBlendingMode((source_alpha)alphaSrcMode, 775 (alpha_function)alphaFncMode); 776 } 777 778 779 static void 780 reserved() 781 { 782 } 783 784 785 const static void* kTableEntries[] = { 786 (const void*)nop, // 0 787 (const void*)move_pen_by, 788 (const void*)stroke_line, 789 (const void*)stroke_rect, 790 (const void*)fill_rect, 791 (const void*)stroke_round_rect, // 5 792 (const void*)fill_round_rect, 793 (const void*)stroke_bezier, 794 (const void*)fill_bezier, 795 (const void*)stroke_arc, 796 (const void*)fill_arc, // 10 797 (const void*)stroke_ellipse, 798 (const void*)fill_ellipse, 799 (const void*)stroke_polygon, 800 (const void*)fill_polygon, 801 (const void*)stroke_shape, // 15 802 (const void*)fill_shape, 803 (const void*)draw_string, 804 (const void*)draw_pixels, 805 (const void*)draw_picture, 806 (const void*)set_clipping_rects, // 20 807 (const void*)clip_to_picture, 808 (const void*)push_state, 809 (const void*)pop_state, 810 (const void*)enter_state_change, 811 (const void*)exit_state_change, // 25 812 (const void*)enter_font_state, 813 (const void*)exit_font_state, 814 (const void*)set_origin, 815 (const void*)set_pen_location, 816 (const void*)set_drawing_mode, // 30 817 (const void*)set_line_mode, 818 (const void*)set_pen_size, 819 (const void*)set_fore_color, 820 (const void*)set_back_color, 821 (const void*)set_stipple_pattern, // 35 822 (const void*)set_scale, 823 (const void*)set_font_family, 824 (const void*)set_font_style, 825 (const void*)set_font_spacing, 826 (const void*)set_font_size, // 40 827 (const void*)set_font_rotate, 828 (const void*)set_font_encoding, 829 (const void*)set_font_flags, 830 (const void*)set_font_shear, 831 (const void*)reserved, // 45 832 (const void*)set_font_face, 833 (const void*)set_blending_mode // 47 834 }; 835 836 837 // #pragma mark - ServerPicture 838 839 840 ServerPicture::ServerPicture() 841 : 842 fFile(NULL), 843 fPictures(NULL), 844 fPushed(NULL), 845 fOwner(NULL) 846 { 847 fToken = gTokenSpace.NewToken(kPictureToken, this); 848 fData = new(std::nothrow) BMallocIO(); 849 850 PictureDataWriter::SetTo(fData); 851 } 852 853 854 ServerPicture::ServerPicture(const ServerPicture& picture) 855 : 856 fFile(NULL), 857 fData(NULL), 858 fPictures(NULL), 859 fPushed(NULL), 860 fOwner(NULL) 861 { 862 fToken = gTokenSpace.NewToken(kPictureToken, this); 863 864 BMallocIO* mallocIO = new(std::nothrow) BMallocIO(); 865 if (mallocIO == NULL) 866 return; 867 868 fData = mallocIO; 869 870 const off_t size = picture.DataLength(); 871 if (mallocIO->SetSize(size) < B_OK) 872 return; 873 874 picture.fData->ReadAt(0, const_cast<void*>(mallocIO->Buffer()), 875 size); 876 877 PictureDataWriter::SetTo(fData); 878 } 879 880 881 ServerPicture::ServerPicture(const char* fileName, int32 offset) 882 : 883 fFile(NULL), 884 fData(NULL), 885 fPictures(NULL), 886 fPushed(NULL), 887 fOwner(NULL) 888 { 889 fToken = gTokenSpace.NewToken(kPictureToken, this); 890 891 fFile = new(std::nothrow) BFile(fileName, B_READ_WRITE); 892 if (fFile == NULL) 893 return; 894 895 BPrivate::Storage::OffsetFile* offsetFile 896 = new(std::nothrow) BPrivate::Storage::OffsetFile(fFile, offset); 897 if (offsetFile == NULL || offsetFile->InitCheck() != B_OK) { 898 delete offsetFile; 899 return; 900 } 901 902 fData = offsetFile; 903 904 PictureDataWriter::SetTo(fData); 905 } 906 907 908 ServerPicture::~ServerPicture() 909 { 910 ASSERT(fOwner == NULL); 911 912 delete fData; 913 delete fFile; 914 gTokenSpace.RemoveToken(fToken); 915 916 if (fPictures != NULL) { 917 for (int32 i = fPictures->CountItems(); i-- > 0;) { 918 ServerPicture* picture = fPictures->ItemAt(i); 919 picture->SetOwner(NULL); 920 picture->ReleaseReference(); 921 } 922 923 delete fPictures; 924 } 925 926 if (fPushed != NULL) { 927 fPushed->SetOwner(NULL); 928 fPushed->ReleaseReference(); 929 } 930 } 931 932 933 bool 934 ServerPicture::SetOwner(ServerApp* owner) 935 { 936 if (owner == fOwner) 937 return true; 938 939 // Acquire an extra reference, since calling RemovePicture() 940 // May remove the last reference and then we will self-destruct right then. 941 // Setting fOwner to NULL would access free'd memory. If owner is another 942 // ServerApp, it's expected to already have a reference of course. 943 BReference<ServerPicture> _(this); 944 945 if (fOwner != NULL) 946 fOwner->RemovePicture(this); 947 948 fOwner = NULL; 949 if (owner == NULL) 950 return true; 951 952 if (!owner->AddPicture(this)) 953 return false; 954 955 fOwner = owner; 956 return true; 957 } 958 959 960 void 961 ServerPicture::EnterStateChange() 962 { 963 BeginOp(B_PIC_ENTER_STATE_CHANGE); 964 } 965 966 967 void 968 ServerPicture::ExitStateChange() 969 { 970 EndOp(); 971 } 972 973 974 void 975 ServerPicture::SyncState(View* view) 976 { 977 // TODO: Finish this 978 EnterStateChange(); 979 980 WriteSetOrigin(view->CurrentState()->Origin()); 981 WriteSetPenLocation(view->CurrentState()->PenLocation()); 982 WriteSetPenSize(view->CurrentState()->PenSize()); 983 WriteSetScale(view->CurrentState()->Scale()); 984 WriteSetLineMode(view->CurrentState()->LineCapMode(), 985 view->CurrentState()->LineJoinMode(), 986 view->CurrentState()->MiterLimit()); 987 //WriteSetPattern(*view->CurrentState()->GetPattern().GetInt8()); 988 WriteSetDrawingMode(view->CurrentState()->GetDrawingMode()); 989 990 WriteSetHighColor(view->CurrentState()->HighColor()); 991 WriteSetLowColor(view->CurrentState()->LowColor()); 992 993 ExitStateChange(); 994 } 995 996 997 void 998 ServerPicture::SetFontFromLink(BPrivate::LinkReceiver& link) 999 { 1000 BeginOp(B_PIC_ENTER_FONT_STATE); 1001 1002 uint16 mask; 1003 link.Read<uint16>(&mask); 1004 1005 if (mask & B_FONT_FAMILY_AND_STYLE) { 1006 uint32 fontID; 1007 link.Read<uint32>(&fontID); 1008 ServerFont font; 1009 font.SetFamilyAndStyle(fontID); 1010 WriteSetFontFamily(font.Family()); 1011 WriteSetFontStyle(font.Style()); 1012 } 1013 1014 if (mask & B_FONT_SIZE) { 1015 float size; 1016 link.Read<float>(&size); 1017 WriteSetFontSize(size); 1018 } 1019 1020 if (mask & B_FONT_SHEAR) { 1021 float shear; 1022 link.Read<float>(&shear); 1023 WriteSetFontShear(shear); 1024 } 1025 1026 if (mask & B_FONT_ROTATION) { 1027 float rotation; 1028 link.Read<float>(&rotation); 1029 WriteSetFontRotation(rotation); 1030 } 1031 1032 if (mask & B_FONT_FALSE_BOLD_WIDTH) { 1033 float falseBoldWidth; 1034 link.Read<float>(&falseBoldWidth); 1035 //SetFalseBoldWidth(falseBoldWidth); 1036 } 1037 1038 if (mask & B_FONT_SPACING) { 1039 uint8 spacing; 1040 link.Read<uint8>(&spacing); 1041 WriteSetFontSpacing(spacing); 1042 } 1043 1044 if (mask & B_FONT_ENCODING) { 1045 uint8 encoding; 1046 link.Read<uint8>((uint8*)&encoding); 1047 WriteSetFontEncoding(encoding); 1048 } 1049 1050 if (mask & B_FONT_FACE) { 1051 uint16 face; 1052 link.Read<uint16>(&face); 1053 WriteSetFontFace(face); 1054 } 1055 1056 if (mask & B_FONT_FLAGS) { 1057 uint32 flags; 1058 link.Read<uint32>(&flags); 1059 WriteSetFontFlags(flags); 1060 } 1061 1062 EndOp(); 1063 } 1064 1065 1066 void 1067 ServerPicture::Play(View* view) 1068 { 1069 // TODO: for now: then change PicturePlayer 1070 // to accept a BPositionIO object 1071 BMallocIO* mallocIO = dynamic_cast<BMallocIO*>(fData); 1072 if (mallocIO == NULL) 1073 return; 1074 1075 BPrivate::PicturePlayer player(mallocIO->Buffer(), 1076 mallocIO->BufferLength(), PictureList::Private(fPictures).AsBList()); 1077 player.Play(const_cast<void**>(kTableEntries), 1078 sizeof(kTableEntries) / sizeof(void*), view); 1079 } 1080 1081 1082 /*! Acquires a reference to the pushed picture. 1083 */ 1084 void 1085 ServerPicture::PushPicture(ServerPicture* picture) 1086 { 1087 if (fPushed != NULL) 1088 debugger("already pushed a picture"); 1089 1090 fPushed = picture; 1091 fPushed->AcquireReference(); 1092 } 1093 1094 1095 /*! Returns a reference with the popped picture. 1096 */ 1097 ServerPicture* 1098 ServerPicture::PopPicture() 1099 { 1100 ServerPicture* old = fPushed; 1101 fPushed = NULL; 1102 return old; 1103 } 1104 1105 1106 void 1107 ServerPicture::AppendPicture(ServerPicture* picture) 1108 { 1109 // A pushed picture is the same as an appended one 1110 PushPicture(picture); 1111 } 1112 1113 1114 bool 1115 ServerPicture::NestPicture(ServerPicture* picture) 1116 { 1117 if (fPictures == NULL) 1118 fPictures = new(std::nothrow) PictureList; 1119 1120 if (fPictures == NULL || !fPictures->AddItem(picture)) 1121 return false; 1122 1123 picture->AcquireReference(); 1124 return true; 1125 } 1126 1127 1128 off_t 1129 ServerPicture::DataLength() const 1130 { 1131 if (fData == NULL) 1132 return 0; 1133 off_t size; 1134 fData->GetSize(&size); 1135 return size; 1136 } 1137 1138 1139 status_t 1140 ServerPicture::ImportData(BPrivate::LinkReceiver& link) 1141 { 1142 int32 size = 0; 1143 link.Read<int32>(&size); 1144 1145 off_t oldPosition = fData->Position(); 1146 fData->Seek(0, SEEK_SET); 1147 1148 status_t status = B_NO_MEMORY; 1149 char* buffer = new(std::nothrow) char[size]; 1150 if (buffer) { 1151 status = B_OK; 1152 ssize_t read = link.Read(buffer, size); 1153 if (read < B_OK || fData->Write(buffer, size) < B_OK) 1154 status = B_ERROR; 1155 delete [] buffer; 1156 } 1157 1158 fData->Seek(oldPosition, SEEK_SET); 1159 return status; 1160 } 1161 1162 1163 status_t 1164 ServerPicture::ExportData(BPrivate::PortLink& link) 1165 { 1166 link.StartMessage(B_OK); 1167 1168 off_t oldPosition = fData->Position(); 1169 fData->Seek(0, SEEK_SET); 1170 1171 int32 subPicturesCount = 0; 1172 if (fPictures != NULL) 1173 subPicturesCount = fPictures->CountItems(); 1174 link.Attach<int32>(subPicturesCount); 1175 if (subPicturesCount > 0) { 1176 for (int32 i = 0; i < subPicturesCount; i++) { 1177 ServerPicture* subPicture = fPictures->ItemAt(i); 1178 link.Attach<int32>(subPicture->Token()); 1179 } 1180 } 1181 1182 off_t size = 0; 1183 fData->GetSize(&size); 1184 link.Attach<int32>((int32)size); 1185 1186 status_t status = B_NO_MEMORY; 1187 char* buffer = new(std::nothrow) char[size]; 1188 if (buffer) { 1189 status = B_OK; 1190 ssize_t read = fData->Read(buffer, size); 1191 if (read < B_OK || link.Attach(buffer, read) < B_OK) 1192 status = B_ERROR; 1193 delete [] buffer; 1194 } 1195 1196 if (status != B_OK) { 1197 link.CancelMessage(); 1198 link.StartMessage(B_ERROR); 1199 } 1200 1201 fData->Seek(oldPosition, SEEK_SET); 1202 return status; 1203 } 1204