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