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