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