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