xref: /haiku/src/kits/interface/Bitmap.cpp (revision 8a6724a0ee3803f1e9f487d8111bb3f6cb8d16db)
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_RGB32) {
641 			// B_RGB32 means actually unpadded B_RGB24_BIG
642 			colorSpace = B_RGB24_BIG;
643 			inBPR = width * 3;
644 		} else if (colorSpace == B_CMAP8 && fColorSpace != B_CMAP8) {
645 			// If in color space is B_CMAP8, but the bitmap's is another one,
646 			// ignore source data row padding.
647 			inBPR = width;
648 		}
649 
650 		// call the sane method, which does the actual work
651 		error = ImportBits(data, length, inBPR, offset, colorSpace);
652 	}
653 }
654 
655 
656 /*!	\brief Assigns data to the bitmap.
657 
658 	Data are directly written into the bitmap's data buffer, being converted
659 	beforehand, if necessary. Unlike for SetBits(), the meaning of
660 	\a colorSpace is exactly the expected one here, i.e. the source buffer
661 	is supposed to contain data of that color space. \a bpr specifies how
662 	many bytes the source contains per row. \c B_ANY_BYTES_PER_ROW can be
663 	supplied, if standard padding to int32 is used.
664 
665 	The currently supported source/target color spaces are
666 	\c B_RGB{32,24,16,15}[_BIG], \c B_CMAP8 and \c B_GRAY{8,1}.
667 
668 	\param data The data to be copied.
669 	\param length The length in bytes of the data to be copied.
670 	\param bpr The number of bytes per row in the source data.
671 	\param offset The offset (in bytes) relative to beginning of the bitmap
672 		   data specifying the position at which the source data shall be
673 		   written.
674 	\param colorSpace Color space of the source data.
675 	\return
676 	- \c B_OK: Everything went fine.
677 	- \c B_BAD_VALUE: \c NULL \a data, invalid \a bpr or \a offset, or
678 	  unsupported \a colorSpace.
679 */
680 status_t
681 BBitmap::ImportBits(const void* data, int32 length, int32 bpr, int32 offset,
682 	color_space colorSpace)
683 {
684 	_AssertPointer();
685 
686 	if (InitCheck() != B_OK)
687 		return B_NO_INIT;
688 
689 	if (!data || offset > fSize || length < 0)
690 		return B_BAD_VALUE;
691 
692 	int32 width = fBounds.IntegerWidth() + 1;
693 	if (bpr <= 0) {
694 		if (bpr == B_ANY_BYTES_PER_ROW)
695 			bpr = get_bytes_per_row(colorSpace, width);
696 		else
697 			return B_BAD_VALUE;
698 	}
699 
700 	return BPrivate::ConvertBits(data, (uint8*)fBasePointer + offset, length,
701 		fSize - offset, bpr, fBytesPerRow, colorSpace, fColorSpace, width,
702 		fBounds.IntegerHeight() + 1);
703 }
704 
705 
706 /*!	\brief Assigns data to the bitmap.
707 
708 	Allows for a BPoint offset in the source and in the bitmap. The region
709 	of the source at \a from extending \a width and \a height is assigned
710 	(and converted if necessary) to the bitmap at \a to.
711 
712 	The currently supported source/target color spaces are
713 	\c B_RGB{32,24,16,15}[_BIG], \c B_CMAP8 and \c B_GRAY{8,1}.
714 
715 	\param data The data to be copied.
716 	\param length The length in bytes of the data to be copied.
717 	\param bpr The number of bytes per row in the source data.
718 	\param colorSpace Color space of the source data.
719 	\param from The offset in the source where reading should begin.
720 	\param to The offset in the bitmap where the source should be written.
721 	\param width The width (in pixels) to be imported.
722 	\param height The height (in pixels) to be imported.
723 	\return
724 	- \c B_OK: Everything went fine.
725 	- \c B_BAD_VALUE: \c NULL \a data, invalid \a bpr, unsupported
726 	  \a colorSpace or invalid width/height.
727 */
728 status_t
729 BBitmap::ImportBits(const void* data, int32 length, int32 bpr,
730 	color_space colorSpace, BPoint from, BPoint to, int32 width, int32 height)
731 {
732 	_AssertPointer();
733 
734 	if (InitCheck() != B_OK)
735 		return B_NO_INIT;
736 
737 	if (!data || length < 0 || width < 0 || height < 0)
738 		return B_BAD_VALUE;
739 
740 	if (bpr <= 0) {
741 		if (bpr == B_ANY_BYTES_PER_ROW)
742 			bpr = get_bytes_per_row(colorSpace, fBounds.IntegerWidth() + 1);
743 		else
744 			return B_BAD_VALUE;
745 	}
746 
747 	return BPrivate::ConvertBits(data, fBasePointer, length, fSize, bpr,
748 		fBytesPerRow, colorSpace, fColorSpace, from, to, width, height);
749 }
750 
751 
752 /*!	\briefly Assigns another bitmap's data to this bitmap.
753 
754 	The supplied bitmap must have the exactly same dimensions as this bitmap.
755 	Its data is converted to the color space of this bitmap.
756 
757 	The currently supported source/target color spaces are
758 	\c B_RGB{32,24,16,15}[_BIG], \c B_CMAP8 and \c B_GRAY{8,1}.
759 
760 	\param bitmap The source bitmap.
761 	\return
762 	- \c B_OK: Everything went fine.
763 	- \c B_BAD_VALUE: \c NULL \a bitmap, or \a bitmap has other dimensions,
764 	  or the conversion from or to one of the color spaces is not supported.
765 */
766 status_t
767 BBitmap::ImportBits(const BBitmap* bitmap)
768 {
769 	if (InitCheck() != B_OK)
770 		return B_NO_INIT;
771 
772 	if (!bitmap || bitmap->InitCheck() != B_OK || bitmap->Bounds() != fBounds)
773 		return B_BAD_VALUE;
774 
775 	return ImportBits(bitmap->Bits(), bitmap->BitsLength(),
776 		bitmap->BytesPerRow(), 0, bitmap->ColorSpace());
777 }
778 
779 
780 /*!	\brief Assigns data to the bitmap.
781 
782 	Allows for a BPoint offset in the source and in the bitmap. The region
783 	of the source at \a from extending \a width and \a height is assigned
784 	(and converted if necessary) to the bitmap at \a to. The source bitmap is
785 	clipped to the bitmap and they don't need to have the same dimensions.
786 
787 	The currently supported source/target color spaces are
788 	\c B_RGB{32,24,16,15}[_BIG], \c B_CMAP8 and \c B_GRAY{8,1}.
789 
790 	\param bitmap The source bitmap.
791 	\param from The offset in the source where reading should begin.
792 	\param to The offset in the bitmap where the source should be written.
793 	\param width The width (in pixels) to be imported.
794 	\param height The height (in pixels) to be imported.
795 	- \c B_OK: Everything went fine.
796 	- \c B_BAD_VALUE: \c NULL \a bitmap, the conversion from or to one of
797 	  the color spaces is not supported, or invalid width/height.
798 */
799 status_t
800 BBitmap::ImportBits(const BBitmap* bitmap, BPoint from, BPoint to, int32 width,
801 	int32 height)
802 {
803 	if (InitCheck() != B_OK)
804 		return B_NO_INIT;
805 
806 	if (!bitmap || bitmap->InitCheck() != B_OK)
807 		return B_BAD_VALUE;
808 
809 	return ImportBits(bitmap->Bits(), bitmap->BitsLength(),
810 		bitmap->BytesPerRow(), bitmap->ColorSpace(), from, to, width, height);
811 }
812 
813 
814 /*!	\brief Returns the overlay_restrictions structure for this bitmap
815 */
816 status_t
817 BBitmap::GetOverlayRestrictions(overlay_restrictions* restrictions) const
818 {
819 	if ((fFlags & B_BITMAP_WILL_OVERLAY) == 0)
820 		return B_BAD_TYPE;
821 
822 	BPrivate::AppServerLink link;
823 
824 	link.StartMessage(AS_GET_BITMAP_OVERLAY_RESTRICTIONS);
825 	link.Attach<int32>(fServerToken);
826 
827 	status_t status;
828 	if (link.FlushWithReply(status) < B_OK)
829 		return status;
830 
831 	link.Read(restrictions, sizeof(overlay_restrictions));
832 	return B_OK;
833 }
834 
835 
836 /*!	\brief Adds a BView to the bitmap's view hierarchy.
837 
838 	The bitmap must accept views and the supplied view must not be child of
839 	another parent.
840 
841 	\param view The view to be added.
842 */
843 void
844 BBitmap::AddChild(BView* view)
845 {
846 	if (fWindow != NULL)
847 		fWindow->AddChild(view);
848 }
849 
850 
851 /*!	\brief Removes a BView from the bitmap's view hierarchy.
852 	\param view The view to be removed.
853 */
854 bool
855 BBitmap::RemoveChild(BView* view)
856 {
857 	return fWindow != NULL ? fWindow->RemoveChild(view) : false;
858 }
859 
860 
861 /*!	\brief Returns the number of BViews currently belonging to the bitmap.
862 	\return The number of BViews currently belonging to the bitmap.
863 */
864 int32
865 BBitmap::CountChildren() const
866 {
867 	return fWindow != NULL ? fWindow->CountChildren() : 0;
868 }
869 
870 
871 /*!	\brief Returns the BView at a certain index in the bitmap's list of views.
872 	\param index The index of the BView to be returned.
873 	\return The BView at index \a index or \c NULL, if the index is out of
874 			range.
875 */
876 BView*
877 BBitmap::ChildAt(int32 index) const
878 {
879 	return fWindow != NULL ? fWindow->ChildAt(index) : NULL;
880 }
881 
882 
883 /*!	\brief Returns a bitmap's BView with a certain name.
884 	\param name The name of the BView to be returned.
885 	\return The BView with the name \a name or \c NULL, if the bitmap doesn't
886 	know a view with that name.
887 */
888 BView*
889 BBitmap::FindView(const char* viewName) const
890 {
891 	return fWindow != NULL ? fWindow->FindView(viewName) : NULL;
892 }
893 
894 
895 /*!	\brief Returns a bitmap's BView at a certain location.
896 	\param point The location.
897 	\return The BView with located at \a point or \c NULL, if the bitmap
898 	doesn't know a view at this location.
899 */
900 BView*
901 BBitmap::FindView(BPoint point) const
902 {
903 	return fWindow != NULL ? fWindow->FindView(point) : NULL;
904 }
905 
906 
907 /*!	\brief Locks the off-screen window that belongs to the bitmap.
908 
909 	The bitmap must accept views, if locking should work.
910 
911 	\return \c true, if the lock was acquired successfully, \c false
912 			otherwise.
913 */
914 bool
915 BBitmap::Lock()
916 {
917 	return fWindow != NULL ? fWindow->Lock() : false;
918 }
919 
920 
921 /*!	\brief Unlocks the off-screen window that belongs to the bitmap.
922 
923 	The bitmap must accept views, if locking should work.
924 */
925 void
926 BBitmap::Unlock()
927 {
928 	if (fWindow != NULL)
929 		fWindow->Unlock();
930 }
931 
932 
933 /*!	\brief Returns whether or not the bitmap's off-screen window is locked.
934 
935 	The bitmap must accept views, if locking should work.
936 
937 	\return \c true, if the caller owns a lock , \c false otherwise.
938 */
939 bool
940 BBitmap::IsLocked() const
941 {
942 	return fWindow != NULL ? fWindow->IsLocked() : false;
943 }
944 
945 
946 BBitmap&
947 BBitmap::operator=(const BBitmap& source)
948 {
949 	_CleanUp();
950 	fInitError = B_NO_INIT;
951 
952 	if (!source.IsValid())
953 		return *this;
954 
955 	_InitObject(source.Bounds(), source.ColorSpace(), source.Flags(),
956 		source.BytesPerRow(), B_MAIN_SCREEN_ID);
957 	if (InitCheck() == B_OK)
958 		memcpy(Bits(), source.Bits(), min_c(BitsLength(), source.BitsLength()));
959 
960 	return *this;
961 }
962 
963 
964 status_t
965 BBitmap::Perform(perform_code d, void* arg)
966 {
967 	return BArchivable::Perform(d, arg);
968 }
969 
970 // FBC
971 void BBitmap::_ReservedBitmap1() {}
972 void BBitmap::_ReservedBitmap2() {}
973 void BBitmap::_ReservedBitmap3() {}
974 
975 
976 #if 0
977 // get_shared_pointer
978 /*!	\brief ???
979 */
980 char*
981 BBitmap::get_shared_pointer() const
982 {
983 	return NULL;	// not implemented
984 }
985 #endif
986 
987 int32
988 BBitmap::_ServerToken() const
989 {
990 	return fServerToken;
991 }
992 
993 
994 /*!	\brief Initializes the bitmap.
995 	\param bounds The bitmap dimensions.
996 	\param colorSpace The bitmap's color space.
997 	\param flags Creation flags.
998 	\param bytesPerRow The number of bytes per row the bitmap should use.
999 		   \c B_ANY_BYTES_PER_ROW to let the constructor choose an appropriate
1000 		   value.
1001 	\param screenID ???
1002 */
1003 void
1004 BBitmap::_InitObject(BRect bounds, color_space colorSpace, uint32 flags,
1005 	int32 bytesPerRow, screen_id screenID)
1006 {
1007 //printf("BBitmap::InitObject(bounds: BRect(%.1f, %.1f, %.1f, %.1f), format: %ld, flags: %ld, bpr: %ld\n",
1008 //	   bounds.left, bounds.top, bounds.right, bounds.bottom, colorSpace, flags, bytesPerRow);
1009 
1010 	// TODO: Should we handle rounding of the "bounds" here? How does R5 behave?
1011 
1012 	status_t error = B_OK;
1013 
1014 #ifdef RUN_WITHOUT_APP_SERVER
1015 	flags |= B_BITMAP_NO_SERVER_LINK;
1016 #endif	// RUN_WITHOUT_APP_SERVER
1017 
1018 	_CleanUp();
1019 
1020 	// check params
1021 	if (!bounds.IsValid() || !bitmaps_support_space(colorSpace, NULL)) {
1022 		error = B_BAD_VALUE;
1023 	} else {
1024 		// bounds is in floats and might be valid but much larger than what we
1025 		// can handle the size could not be expressed in int32
1026 		double realSize = bounds.Width() * bounds.Height();
1027 		if (realSize > (double)(INT_MAX / 4)) {
1028 			fprintf(stderr, "bitmap bounds is much too large: "
1029 				"BRect(%.1f, %.1f, %.1f, %.1f)\n",
1030 				bounds.left, bounds.top, bounds.right, bounds.bottom);
1031 			error = B_BAD_VALUE;
1032 		}
1033 	}
1034 	if (error == B_OK) {
1035 		int32 bpr = get_bytes_per_row(colorSpace, bounds.IntegerWidth() + 1);
1036 		if (bytesPerRow < 0)
1037 			bytesPerRow = bpr;
1038 		else if (bytesPerRow < bpr)
1039 // NOTE: How does R5 behave?
1040 			error = B_BAD_VALUE;
1041 	}
1042 	// allocate the bitmap buffer
1043 	if (error == B_OK) {
1044 		// TODO: Let the app_server return the size when it allocated the bitmap
1045 		int32 size = bytesPerRow * (bounds.IntegerHeight() + 1);
1046 
1047 		if ((flags & B_BITMAP_NO_SERVER_LINK) != 0) {
1048 			fBasePointer = (uint8*)malloc(size);
1049 			if (fBasePointer) {
1050 				fSize = size;
1051 				fColorSpace = colorSpace;
1052 				fBounds = bounds;
1053 				fBytesPerRow = bytesPerRow;
1054 				fFlags = flags;
1055 			} else
1056 				error = B_NO_MEMORY;
1057 		} else {
1058 			// Ask the server (via our owning application) to create a bitmap.
1059 			BPrivate::AppServerLink link;
1060 
1061 			// Attach Data:
1062 			// 1) BRect bounds
1063 			// 2) color_space space
1064 			// 3) int32 bitmap_flags
1065 			// 4) int32 bytes_per_row
1066 			// 5) int32 screen_id::id
1067 			link.StartMessage(AS_CREATE_BITMAP);
1068 			link.Attach<BRect>(bounds);
1069 			link.Attach<color_space>(colorSpace);
1070 			link.Attach<uint32>(flags);
1071 			link.Attach<int32>(bytesPerRow);
1072 			link.Attach<int32>(screenID.id);
1073 
1074 			if (link.FlushWithReply(error) == B_OK && error == B_OK) {
1075 				// server side success
1076 				// Get token
1077 				link.Read<int32>(&fServerToken);
1078 
1079 				uint8 allocationFlags;
1080 				link.Read<uint8>(&allocationFlags);
1081 				link.Read<area_id>(&fServerArea);
1082 				link.Read<int32>(&fAreaOffset);
1083 
1084 				BPrivate::ServerMemoryAllocator* allocator
1085 					= BApplication::Private::ServerAllocator();
1086 
1087 				if ((allocationFlags & kNewAllocatorArea) != 0) {
1088 					error = allocator->AddArea(fServerArea, fArea,
1089 						fBasePointer, size);
1090 				} else {
1091 					error = allocator->AreaAndBaseFor(fServerArea, fArea,
1092 						fBasePointer);
1093 					if (error == B_OK)
1094 						fBasePointer += fAreaOffset;
1095 				}
1096 
1097 				if ((allocationFlags & kFramebuffer) != 0) {
1098 					// The base pointer will now point to an overlay_client_data
1099 					// structure bytes per row might be modified to match
1100 					// hardware constraints
1101 					link.Read<int32>(&bytesPerRow);
1102 					size = bytesPerRow * (bounds.IntegerHeight() + 1);
1103 				}
1104 
1105 				if (fServerArea >= B_OK) {
1106 					fSize = size;
1107 					fColorSpace = colorSpace;
1108 					fBounds = bounds;
1109 					fBytesPerRow = bytesPerRow;
1110 					fFlags = flags;
1111 				} else
1112 					error = fServerArea;
1113 			}
1114 
1115 			if (error < B_OK) {
1116 				fBasePointer = NULL;
1117 				fServerToken = -1;
1118 				fArea = -1;
1119 				fServerArea = -1;
1120 				fAreaOffset = -1;
1121 				// NOTE: why not "0" in case of error?
1122 				fFlags = flags;
1123 			} else {
1124 				BAutolock _(sBitmapListLock);
1125 				sBitmapList.AddItem(this);
1126 			}
1127 		}
1128 		fWindow = NULL;
1129 	}
1130 
1131 	fInitError = error;
1132 
1133 	if (fInitError == B_OK) {
1134 		// clear to white if the flags say so.
1135 		if (flags & (B_BITMAP_CLEAR_TO_WHITE | B_BITMAP_ACCEPTS_VIEWS)) {
1136 			if (fColorSpace == B_CMAP8) {
1137 				// "255" is the "transparent magic" index for B_CMAP8 bitmaps
1138 				// use the correct index for "white"
1139 				memset(fBasePointer, 65, fSize);
1140 			} else {
1141 				// should work for most colorspaces
1142 				memset(fBasePointer, 0xff, fSize);
1143 			}
1144 		}
1145 		// TODO: Creating an offscreen window with a non32 bit bitmap
1146 		// copies the current content of the bitmap to a back buffer.
1147 		// So at this point the bitmap has to be already cleared to white.
1148 		// Better move the above code to the server so the problem looks more
1149 		// clear.
1150 		if (flags & B_BITMAP_ACCEPTS_VIEWS) {
1151 			fWindow = new(std::nothrow) BWindow(Bounds(), fServerToken);
1152 			if (fWindow) {
1153 				// A BWindow starts life locked and is unlocked
1154 				// in Show(), but this window is never shown and
1155 				// it's message loop is never started.
1156 				fWindow->Unlock();
1157 			} else
1158 				fInitError = B_NO_MEMORY;
1159 		}
1160 	}
1161 }
1162 
1163 
1164 /*!	\brief Cleans up any memory allocated by the bitmap and
1165 		informs the server to do so as well (if needed).
1166 */
1167 void
1168 BBitmap::_CleanUp()
1169 {
1170 	if (fWindow != NULL) {
1171 		if (fWindow->Lock())
1172 			delete fWindow;
1173 		fWindow = NULL;
1174 			// this will leak fWindow if it couldn't be locked
1175 	}
1176 
1177 	if (fBasePointer == NULL)
1178 		return;
1179 
1180 	if ((fFlags & B_BITMAP_NO_SERVER_LINK) != 0) {
1181 		free(fBasePointer);
1182 	} else if (fServerToken != -1) {
1183 		BPrivate::AppServerLink link;
1184 		// AS_DELETE_BITMAP:
1185 		// Attached Data:
1186 		//	1) int32 server token
1187 		link.StartMessage(AS_DELETE_BITMAP);
1188 		link.Attach<int32>(fServerToken);
1189 		link.Flush();
1190 
1191 		// The server areas are deleted via kMsgDeleteServerMemoryArea message
1192 
1193 		fArea = -1;
1194 		fServerToken = -1;
1195 		fAreaOffset = -1;
1196 
1197 		BAutolock _(sBitmapListLock);
1198 		sBitmapList.RemoveItem(this);
1199 	}
1200 	fBasePointer = NULL;
1201 }
1202 
1203 
1204 void
1205 BBitmap::_AssertPointer()
1206 {
1207 	if (fBasePointer == NULL && fServerArea >= B_OK && fAreaOffset == -1) {
1208 		// We lazily clone our own areas - if the bitmap is part of the usual
1209 		// server memory area, or is a B_BITMAP_NO_SERVER_LINK bitmap, it
1210 		// already has its data.
1211 		fArea = clone_area("shared bitmap area", (void**)&fBasePointer,
1212 			B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA, fServerArea);
1213 	}
1214 }
1215 
1216 
1217 void
1218 BBitmap::_ReconnectToAppServer()
1219 {
1220 	BPrivate::AppServerLink link;
1221 
1222 	link.StartMessage(AS_RECONNECT_BITMAP);
1223 	link.Attach<BRect>(fBounds);
1224 	link.Attach<color_space>(fColorSpace);
1225 	link.Attach<uint32>(fFlags);
1226 	link.Attach<int32>(fBytesPerRow);
1227 	link.Attach<int32>(0);
1228 	link.Attach<int32>(fArea);
1229 	link.Attach<int32>(fAreaOffset);
1230 
1231 	status_t error;
1232 	if (link.FlushWithReply(error) == B_OK && error == B_OK) {
1233 		// server side success
1234 		// Get token
1235 		link.Read<int32>(&fServerToken);
1236 
1237 		link.Read<area_id>(&fServerArea);
1238 	}
1239 }
1240