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 953 // can handle 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: " 957 "BRect(%.1f, %.1f, %.1f, %.1f)\n", 958 bounds.left, bounds.top, bounds.right, bounds.bottom); 959 error = B_BAD_VALUE; 960 } 961 } 962 if (error == B_OK) { 963 int32 bpr = get_bytes_per_row(colorSpace, bounds.IntegerWidth() + 1); 964 if (bytesPerRow < 0) 965 bytesPerRow = bpr; 966 else if (bytesPerRow < bpr) 967 // NOTE: How does R5 behave? 968 error = B_BAD_VALUE; 969 } 970 // allocate the bitmap buffer 971 if (error == B_OK) { 972 // NOTE: Maybe the code would look more robust if the 973 // "size" was not calculated here when we ask the server 974 // to allocate the bitmap. -Stephan 975 int32 size = bytesPerRow * (bounds.IntegerHeight() + 1); 976 977 if (flags & B_BITMAP_NO_SERVER_LINK) { 978 fBasePointer = (uint8*)malloc(size); 979 if (fBasePointer) { 980 fSize = size; 981 fColorSpace = colorSpace; 982 fBounds = bounds; 983 fBytesPerRow = bytesPerRow; 984 fFlags = flags; 985 } else 986 error = B_NO_MEMORY; 987 } else { 988 // Ask the server (via our owning application) to create a bitmap. 989 BPrivate::AppServerLink link; 990 991 // Attach Data: 992 // 1) BRect bounds 993 // 2) color_space space 994 // 3) int32 bitmap_flags 995 // 4) int32 bytes_per_row 996 // 5) int32 screen_id::id 997 link.StartMessage(AS_CREATE_BITMAP); 998 link.Attach<BRect>(bounds); 999 link.Attach<color_space>(colorSpace); 1000 link.Attach<int32>((int32)flags); 1001 link.Attach<int32>(bytesPerRow); 1002 link.Attach<int32>(screenID.id); 1003 1004 if (link.FlushWithReply(error) == B_OK && error == B_OK) { 1005 // server side success 1006 // Get token 1007 link.Read<int32>(&fServerToken); 1008 1009 uint8 allocationFlags; 1010 link.Read<uint8>(&allocationFlags); 1011 link.Read<area_id>(&fServerArea); 1012 link.Read<int32>(&fAreaOffset); 1013 1014 BPrivate::ServerMemoryAllocator* allocator 1015 = BApplication::Private::ServerAllocator(); 1016 1017 if (allocationFlags & kNewAllocatorArea) 1018 error = allocator->AddArea(fServerArea, fArea, fBasePointer); 1019 else { 1020 error = allocator->AreaAndBaseFor(fServerArea, fArea, fBasePointer); 1021 if (error == B_OK) 1022 fBasePointer += fAreaOffset; 1023 } 1024 1025 if (allocationFlags & kFramebuffer) { 1026 // the base pointer will now point to an overlay_client_data structure 1027 // bytes per row might be modified to match hardware constraints 1028 link.Read<int32>(&bytesPerRow); 1029 size = bytesPerRow * (bounds.IntegerHeight() + 1); 1030 } 1031 1032 if (fServerArea >= B_OK) { 1033 fSize = size; 1034 fColorSpace = colorSpace; 1035 fBounds = bounds; 1036 fBytesPerRow = bytesPerRow; 1037 fFlags = flags; 1038 } else 1039 error = fServerArea; 1040 } 1041 1042 if (error < B_OK) { 1043 fBasePointer = NULL; 1044 fServerToken = -1; 1045 fArea = -1; 1046 fServerArea = -1; 1047 fAreaOffset = -1; 1048 // NOTE: why not "0" in case of error? 1049 fFlags = flags; 1050 } 1051 } 1052 fWindow = NULL; 1053 } 1054 1055 fInitError = error; 1056 1057 if (fInitError == B_OK) { 1058 if (flags & B_BITMAP_ACCEPTS_VIEWS) { 1059 fWindow = new(std::nothrow) BWindow(Bounds(), fServerToken); 1060 if (fWindow) { 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 } else 1066 fInitError = B_NO_MEMORY; 1067 } 1068 // clear to white if the flags say so. 1069 if (flags & (B_BITMAP_CLEAR_TO_WHITE | B_BITMAP_ACCEPTS_VIEWS)) { 1070 if (fColorSpace == B_CMAP8) { 1071 // "255" is the "transparent magic" index for B_CMAP8 bitmaps 1072 // use the correct index for "white" 1073 memset(fBasePointer, 65, fSize); 1074 } else { 1075 // should work for most colorspaces 1076 memset(fBasePointer, 0xff, fSize); 1077 } 1078 } 1079 } 1080 } 1081 1082 1083 /*! 1084 \brief Cleans up any memory allocated by the bitmap and 1085 informs the server to do so as well (if needed). 1086 */ 1087 void 1088 BBitmap::_CleanUp() 1089 { 1090 if (fBasePointer == NULL) 1091 return; 1092 1093 if (fFlags & B_BITMAP_NO_SERVER_LINK) { 1094 free(fBasePointer); 1095 } else { 1096 BPrivate::AppServerLink link; 1097 // AS_DELETE_BITMAP: 1098 // Attached Data: 1099 // 1) int32 server token 1100 link.StartMessage(AS_DELETE_BITMAP); 1101 link.Attach<int32>(fServerToken); 1102 link.Flush(); 1103 1104 // TODO: we may want to delete parts of the server memory areas here! 1105 1106 fArea = -1; 1107 fServerToken = -1; 1108 fAreaOffset = -1; 1109 } 1110 fBasePointer = NULL; 1111 } 1112 1113 1114 void 1115 BBitmap::_AssertPointer() 1116 { 1117 if (fBasePointer == NULL && fServerArea >= B_OK && fAreaOffset == -1) { 1118 // We lazily clone our own areas - if the bitmap is part of the usual 1119 // server memory area, or is a B_BITMAP_NO_SERVER_LINK bitmap, it already 1120 // has its data. 1121 fArea = clone_area("shared bitmap area", (void **)&fBasePointer, B_ANY_ADDRESS, 1122 B_READ_AREA | B_WRITE_AREA, fServerArea); 1123 } 1124 } 1125 1126