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