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