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