1 /* 2 * Copyright 2001-2006, 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 if (fFlags & B_BITMAP_WILL_OVERLAY) { 413 overlay_client_data* data = (overlay_client_data*)fBasePointer; 414 415 status_t status; 416 do { 417 status = acquire_sem(data->lock); 418 } while (status == B_INTERRUPTED); 419 420 return status; 421 } 422 423 // NOTE: maybe this is used to prevent the app_server from 424 // drawing the bitmap yet? 425 // axeld: you mean for non overlays? 426 427 return B_ERROR; 428 } 429 430 431 /*! 432 \brief Unlocks the bitmap's buffer again. 433 Counterpart to LockBits(), see there for comments. 434 */ 435 void 436 BBitmap::UnlockBits() 437 { 438 if ((fFlags & B_BITMAP_WILL_OVERLAY) == 0) 439 return; 440 441 overlay_client_data* data = (overlay_client_data*)fBasePointer; 442 release_sem(data->lock); 443 } 444 445 // Area 446 /*! \brief Returns the ID of the area the bitmap data reside in. 447 \return The ID of the area the bitmap data reside in. 448 */ 449 area_id 450 BBitmap::Area() const 451 { 452 const_cast<BBitmap *>(this)->_AssertPointer(); 453 return fArea; 454 } 455 456 457 /*! \brief Returns the pointer to the bitmap data. 458 \return The pointer to the bitmap data. 459 */ 460 void * 461 BBitmap::Bits() const 462 { 463 const_cast<BBitmap *>(this)->_AssertPointer(); 464 465 if (fFlags & B_BITMAP_WILL_OVERLAY) { 466 overlay_client_data* data = (overlay_client_data*)fBasePointer; 467 return data->buffer; 468 } 469 470 return (void*)fBasePointer; 471 } 472 473 // BitsLength 474 /*! \brief Returns the size of the bitmap data. 475 \return The size of the bitmap data. 476 */ 477 int32 478 BBitmap::BitsLength() const 479 { 480 return fSize; 481 } 482 483 // BytesPerRow 484 /*! \brief Returns the number of bytes used to store a row of bitmap data. 485 \return The number of bytes used to store a row of bitmap data. 486 */ 487 int32 488 BBitmap::BytesPerRow() const 489 { 490 return fBytesPerRow; 491 } 492 493 // ColorSpace 494 /*! \brief Returns the bitmap's color space. 495 \return The bitmap's color space. 496 */ 497 color_space 498 BBitmap::ColorSpace() const 499 { 500 return fColorSpace; 501 } 502 503 // Bounds 504 /*! \brief Returns the bitmap's dimensions. 505 \return The bitmap's dimensions. 506 */ 507 BRect 508 BBitmap::Bounds() const 509 { 510 return fBounds; 511 } 512 513 // Flags 514 /*! \brief Returns the bitmap's creating flags. 515 516 This method informs about which flags have been used to create the 517 bitmap. It would for example tell you wether this is an overlay 518 bitmap. If bitmap creation succeeded, all flags are fulfilled. 519 520 \return The bitmap's creation flags. 521 */ 522 uint32 523 BBitmap::Flags() const 524 { 525 return fFlags; 526 } 527 528 529 // SetBits 530 /*! \brief Assigns data to the bitmap. 531 532 Data are directly written into the bitmap's data buffer, being converted 533 beforehand, if necessary. Some conversions work rather unintuitively: 534 - \c B_RGB32: The source buffer is supposed to contain \c B_RGB24_BIG 535 data without padding at the end of the rows. 536 - \c B_RGB32: The source buffer is supposed to contain \c B_CMAP8 537 data without padding at the end of the rows. 538 - other color spaces: The source buffer is supposed to contain data 539 according to the specified color space being rowwise padded to int32. 540 541 The currently supported source/target color spaces are 542 \c B_RGB{32,24,16,15}[_BIG], \c B_CMAP8 and \c B_GRAY{8,1}. 543 544 \note As this methods is apparently a bit strange to use, Haiku introduces 545 ImportBits() methods, which are recommended to be used instead. 546 547 \param data The data to be copied. 548 \param length The length in bytes of the data to be copied. 549 \param offset The offset (in bytes) relative to beginning of the bitmap 550 data specifying the position at which the source data shall be 551 written. 552 \param colorSpace Color space of the source data. 553 */ 554 void 555 BBitmap::SetBits(const void *data, int32 length, int32 offset, 556 color_space colorSpace) 557 { 558 status_t error = (InitCheck() == B_OK ? B_OK : B_NO_INIT); 559 // check params 560 if (error == B_OK && (data == NULL || offset > fSize || length < 0)) 561 error = B_BAD_VALUE; 562 int32 width = 0; 563 if (error == B_OK) 564 width = fBounds.IntegerWidth() + 1; 565 int32 inBPR = -1; 566 // tweaks to mimic R5 behavior 567 if (error == B_OK) { 568 // B_RGB32 means actually unpadded B_RGB24_BIG 569 if (colorSpace == B_RGB32) { 570 colorSpace = B_RGB24_BIG; 571 inBPR = width * 3; 572 // If in color space is B_CMAP8, but the bitmap's is another one, 573 // ignore source data row padding. 574 } else if (colorSpace == B_CMAP8 && fColorSpace != B_CMAP8) 575 inBPR = width; 576 } 577 // call the sane method, which does the actual work 578 if (error == B_OK) 579 error = ImportBits(data, length, inBPR, offset, colorSpace); 580 } 581 582 // ImportBits 583 /*! \brief Assigns data to the bitmap. 584 585 Data are directly written into the bitmap's data buffer, being converted 586 beforehand, if necessary. Unlike for SetBits(), the meaning of 587 \a colorSpace is exactly the expected one here, i.e. the source buffer 588 is supposed to contain data of that color space. \a bpr specifies how 589 many bytes the source contains per row. \c B_ANY_BYTES_PER_ROW can be 590 supplied, if standard padding to int32 is used. 591 592 The currently supported source/target color spaces are 593 \c B_RGB{32,24,16,15}[_BIG], \c B_CMAP8 and \c B_GRAY{8,1}. 594 595 \param data The data to be copied. 596 \param length The length in bytes of the data to be copied. 597 \param bpr The number of bytes per row in the source data. 598 \param offset The offset (in bytes) relative to beginning of the bitmap 599 data specifying the position at which the source data shall be 600 written. 601 \param colorSpace Color space of the source data. 602 \return 603 - \c B_OK: Everything went fine. 604 - \c B_BAD_VALUE: \c NULL \a data, invalid \a bpr or \a offset, or 605 unsupported \a colorSpace. 606 */ 607 status_t 608 BBitmap::ImportBits(const void *data, int32 length, int32 bpr, int32 offset, 609 color_space colorSpace) 610 { 611 _AssertPointer(); 612 613 if (InitCheck() != B_OK) 614 return B_NO_INIT; 615 616 if (!data || offset > fSize || length < 0) 617 return B_BAD_VALUE; 618 619 int32 width = fBounds.IntegerWidth() + 1; 620 if (bpr < 0) 621 bpr = get_bytes_per_row(colorSpace, width); 622 623 return BPrivate::ConvertBits(data, (uint8*)fBasePointer + offset, length, 624 fSize - offset, bpr, fBytesPerRow, colorSpace, fColorSpace, width, 625 fBounds.IntegerHeight() + 1); 626 } 627 628 629 /*! \brief Assigns data to the bitmap. 630 631 Allows for a BPoint offset in the source and in the bitmap. The region 632 of the source at \a from extending \a width and \a height is assigned 633 (and converted if necessary) to the bitmap at \a to. 634 635 The currently supported source/target color spaces are 636 \c B_RGB{32,24,16,15}[_BIG], \c B_CMAP8 and \c B_GRAY{8,1}. 637 638 \param data The data to be copied. 639 \param length The length in bytes of the data to be copied. 640 \param bpr The number of bytes per row in the source data. 641 \param colorSpace Color space of the source data. 642 \param from The offset in the source where reading should begin. 643 \param to The offset in the bitmap where the source should be written. 644 \param width The width (in pixels) to be imported. 645 \param height The height (in pixels) to be imported. 646 \return 647 - \c B_OK: Everything went fine. 648 - \c B_BAD_VALUE: \c NULL \a data, invalid \a bpr, unsupported 649 \a colorSpace or invalid width/height. 650 */ 651 status_t 652 BBitmap::ImportBits(const void *data, int32 length, int32 bpr, 653 color_space colorSpace, BPoint from, BPoint to, int32 width, int32 height) 654 { 655 _AssertPointer(); 656 657 if (InitCheck() != B_OK) 658 return B_NO_INIT; 659 660 if (!data || length < 0 || bpr < 0 || width < 0 || height < 0) 661 return B_BAD_VALUE; 662 663 if (bpr < 0) 664 bpr = get_bytes_per_row(colorSpace, fBounds.IntegerWidth() + 1); 665 666 return BPrivate::ConvertBits(data, fBasePointer, length, fSize, bpr, 667 fBytesPerRow, colorSpace, fColorSpace, from, to, width, height); 668 } 669 670 671 /*! \briefly Assigns another bitmap's data to this bitmap. 672 673 The supplied bitmap must have the exactly same dimensions as this bitmap. 674 Its data is converted to the color space of this bitmap. 675 676 The currently supported source/target color spaces are 677 \c B_RGB{32,24,16,15}[_BIG], \c B_CMAP8 and \c B_GRAY{8,1}. 678 679 \param bitmap The source bitmap. 680 \return 681 - \c B_OK: Everything went fine. 682 - \c B_BAD_VALUE: \c NULL \a bitmap, or \a bitmap has other dimensions, 683 or the conversion from or to one of the color spaces is not supported. 684 */ 685 status_t 686 BBitmap::ImportBits(const BBitmap *bitmap) 687 { 688 if (InitCheck() != B_OK) 689 return B_NO_INIT; 690 691 if (!bitmap || bitmap->InitCheck() != B_OK || bitmap->Bounds() != fBounds) 692 return B_BAD_VALUE; 693 694 return ImportBits(bitmap->Bits(), bitmap->BitsLength(), 695 bitmap->BytesPerRow(), 0, bitmap->ColorSpace()); 696 } 697 698 699 /*! \brief Assigns data to the bitmap. 700 701 Allows for a BPoint offset in the source and in the bitmap. The region 702 of the source at \a from extending \a width and \a height is assigned 703 (and converted if necessary) to the bitmap at \a to. The source bitmap is 704 clipped to the bitmap and they don't need to have the same dimensions. 705 706 The currently supported source/target color spaces are 707 \c B_RGB{32,24,16,15}[_BIG], \c B_CMAP8 and \c B_GRAY{8,1}. 708 709 \param bitmap The source bitmap. 710 \param from The offset in the source where reading should begin. 711 \param to The offset in the bitmap where the source should be written. 712 \param width The width (in pixels) to be imported. 713 \param height The height (in pixels) to be imported. 714 - \c B_OK: Everything went fine. 715 - \c B_BAD_VALUE: \c NULL \a bitmap, the conversion from or to one of 716 the color spaces is not supported, or invalid width/height. 717 */ 718 status_t 719 BBitmap::ImportBits(const BBitmap *bitmap, BPoint from, BPoint to, int32 width, 720 int32 height) 721 { 722 if (InitCheck() != B_OK) 723 return B_NO_INIT; 724 725 if (!bitmap || bitmap->InitCheck() != B_OK) 726 return B_BAD_VALUE; 727 728 return ImportBits(bitmap->Bits(), bitmap->BitsLength(), 729 bitmap->BytesPerRow(), bitmap->ColorSpace(), from, to, width, height); 730 } 731 732 733 /*! \brief Returns the overlay_restrictions structure for this bitmap 734 */ 735 status_t 736 BBitmap::GetOverlayRestrictions(overlay_restrictions *restrictions) const 737 { 738 if ((fFlags & B_BITMAP_WILL_OVERLAY) == 0) 739 return B_BAD_TYPE; 740 741 BPrivate::AppServerLink link; 742 743 link.StartMessage(AS_GET_BITMAP_OVERLAY_RESTRICTIONS); 744 link.Attach<int32>(fServerToken); 745 746 status_t status; 747 if (link.FlushWithReply(status) < B_OK) 748 return B_ERROR; 749 750 return status; 751 } 752 753 754 /*! \brief Adds a BView to the bitmap's view hierarchy. 755 756 The bitmap must accept views and the supplied view must not be child of 757 another parent. 758 759 \param view The view to be added. 760 */ 761 void 762 BBitmap::AddChild(BView *view) 763 { 764 if (fWindow != NULL) 765 fWindow->AddChild(view); 766 } 767 768 // RemoveChild 769 /*! \brief Removes a BView from the bitmap's view hierarchy. 770 \param view The view to be removed. 771 */ 772 bool 773 BBitmap::RemoveChild(BView *view) 774 { 775 return fWindow != NULL ? fWindow->RemoveChild(view) : false; 776 } 777 778 // CountChildren 779 /*! \brief Returns the number of BViews currently belonging to the bitmap. 780 \return The number of BViews currently belonging to the bitmap. 781 */ 782 int32 783 BBitmap::CountChildren() const 784 { 785 return fWindow != NULL ? fWindow->CountChildren() : 0; 786 } 787 788 // ChildAt 789 /*! \brief Returns the BView at a certain index in the bitmap's list of views. 790 \param index The index of the BView to be returned. 791 \return The BView at index \a index or \c NULL, if the index is out of 792 range. 793 */ 794 BView* 795 BBitmap::ChildAt(int32 index) const 796 { 797 return fWindow != NULL ? fWindow->ChildAt(index) : NULL; 798 } 799 800 // FindView 801 /*! \brief Returns a bitmap's BView with a certain name. 802 \param name The name of the BView to be returned. 803 \return The BView with the name \a name or \c NULL, if the bitmap doesn't 804 know a view with that name. 805 */ 806 BView* 807 BBitmap::FindView(const char *viewName) const 808 { 809 return fWindow != NULL ? fWindow->FindView(viewName) : NULL; 810 } 811 812 // FindView 813 /*! \brief Returns a bitmap's BView at a certain location. 814 \param point The location. 815 \return The BView with located at \a point or \c NULL, if the bitmap 816 doesn't know a view at this location. 817 */ 818 BView * 819 BBitmap::FindView(BPoint point) const 820 { 821 return fWindow != NULL ? fWindow->FindView(point) : NULL; 822 } 823 824 // Lock 825 /*! \brief Locks the off-screen window that belongs to the bitmap. 826 827 The bitmap must accept views, if locking should work. 828 829 \return \c true, if the lock was acquired successfully, \c false 830 otherwise. 831 */ 832 bool 833 BBitmap::Lock() 834 { 835 return fWindow != NULL ? fWindow->Lock() : false; 836 } 837 838 // Unlock 839 /*! \brief Unlocks the off-screen window that belongs to the bitmap. 840 841 The bitmap must accept views, if locking should work. 842 */ 843 void 844 BBitmap::Unlock() 845 { 846 if (fWindow != NULL) 847 fWindow->Unlock(); 848 } 849 850 // IsLocked 851 /*! \brief Returns whether or not the bitmap's off-screen window is locked. 852 853 The bitmap must accept views, if locking should work. 854 855 \return \c true, if the caller owns a lock , \c false otherwise. 856 */ 857 bool 858 BBitmap::IsLocked() const 859 { 860 return fWindow != NULL ? fWindow->IsLocked() : false; 861 } 862 863 864 BBitmap & 865 BBitmap::operator=(const BBitmap& source) 866 { 867 _CleanUp(); 868 fInitError = B_NO_INIT; 869 870 if (!source.IsValid()) 871 return *this; 872 873 _InitObject(source.Bounds(), source.ColorSpace(), source.Flags(), 874 source.BytesPerRow(), B_MAIN_SCREEN_ID); 875 if (InitCheck() == B_OK) 876 memcpy(Bits(), source.Bits(), min_c(BitsLength(), source.BitsLength())); 877 878 return *this; 879 } 880 881 882 status_t 883 BBitmap::Perform(perform_code d, void *arg) 884 { 885 return BArchivable::Perform(d, arg); 886 } 887 888 // FBC 889 void BBitmap::_ReservedBitmap1() {} 890 void BBitmap::_ReservedBitmap2() {} 891 void BBitmap::_ReservedBitmap3() {} 892 893 894 #if 0 895 // get_shared_pointer 896 /*! \brief ??? 897 */ 898 char * 899 BBitmap::get_shared_pointer() const 900 { 901 return NULL; // not implemented 902 } 903 #endif 904 905 int32 906 BBitmap::_ServerToken() const 907 { 908 return fServerToken; 909 } 910 911 912 /*! \brief Initializes the bitmap. 913 \param bounds The bitmap dimensions. 914 \param colorSpace The bitmap's color space. 915 \param flags Creation flags. 916 \param bytesPerRow The number of bytes per row the bitmap should use. 917 \c B_ANY_BYTES_PER_ROW to let the constructor choose an appropriate 918 value. 919 \param screenID ??? 920 */ 921 void 922 BBitmap::_InitObject(BRect bounds, color_space colorSpace, uint32 flags, 923 int32 bytesPerRow, screen_id screenID) 924 { 925 //printf("BBitmap::InitObject(bounds: BRect(%.1f, %.1f, %.1f, %.1f), format: %ld, flags: %ld, bpr: %ld\n", 926 // bounds.left, bounds.top, bounds.right, bounds.bottom, colorSpace, flags, bytesPerRow); 927 928 // TODO: Should we handle rounding of the "bounds" here? How does R5 behave? 929 930 status_t error = B_OK; 931 932 #ifdef RUN_WITHOUT_APP_SERVER 933 flags |= B_BITMAP_NO_SERVER_LINK; 934 #endif // RUN_WITHOUT_APP_SERVER 935 936 _CleanUp(); 937 938 // check params 939 if (!bounds.IsValid() || !bitmaps_support_space(colorSpace, NULL)) { 940 error = B_BAD_VALUE; 941 } else { 942 // bounds is in floats and might be valid but much larger than what we can handle 943 // the size could not be expressed in int32 944 double realSize = bounds.Width() * bounds.Height(); 945 if (realSize > (double)(INT_MAX / 4)) { 946 fprintf(stderr, "bitmap bounds is much too large: BRect(%.1f, %.1f, %.1f, %.1f)\n", 947 bounds.left, bounds.top, bounds.right, bounds.bottom); 948 error = B_BAD_VALUE; 949 } 950 } 951 if (error == B_OK) { 952 int32 bpr = get_bytes_per_row(colorSpace, bounds.IntegerWidth() + 1); 953 if (bytesPerRow < 0) 954 bytesPerRow = bpr; 955 else if (bytesPerRow < bpr) 956 // NOTE: How does R5 behave? 957 error = B_BAD_VALUE; 958 } 959 // allocate the bitmap buffer 960 if (error == B_OK) { 961 // NOTE: Maybe the code would look more robust if the 962 // "size" was not calculated here when we ask the server 963 // to allocate the bitmap. -Stephan 964 int32 size = bytesPerRow * (bounds.IntegerHeight() + 1); 965 966 if (flags & B_BITMAP_NO_SERVER_LINK) { 967 fBasePointer = (uint8*)malloc(size); 968 if (fBasePointer) { 969 fSize = size; 970 fColorSpace = colorSpace; 971 fBounds = bounds; 972 fBytesPerRow = bytesPerRow; 973 fFlags = flags; 974 } else 975 error = B_NO_MEMORY; 976 } else { 977 // Ask the server (via our owning application) to create a bitmap. 978 BPrivate::AppServerLink link; 979 980 // Attach Data: 981 // 1) BRect bounds 982 // 2) color_space space 983 // 3) int32 bitmap_flags 984 // 4) int32 bytes_per_row 985 // 5) int32 screen_id::id 986 link.StartMessage(AS_CREATE_BITMAP); 987 link.Attach<BRect>(bounds); 988 link.Attach<color_space>(colorSpace); 989 link.Attach<int32>((int32)flags); 990 link.Attach<int32>(bytesPerRow); 991 link.Attach<int32>(screenID.id); 992 993 if (link.FlushWithReply(error) == B_OK && error == B_OK) { 994 // server side success 995 // Get token 996 link.Read<int32>(&fServerToken); 997 998 uint8 allocationFlags; 999 link.Read<uint8>(&allocationFlags); 1000 link.Read<area_id>(&fServerArea); 1001 link.Read<int32>(&fAreaOffset); 1002 1003 BPrivate::ServerMemoryAllocator* allocator 1004 = BApplication::Private::ServerAllocator(); 1005 1006 if (allocationFlags & kNewAllocatorArea) 1007 error = allocator->AddArea(fServerArea, fArea, fBasePointer); 1008 else { 1009 error = allocator->AreaAndBaseFor(fServerArea, fArea, fBasePointer); 1010 if (error == B_OK) 1011 fBasePointer += fAreaOffset; 1012 } 1013 1014 if (allocationFlags & kFramebuffer) { 1015 // the base pointer will now point to an overlay_client_data structure 1016 // bytes per row might be modified to match hardware constraints 1017 link.Read<int32>(&bytesPerRow); 1018 size = bytesPerRow * (bounds.IntegerHeight() + 1); 1019 } 1020 1021 if (fServerArea >= B_OK) { 1022 fSize = size; 1023 fColorSpace = colorSpace; 1024 fBounds = bounds; 1025 fBytesPerRow = bytesPerRow; 1026 fFlags = flags; 1027 } else 1028 error = fServerArea; 1029 } 1030 1031 if (error < B_OK) { 1032 fBasePointer = NULL; 1033 fServerToken = -1; 1034 fArea = -1; 1035 fServerArea = -1; 1036 fAreaOffset = -1; 1037 // NOTE: why not "0" in case of error? 1038 fFlags = flags; 1039 } 1040 } 1041 fWindow = NULL; 1042 } 1043 1044 fInitError = error; 1045 // TODO: on success, handle clearing to white if the flags say so. Needs to be 1046 // dependent on color space. 1047 1048 if (fInitError == B_OK) { 1049 if (flags & B_BITMAP_ACCEPTS_VIEWS) { 1050 fWindow = new BWindow(Bounds(), fServerToken); 1051 // A BWindow starts life locked and is unlocked 1052 // in Show(), but this window is never shown and 1053 // it's message loop is never started. 1054 fWindow->Unlock(); 1055 } 1056 } 1057 } 1058 1059 1060 /*! 1061 \brief Cleans up any memory allocated by the bitmap and 1062 informs the server to do so as well (if needed). 1063 */ 1064 void 1065 BBitmap::_CleanUp() 1066 { 1067 if (fBasePointer == NULL) 1068 return; 1069 1070 if (fFlags & B_BITMAP_NO_SERVER_LINK) { 1071 free(fBasePointer); 1072 } else { 1073 BPrivate::AppServerLink link; 1074 // AS_DELETE_BITMAP: 1075 // Attached Data: 1076 // 1) int32 server token 1077 link.StartMessage(AS_DELETE_BITMAP); 1078 link.Attach<int32>(fServerToken); 1079 link.Flush(); 1080 1081 // TODO: we may want to delete parts of the server memory areas here! 1082 1083 fArea = -1; 1084 fServerToken = -1; 1085 fAreaOffset = -1; 1086 } 1087 fBasePointer = NULL; 1088 } 1089 1090 1091 void 1092 BBitmap::_AssertPointer() 1093 { 1094 if (fBasePointer == NULL && fServerArea >= B_OK && fAreaOffset == -1) { 1095 // We lazily clone our own areas - if the bitmap is part of the usual 1096 // server memory area, or is a B_BITMAP_NO_SERVER_LINK bitmap, it already 1097 // has its data. 1098 fArea = clone_area("shared bitmap area", (void **)&fBasePointer, B_ANY_ADDRESS, 1099 B_READ_AREA | B_WRITE_AREA, fServerArea); 1100 } 1101 } 1102 1103