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