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