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