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