1 /* 2 * Copyright 2001-2009, Haiku Inc. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Ingo Weinhold (bonefish@users.sf.net) 7 * DarkWyrm <bpmagic@columbus.rr.com> 8 * Stephan Aßmus <superstippi@gmx.de> 9 * Axel Dörfler, axeld@pinc-software.de 10 */ 11 12 13 /*! BBitmap objects represent off-screen windows that 14 contain bitmap data. 15 */ 16 17 18 #include <Bitmap.h> 19 20 #include <algorithm> 21 #include <limits.h> 22 #include <new> 23 #include <stdio.h> 24 #include <stdlib.h> 25 #include <string.h> 26 27 #include <Application.h> 28 #include <GraphicsDefs.h> 29 #include <Locker.h> 30 #include <View.h> 31 #include <Window.h> 32 33 #include <ApplicationPrivate.h> 34 #include <AppServerLink.h> 35 #include <ServerMemoryAllocator.h> 36 #include <ServerProtocol.h> 37 38 #include "ColorConversion.h" 39 #include "BitmapPrivate.h" 40 41 42 using namespace BPrivate; 43 44 45 /*! \brief Returns the number of bytes per row needed to store the actual 46 bitmap data (not including any padding) given a color space and a 47 row width. 48 \param colorSpace The color space. 49 \param width The width. 50 \return The number of bytes per row needed to store data for a row, or 51 0, if the color space is not supported. 52 */ 53 static inline int32 54 get_raw_bytes_per_row(color_space colorSpace, int32 width) 55 { 56 int32 bpr = 0; 57 switch (colorSpace) { 58 // supported 59 case B_RGB32: case B_RGBA32: 60 case B_RGB32_BIG: case B_RGBA32_BIG: 61 case B_UVL32: case B_UVLA32: 62 case B_LAB32: case B_LABA32: 63 case B_HSI32: case B_HSIA32: 64 case B_HSV32: case B_HSVA32: 65 case B_HLS32: case B_HLSA32: 66 case B_CMY32: case B_CMYA32: case B_CMYK32: 67 bpr = 4 * width; 68 break; 69 case B_RGB24: case B_RGB24_BIG: 70 case B_UVL24: case B_LAB24: case B_HSI24: 71 case B_HSV24: case B_HLS24: case B_CMY24: 72 bpr = 3 * width; 73 break; 74 case B_RGB16: case B_RGB15: case B_RGBA15: 75 case B_RGB16_BIG: case B_RGB15_BIG: case B_RGBA15_BIG: 76 bpr = 2 * width; 77 break; 78 case B_CMAP8: case B_GRAY8: 79 bpr = width; 80 break; 81 case B_GRAY1: 82 bpr = (width + 7) / 8; 83 break; 84 case B_YCbCr422: case B_YUV422: 85 bpr = (width + 3) / 4 * 8; 86 break; 87 case B_YCbCr411: case B_YUV411: 88 bpr = (width + 3) / 4 * 6; 89 break; 90 case B_YCbCr444: case B_YUV444: 91 bpr = (width + 3) / 4 * 12; 92 break; 93 case B_YCbCr420: case B_YUV420: 94 bpr = (width + 3) / 4 * 6; 95 break; 96 // unsupported 97 case B_NO_COLOR_SPACE: 98 case B_YUV9: case B_YUV12: 99 break; 100 } 101 return bpr; 102 } 103 104 105 namespace BPrivate { 106 107 /*! \brief Returns the number of bytes per row needed to store the bitmap 108 data (including any padding) given a color space and a row width. 109 \param colorSpace The color space. 110 \param width The width. 111 \return The number of bytes per row needed to store data for a row, or 112 0, if the color space is not supported. 113 */ 114 int32 115 get_bytes_per_row(color_space colorSpace, int32 width) 116 { 117 int32 bpr = get_raw_bytes_per_row(colorSpace, width); 118 // align to int32 119 bpr = (bpr + 3) & 0x7ffffffc; 120 return bpr; 121 } 122 123 } // namespace BPrivate 124 125 126 // #pragma mark - 127 128 129 /*! \brief Creates and initializes a BBitmap. 130 \param bounds The bitmap dimensions. 131 \param flags Creation flags. 132 \param colorSpace The bitmap's color space. 133 \param bytesPerRow The number of bytes per row the bitmap should use. 134 \c B_ANY_BYTES_PER_ROW to let the constructor choose an appropriate 135 value. 136 \param screenID ??? 137 */ 138 BBitmap::BBitmap(BRect bounds, uint32 flags, color_space colorSpace, 139 int32 bytesPerRow, screen_id screenID) 140 : 141 fBasePointer(NULL), 142 fSize(0), 143 fColorSpace(B_NO_COLOR_SPACE), 144 fBounds(0, 0, -1, -1), 145 fBytesPerRow(0), 146 fWindow(NULL), 147 fServerToken(-1), 148 fAreaOffset(-1), 149 fArea(-1), 150 fServerArea(-1), 151 fFlags(0), 152 fInitError(B_NO_INIT) 153 { 154 _InitObject(bounds, colorSpace, flags, bytesPerRow, screenID); 155 } 156 157 158 /*! \brief Creates and initializes a BBitmap. 159 \param bounds The bitmap dimensions. 160 \param colorSpace The bitmap's color space. 161 \param acceptsViews \c true, if the bitmap shall accept BViews, i.e. if 162 it shall be possible to attach BView to the bitmap and draw into 163 it. 164 \param needsContiguous If \c true a physically contiguous chunk of memory 165 will be allocated. 166 */ 167 BBitmap::BBitmap(BRect bounds, color_space colorSpace, bool acceptsViews, 168 bool needsContiguous) 169 : 170 fBasePointer(NULL), 171 fSize(0), 172 fColorSpace(B_NO_COLOR_SPACE), 173 fBounds(0, 0, -1, -1), 174 fBytesPerRow(0), 175 fWindow(NULL), 176 fServerToken(-1), 177 fAreaOffset(-1), 178 fArea(-1), 179 fServerArea(-1), 180 fFlags(0), 181 fInitError(B_NO_INIT) 182 { 183 int32 flags = (acceptsViews ? B_BITMAP_ACCEPTS_VIEWS : 0) 184 | (needsContiguous ? B_BITMAP_IS_CONTIGUOUS : 0); 185 _InitObject(bounds, colorSpace, flags, B_ANY_BYTES_PER_ROW, 186 B_MAIN_SCREEN_ID); 187 } 188 189 190 /*! \brief Creates a BBitmap as a clone of another bitmap. 191 \param source The source bitmap. 192 \param acceptsViews \c true, if the bitmap shall accept BViews, i.e. if 193 it shall be possible to attach BView to the bitmap and draw into 194 it. 195 \param needsContiguous If \c true a physically contiguous chunk of memory 196 will be allocated. 197 */ 198 BBitmap::BBitmap(const BBitmap* source, bool acceptsViews, bool needsContiguous) 199 : 200 fBasePointer(NULL), 201 fSize(0), 202 fColorSpace(B_NO_COLOR_SPACE), 203 fBounds(0, 0, -1, -1), 204 fBytesPerRow(0), 205 fWindow(NULL), 206 fServerToken(-1), 207 fAreaOffset(-1), 208 fArea(-1), 209 fServerArea(-1), 210 fFlags(0), 211 fInitError(B_NO_INIT) 212 { 213 if (source && source->IsValid()) { 214 int32 flags = (acceptsViews ? B_BITMAP_ACCEPTS_VIEWS : 0) 215 | (needsContiguous ? B_BITMAP_IS_CONTIGUOUS : 0); 216 _InitObject(source->Bounds(), source->ColorSpace(), flags, 217 source->BytesPerRow(), B_MAIN_SCREEN_ID); 218 if (InitCheck() == B_OK) { 219 memcpy(Bits(), source->Bits(), min_c(BitsLength(), 220 source->BitsLength())); 221 } 222 } 223 } 224 225 226 BBitmap::BBitmap(const BBitmap& source, uint32 flags) 227 { 228 if (!source.IsValid()) 229 return; 230 231 _InitObject(source.Bounds(), source.ColorSpace(), flags, 232 source.BytesPerRow(), B_MAIN_SCREEN_ID); 233 234 if (InitCheck() == B_OK) 235 memcpy(Bits(), source.Bits(), min_c(BitsLength(), source.BitsLength())); 236 } 237 238 239 BBitmap::BBitmap(const BBitmap& source) 240 { 241 fBasePointer = NULL; 242 *this = source; 243 } 244 245 246 /*! \brief Frees all resources associated with this object. 247 */ 248 BBitmap::~BBitmap() 249 { 250 if (fWindow && fWindow->Lock()) 251 delete fWindow; 252 _CleanUp(); 253 } 254 255 256 /*! \brief Unarchives a bitmap from a BMessage. 257 \param data The archive. 258 */ 259 BBitmap::BBitmap(BMessage* data) 260 : 261 BArchivable(data), 262 fBasePointer(NULL), 263 fSize(0), 264 fColorSpace(B_NO_COLOR_SPACE), 265 fBounds(0, 0, -1, -1), 266 fBytesPerRow(0), 267 fWindow(NULL), 268 fServerToken(-1), 269 fAreaOffset(-1), 270 fArea(-1), 271 fServerArea(-1), 272 fFlags(0), 273 fInitError(B_NO_INIT) 274 { 275 int32 flags; 276 if (data->FindInt32("_bmflags", &flags) != B_OK) { 277 // this bitmap is archived in some archaic format 278 flags = 0; 279 280 bool acceptsViews; 281 if (data->FindBool("_view_ok", &acceptsViews) == B_OK && acceptsViews) 282 flags |= B_BITMAP_ACCEPTS_VIEWS; 283 284 bool contiguous; 285 if (data->FindBool("_contiguous", &contiguous) == B_OK && contiguous) 286 flags |= B_BITMAP_IS_CONTIGUOUS; 287 } 288 289 int32 rowBytes; 290 if (data->FindInt32("_rowbytes", &rowBytes) != B_OK) { 291 rowBytes = -1; 292 // bytes per row are computed in InitObject(), then 293 } 294 295 BRect bounds; 296 color_space cspace; 297 if (data->FindRect("_frame", &bounds) == B_OK 298 && data->FindInt32("_cspace", (int32*)&cspace) == B_OK) { 299 _InitObject(bounds, cspace, flags, rowBytes, B_MAIN_SCREEN_ID); 300 } 301 302 if (InitCheck() == B_OK) { 303 ssize_t size; 304 const void* buffer; 305 if (data->FindData("_data", B_RAW_TYPE, &buffer, &size) == B_OK) { 306 if (size == BitsLength()) { 307 _AssertPointer(); 308 memcpy(fBasePointer, buffer, size); 309 } 310 } 311 } 312 313 if ((fFlags & B_BITMAP_ACCEPTS_VIEWS) != 0) { 314 BMessage message; 315 int32 i = 0; 316 317 while (data->FindMessage("_views", i++, &message) == B_OK) { 318 if (BView* view 319 = dynamic_cast<BView*>(instantiate_object(&message))) 320 AddChild(view); 321 } 322 } 323 } 324 325 326 /*! \brief Instantiates a BBitmap from an archive. 327 \param data The archive. 328 \return A bitmap reconstructed from the archive or \c NULL, if an error 329 occured. 330 */ 331 BArchivable* 332 BBitmap::Instantiate(BMessage* data) 333 { 334 if (validate_instantiation(data, "BBitmap")) 335 return new BBitmap(data); 336 337 return NULL; 338 } 339 340 341 /*! \brief Archives the BBitmap object. 342 \param data The archive. 343 \param deep \c true, if child object shall be archived as well, \c false 344 otherwise. 345 \return \c B_OK, if everything went fine, an error code otherwise. 346 */ 347 status_t 348 BBitmap::Archive(BMessage* data, bool deep) const 349 { 350 status_t ret = BArchivable::Archive(data, deep); 351 352 if (ret == B_OK) 353 ret = data->AddRect("_frame", fBounds); 354 355 if (ret == B_OK) 356 ret = data->AddInt32("_cspace", (int32)fColorSpace); 357 358 if (ret == B_OK) 359 ret = data->AddInt32("_bmflags", fFlags); 360 361 if (ret == B_OK) 362 ret = data->AddInt32("_rowbytes", fBytesPerRow); 363 364 if (ret == B_OK && deep) { 365 if ((fFlags & B_BITMAP_ACCEPTS_VIEWS) != 0) { 366 BMessage views; 367 for (int32 i = 0; i < CountChildren(); i++) { 368 if (ChildAt(i)->Archive(&views, deep)) 369 ret = data->AddMessage("_views", &views); 370 views.MakeEmpty(); 371 if (ret < B_OK) 372 break; 373 } 374 } 375 // Note: R5 does not archive the data if B_BITMAP_IS_CONTIGUOUS is 376 // true and it does save all formats as B_RAW_TYPE and it does save 377 // the data even if B_BITMAP_ACCEPTS_VIEWS is set (as opposed to 378 // the BeBook) 379 if (ret == B_OK) { 380 const_cast<BBitmap*>(this)->_AssertPointer(); 381 ret = data->AddData("_data", B_RAW_TYPE, fBasePointer, fSize); 382 } 383 } 384 385 return ret; 386 } 387 388 389 /*! \brief Returns the result from the construction. 390 \return \c B_OK, if the object is properly initialized, an error code 391 otherwise. 392 */ 393 status_t 394 BBitmap::InitCheck() const 395 { 396 return fInitError; 397 } 398 399 400 /*! \brief Returns whether or not the BBitmap object is valid. 401 \return \c true, if the object is properly initialized, \c false otherwise. 402 */ 403 bool 404 BBitmap::IsValid() const 405 { 406 return InitCheck() == B_OK; 407 } 408 409 410 /*! \brief Locks the bitmap bits so that they cannot be relocated. 411 412 This is currently only used for overlay bitmaps - whenever you 413 need to access their Bits(), you have to lock them first. 414 On resolution change overlay bitmaps can be relocated in memory; 415 using this call prevents you from accessing an invalid pointer 416 and clobbering memory that doesn't belong you. 417 */ 418 status_t 419 BBitmap::LockBits(uint32* state) 420 { 421 // TODO: how do we fill the "state"? 422 // It would be more or less useful to report what kind of bitmap 423 // we got (ie. overlay, placeholder, or non-overlay) 424 if ((fFlags & B_BITMAP_WILL_OVERLAY) != 0) { 425 overlay_client_data* data = (overlay_client_data*)fBasePointer; 426 427 status_t status; 428 do { 429 status = acquire_sem(data->lock); 430 } while (status == B_INTERRUPTED); 431 432 if (data->buffer == NULL) { 433 // the app_server does not grant us access to the frame buffer 434 // right now - let's release the lock and fail 435 release_sem_etc(data->lock, 1, B_DO_NOT_RESCHEDULE); 436 return B_BUSY; 437 } 438 return status; 439 } 440 441 // NOTE: maybe this is used to prevent the app_server from 442 // drawing the bitmap yet? 443 // axeld: you mean for non overlays? 444 445 return B_OK; 446 } 447 448 449 /*! \brief Unlocks the bitmap's buffer again. 450 Counterpart to LockBits(), see there for comments. 451 */ 452 void 453 BBitmap::UnlockBits() 454 { 455 if ((fFlags & B_BITMAP_WILL_OVERLAY) == 0) 456 return; 457 458 overlay_client_data* data = (overlay_client_data*)fBasePointer; 459 release_sem_etc(data->lock, 1, B_DO_NOT_RESCHEDULE); 460 } 461 462 463 /*! \brief Returns the ID of the area the bitmap data reside in. 464 \return The ID of the area the bitmap data reside in. 465 */ 466 area_id 467 BBitmap::Area() const 468 { 469 const_cast<BBitmap*>(this)->_AssertPointer(); 470 return fArea; 471 } 472 473 474 /*! \brief Returns the pointer to the bitmap data. 475 \return The pointer to the bitmap data. 476 */ 477 void* 478 BBitmap::Bits() const 479 { 480 const_cast<BBitmap*>(this)->_AssertPointer(); 481 482 if ((fFlags & B_BITMAP_WILL_OVERLAY) != 0) { 483 overlay_client_data* data = (overlay_client_data*)fBasePointer; 484 return data->buffer; 485 } 486 487 return (void*)fBasePointer; 488 } 489 490 491 /*! \brief Returns the size of the bitmap data. 492 \return The size of the bitmap data. 493 */ 494 int32 495 BBitmap::BitsLength() const 496 { 497 return fSize; 498 } 499 500 501 /*! \brief Returns the number of bytes used to store a row of bitmap data. 502 \return The number of bytes used to store a row of bitmap data. 503 */ 504 int32 505 BBitmap::BytesPerRow() const 506 { 507 return fBytesPerRow; 508 } 509 510 511 /*! \brief Returns the bitmap's color space. 512 \return The bitmap's color space. 513 */ 514 color_space 515 BBitmap::ColorSpace() const 516 { 517 return fColorSpace; 518 } 519 520 521 /*! \brief Returns the bitmap's dimensions. 522 \return The bitmap's dimensions. 523 */ 524 BRect 525 BBitmap::Bounds() const 526 { 527 return fBounds; 528 } 529 530 531 /*! \brief Returns the bitmap's creating flags. 532 533 This method informs about which flags have been used to create the 534 bitmap. It would for example tell you wether this is an overlay 535 bitmap. If bitmap creation succeeded, all flags are fulfilled. 536 537 \return The bitmap's creation flags. 538 */ 539 uint32 540 BBitmap::Flags() const 541 { 542 return fFlags; 543 } 544 545 546 /*! \brief Assigns data to the bitmap. 547 548 Data are directly written into the bitmap's data buffer, being converted 549 beforehand, if necessary. Some conversions work rather unintuitively: 550 - \c B_RGB32: The source buffer is supposed to contain \c B_RGB24_BIG 551 data without padding at the end of the rows. 552 - \c B_RGB32: The source buffer is supposed to contain \c B_CMAP8 553 data without padding at the end of the rows. 554 - other color spaces: The source buffer is supposed to contain data 555 according to the specified color space being rowwise padded to int32. 556 557 The currently supported source/target color spaces are 558 \c B_RGB{32,24,16,15}[_BIG], \c B_CMAP8 and \c B_GRAY{8,1}. 559 560 \note As this methods is apparently a bit strange to use, Haiku introduces 561 ImportBits() methods, which are recommended to be used instead. 562 563 \param data The data to be copied. 564 \param length The length in bytes of the data to be copied. 565 \param offset The offset (in bytes) relative to beginning of the bitmap 566 data specifying the position at which the source data shall be 567 written. 568 \param colorSpace Color space of the source data. 569 */ 570 void 571 BBitmap::SetBits(const void* data, int32 length, int32 offset, 572 color_space colorSpace) 573 { 574 status_t error = (InitCheck() == B_OK ? B_OK : B_NO_INIT); 575 // check params 576 if (error == B_OK && (data == NULL || offset > fSize || length < 0)) 577 error = B_BAD_VALUE; 578 int32 width = 0; 579 if (error == B_OK) 580 width = fBounds.IntegerWidth() + 1; 581 int32 inBPR = -1; 582 // tweaks to mimic R5 behavior 583 if (error == B_OK) { 584 if (colorSpace == B_RGB32) { 585 // B_RGB32 means actually unpadded B_RGB24_BIG 586 colorSpace = B_RGB24_BIG; 587 inBPR = width * 3; 588 } else if (colorSpace == B_CMAP8 && fColorSpace != B_CMAP8) { 589 // If in color space is B_CMAP8, but the bitmap's is another one, 590 // ignore source data row padding. 591 inBPR = width; 592 } 593 } 594 // call the sane method, which does the actual work 595 if (error == B_OK) 596 error = ImportBits(data, length, inBPR, offset, colorSpace); 597 } 598 599 600 /*! \brief Assigns data to the bitmap. 601 602 Data are directly written into the bitmap's data buffer, being converted 603 beforehand, if necessary. Unlike for SetBits(), the meaning of 604 \a colorSpace is exactly the expected one here, i.e. the source buffer 605 is supposed to contain data of that color space. \a bpr specifies how 606 many bytes the source contains per row. \c B_ANY_BYTES_PER_ROW can be 607 supplied, if standard padding to int32 is used. 608 609 The currently supported source/target color spaces are 610 \c B_RGB{32,24,16,15}[_BIG], \c B_CMAP8 and \c B_GRAY{8,1}. 611 612 \param data The data to be copied. 613 \param length The length in bytes of the data to be copied. 614 \param bpr The number of bytes per row in the source data. 615 \param offset The offset (in bytes) relative to beginning of the bitmap 616 data specifying the position at which the source data shall be 617 written. 618 \param colorSpace Color space of the source data. 619 \return 620 - \c B_OK: Everything went fine. 621 - \c B_BAD_VALUE: \c NULL \a data, invalid \a bpr or \a offset, or 622 unsupported \a colorSpace. 623 */ 624 status_t 625 BBitmap::ImportBits(const void* data, int32 length, int32 bpr, int32 offset, 626 color_space colorSpace) 627 { 628 _AssertPointer(); 629 630 if (InitCheck() != B_OK) 631 return B_NO_INIT; 632 633 if (!data || offset > fSize || length < 0) 634 return B_BAD_VALUE; 635 636 int32 width = fBounds.IntegerWidth() + 1; 637 if (bpr <= 0) { 638 if (bpr == B_ANY_BYTES_PER_ROW) 639 bpr = get_bytes_per_row(colorSpace, width); 640 else 641 return B_BAD_VALUE; 642 } 643 644 return BPrivate::ConvertBits(data, (uint8*)fBasePointer + offset, length, 645 fSize - offset, bpr, fBytesPerRow, colorSpace, fColorSpace, width, 646 fBounds.IntegerHeight() + 1); 647 } 648 649 650 /*! \brief Assigns data to the bitmap. 651 652 Allows for a BPoint offset in the source and in the bitmap. The region 653 of the source at \a from extending \a width and \a height is assigned 654 (and converted if necessary) to the bitmap at \a to. 655 656 The currently supported source/target color spaces are 657 \c B_RGB{32,24,16,15}[_BIG], \c B_CMAP8 and \c B_GRAY{8,1}. 658 659 \param data The data to be copied. 660 \param length The length in bytes of the data to be copied. 661 \param bpr The number of bytes per row in the source data. 662 \param colorSpace Color space of the source data. 663 \param from The offset in the source where reading should begin. 664 \param to The offset in the bitmap where the source should be written. 665 \param width The width (in pixels) to be imported. 666 \param height The height (in pixels) to be imported. 667 \return 668 - \c B_OK: Everything went fine. 669 - \c B_BAD_VALUE: \c NULL \a data, invalid \a bpr, unsupported 670 \a colorSpace or invalid width/height. 671 */ 672 status_t 673 BBitmap::ImportBits(const void* data, int32 length, int32 bpr, 674 color_space colorSpace, BPoint from, BPoint to, int32 width, int32 height) 675 { 676 _AssertPointer(); 677 678 if (InitCheck() != B_OK) 679 return B_NO_INIT; 680 681 if (!data || length < 0 || width < 0 || height < 0) 682 return B_BAD_VALUE; 683 684 if (bpr <= 0) { 685 if (bpr == B_ANY_BYTES_PER_ROW) 686 bpr = get_bytes_per_row(colorSpace, fBounds.IntegerWidth() + 1); 687 else 688 return B_BAD_VALUE; 689 } 690 691 return BPrivate::ConvertBits(data, fBasePointer, length, fSize, bpr, 692 fBytesPerRow, colorSpace, fColorSpace, from, to, width, height); 693 } 694 695 696 /*! \briefly Assigns another bitmap's data to this bitmap. 697 698 The supplied bitmap must have the exactly same dimensions as this bitmap. 699 Its data is converted to the color space of this bitmap. 700 701 The currently supported source/target color spaces are 702 \c B_RGB{32,24,16,15}[_BIG], \c B_CMAP8 and \c B_GRAY{8,1}. 703 704 \param bitmap The source bitmap. 705 \return 706 - \c B_OK: Everything went fine. 707 - \c B_BAD_VALUE: \c NULL \a bitmap, or \a bitmap has other dimensions, 708 or the conversion from or to one of the color spaces is not supported. 709 */ 710 status_t 711 BBitmap::ImportBits(const BBitmap* bitmap) 712 { 713 if (InitCheck() != B_OK) 714 return B_NO_INIT; 715 716 if (!bitmap || bitmap->InitCheck() != B_OK || bitmap->Bounds() != fBounds) 717 return B_BAD_VALUE; 718 719 return ImportBits(bitmap->Bits(), bitmap->BitsLength(), 720 bitmap->BytesPerRow(), 0, bitmap->ColorSpace()); 721 } 722 723 724 /*! \brief Assigns data to the bitmap. 725 726 Allows for a BPoint offset in the source and in the bitmap. The region 727 of the source at \a from extending \a width and \a height is assigned 728 (and converted if necessary) to the bitmap at \a to. The source bitmap is 729 clipped to the bitmap and they don't need to have the same dimensions. 730 731 The currently supported source/target color spaces are 732 \c B_RGB{32,24,16,15}[_BIG], \c B_CMAP8 and \c B_GRAY{8,1}. 733 734 \param bitmap The source bitmap. 735 \param from The offset in the source where reading should begin. 736 \param to The offset in the bitmap where the source should be written. 737 \param width The width (in pixels) to be imported. 738 \param height The height (in pixels) to be imported. 739 - \c B_OK: Everything went fine. 740 - \c B_BAD_VALUE: \c NULL \a bitmap, the conversion from or to one of 741 the color spaces is not supported, or invalid width/height. 742 */ 743 status_t 744 BBitmap::ImportBits(const BBitmap* bitmap, BPoint from, BPoint to, int32 width, 745 int32 height) 746 { 747 if (InitCheck() != B_OK) 748 return B_NO_INIT; 749 750 if (!bitmap || bitmap->InitCheck() != B_OK) 751 return B_BAD_VALUE; 752 753 return ImportBits(bitmap->Bits(), bitmap->BitsLength(), 754 bitmap->BytesPerRow(), bitmap->ColorSpace(), from, to, width, height); 755 } 756 757 758 /*! \brief Returns the overlay_restrictions structure for this bitmap 759 */ 760 status_t 761 BBitmap::GetOverlayRestrictions(overlay_restrictions* restrictions) const 762 { 763 if ((fFlags & B_BITMAP_WILL_OVERLAY) == 0) 764 return B_BAD_TYPE; 765 766 BPrivate::AppServerLink link; 767 768 link.StartMessage(AS_GET_BITMAP_OVERLAY_RESTRICTIONS); 769 link.Attach<int32>(fServerToken); 770 771 status_t status; 772 if (link.FlushWithReply(status) < B_OK) 773 return status; 774 775 link.Read(restrictions, sizeof(overlay_restrictions)); 776 return B_OK; 777 } 778 779 780 /*! \brief Adds a BView to the bitmap's view hierarchy. 781 782 The bitmap must accept views and the supplied view must not be child of 783 another parent. 784 785 \param view The view to be added. 786 */ 787 void 788 BBitmap::AddChild(BView* view) 789 { 790 if (fWindow != NULL) 791 fWindow->AddChild(view); 792 } 793 794 795 /*! \brief Removes a BView from the bitmap's view hierarchy. 796 \param view The view to be removed. 797 */ 798 bool 799 BBitmap::RemoveChild(BView* view) 800 { 801 return fWindow != NULL ? fWindow->RemoveChild(view) : false; 802 } 803 804 805 /*! \brief Returns the number of BViews currently belonging to the bitmap. 806 \return The number of BViews currently belonging to the bitmap. 807 */ 808 int32 809 BBitmap::CountChildren() const 810 { 811 return fWindow != NULL ? fWindow->CountChildren() : 0; 812 } 813 814 815 /*! \brief Returns the BView at a certain index in the bitmap's list of views. 816 \param index The index of the BView to be returned. 817 \return The BView at index \a index or \c NULL, if the index is out of 818 range. 819 */ 820 BView* 821 BBitmap::ChildAt(int32 index) const 822 { 823 return fWindow != NULL ? fWindow->ChildAt(index) : NULL; 824 } 825 826 827 /*! \brief Returns a bitmap's BView with a certain name. 828 \param name The name of the BView to be returned. 829 \return The BView with the name \a name or \c NULL, if the bitmap doesn't 830 know a view with that name. 831 */ 832 BView* 833 BBitmap::FindView(const char* viewName) const 834 { 835 return fWindow != NULL ? fWindow->FindView(viewName) : NULL; 836 } 837 838 839 /*! \brief Returns a bitmap's BView at a certain location. 840 \param point The location. 841 \return The BView with located at \a point or \c NULL, if the bitmap 842 doesn't know a view at this location. 843 */ 844 BView* 845 BBitmap::FindView(BPoint point) const 846 { 847 return fWindow != NULL ? fWindow->FindView(point) : NULL; 848 } 849 850 851 /*! \brief Locks the off-screen window that belongs to the bitmap. 852 853 The bitmap must accept views, if locking should work. 854 855 \return \c true, if the lock was acquired successfully, \c false 856 otherwise. 857 */ 858 bool 859 BBitmap::Lock() 860 { 861 return fWindow != NULL ? fWindow->Lock() : false; 862 } 863 864 865 /*! \brief Unlocks the off-screen window that belongs to the bitmap. 866 867 The bitmap must accept views, if locking should work. 868 */ 869 void 870 BBitmap::Unlock() 871 { 872 if (fWindow != NULL) 873 fWindow->Unlock(); 874 } 875 876 877 /*! \brief Returns whether or not the bitmap's off-screen window is locked. 878 879 The bitmap must accept views, if locking should work. 880 881 \return \c true, if the caller owns a lock , \c false otherwise. 882 */ 883 bool 884 BBitmap::IsLocked() const 885 { 886 return fWindow != NULL ? fWindow->IsLocked() : false; 887 } 888 889 890 BBitmap& 891 BBitmap::operator=(const BBitmap& source) 892 { 893 _CleanUp(); 894 fInitError = B_NO_INIT; 895 896 if (!source.IsValid()) 897 return *this; 898 899 _InitObject(source.Bounds(), source.ColorSpace(), source.Flags(), 900 source.BytesPerRow(), B_MAIN_SCREEN_ID); 901 if (InitCheck() == B_OK) 902 memcpy(Bits(), source.Bits(), min_c(BitsLength(), source.BitsLength())); 903 904 return *this; 905 } 906 907 908 status_t 909 BBitmap::Perform(perform_code d, void* arg) 910 { 911 return BArchivable::Perform(d, arg); 912 } 913 914 // FBC 915 void BBitmap::_ReservedBitmap1() {} 916 void BBitmap::_ReservedBitmap2() {} 917 void BBitmap::_ReservedBitmap3() {} 918 919 920 #if 0 921 // get_shared_pointer 922 /*! \brief ??? 923 */ 924 char* 925 BBitmap::get_shared_pointer() const 926 { 927 return NULL; // not implemented 928 } 929 #endif 930 931 int32 932 BBitmap::_ServerToken() const 933 { 934 return fServerToken; 935 } 936 937 938 /*! \brief Initializes the bitmap. 939 \param bounds The bitmap dimensions. 940 \param colorSpace The bitmap's color space. 941 \param flags Creation flags. 942 \param bytesPerRow The number of bytes per row the bitmap should use. 943 \c B_ANY_BYTES_PER_ROW to let the constructor choose an appropriate 944 value. 945 \param screenID ??? 946 */ 947 void 948 BBitmap::_InitObject(BRect bounds, color_space colorSpace, uint32 flags, 949 int32 bytesPerRow, screen_id screenID) 950 { 951 //printf("BBitmap::InitObject(bounds: BRect(%.1f, %.1f, %.1f, %.1f), format: %ld, flags: %ld, bpr: %ld\n", 952 // bounds.left, bounds.top, bounds.right, bounds.bottom, colorSpace, flags, bytesPerRow); 953 954 // TODO: Should we handle rounding of the "bounds" here? How does R5 behave? 955 956 status_t error = B_OK; 957 958 #ifdef RUN_WITHOUT_APP_SERVER 959 flags |= B_BITMAP_NO_SERVER_LINK; 960 #endif // RUN_WITHOUT_APP_SERVER 961 962 _CleanUp(); 963 964 // check params 965 if (!bounds.IsValid() || !bitmaps_support_space(colorSpace, NULL)) { 966 error = B_BAD_VALUE; 967 } else { 968 // bounds is in floats and might be valid but much larger than what we 969 // can handle the size could not be expressed in int32 970 double realSize = bounds.Width() * bounds.Height(); 971 if (realSize > (double)(INT_MAX / 4)) { 972 fprintf(stderr, "bitmap bounds is much too large: " 973 "BRect(%.1f, %.1f, %.1f, %.1f)\n", 974 bounds.left, bounds.top, bounds.right, bounds.bottom); 975 error = B_BAD_VALUE; 976 } 977 } 978 if (error == B_OK) { 979 int32 bpr = get_bytes_per_row(colorSpace, bounds.IntegerWidth() + 1); 980 if (bytesPerRow < 0) 981 bytesPerRow = bpr; 982 else if (bytesPerRow < bpr) 983 // NOTE: How does R5 behave? 984 error = B_BAD_VALUE; 985 } 986 // allocate the bitmap buffer 987 if (error == B_OK) { 988 // NOTE: Maybe the code would look more robust if the 989 // "size" was not calculated here when we ask the server 990 // to allocate the bitmap. -Stephan 991 int32 size = bytesPerRow * (bounds.IntegerHeight() + 1); 992 993 if (flags & B_BITMAP_NO_SERVER_LINK) { 994 fBasePointer = (uint8*)malloc(size); 995 if (fBasePointer) { 996 fSize = size; 997 fColorSpace = colorSpace; 998 fBounds = bounds; 999 fBytesPerRow = bytesPerRow; 1000 fFlags = flags; 1001 } else 1002 error = B_NO_MEMORY; 1003 } else { 1004 // Ask the server (via our owning application) to create a bitmap. 1005 BPrivate::AppServerLink link; 1006 1007 // Attach Data: 1008 // 1) BRect bounds 1009 // 2) color_space space 1010 // 3) int32 bitmap_flags 1011 // 4) int32 bytes_per_row 1012 // 5) int32 screen_id::id 1013 link.StartMessage(AS_CREATE_BITMAP); 1014 link.Attach<BRect>(bounds); 1015 link.Attach<color_space>(colorSpace); 1016 link.Attach<uint32>(flags); 1017 link.Attach<int32>(bytesPerRow); 1018 link.Attach<int32>(screenID.id); 1019 1020 if (link.FlushWithReply(error) == B_OK && error == B_OK) { 1021 // server side success 1022 // Get token 1023 link.Read<int32>(&fServerToken); 1024 1025 uint8 allocationFlags; 1026 link.Read<uint8>(&allocationFlags); 1027 link.Read<area_id>(&fServerArea); 1028 link.Read<int32>(&fAreaOffset); 1029 1030 BPrivate::ServerMemoryAllocator* allocator 1031 = BApplication::Private::ServerAllocator(); 1032 1033 if (allocationFlags & kNewAllocatorArea) { 1034 error = allocator->AddArea(fServerArea, fArea, 1035 fBasePointer); 1036 } else { 1037 error = allocator->AreaAndBaseFor(fServerArea, fArea, 1038 fBasePointer); 1039 if (error == B_OK) 1040 fBasePointer += fAreaOffset; 1041 } 1042 1043 if ((allocationFlags & kFramebuffer) != 0) { 1044 // The base pointer will now point to an overlay_client_data 1045 // structure bytes per row might be modified to match 1046 // hardware constraints 1047 link.Read<int32>(&bytesPerRow); 1048 size = bytesPerRow * (bounds.IntegerHeight() + 1); 1049 } 1050 1051 if (fServerArea >= B_OK) { 1052 fSize = size; 1053 fColorSpace = colorSpace; 1054 fBounds = bounds; 1055 fBytesPerRow = bytesPerRow; 1056 fFlags = flags; 1057 } else 1058 error = fServerArea; 1059 } 1060 1061 if (error < B_OK) { 1062 fBasePointer = NULL; 1063 fServerToken = -1; 1064 fArea = -1; 1065 fServerArea = -1; 1066 fAreaOffset = -1; 1067 // NOTE: why not "0" in case of error? 1068 fFlags = flags; 1069 } 1070 } 1071 fWindow = NULL; 1072 } 1073 1074 fInitError = error; 1075 1076 if (fInitError == B_OK) { 1077 // clear to white if the flags say so. 1078 if (flags & (B_BITMAP_CLEAR_TO_WHITE | B_BITMAP_ACCEPTS_VIEWS)) { 1079 if (fColorSpace == B_CMAP8) { 1080 // "255" is the "transparent magic" index for B_CMAP8 bitmaps 1081 // use the correct index for "white" 1082 memset(fBasePointer, 65, fSize); 1083 } else { 1084 // should work for most colorspaces 1085 memset(fBasePointer, 0xff, fSize); 1086 } 1087 } 1088 // TODO: Creating an offscreen window with a non32 bit bitmap 1089 // copies the current content of the bitmap to a back buffer. 1090 // So at this point the bitmap has to be already cleared to white. 1091 // Better move the above code to the server so the problem looks more 1092 // clear. 1093 if (flags & B_BITMAP_ACCEPTS_VIEWS) { 1094 fWindow = new(std::nothrow) BWindow(Bounds(), fServerToken); 1095 if (fWindow) { 1096 // A BWindow starts life locked and is unlocked 1097 // in Show(), but this window is never shown and 1098 // it's message loop is never started. 1099 fWindow->Unlock(); 1100 } else 1101 fInitError = B_NO_MEMORY; 1102 } 1103 } 1104 } 1105 1106 1107 /*! \brief Cleans up any memory allocated by the bitmap and 1108 informs the server to do so as well (if needed). 1109 */ 1110 void 1111 BBitmap::_CleanUp() 1112 { 1113 if (fBasePointer == NULL) 1114 return; 1115 1116 if ((fFlags & B_BITMAP_NO_SERVER_LINK) != 0) { 1117 free(fBasePointer); 1118 } else { 1119 BPrivate::AppServerLink link; 1120 // AS_DELETE_BITMAP: 1121 // Attached Data: 1122 // 1) int32 server token 1123 link.StartMessage(AS_DELETE_BITMAP); 1124 link.Attach<int32>(fServerToken); 1125 link.Flush(); 1126 1127 // TODO: we may want to delete parts of the server memory areas here! 1128 1129 fArea = -1; 1130 fServerToken = -1; 1131 fAreaOffset = -1; 1132 } 1133 fBasePointer = NULL; 1134 } 1135 1136 1137 void 1138 BBitmap::_AssertPointer() 1139 { 1140 if (fBasePointer == NULL && fServerArea >= B_OK && fAreaOffset == -1) { 1141 // We lazily clone our own areas - if the bitmap is part of the usual 1142 // server memory area, or is a B_BITMAP_NO_SERVER_LINK bitmap, it 1143 // already has its data. 1144 fArea = clone_area("shared bitmap area", (void**)&fBasePointer, 1145 B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA, fServerArea); 1146 } 1147 } 1148 1149