HaikuDepot: notify work status from main window
[haiku.git] / src / kits / interface / Bitmap.cpp
blob42da3167335aa7be82c5f97ac87e758f18766d6e
1 /*
2 * Copyright 2001-2009, Haiku Inc.
3 * Distributed under the terms of the MIT License.
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
13 /*! BBitmap objects represent off-screen windows that
14 contain bitmap data.
18 #include <Bitmap.h>
20 #include <algorithm>
21 #include <limits.h>
22 #include <new>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
27 #include <Application.h>
28 #include <GraphicsDefs.h>
29 #include <Locker.h>
30 #include <View.h>
31 #include <Window.h>
33 #include <ApplicationPrivate.h>
34 #include <AppServerLink.h>
35 #include <Autolock.h>
36 #include <ObjectList.h>
37 #include <ServerMemoryAllocator.h>
38 #include <ServerProtocol.h>
40 #include "ColorConversion.h"
41 #include "BitmapPrivate.h"
44 using namespace BPrivate;
47 static BObjectList<BBitmap> sBitmapList;
48 static BLocker sBitmapListLock;
51 void
52 reconnect_bitmaps_to_app_server()
54 BAutolock _(sBitmapListLock);
55 for (int32 i = 0; i < sBitmapList.CountItems(); i++) {
56 BBitmap::Private bitmap(sBitmapList.ItemAt(i));
57 bitmap.ReconnectToAppServer();
62 BBitmap::Private::Private(BBitmap* bitmap)
64 fBitmap(bitmap)
69 void
70 BBitmap::Private::ReconnectToAppServer()
72 fBitmap->_ReconnectToAppServer();
76 /*! \brief Returns the number of bytes per row needed to store the actual
77 bitmap data (not including any padding) given a color space and a
78 row width.
79 \param colorSpace The color space.
80 \param width The width.
81 \return The number of bytes per row needed to store data for a row, or
82 0, if the color space is not supported.
84 static inline int32
85 get_raw_bytes_per_row(color_space colorSpace, int32 width)
87 int32 bpr = 0;
88 switch (colorSpace) {
89 // supported
90 case B_RGB32: case B_RGBA32:
91 case B_RGB32_BIG: case B_RGBA32_BIG:
92 case B_UVL32: case B_UVLA32:
93 case B_LAB32: case B_LABA32:
94 case B_HSI32: case B_HSIA32:
95 case B_HSV32: case B_HSVA32:
96 case B_HLS32: case B_HLSA32:
97 case B_CMY32: case B_CMYA32: case B_CMYK32:
98 bpr = 4 * width;
99 break;
100 case B_RGB24: case B_RGB24_BIG:
101 case B_UVL24: case B_LAB24: case B_HSI24:
102 case B_HSV24: case B_HLS24: case B_CMY24:
103 bpr = 3 * width;
104 break;
105 case B_RGB16: case B_RGB15: case B_RGBA15:
106 case B_RGB16_BIG: case B_RGB15_BIG: case B_RGBA15_BIG:
107 bpr = 2 * width;
108 break;
109 case B_CMAP8: case B_GRAY8:
110 bpr = width;
111 break;
112 case B_GRAY1:
113 bpr = (width + 7) / 8;
114 break;
115 case B_YCbCr422: case B_YUV422:
116 bpr = (width + 3) / 4 * 8;
117 break;
118 case B_YCbCr411: case B_YUV411:
119 bpr = (width + 3) / 4 * 6;
120 break;
121 case B_YCbCr444: case B_YUV444:
122 bpr = (width + 3) / 4 * 12;
123 break;
124 case B_YCbCr420: case B_YUV420:
125 bpr = (width + 3) / 4 * 6;
126 break;
127 case B_YUV9:
128 bpr = (width + 15) / 16 * 18;
129 break;
130 // unsupported
131 case B_NO_COLOR_SPACE:
132 case B_YUV12:
133 break;
135 return bpr;
139 namespace BPrivate {
141 /*! \brief Returns the number of bytes per row needed to store the bitmap
142 data (including any padding) given a color space and a row width.
143 \param colorSpace The color space.
144 \param width The width.
145 \return The number of bytes per row needed to store data for a row, or
146 0, if the color space is not supported.
148 int32
149 get_bytes_per_row(color_space colorSpace, int32 width)
151 int32 bpr = get_raw_bytes_per_row(colorSpace, width);
152 // align to int32
153 bpr = (bpr + 3) & 0x7ffffffc;
154 return bpr;
157 } // namespace BPrivate
160 // #pragma mark -
163 /*! \brief Creates and initializes a BBitmap.
164 \param bounds The bitmap dimensions.
165 \param flags Creation flags.
166 \param colorSpace The bitmap's color space.
167 \param bytesPerRow The number of bytes per row the bitmap should use.
168 \c B_ANY_BYTES_PER_ROW to let the constructor choose an appropriate
169 value.
170 \param screenID ???
172 BBitmap::BBitmap(BRect bounds, uint32 flags, color_space colorSpace,
173 int32 bytesPerRow, screen_id screenID)
175 fBasePointer(NULL),
176 fSize(0),
177 fColorSpace(B_NO_COLOR_SPACE),
178 fBounds(0, 0, -1, -1),
179 fBytesPerRow(0),
180 fWindow(NULL),
181 fServerToken(-1),
182 fAreaOffset(-1),
183 fArea(-1),
184 fServerArea(-1),
185 fFlags(0),
186 fInitError(B_NO_INIT)
188 _InitObject(bounds, colorSpace, flags, bytesPerRow, screenID);
192 /*! \brief Creates and initializes a BBitmap.
193 \param bounds The bitmap dimensions.
194 \param colorSpace The bitmap's color space.
195 \param acceptsViews \c true, if the bitmap shall accept BViews, i.e. if
196 it shall be possible to attach BView to the bitmap and draw into
198 \param needsContiguous If \c true a physically contiguous chunk of memory
199 will be allocated.
201 BBitmap::BBitmap(BRect bounds, color_space colorSpace, bool acceptsViews,
202 bool needsContiguous)
204 fBasePointer(NULL),
205 fSize(0),
206 fColorSpace(B_NO_COLOR_SPACE),
207 fBounds(0, 0, -1, -1),
208 fBytesPerRow(0),
209 fWindow(NULL),
210 fServerToken(-1),
211 fAreaOffset(-1),
212 fArea(-1),
213 fServerArea(-1),
214 fFlags(0),
215 fInitError(B_NO_INIT)
217 int32 flags = (acceptsViews ? B_BITMAP_ACCEPTS_VIEWS : 0)
218 | (needsContiguous ? B_BITMAP_IS_CONTIGUOUS : 0);
219 _InitObject(bounds, colorSpace, flags, B_ANY_BYTES_PER_ROW,
220 B_MAIN_SCREEN_ID);
224 /*! \brief Creates a BBitmap as a clone of another bitmap.
225 \param source The source bitmap.
226 \param acceptsViews \c true, if the bitmap shall accept BViews, i.e. if
227 it shall be possible to attach BView to the bitmap and draw into
229 \param needsContiguous If \c true a physically contiguous chunk of memory
230 will be allocated.
232 BBitmap::BBitmap(const BBitmap* source, bool acceptsViews, bool needsContiguous)
234 fBasePointer(NULL),
235 fSize(0),
236 fColorSpace(B_NO_COLOR_SPACE),
237 fBounds(0, 0, -1, -1),
238 fBytesPerRow(0),
239 fWindow(NULL),
240 fServerToken(-1),
241 fAreaOffset(-1),
242 fArea(-1),
243 fServerArea(-1),
244 fFlags(0),
245 fInitError(B_NO_INIT)
247 if (source && source->IsValid()) {
248 int32 flags = (acceptsViews ? B_BITMAP_ACCEPTS_VIEWS : 0)
249 | (needsContiguous ? B_BITMAP_IS_CONTIGUOUS : 0);
250 _InitObject(source->Bounds(), source->ColorSpace(), flags,
251 source->BytesPerRow(), B_MAIN_SCREEN_ID);
252 if (InitCheck() == B_OK) {
253 memcpy(Bits(), source->Bits(), min_c(BitsLength(),
254 source->BitsLength()));
260 BBitmap::BBitmap(const BBitmap& source, uint32 flags)
262 fBasePointer(NULL),
263 fSize(0),
264 fColorSpace(B_NO_COLOR_SPACE),
265 fBounds(0, 0, -1, -1),
266 fBytesPerRow(0),
267 fWindow(NULL),
268 fServerToken(-1),
269 fAreaOffset(-1),
270 fArea(-1),
271 fServerArea(-1),
272 fFlags(0),
273 fInitError(B_NO_INIT)
275 if (!source.IsValid())
276 return;
278 _InitObject(source.Bounds(), source.ColorSpace(), flags,
279 source.BytesPerRow(), B_MAIN_SCREEN_ID);
281 if (InitCheck() == B_OK)
282 memcpy(Bits(), source.Bits(), min_c(BitsLength(), source.BitsLength()));
286 BBitmap::BBitmap(const BBitmap& source)
288 fBasePointer(NULL),
289 fSize(0),
290 fColorSpace(B_NO_COLOR_SPACE),
291 fBounds(0, 0, -1, -1),
292 fBytesPerRow(0),
293 fWindow(NULL),
294 fServerToken(-1),
295 fAreaOffset(-1),
296 fArea(-1),
297 fServerArea(-1),
298 fFlags(0),
299 fInitError(B_NO_INIT)
301 *this = source;
305 /*! \brief Frees all resources associated with this object.
307 BBitmap::~BBitmap()
309 _CleanUp();
313 /*! \brief Unarchives a bitmap from a BMessage.
314 \param data The archive.
316 BBitmap::BBitmap(BMessage* data)
318 BArchivable(data),
319 fBasePointer(NULL),
320 fSize(0),
321 fColorSpace(B_NO_COLOR_SPACE),
322 fBounds(0, 0, -1, -1),
323 fBytesPerRow(0),
324 fWindow(NULL),
325 fServerToken(-1),
326 fAreaOffset(-1),
327 fArea(-1),
328 fServerArea(-1),
329 fFlags(0),
330 fInitError(B_NO_INIT)
332 int32 flags;
333 if (data->FindInt32("_bmflags", &flags) != B_OK) {
334 // this bitmap is archived in some archaic format
335 flags = 0;
337 bool acceptsViews;
338 if (data->FindBool("_view_ok", &acceptsViews) == B_OK && acceptsViews)
339 flags |= B_BITMAP_ACCEPTS_VIEWS;
341 bool contiguous;
342 if (data->FindBool("_contiguous", &contiguous) == B_OK && contiguous)
343 flags |= B_BITMAP_IS_CONTIGUOUS;
346 int32 rowBytes;
347 if (data->FindInt32("_rowbytes", &rowBytes) != B_OK) {
348 rowBytes = -1;
349 // bytes per row are computed in InitObject(), then
352 BRect bounds;
353 color_space cspace;
354 if (data->FindRect("_frame", &bounds) == B_OK
355 && data->FindInt32("_cspace", (int32*)&cspace) == B_OK) {
356 _InitObject(bounds, cspace, flags, rowBytes, B_MAIN_SCREEN_ID);
359 if (InitCheck() == B_OK) {
360 ssize_t size;
361 const void* buffer;
362 if (data->FindData("_data", B_RAW_TYPE, &buffer, &size) == B_OK) {
363 if (size == BitsLength()) {
364 _AssertPointer();
365 memcpy(fBasePointer, buffer, size);
370 if ((fFlags & B_BITMAP_ACCEPTS_VIEWS) != 0) {
371 BMessage message;
372 int32 i = 0;
374 while (data->FindMessage("_views", i++, &message) == B_OK) {
375 if (BView* view
376 = dynamic_cast<BView*>(instantiate_object(&message)))
377 AddChild(view);
383 /*! \brief Instantiates a BBitmap from an archive.
384 \param data The archive.
385 \return A bitmap reconstructed from the archive or \c NULL, if an error
386 occured.
388 BArchivable*
389 BBitmap::Instantiate(BMessage* data)
391 if (validate_instantiation(data, "BBitmap"))
392 return new BBitmap(data);
394 return NULL;
398 /*! \brief Archives the BBitmap object.
399 \param data The archive.
400 \param deep \c true, if child object shall be archived as well, \c false
401 otherwise.
402 \return \c B_OK, if everything went fine, an error code otherwise.
404 status_t
405 BBitmap::Archive(BMessage* data, bool deep) const
407 status_t ret = BArchivable::Archive(data, deep);
409 if (ret == B_OK)
410 ret = data->AddRect("_frame", fBounds);
412 if (ret == B_OK)
413 ret = data->AddInt32("_cspace", (int32)fColorSpace);
415 if (ret == B_OK)
416 ret = data->AddInt32("_bmflags", fFlags);
418 if (ret == B_OK)
419 ret = data->AddInt32("_rowbytes", fBytesPerRow);
421 if (ret == B_OK && deep) {
422 if ((fFlags & B_BITMAP_ACCEPTS_VIEWS) != 0) {
423 BMessage views;
424 for (int32 i = 0; i < CountChildren(); i++) {
425 if (ChildAt(i)->Archive(&views, deep))
426 ret = data->AddMessage("_views", &views);
427 views.MakeEmpty();
428 if (ret < B_OK)
429 break;
433 // Note: R5 does not archive the data if B_BITMAP_IS_CONTIGUOUS is
434 // true and it does save all formats as B_RAW_TYPE and it does save
435 // the data even if B_BITMAP_ACCEPTS_VIEWS is set (as opposed to
436 // the BeBook)
437 if (ret == B_OK) {
438 const_cast<BBitmap*>(this)->_AssertPointer();
439 ret = data->AddData("_data", B_RAW_TYPE, fBasePointer, fSize);
441 return ret;
445 /*! \brief Returns the result from the construction.
446 \return \c B_OK, if the object is properly initialized, an error code
447 otherwise.
449 status_t
450 BBitmap::InitCheck() const
452 return fInitError;
456 /*! \brief Returns whether or not the BBitmap object is valid.
457 \return \c true, if the object is properly initialized, \c false otherwise.
459 bool
460 BBitmap::IsValid() const
462 return InitCheck() == B_OK;
466 /*! \brief Locks the bitmap bits so that they cannot be relocated.
468 This is currently only used for overlay bitmaps - whenever you
469 need to access their Bits(), you have to lock them first.
470 On resolution change overlay bitmaps can be relocated in memory;
471 using this call prevents you from accessing an invalid pointer
472 and clobbering memory that doesn't belong you.
474 status_t
475 BBitmap::LockBits(uint32* state)
477 // TODO: how do we fill the "state"?
478 // It would be more or less useful to report what kind of bitmap
479 // we got (ie. overlay, placeholder, or non-overlay)
480 if ((fFlags & B_BITMAP_WILL_OVERLAY) != 0) {
481 overlay_client_data* data = (overlay_client_data*)fBasePointer;
483 status_t status;
484 do {
485 status = acquire_sem(data->lock);
486 } while (status == B_INTERRUPTED);
488 if (data->buffer == NULL) {
489 // the app_server does not grant us access to the frame buffer
490 // right now - let's release the lock and fail
491 release_sem_etc(data->lock, 1, B_DO_NOT_RESCHEDULE);
492 return B_BUSY;
494 return status;
497 // NOTE: maybe this is used to prevent the app_server from
498 // drawing the bitmap yet?
499 // axeld: you mean for non overlays?
501 return B_OK;
505 /*! \brief Unlocks the bitmap's buffer again.
506 Counterpart to LockBits(), see there for comments.
508 void
509 BBitmap::UnlockBits()
511 if ((fFlags & B_BITMAP_WILL_OVERLAY) == 0)
512 return;
514 overlay_client_data* data = (overlay_client_data*)fBasePointer;
515 release_sem_etc(data->lock, 1, B_DO_NOT_RESCHEDULE);
519 /*! \brief Returns the ID of the area the bitmap data reside in.
520 \return The ID of the area the bitmap data reside in.
522 area_id
523 BBitmap::Area() const
525 const_cast<BBitmap*>(this)->_AssertPointer();
526 return fArea;
530 /*! \brief Returns the pointer to the bitmap data.
531 \return The pointer to the bitmap data.
533 void*
534 BBitmap::Bits() const
536 const_cast<BBitmap*>(this)->_AssertPointer();
538 if ((fFlags & B_BITMAP_WILL_OVERLAY) != 0) {
539 overlay_client_data* data = (overlay_client_data*)fBasePointer;
540 return data->buffer;
543 return (void*)fBasePointer;
547 /*! \brief Returns the size of the bitmap data.
548 \return The size of the bitmap data.
550 int32
551 BBitmap::BitsLength() const
553 return fSize;
557 /*! \brief Returns the number of bytes used to store a row of bitmap data.
558 \return The number of bytes used to store a row of bitmap data.
560 int32
561 BBitmap::BytesPerRow() const
563 return fBytesPerRow;
567 /*! \brief Returns the bitmap's color space.
568 \return The bitmap's color space.
570 color_space
571 BBitmap::ColorSpace() const
573 return fColorSpace;
577 /*! \brief Returns the bitmap's dimensions.
578 \return The bitmap's dimensions.
580 BRect
581 BBitmap::Bounds() const
583 return fBounds;
587 /*! \brief Returns the bitmap's creating flags.
589 This method informs about which flags have been used to create the
590 bitmap. It would for example tell you whether this is an overlay
591 bitmap. If bitmap creation succeeded, all flags are fulfilled.
593 \return The bitmap's creation flags.
595 uint32
596 BBitmap::Flags() const
598 return fFlags;
602 /*! \brief Assigns data to the bitmap.
604 Data are directly written into the bitmap's data buffer, being converted
605 beforehand, if necessary. Some conversions work rather unintuitively:
606 - \c B_RGB32: The source buffer is supposed to contain \c B_RGB24_BIG
607 data without padding at the end of the rows.
608 - \c B_RGB32: The source buffer is supposed to contain \c B_CMAP8
609 data without padding at the end of the rows.
610 - other color spaces: The source buffer is supposed to contain data
611 according to the specified color space being rowwise padded to int32.
613 The currently supported source/target color spaces are
614 \c B_RGB{32,24,16,15}[_BIG], \c B_CMAP8 and \c B_GRAY{8,1}.
616 \note As this methods is apparently a bit strange to use, Haiku introduces
617 ImportBits() methods, which are recommended to be used instead.
619 \param data The data to be copied.
620 \param length The length in bytes of the data to be copied.
621 \param offset The offset (in bytes) relative to beginning of the bitmap
622 data specifying the position at which the source data shall be
623 written.
624 \param colorSpace Color space of the source data.
626 void
627 BBitmap::SetBits(const void* data, int32 length, int32 offset,
628 color_space colorSpace)
630 status_t error = (InitCheck() == B_OK ? B_OK : B_NO_INIT);
631 // check params
632 if (error == B_OK && (data == NULL || offset > fSize || length < 0))
633 error = B_BAD_VALUE;
634 int32 width = 0;
635 if (error == B_OK)
636 width = fBounds.IntegerWidth() + 1;
637 int32 inBPR = -1;
638 // tweaks to mimic R5 behavior
639 if (error == B_OK) {
640 if (colorSpace == B_RGB32) {
641 // B_RGB32 means actually unpadded B_RGB24_BIG
642 colorSpace = B_RGB24_BIG;
643 inBPR = width * 3;
644 } else if (colorSpace == B_CMAP8 && fColorSpace != B_CMAP8) {
645 // If in color space is B_CMAP8, but the bitmap's is another one,
646 // ignore source data row padding.
647 inBPR = width;
650 // call the sane method, which does the actual work
651 error = ImportBits(data, length, inBPR, offset, colorSpace);
656 /*! \brief Assigns data to the bitmap.
658 Data are directly written into the bitmap's data buffer, being converted
659 beforehand, if necessary. Unlike for SetBits(), the meaning of
660 \a colorSpace is exactly the expected one here, i.e. the source buffer
661 is supposed to contain data of that color space. \a bpr specifies how
662 many bytes the source contains per row. \c B_ANY_BYTES_PER_ROW can be
663 supplied, if standard padding to int32 is used.
665 The currently supported source/target color spaces are
666 \c B_RGB{32,24,16,15}[_BIG], \c B_CMAP8 and \c B_GRAY{8,1}.
668 \param data The data to be copied.
669 \param length The length in bytes of the data to be copied.
670 \param bpr The number of bytes per row in the source data.
671 \param offset The offset (in bytes) relative to beginning of the bitmap
672 data specifying the position at which the source data shall be
673 written.
674 \param colorSpace Color space of the source data.
675 \return
676 - \c B_OK: Everything went fine.
677 - \c B_BAD_VALUE: \c NULL \a data, invalid \a bpr or \a offset, or
678 unsupported \a colorSpace.
680 status_t
681 BBitmap::ImportBits(const void* data, int32 length, int32 bpr, int32 offset,
682 color_space colorSpace)
684 _AssertPointer();
686 if (InitCheck() != B_OK)
687 return B_NO_INIT;
689 if (!data || offset > fSize || length < 0)
690 return B_BAD_VALUE;
692 int32 width = fBounds.IntegerWidth() + 1;
693 if (bpr <= 0) {
694 if (bpr == B_ANY_BYTES_PER_ROW)
695 bpr = get_bytes_per_row(colorSpace, width);
696 else
697 return B_BAD_VALUE;
700 return BPrivate::ConvertBits(data, (uint8*)fBasePointer + offset, length,
701 fSize - offset, bpr, fBytesPerRow, colorSpace, fColorSpace, width,
702 fBounds.IntegerHeight() + 1);
706 /*! \brief Assigns data to the bitmap.
708 Allows for a BPoint offset in the source and in the bitmap. The region
709 of the source at \a from extending \a width and \a height is assigned
710 (and converted if necessary) to the bitmap at \a to.
712 The currently supported source/target color spaces are
713 \c B_RGB{32,24,16,15}[_BIG], \c B_CMAP8 and \c B_GRAY{8,1}.
715 \param data The data to be copied.
716 \param length The length in bytes of the data to be copied.
717 \param bpr The number of bytes per row in the source data.
718 \param colorSpace Color space of the source data.
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 \return
724 - \c B_OK: Everything went fine.
725 - \c B_BAD_VALUE: \c NULL \a data, invalid \a bpr, unsupported
726 \a colorSpace or invalid width/height.
728 status_t
729 BBitmap::ImportBits(const void* data, int32 length, int32 bpr,
730 color_space colorSpace, BPoint from, BPoint to, int32 width, int32 height)
732 _AssertPointer();
734 if (InitCheck() != B_OK)
735 return B_NO_INIT;
737 if (!data || length < 0 || width < 0 || height < 0)
738 return B_BAD_VALUE;
740 if (bpr <= 0) {
741 if (bpr == B_ANY_BYTES_PER_ROW)
742 bpr = get_bytes_per_row(colorSpace, fBounds.IntegerWidth() + 1);
743 else
744 return B_BAD_VALUE;
747 return BPrivate::ConvertBits(data, fBasePointer, length, fSize, bpr,
748 fBytesPerRow, colorSpace, fColorSpace, from, to, width, height);
752 /*! \briefly Assigns another bitmap's data to this bitmap.
754 The supplied bitmap must have the exactly same dimensions as this bitmap.
755 Its data is converted to the color space of this bitmap.
757 The currently supported source/target color spaces are
758 \c B_RGB{32,24,16,15}[_BIG], \c B_CMAP8 and \c B_GRAY{8,1}.
760 \param bitmap The source bitmap.
761 \return
762 - \c B_OK: Everything went fine.
763 - \c B_BAD_VALUE: \c NULL \a bitmap, or \a bitmap has other dimensions,
764 or the conversion from or to one of the color spaces is not supported.
766 status_t
767 BBitmap::ImportBits(const BBitmap* bitmap)
769 if (InitCheck() != B_OK)
770 return B_NO_INIT;
772 if (!bitmap || bitmap->InitCheck() != B_OK || bitmap->Bounds() != fBounds)
773 return B_BAD_VALUE;
775 return ImportBits(bitmap->Bits(), bitmap->BitsLength(),
776 bitmap->BytesPerRow(), 0, bitmap->ColorSpace());
780 /*! \brief Assigns data to the bitmap.
782 Allows for a BPoint offset in the source and in the bitmap. The region
783 of the source at \a from extending \a width and \a height is assigned
784 (and converted if necessary) to the bitmap at \a to. The source bitmap is
785 clipped to the bitmap and they don't need to have the same dimensions.
787 The currently supported source/target color spaces are
788 \c B_RGB{32,24,16,15}[_BIG], \c B_CMAP8 and \c B_GRAY{8,1}.
790 \param bitmap The source bitmap.
791 \param from The offset in the source where reading should begin.
792 \param to The offset in the bitmap where the source should be written.
793 \param width The width (in pixels) to be imported.
794 \param height The height (in pixels) to be imported.
795 - \c B_OK: Everything went fine.
796 - \c B_BAD_VALUE: \c NULL \a bitmap, the conversion from or to one of
797 the color spaces is not supported, or invalid width/height.
799 status_t
800 BBitmap::ImportBits(const BBitmap* bitmap, BPoint from, BPoint to, int32 width,
801 int32 height)
803 if (InitCheck() != B_OK)
804 return B_NO_INIT;
806 if (!bitmap || bitmap->InitCheck() != B_OK)
807 return B_BAD_VALUE;
809 return ImportBits(bitmap->Bits(), bitmap->BitsLength(),
810 bitmap->BytesPerRow(), bitmap->ColorSpace(), from, to, width, height);
814 /*! \brief Returns the overlay_restrictions structure for this bitmap
816 status_t
817 BBitmap::GetOverlayRestrictions(overlay_restrictions* restrictions) const
819 if ((fFlags & B_BITMAP_WILL_OVERLAY) == 0)
820 return B_BAD_TYPE;
822 BPrivate::AppServerLink link;
824 link.StartMessage(AS_GET_BITMAP_OVERLAY_RESTRICTIONS);
825 link.Attach<int32>(fServerToken);
827 status_t status;
828 if (link.FlushWithReply(status) < B_OK)
829 return status;
831 link.Read(restrictions, sizeof(overlay_restrictions));
832 return B_OK;
836 /*! \brief Adds a BView to the bitmap's view hierarchy.
838 The bitmap must accept views and the supplied view must not be child of
839 another parent.
841 \param view The view to be added.
843 void
844 BBitmap::AddChild(BView* view)
846 if (fWindow != NULL)
847 fWindow->AddChild(view);
851 /*! \brief Removes a BView from the bitmap's view hierarchy.
852 \param view The view to be removed.
854 bool
855 BBitmap::RemoveChild(BView* view)
857 return fWindow != NULL ? fWindow->RemoveChild(view) : false;
861 /*! \brief Returns the number of BViews currently belonging to the bitmap.
862 \return The number of BViews currently belonging to the bitmap.
864 int32
865 BBitmap::CountChildren() const
867 return fWindow != NULL ? fWindow->CountChildren() : 0;
871 /*! \brief Returns the BView at a certain index in the bitmap's list of views.
872 \param index The index of the BView to be returned.
873 \return The BView at index \a index or \c NULL, if the index is out of
874 range.
876 BView*
877 BBitmap::ChildAt(int32 index) const
879 return fWindow != NULL ? fWindow->ChildAt(index) : NULL;
883 /*! \brief Returns a bitmap's BView with a certain name.
884 \param name The name of the BView to be returned.
885 \return The BView with the name \a name or \c NULL, if the bitmap doesn't
886 know a view with that name.
888 BView*
889 BBitmap::FindView(const char* viewName) const
891 return fWindow != NULL ? fWindow->FindView(viewName) : NULL;
895 /*! \brief Returns a bitmap's BView at a certain location.
896 \param point The location.
897 \return The BView with located at \a point or \c NULL, if the bitmap
898 doesn't know a view at this location.
900 BView*
901 BBitmap::FindView(BPoint point) const
903 return fWindow != NULL ? fWindow->FindView(point) : NULL;
907 /*! \brief Locks the off-screen window that belongs to the bitmap.
909 The bitmap must accept views, if locking should work.
911 \return \c true, if the lock was acquired successfully, \c false
912 otherwise.
914 bool
915 BBitmap::Lock()
917 return fWindow != NULL ? fWindow->Lock() : false;
921 /*! \brief Unlocks the off-screen window that belongs to the bitmap.
923 The bitmap must accept views, if locking should work.
925 void
926 BBitmap::Unlock()
928 if (fWindow != NULL)
929 fWindow->Unlock();
933 /*! \brief Returns whether or not the bitmap's off-screen window is locked.
935 The bitmap must accept views, if locking should work.
937 \return \c true, if the caller owns a lock , \c false otherwise.
939 bool
940 BBitmap::IsLocked() const
942 return fWindow != NULL ? fWindow->IsLocked() : false;
946 BBitmap&
947 BBitmap::operator=(const BBitmap& source)
949 _CleanUp();
950 fInitError = B_NO_INIT;
952 if (!source.IsValid())
953 return *this;
955 _InitObject(source.Bounds(), source.ColorSpace(), source.Flags(),
956 source.BytesPerRow(), B_MAIN_SCREEN_ID);
957 if (InitCheck() == B_OK)
958 memcpy(Bits(), source.Bits(), min_c(BitsLength(), source.BitsLength()));
960 return *this;
964 status_t
965 BBitmap::Perform(perform_code d, void* arg)
967 return BArchivable::Perform(d, arg);
970 // FBC
971 void BBitmap::_ReservedBitmap1() {}
972 void BBitmap::_ReservedBitmap2() {}
973 void BBitmap::_ReservedBitmap3() {}
976 #if 0
977 // get_shared_pointer
978 /*! \brief ???
980 char*
981 BBitmap::get_shared_pointer() const
983 return NULL; // not implemented
985 #endif
987 int32
988 BBitmap::_ServerToken() const
990 return fServerToken;
994 /*! \brief Initializes the bitmap.
995 \param bounds The bitmap dimensions.
996 \param colorSpace The bitmap's color space.
997 \param flags Creation flags.
998 \param bytesPerRow The number of bytes per row the bitmap should use.
999 \c B_ANY_BYTES_PER_ROW to let the constructor choose an appropriate
1000 value.
1001 \param screenID ???
1003 void
1004 BBitmap::_InitObject(BRect bounds, color_space colorSpace, uint32 flags,
1005 int32 bytesPerRow, screen_id screenID)
1007 //printf("BBitmap::InitObject(bounds: BRect(%.1f, %.1f, %.1f, %.1f), format: %ld, flags: %ld, bpr: %ld\n",
1008 // bounds.left, bounds.top, bounds.right, bounds.bottom, colorSpace, flags, bytesPerRow);
1010 // TODO: Should we handle rounding of the "bounds" here? How does R5 behave?
1012 status_t error = B_OK;
1014 #ifdef RUN_WITHOUT_APP_SERVER
1015 flags |= B_BITMAP_NO_SERVER_LINK;
1016 #endif // RUN_WITHOUT_APP_SERVER
1018 _CleanUp();
1020 // check params
1021 if (!bounds.IsValid() || !bitmaps_support_space(colorSpace, NULL)) {
1022 error = B_BAD_VALUE;
1023 } else {
1024 // bounds is in floats and might be valid but much larger than what we
1025 // can handle the size could not be expressed in int32
1026 double realSize = bounds.Width() * bounds.Height();
1027 if (realSize > (double)(INT_MAX / 4)) {
1028 fprintf(stderr, "bitmap bounds is much too large: "
1029 "BRect(%.1f, %.1f, %.1f, %.1f)\n",
1030 bounds.left, bounds.top, bounds.right, bounds.bottom);
1031 error = B_BAD_VALUE;
1034 if (error == B_OK) {
1035 int32 bpr = get_bytes_per_row(colorSpace, bounds.IntegerWidth() + 1);
1036 if (bytesPerRow < 0)
1037 bytesPerRow = bpr;
1038 else if (bytesPerRow < bpr)
1039 // NOTE: How does R5 behave?
1040 error = B_BAD_VALUE;
1042 // allocate the bitmap buffer
1043 if (error == B_OK) {
1044 // TODO: Let the app_server return the size when it allocated the bitmap
1045 int32 size = bytesPerRow * (bounds.IntegerHeight() + 1);
1047 if ((flags & B_BITMAP_NO_SERVER_LINK) != 0) {
1048 fBasePointer = (uint8*)malloc(size);
1049 if (fBasePointer) {
1050 fSize = size;
1051 fColorSpace = colorSpace;
1052 fBounds = bounds;
1053 fBytesPerRow = bytesPerRow;
1054 fFlags = flags;
1055 } else
1056 error = B_NO_MEMORY;
1057 } else {
1058 // Ask the server (via our owning application) to create a bitmap.
1059 BPrivate::AppServerLink link;
1061 // Attach Data:
1062 // 1) BRect bounds
1063 // 2) color_space space
1064 // 3) int32 bitmap_flags
1065 // 4) int32 bytes_per_row
1066 // 5) int32 screen_id::id
1067 link.StartMessage(AS_CREATE_BITMAP);
1068 link.Attach<BRect>(bounds);
1069 link.Attach<color_space>(colorSpace);
1070 link.Attach<uint32>(flags);
1071 link.Attach<int32>(bytesPerRow);
1072 link.Attach<int32>(screenID.id);
1074 if (link.FlushWithReply(error) == B_OK && error == B_OK) {
1075 // server side success
1076 // Get token
1077 link.Read<int32>(&fServerToken);
1079 uint8 allocationFlags;
1080 link.Read<uint8>(&allocationFlags);
1081 link.Read<area_id>(&fServerArea);
1082 link.Read<int32>(&fAreaOffset);
1084 BPrivate::ServerMemoryAllocator* allocator
1085 = BApplication::Private::ServerAllocator();
1087 if ((allocationFlags & kNewAllocatorArea) != 0) {
1088 error = allocator->AddArea(fServerArea, fArea,
1089 fBasePointer, size);
1090 } else {
1091 error = allocator->AreaAndBaseFor(fServerArea, fArea,
1092 fBasePointer);
1093 if (error == B_OK)
1094 fBasePointer += fAreaOffset;
1097 if ((allocationFlags & kFramebuffer) != 0) {
1098 // The base pointer will now point to an overlay_client_data
1099 // structure bytes per row might be modified to match
1100 // hardware constraints
1101 link.Read<int32>(&bytesPerRow);
1102 size = bytesPerRow * (bounds.IntegerHeight() + 1);
1105 if (fServerArea >= B_OK) {
1106 fSize = size;
1107 fColorSpace = colorSpace;
1108 fBounds = bounds;
1109 fBytesPerRow = bytesPerRow;
1110 fFlags = flags;
1111 } else
1112 error = fServerArea;
1115 if (error < B_OK) {
1116 fBasePointer = NULL;
1117 fServerToken = -1;
1118 fArea = -1;
1119 fServerArea = -1;
1120 fAreaOffset = -1;
1121 // NOTE: why not "0" in case of error?
1122 fFlags = flags;
1123 } else {
1124 BAutolock _(sBitmapListLock);
1125 sBitmapList.AddItem(this);
1128 fWindow = NULL;
1131 fInitError = error;
1133 if (fInitError == B_OK) {
1134 // clear to white if the flags say so.
1135 if (flags & (B_BITMAP_CLEAR_TO_WHITE | B_BITMAP_ACCEPTS_VIEWS)) {
1136 if (fColorSpace == B_CMAP8) {
1137 // "255" is the "transparent magic" index for B_CMAP8 bitmaps
1138 // use the correct index for "white"
1139 memset(fBasePointer, 65, fSize);
1140 } else {
1141 // should work for most colorspaces
1142 memset(fBasePointer, 0xff, fSize);
1145 // TODO: Creating an offscreen window with a non32 bit bitmap
1146 // copies the current content of the bitmap to a back buffer.
1147 // So at this point the bitmap has to be already cleared to white.
1148 // Better move the above code to the server so the problem looks more
1149 // clear.
1150 if (flags & B_BITMAP_ACCEPTS_VIEWS) {
1151 fWindow = new(std::nothrow) BWindow(Bounds(), fServerToken);
1152 if (fWindow) {
1153 // A BWindow starts life locked and is unlocked
1154 // in Show(), but this window is never shown and
1155 // it's message loop is never started.
1156 fWindow->Unlock();
1157 } else
1158 fInitError = B_NO_MEMORY;
1164 /*! \brief Cleans up any memory allocated by the bitmap and
1165 informs the server to do so as well (if needed).
1167 void
1168 BBitmap::_CleanUp()
1170 if (fWindow != NULL) {
1171 if (fWindow->Lock())
1172 delete fWindow;
1173 fWindow = NULL;
1174 // this will leak fWindow if it couldn't be locked
1177 if (fBasePointer == NULL)
1178 return;
1180 if ((fFlags & B_BITMAP_NO_SERVER_LINK) != 0) {
1181 free(fBasePointer);
1182 } else if (fServerToken != -1) {
1183 BPrivate::AppServerLink link;
1184 // AS_DELETE_BITMAP:
1185 // Attached Data:
1186 // 1) int32 server token
1187 link.StartMessage(AS_DELETE_BITMAP);
1188 link.Attach<int32>(fServerToken);
1189 link.Flush();
1191 // The server areas are deleted via kMsgDeleteServerMemoryArea message
1193 fArea = -1;
1194 fServerToken = -1;
1195 fAreaOffset = -1;
1197 BAutolock _(sBitmapListLock);
1198 sBitmapList.RemoveItem(this);
1200 fBasePointer = NULL;
1204 void
1205 BBitmap::_AssertPointer()
1207 if (fBasePointer == NULL && fServerArea >= B_OK && fAreaOffset == -1) {
1208 // We lazily clone our own areas - if the bitmap is part of the usual
1209 // server memory area, or is a B_BITMAP_NO_SERVER_LINK bitmap, it
1210 // already has its data.
1211 fArea = clone_area("shared bitmap area", (void**)&fBasePointer,
1212 B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA, fServerArea);
1217 void
1218 BBitmap::_ReconnectToAppServer()
1220 BPrivate::AppServerLink link;
1222 link.StartMessage(AS_RECONNECT_BITMAP);
1223 link.Attach<BRect>(fBounds);
1224 link.Attach<color_space>(fColorSpace);
1225 link.Attach<uint32>(fFlags);
1226 link.Attach<int32>(fBytesPerRow);
1227 link.Attach<int32>(0);
1228 link.Attach<int32>(fArea);
1229 link.Attach<int32>(fAreaOffset);
1231 status_t error;
1232 if (link.FlushWithReply(error) == B_OK && error == B_OK) {
1233 // server side success
1234 // Get token
1235 link.Read<int32>(&fServerToken);
1237 link.Read<area_id>(&fServerArea);