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