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