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