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