xref: /haiku/src/kits/interface/Bitmap.cpp (revision 3d4afef9cba2f328e238089d4609d00d4b1524f3)
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_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;
134 	}
135 	return bpr;
136 }
137 
138 
139 namespace BPrivate {
140 
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.
147 */
148 int32
149 get_bytes_per_row(color_space colorSpace, int32 width)
150 {
151 	int32 bpr = get_raw_bytes_per_row(colorSpace, width);
152 	// align to int32
153 	bpr = (bpr + 3) & 0x7ffffffc;
154 	return bpr;
155 }
156 
157 }	// namespace BPrivate
158 
159 
160 //	#pragma mark -
161 
162 
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 ???
171 */
172 BBitmap::BBitmap(BRect bounds, uint32 flags, color_space colorSpace,
173 		int32 bytesPerRow, screen_id screenID)
174 	:
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)
187 {
188 	_InitObject(bounds, colorSpace, flags, bytesPerRow, screenID);
189 }
190 
191 
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
197 		   it.
198 	\param needsContiguous If \c true a physically contiguous chunk of memory
199 		   will be allocated.
200 */
201 BBitmap::BBitmap(BRect bounds, color_space colorSpace, bool acceptsViews,
202 		bool needsContiguous)
203 	:
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)
216 {
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);
221 }
222 
223 
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
228 		   it.
229 	\param needsContiguous If \c true a physically contiguous chunk of memory
230 		   will be allocated.
231 */
232 BBitmap::BBitmap(const BBitmap* source, bool acceptsViews, bool needsContiguous)
233 	:
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)
246 {
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()));
255 		}
256 	}
257 }
258 
259 
260 BBitmap::BBitmap(const BBitmap& source, uint32 flags)
261 	:
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)
274 {
275 	if (!source.IsValid())
276 		return;
277 
278 	_InitObject(source.Bounds(), source.ColorSpace(), flags,
279 		source.BytesPerRow(), B_MAIN_SCREEN_ID);
280 
281 	if (InitCheck() == B_OK)
282 		memcpy(Bits(), source.Bits(), min_c(BitsLength(), source.BitsLength()));
283 }
284 
285 
286 BBitmap::BBitmap(const BBitmap& source)
287 	:
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)
300 {
301 	*this = source;
302 }
303 
304 
305 /*!	\brief Frees all resources associated with this object.
306 */
307 BBitmap::~BBitmap()
308 {
309 	_CleanUp();
310 }
311 
312 
313 /*!	\brief Unarchives a bitmap from a BMessage.
314 	\param data The archive.
315 */
316 BBitmap::BBitmap(BMessage* data)
317 	:
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)
331 {
332 	int32 flags;
333 	if (data->FindInt32("_bmflags", &flags) != B_OK) {
334 		// this bitmap is archived in some archaic format
335 		flags = 0;
336 
337 		bool acceptsViews;
338 		if (data->FindBool("_view_ok", &acceptsViews) == B_OK && acceptsViews)
339 			flags |= B_BITMAP_ACCEPTS_VIEWS;
340 
341 		bool contiguous;
342 		if (data->FindBool("_contiguous", &contiguous) == B_OK && contiguous)
343 			flags |= B_BITMAP_IS_CONTIGUOUS;
344 	}
345 
346 	int32 rowBytes;
347 	if (data->FindInt32("_rowbytes", &rowBytes) != B_OK) {
348 		rowBytes = -1;
349 			// bytes per row are computed in InitObject(), then
350 	}
351 
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);
357 	}
358 
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);
366 			}
367 		}
368 	}
369 
370 	if ((fFlags & B_BITMAP_ACCEPTS_VIEWS) != 0) {
371 		BMessage message;
372 		int32 i = 0;
373 
374 		while (data->FindMessage("_views", i++, &message) == B_OK) {
375 			if (BView* view
376 					= dynamic_cast<BView*>(instantiate_object(&message)))
377 				AddChild(view);
378 		}
379 	}
380 }
381 
382 
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.
387 */
388 BArchivable*
389 BBitmap::Instantiate(BMessage* data)
390 {
391 	if (validate_instantiation(data, "BBitmap"))
392 		return new BBitmap(data);
393 
394 	return NULL;
395 }
396 
397 
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.
403 */
404 status_t
405 BBitmap::Archive(BMessage* data, bool deep) const
406 {
407 	status_t ret = BArchivable::Archive(data, deep);
408 
409 	if (ret == B_OK)
410 		ret = data->AddRect("_frame", fBounds);
411 
412 	if (ret == B_OK)
413 		ret = data->AddInt32("_cspace", (int32)fColorSpace);
414 
415 	if (ret == B_OK)
416 		ret = data->AddInt32("_bmflags", fFlags);
417 
418 	if (ret == B_OK)
419 		ret = data->AddInt32("_rowbytes", fBytesPerRow);
420 
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;
430 			}
431 		}
432 	}
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);
440 	}
441 	return ret;
442 }
443 
444 
445 /*!	\brief Returns the result from the construction.
446 	\return \c B_OK, if the object is properly initialized, an error code
447 			otherwise.
448 */
449 status_t
450 BBitmap::InitCheck() const
451 {
452 	return fInitError;
453 }
454 
455 
456 /*!	\brief Returns whether or not the BBitmap object is valid.
457 	\return \c true, if the object is properly initialized, \c false otherwise.
458 */
459 bool
460 BBitmap::IsValid() const
461 {
462 	return InitCheck() == B_OK;
463 }
464 
465 
466 /*!	\brief Locks the bitmap bits so that they cannot be relocated.
467 
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.
473 */
474 status_t
475 BBitmap::LockBits(uint32* state)
476 {
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;
482 
483 		status_t status;
484 		do {
485 			status = acquire_sem(data->lock);
486 		} while (status == B_INTERRUPTED);
487 
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;
493 		}
494 		return status;
495 	}
496 
497 	// NOTE: maybe this is used to prevent the app_server from
498 	// drawing the bitmap yet?
499 	// axeld: you mean for non overlays?
500 
501 	return B_OK;
502 }
503 
504 
505 /*!	\brief Unlocks the bitmap's buffer again.
506 	Counterpart to LockBits(), see there for comments.
507 */
508 void
509 BBitmap::UnlockBits()
510 {
511 	if ((fFlags & B_BITMAP_WILL_OVERLAY) == 0)
512 		return;
513 
514 	overlay_client_data* data = (overlay_client_data*)fBasePointer;
515 	release_sem_etc(data->lock, 1, B_DO_NOT_RESCHEDULE);
516 }
517 
518 
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.
521 */
522 area_id
523 BBitmap::Area() const
524 {
525 	const_cast<BBitmap*>(this)->_AssertPointer();
526 	return fArea;
527 }
528 
529 
530 /*!	\brief Returns the pointer to the bitmap data.
531 	\return The pointer to the bitmap data.
532 */
533 void*
534 BBitmap::Bits() const
535 {
536 	const_cast<BBitmap*>(this)->_AssertPointer();
537 
538 	if ((fFlags & B_BITMAP_WILL_OVERLAY) != 0) {
539 		overlay_client_data* data = (overlay_client_data*)fBasePointer;
540 		return data->buffer;
541 	}
542 
543 	return (void*)fBasePointer;
544 }
545 
546 
547 /*!	\brief Returns the size of the bitmap data.
548 	\return The size of the bitmap data.
549 */
550 int32
551 BBitmap::BitsLength() const
552 {
553 	return fSize;
554 }
555 
556 
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.
559 */
560 int32
561 BBitmap::BytesPerRow() const
562 {
563 	return fBytesPerRow;
564 }
565 
566 
567 /*!	\brief Returns the bitmap's color space.
568 	\return The bitmap's color space.
569 */
570 color_space
571 BBitmap::ColorSpace() const
572 {
573 	return fColorSpace;
574 }
575 
576 
577 /*!	\brief Returns the bitmap's dimensions.
578 	\return The bitmap's dimensions.
579 */
580 BRect
581 BBitmap::Bounds() const
582 {
583 	return fBounds;
584 }
585 
586 
587 /*!	\brief Returns the bitmap's creating flags.
588 
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.
592 
593 	\return The bitmap's creation flags.
594 */
595 uint32
596 BBitmap::Flags() const
597 {
598 	return fFlags;
599 }
600 
601 
602 /*!	\brief Assigns data to the bitmap.
603 
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.
612 
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}.
615 
616 	\note As this methods is apparently a bit strange to use, Haiku introduces
617 		  ImportBits() methods, which are recommended to be used instead.
618 
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.
625 */
626 void
627 BBitmap::SetBits(const void* data, int32 length, int32 offset,
628 	color_space colorSpace)
629 {
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_CMAP8 && fColorSpace != B_CMAP8) {
641 			// If in color space is B_CMAP8, but the bitmap's is another one,
642 			// ignore source data row padding.
643 			inBPR = width;
644 		}
645 
646 		// call the sane method, which does the actual work
647 		error = ImportBits(data, length, inBPR, offset, colorSpace);
648 	}
649 }
650 
651 
652 /*!	\brief Assigns data to the bitmap.
653 
654 	Data are directly written into the bitmap's data buffer, being converted
655 	beforehand, if necessary. Unlike for SetBits(), the meaning of
656 	\a colorSpace is exactly the expected one here, i.e. the source buffer
657 	is supposed to contain data of that color space. \a bpr specifies how
658 	many bytes the source contains per row. \c B_ANY_BYTES_PER_ROW can be
659 	supplied, if standard padding to int32 is used.
660 
661 	The currently supported source/target color spaces are
662 	\c B_RGB{32,24,16,15}[_BIG], \c B_CMAP8 and \c B_GRAY{8,1}.
663 
664 	\param data The data to be copied.
665 	\param length The length in bytes of the data to be copied.
666 	\param bpr The number of bytes per row in the source data.
667 	\param offset The offset (in bytes) relative to beginning of the bitmap
668 		   data specifying the position at which the source data shall be
669 		   written.
670 	\param colorSpace Color space of the source data.
671 	\return
672 	- \c B_OK: Everything went fine.
673 	- \c B_BAD_VALUE: \c NULL \a data, invalid \a bpr or \a offset, or
674 	  unsupported \a colorSpace.
675 */
676 status_t
677 BBitmap::ImportBits(const void* data, int32 length, int32 bpr, int32 offset,
678 	color_space colorSpace)
679 {
680 	_AssertPointer();
681 
682 	if (InitCheck() != B_OK)
683 		return B_NO_INIT;
684 
685 	if (!data || offset > fSize || length < 0)
686 		return B_BAD_VALUE;
687 
688 	int32 width = fBounds.IntegerWidth() + 1;
689 	if (bpr <= 0) {
690 		if (bpr == B_ANY_BYTES_PER_ROW)
691 			bpr = get_bytes_per_row(colorSpace, width);
692 		else
693 			return B_BAD_VALUE;
694 	}
695 
696 	return BPrivate::ConvertBits(data, (uint8*)fBasePointer + offset, length,
697 		fSize - offset, bpr, fBytesPerRow, colorSpace, fColorSpace, width,
698 		fBounds.IntegerHeight() + 1);
699 }
700 
701 
702 /*!	\brief Assigns data to the bitmap.
703 
704 	Allows for a BPoint offset in the source and in the bitmap. The region
705 	of the source at \a from extending \a width and \a height is assigned
706 	(and converted if necessary) to the bitmap at \a to.
707 
708 	The currently supported source/target color spaces are
709 	\c B_RGB{32,24,16,15}[_BIG], \c B_CMAP8 and \c B_GRAY{8,1}.
710 
711 	\param data The data to be copied.
712 	\param length The length in bytes of the data to be copied.
713 	\param bpr The number of bytes per row in the source data.
714 	\param colorSpace Color space of the source data.
715 	\param from The offset in the source where reading should begin.
716 	\param to The offset in the bitmap where the source should be written.
717 	\param width The width (in pixels) to be imported.
718 	\param height The height (in pixels) to be imported.
719 	\return
720 	- \c B_OK: Everything went fine.
721 	- \c B_BAD_VALUE: \c NULL \a data, invalid \a bpr, unsupported
722 	  \a colorSpace or invalid width/height.
723 */
724 status_t
725 BBitmap::ImportBits(const void* data, int32 length, int32 bpr,
726 	color_space colorSpace, BPoint from, BPoint to, int32 width, int32 height)
727 {
728 	_AssertPointer();
729 
730 	if (InitCheck() != B_OK)
731 		return B_NO_INIT;
732 
733 	if (!data || length < 0 || width < 0 || height < 0)
734 		return B_BAD_VALUE;
735 
736 	if (bpr <= 0) {
737 		if (bpr == B_ANY_BYTES_PER_ROW)
738 			bpr = get_bytes_per_row(colorSpace, fBounds.IntegerWidth() + 1);
739 		else
740 			return B_BAD_VALUE;
741 	}
742 
743 	return BPrivate::ConvertBits(data, fBasePointer, length, fSize, bpr,
744 		fBytesPerRow, colorSpace, fColorSpace, from, to, width, height);
745 }
746 
747 
748 /*!	\briefly Assigns another bitmap's data to this bitmap.
749 
750 	The supplied bitmap must have the exactly same dimensions as this bitmap.
751 	Its data is converted to the color space of this bitmap.
752 
753 	The currently supported source/target color spaces are
754 	\c B_RGB{32,24,16,15}[_BIG], \c B_CMAP8 and \c B_GRAY{8,1}.
755 
756 	\param bitmap The source bitmap.
757 	\return
758 	- \c B_OK: Everything went fine.
759 	- \c B_BAD_VALUE: \c NULL \a bitmap, or \a bitmap has other dimensions,
760 	  or the conversion from or to one of the color spaces is not supported.
761 */
762 status_t
763 BBitmap::ImportBits(const BBitmap* bitmap)
764 {
765 	if (InitCheck() != B_OK)
766 		return B_NO_INIT;
767 
768 	if (!bitmap || bitmap->InitCheck() != B_OK || bitmap->Bounds() != fBounds)
769 		return B_BAD_VALUE;
770 
771 	return ImportBits(bitmap->Bits(), bitmap->BitsLength(),
772 		bitmap->BytesPerRow(), 0, bitmap->ColorSpace());
773 }
774 
775 
776 /*!	\brief Assigns data to the bitmap.
777 
778 	Allows for a BPoint offset in the source and in the bitmap. The region
779 	of the source at \a from extending \a width and \a height is assigned
780 	(and converted if necessary) to the bitmap at \a to. The source bitmap is
781 	clipped to the bitmap and they don't need to have the same dimensions.
782 
783 	The currently supported source/target color spaces are
784 	\c B_RGB{32,24,16,15}[_BIG], \c B_CMAP8 and \c B_GRAY{8,1}.
785 
786 	\param bitmap The source bitmap.
787 	\param from The offset in the source where reading should begin.
788 	\param to The offset in the bitmap where the source should be written.
789 	\param width The width (in pixels) to be imported.
790 	\param height The height (in pixels) to be imported.
791 	- \c B_OK: Everything went fine.
792 	- \c B_BAD_VALUE: \c NULL \a bitmap, the conversion from or to one of
793 	  the color spaces is not supported, or invalid width/height.
794 */
795 status_t
796 BBitmap::ImportBits(const BBitmap* bitmap, BPoint from, BPoint to, int32 width,
797 	int32 height)
798 {
799 	if (InitCheck() != B_OK)
800 		return B_NO_INIT;
801 
802 	if (!bitmap || bitmap->InitCheck() != B_OK)
803 		return B_BAD_VALUE;
804 
805 	return ImportBits(bitmap->Bits(), bitmap->BitsLength(),
806 		bitmap->BytesPerRow(), bitmap->ColorSpace(), from, to, width, height);
807 }
808 
809 
810 /*!	\brief Returns the overlay_restrictions structure for this bitmap
811 */
812 status_t
813 BBitmap::GetOverlayRestrictions(overlay_restrictions* restrictions) const
814 {
815 	if ((fFlags & B_BITMAP_WILL_OVERLAY) == 0)
816 		return B_BAD_TYPE;
817 
818 	BPrivate::AppServerLink link;
819 
820 	link.StartMessage(AS_GET_BITMAP_OVERLAY_RESTRICTIONS);
821 	link.Attach<int32>(fServerToken);
822 
823 	status_t status;
824 	if (link.FlushWithReply(status) < B_OK)
825 		return status;
826 
827 	link.Read(restrictions, sizeof(overlay_restrictions));
828 	return B_OK;
829 }
830 
831 
832 /*!	\brief Adds a BView to the bitmap's view hierarchy.
833 
834 	The bitmap must accept views and the supplied view must not be child of
835 	another parent.
836 
837 	\param view The view to be added.
838 */
839 void
840 BBitmap::AddChild(BView* view)
841 {
842 	if (fWindow != NULL)
843 		fWindow->AddChild(view);
844 }
845 
846 
847 /*!	\brief Removes a BView from the bitmap's view hierarchy.
848 	\param view The view to be removed.
849 */
850 bool
851 BBitmap::RemoveChild(BView* view)
852 {
853 	return fWindow != NULL ? fWindow->RemoveChild(view) : false;
854 }
855 
856 
857 /*!	\brief Returns the number of BViews currently belonging to the bitmap.
858 	\return The number of BViews currently belonging to the bitmap.
859 */
860 int32
861 BBitmap::CountChildren() const
862 {
863 	return fWindow != NULL ? fWindow->CountChildren() : 0;
864 }
865 
866 
867 /*!	\brief Returns the BView at a certain index in the bitmap's list of views.
868 	\param index The index of the BView to be returned.
869 	\return The BView at index \a index or \c NULL, if the index is out of
870 			range.
871 */
872 BView*
873 BBitmap::ChildAt(int32 index) const
874 {
875 	return fWindow != NULL ? fWindow->ChildAt(index) : NULL;
876 }
877 
878 
879 /*!	\brief Returns a bitmap's BView with a certain name.
880 	\param name The name of the BView to be returned.
881 	\return The BView with the name \a name or \c NULL, if the bitmap doesn't
882 	know a view with that name.
883 */
884 BView*
885 BBitmap::FindView(const char* viewName) const
886 {
887 	return fWindow != NULL ? fWindow->FindView(viewName) : NULL;
888 }
889 
890 
891 /*!	\brief Returns a bitmap's BView at a certain location.
892 	\param point The location.
893 	\return The BView with located at \a point or \c NULL, if the bitmap
894 	doesn't know a view at this location.
895 */
896 BView*
897 BBitmap::FindView(BPoint point) const
898 {
899 	return fWindow != NULL ? fWindow->FindView(point) : NULL;
900 }
901 
902 
903 /*!	\brief Locks the off-screen window that belongs to the bitmap.
904 
905 	The bitmap must accept views, if locking should work.
906 
907 	\return \c true, if the lock was acquired successfully, \c false
908 			otherwise.
909 */
910 bool
911 BBitmap::Lock()
912 {
913 	return fWindow != NULL ? fWindow->Lock() : false;
914 }
915 
916 
917 /*!	\brief Unlocks the off-screen window that belongs to the bitmap.
918 
919 	The bitmap must accept views, if locking should work.
920 */
921 void
922 BBitmap::Unlock()
923 {
924 	if (fWindow != NULL)
925 		fWindow->Unlock();
926 }
927 
928 
929 /*!	\brief Returns whether or not the bitmap's off-screen window is locked.
930 
931 	The bitmap must accept views, if locking should work.
932 
933 	\return \c true, if the caller owns a lock , \c false otherwise.
934 */
935 bool
936 BBitmap::IsLocked() const
937 {
938 	return fWindow != NULL ? fWindow->IsLocked() : false;
939 }
940 
941 
942 BBitmap&
943 BBitmap::operator=(const BBitmap& source)
944 {
945 	_CleanUp();
946 	fInitError = B_NO_INIT;
947 
948 	if (!source.IsValid())
949 		return *this;
950 
951 	_InitObject(source.Bounds(), source.ColorSpace(), source.Flags(),
952 		source.BytesPerRow(), B_MAIN_SCREEN_ID);
953 	if (InitCheck() == B_OK)
954 		memcpy(Bits(), source.Bits(), min_c(BitsLength(), source.BitsLength()));
955 
956 	return *this;
957 }
958 
959 
960 status_t
961 BBitmap::Perform(perform_code d, void* arg)
962 {
963 	return BArchivable::Perform(d, arg);
964 }
965 
966 // FBC
967 void BBitmap::_ReservedBitmap1() {}
968 void BBitmap::_ReservedBitmap2() {}
969 void BBitmap::_ReservedBitmap3() {}
970 
971 
972 #if 0
973 // get_shared_pointer
974 /*!	\brief ???
975 */
976 char*
977 BBitmap::get_shared_pointer() const
978 {
979 	return NULL;	// not implemented
980 }
981 #endif
982 
983 int32
984 BBitmap::_ServerToken() const
985 {
986 	return fServerToken;
987 }
988 
989 
990 /*!	\brief Initializes the bitmap.
991 	\param bounds The bitmap dimensions.
992 	\param colorSpace The bitmap's color space.
993 	\param flags Creation flags.
994 	\param bytesPerRow The number of bytes per row the bitmap should use.
995 		   \c B_ANY_BYTES_PER_ROW to let the constructor choose an appropriate
996 		   value.
997 	\param screenID ???
998 */
999 void
1000 BBitmap::_InitObject(BRect bounds, color_space colorSpace, uint32 flags,
1001 	int32 bytesPerRow, screen_id screenID)
1002 {
1003 //printf("BBitmap::InitObject(bounds: BRect(%.1f, %.1f, %.1f, %.1f), format: %ld, flags: %ld, bpr: %ld\n",
1004 //	   bounds.left, bounds.top, bounds.right, bounds.bottom, colorSpace, flags, bytesPerRow);
1005 
1006 	// TODO: Should we handle rounding of the "bounds" here? How does R5 behave?
1007 
1008 	status_t error = B_OK;
1009 
1010 #ifdef RUN_WITHOUT_APP_SERVER
1011 	flags |= B_BITMAP_NO_SERVER_LINK;
1012 #endif	// RUN_WITHOUT_APP_SERVER
1013 
1014 	_CleanUp();
1015 
1016 	// check params
1017 	if (!bounds.IsValid() || !bitmaps_support_space(colorSpace, NULL)) {
1018 		error = B_BAD_VALUE;
1019 	} else {
1020 		// bounds is in floats and might be valid but much larger than what we
1021 		// can handle the size could not be expressed in int32
1022 		double realSize = bounds.Width() * bounds.Height();
1023 		if (realSize > (double)(INT_MAX / 4)) {
1024 			fprintf(stderr, "bitmap bounds is much too large: "
1025 				"BRect(%.1f, %.1f, %.1f, %.1f)\n",
1026 				bounds.left, bounds.top, bounds.right, bounds.bottom);
1027 			error = B_BAD_VALUE;
1028 		}
1029 	}
1030 	if (error == B_OK) {
1031 		int32 bpr = get_bytes_per_row(colorSpace, bounds.IntegerWidth() + 1);
1032 		if (bytesPerRow < 0)
1033 			bytesPerRow = bpr;
1034 		else if (bytesPerRow < bpr)
1035 // NOTE: How does R5 behave?
1036 			error = B_BAD_VALUE;
1037 	}
1038 	// allocate the bitmap buffer
1039 	if (error == B_OK) {
1040 		// TODO: Let the app_server return the size when it allocated the bitmap
1041 		int32 size = bytesPerRow * (bounds.IntegerHeight() + 1);
1042 
1043 		if ((flags & B_BITMAP_NO_SERVER_LINK) != 0) {
1044 			fBasePointer = (uint8*)malloc(size);
1045 			if (fBasePointer) {
1046 				fSize = size;
1047 				fColorSpace = colorSpace;
1048 				fBounds = bounds;
1049 				fBytesPerRow = bytesPerRow;
1050 				fFlags = flags;
1051 			} else
1052 				error = B_NO_MEMORY;
1053 		} else {
1054 			// Ask the server (via our owning application) to create a bitmap.
1055 			BPrivate::AppServerLink link;
1056 
1057 			// Attach Data:
1058 			// 1) BRect bounds
1059 			// 2) color_space space
1060 			// 3) int32 bitmap_flags
1061 			// 4) int32 bytes_per_row
1062 			// 5) int32 screen_id::id
1063 			link.StartMessage(AS_CREATE_BITMAP);
1064 			link.Attach<BRect>(bounds);
1065 			link.Attach<color_space>(colorSpace);
1066 			link.Attach<uint32>(flags);
1067 			link.Attach<int32>(bytesPerRow);
1068 			link.Attach<int32>(screenID.id);
1069 
1070 			if (link.FlushWithReply(error) == B_OK && error == B_OK) {
1071 				// server side success
1072 				// Get token
1073 				link.Read<int32>(&fServerToken);
1074 
1075 				uint8 allocationFlags;
1076 				link.Read<uint8>(&allocationFlags);
1077 				link.Read<area_id>(&fServerArea);
1078 				link.Read<int32>(&fAreaOffset);
1079 
1080 				BPrivate::ServerMemoryAllocator* allocator
1081 					= BApplication::Private::ServerAllocator();
1082 
1083 				if ((allocationFlags & kNewAllocatorArea) != 0) {
1084 					error = allocator->AddArea(fServerArea, fArea,
1085 						fBasePointer, size);
1086 				} else {
1087 					error = allocator->AreaAndBaseFor(fServerArea, fArea,
1088 						fBasePointer);
1089 					if (error == B_OK)
1090 						fBasePointer += fAreaOffset;
1091 				}
1092 
1093 				if ((allocationFlags & kFramebuffer) != 0) {
1094 					// The base pointer will now point to an overlay_client_data
1095 					// structure bytes per row might be modified to match
1096 					// hardware constraints
1097 					link.Read<int32>(&bytesPerRow);
1098 					size = bytesPerRow * (bounds.IntegerHeight() + 1);
1099 				}
1100 
1101 				if (fServerArea >= B_OK) {
1102 					fSize = size;
1103 					fColorSpace = colorSpace;
1104 					fBounds = bounds;
1105 					fBytesPerRow = bytesPerRow;
1106 					fFlags = flags;
1107 				} else
1108 					error = fServerArea;
1109 			}
1110 
1111 			if (error < B_OK) {
1112 				fBasePointer = NULL;
1113 				fServerToken = -1;
1114 				fArea = -1;
1115 				fServerArea = -1;
1116 				fAreaOffset = -1;
1117 				// NOTE: why not "0" in case of error?
1118 				fFlags = flags;
1119 			} else {
1120 				BAutolock _(sBitmapListLock);
1121 				sBitmapList.AddItem(this);
1122 			}
1123 		}
1124 		fWindow = NULL;
1125 	}
1126 
1127 	fInitError = error;
1128 
1129 	if (fInitError == B_OK) {
1130 		// clear to white if the flags say so.
1131 		if (flags & (B_BITMAP_CLEAR_TO_WHITE | B_BITMAP_ACCEPTS_VIEWS)) {
1132 			if (fColorSpace == B_CMAP8) {
1133 				// "255" is the "transparent magic" index for B_CMAP8 bitmaps
1134 				// use the correct index for "white"
1135 				memset(fBasePointer, 65, fSize);
1136 			} else {
1137 				// should work for most colorspaces
1138 				memset(fBasePointer, 0xff, fSize);
1139 			}
1140 		}
1141 		// TODO: Creating an offscreen window with a non32 bit bitmap
1142 		// copies the current content of the bitmap to a back buffer.
1143 		// So at this point the bitmap has to be already cleared to white.
1144 		// Better move the above code to the server so the problem looks more
1145 		// clear.
1146 		if (flags & B_BITMAP_ACCEPTS_VIEWS) {
1147 			fWindow = new(std::nothrow) BWindow(Bounds(), fServerToken);
1148 			if (fWindow) {
1149 				// A BWindow starts life locked and is unlocked
1150 				// in Show(), but this window is never shown and
1151 				// it's message loop is never started.
1152 				fWindow->Unlock();
1153 			} else
1154 				fInitError = B_NO_MEMORY;
1155 		}
1156 	}
1157 }
1158 
1159 
1160 /*!	\brief Cleans up any memory allocated by the bitmap and
1161 		informs the server to do so as well (if needed).
1162 */
1163 void
1164 BBitmap::_CleanUp()
1165 {
1166 	if (fWindow != NULL) {
1167 		if (fWindow->Lock())
1168 			delete fWindow;
1169 		fWindow = NULL;
1170 			// this will leak fWindow if it couldn't be locked
1171 	}
1172 
1173 	if (fBasePointer == NULL)
1174 		return;
1175 
1176 	if ((fFlags & B_BITMAP_NO_SERVER_LINK) != 0) {
1177 		free(fBasePointer);
1178 	} else if (fServerToken != -1) {
1179 		BPrivate::AppServerLink link;
1180 		// AS_DELETE_BITMAP:
1181 		// Attached Data:
1182 		//	1) int32 server token
1183 		link.StartMessage(AS_DELETE_BITMAP);
1184 		link.Attach<int32>(fServerToken);
1185 		link.Flush();
1186 
1187 		// The server areas are deleted via kMsgDeleteServerMemoryArea message
1188 
1189 		fArea = -1;
1190 		fServerToken = -1;
1191 		fAreaOffset = -1;
1192 
1193 		BAutolock _(sBitmapListLock);
1194 		sBitmapList.RemoveItem(this);
1195 	}
1196 	fBasePointer = NULL;
1197 }
1198 
1199 
1200 void
1201 BBitmap::_AssertPointer()
1202 {
1203 	if (fBasePointer == NULL && fServerArea >= B_OK && fAreaOffset == -1) {
1204 		// We lazily clone our own areas - if the bitmap is part of the usual
1205 		// server memory area, or is a B_BITMAP_NO_SERVER_LINK bitmap, it
1206 		// already has its data.
1207 		fArea = clone_area("shared bitmap area", (void**)&fBasePointer,
1208 			B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA, fServerArea);
1209 	}
1210 }
1211 
1212 
1213 void
1214 BBitmap::_ReconnectToAppServer()
1215 {
1216 	BPrivate::AppServerLink link;
1217 
1218 	link.StartMessage(AS_RECONNECT_BITMAP);
1219 	link.Attach<BRect>(fBounds);
1220 	link.Attach<color_space>(fColorSpace);
1221 	link.Attach<uint32>(fFlags);
1222 	link.Attach<int32>(fBytesPerRow);
1223 	link.Attach<int32>(0);
1224 	link.Attach<int32>(fArea);
1225 	link.Attach<int32>(fAreaOffset);
1226 
1227 	status_t error;
1228 	if (link.FlushWithReply(error) == B_OK && error == B_OK) {
1229 		// server side success
1230 		// Get token
1231 		link.Read<int32>(&fServerToken);
1232 
1233 		link.Read<area_id>(&fServerArea);
1234 	}
1235 }
1236