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