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_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
145namespace 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*/
154int32
155get_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*/
178BBitmap::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*/
207BBitmap::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*/
238BBitmap::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
266BBitmap::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
292BBitmap::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
311BBitmap::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*/
335BBitmap::~BBitmap()
336{
337	_CleanUp();
338}
339
340
341/*!	\brief Unarchives a bitmap from a BMessage.
342	\param data The archive.
343*/
344BBitmap::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*/
416BArchivable*
417BBitmap::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*/
432status_t
433BBitmap::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*/
477status_t
478BBitmap::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*/
487bool
488BBitmap::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*/
502status_t
503BBitmap::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*/
536void
537BBitmap::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*/
550area_id
551BBitmap::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*/
561void*
562BBitmap::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*/
578int32
579BBitmap::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*/
588int32
589BBitmap::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*/
598color_space
599BBitmap::ColorSpace() const
600{
601	return fColorSpace;
602}
603
604
605/*!	\brief Returns the bitmap's dimensions.
606	\return The bitmap's dimensions.
607*/
608BRect
609BBitmap::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*/
623uint32
624BBitmap::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*/
654void
655BBitmap::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_CMAP8 && fColorSpace != B_CMAP8) {
669			// If in color space is B_CMAP8, but the bitmap's is another one,
670			// ignore source data row padding.
671			inBPR = width;
672		}
673
674		// call the sane method, which does the actual work
675		error = ImportBits(data, length, inBPR, offset, colorSpace);
676	}
677}
678
679
680/*!	\brief Assigns data to the bitmap.
681
682	Data are directly written into the bitmap's data buffer, being converted
683	beforehand, if necessary. Unlike for SetBits(), the meaning of
684	\a colorSpace is exactly the expected one here, i.e. the source buffer
685	is supposed to contain data of that color space. \a bpr specifies how
686	many bytes the source contains per row. \c B_ANY_BYTES_PER_ROW can be
687	supplied, if standard padding to int32 is used.
688
689	The currently supported source/target color spaces are
690	\c B_RGB{32,24,16,15}[_BIG], \c B_CMAP8 and \c B_GRAY{8,1}.
691
692	\param data The data to be copied.
693	\param length The length in bytes of the data to be copied.
694	\param bpr The number of bytes per row in the source data.
695	\param offset The offset (in bytes) relative to beginning of the bitmap
696		   data specifying the position at which the source data shall be
697		   written.
698	\param colorSpace Color space of the source data.
699	\return
700	- \c B_OK: Everything went fine.
701	- \c B_BAD_VALUE: \c NULL \a data, invalid \a bpr or \a offset, or
702	  unsupported \a colorSpace.
703*/
704status_t
705BBitmap::ImportBits(const void* data, int32 length, int32 bpr, int32 offset,
706	color_space colorSpace)
707{
708	_AssertPointer();
709
710	if (InitCheck() != B_OK)
711		return B_NO_INIT;
712
713	if (!data || offset > fSize || length < 0)
714		return B_BAD_VALUE;
715
716	int32 width = fBounds.IntegerWidth() + 1;
717	if (bpr <= 0) {
718		if (bpr == B_ANY_BYTES_PER_ROW)
719			bpr = get_bytes_per_row(colorSpace, width);
720		else
721			return B_BAD_VALUE;
722	}
723
724	return BPrivate::ConvertBits(data, (uint8*)fBasePointer + offset, length,
725		fSize - offset, bpr, fBytesPerRow, colorSpace, fColorSpace, width,
726		fBounds.IntegerHeight() + 1);
727}
728
729
730/*!	\brief Assigns data to the bitmap.
731
732	Allows for a BPoint offset in the source and in the bitmap. The region
733	of the source at \a from extending \a width and \a height is assigned
734	(and converted if necessary) to the bitmap at \a to.
735
736	The currently supported source/target color spaces are
737	\c B_RGB{32,24,16,15}[_BIG], \c B_CMAP8 and \c B_GRAY{8,1}.
738
739	\param data The data to be copied.
740	\param length The length in bytes of the data to be copied.
741	\param bpr The number of bytes per row in the source data.
742	\param colorSpace Color space of the source data.
743	\param from The offset in the source where reading should begin.
744	\param to The offset in the bitmap where the source should be written.
745	\param size The size (in pixels) to be imported.
746	\return
747	- \c B_OK: Everything went fine.
748	- \c B_BAD_VALUE: \c NULL \a data, invalid \a bpr, unsupported
749	  \a colorSpace or invalid width/height.
750*/
751status_t
752BBitmap::ImportBits(const void* data, int32 length, int32 bpr,
753	color_space colorSpace, BPoint from, BPoint to, BSize size)
754{
755	_AssertPointer();
756
757	if (InitCheck() != B_OK)
758		return B_NO_INIT;
759
760	if (!data || length < 0 || size.IntegerWidth() < 0 || size.IntegerHeight() < 0)
761		return B_BAD_VALUE;
762
763	if (bpr <= 0) {
764		if (bpr == B_ANY_BYTES_PER_ROW)
765			bpr = get_bytes_per_row(colorSpace, fBounds.IntegerWidth() + 1);
766		else
767			return B_BAD_VALUE;
768	}
769
770	return BPrivate::ConvertBits(data, fBasePointer, length, fSize, bpr,
771		fBytesPerRow, colorSpace, fColorSpace, from, to,
772		size.IntegerWidth() + 1, size.IntegerHeight() + 1);
773}
774
775
776status_t
777BBitmap::ImportBits(const void* data, int32 length, int32 bpr,
778	color_space colorSpace, BPoint from, BPoint to, int32 width, int32 height)
779{
780	return ImportBits(data, length, bpr, colorSpace, from, to, BSize(width - 1, height - 1));
781}
782
783
784/*!	\brief Assigns another bitmap's data to this bitmap.
785
786	The supplied bitmap must have the exactly same dimensions as this bitmap.
787	Its data is converted to the color space of this bitmap.
788
789	The currently supported source/target color spaces are
790	\c B_RGB{32,24,16,15}[_BIG], \c B_CMAP8 and \c B_GRAY{8,1}.
791
792	\param bitmap The source bitmap.
793	\return
794	- \c B_OK: Everything went fine.
795	- \c B_BAD_VALUE: \c NULL \a bitmap, or \a bitmap has other dimensions,
796	  or the conversion from or to one of the color spaces is not supported.
797*/
798status_t
799BBitmap::ImportBits(const BBitmap* bitmap)
800{
801	if (InitCheck() != B_OK)
802		return B_NO_INIT;
803
804	if (!bitmap || bitmap->InitCheck() != B_OK || bitmap->Bounds() != fBounds)
805		return B_BAD_VALUE;
806
807	return ImportBits(bitmap->Bits(), bitmap->BitsLength(),
808		bitmap->BytesPerRow(), 0, bitmap->ColorSpace());
809}
810
811
812/*!	\brief Assigns data to the bitmap.
813
814	Allows for a BPoint offset in the source and in the bitmap. The region
815	of the source at \a from extending \a width and \a height is assigned
816	(and converted if necessary) to the bitmap at \a to. The source bitmap is
817	clipped to the bitmap and they don't need to have the same dimensions.
818
819	The currently supported source/target color spaces are
820	\c B_RGB{32,24,16,15}[_BIG], \c B_CMAP8 and \c B_GRAY{8,1}.
821
822	\param bitmap The source bitmap.
823	\param from The offset in the source where reading should begin.
824	\param to The offset in the bitmap where the source should be written.
825	\param size The size (in pixels) to be imported.
826	- \c B_OK: Everything went fine.
827	- \c B_BAD_VALUE: \c NULL \a bitmap, the conversion from or to one of
828	  the color spaces is not supported, or invalid width/height.
829*/
830status_t
831BBitmap::ImportBits(const BBitmap* bitmap, BPoint from, BPoint to, BSize size)
832{
833	if (InitCheck() != B_OK)
834		return B_NO_INIT;
835
836	if (!bitmap || bitmap->InitCheck() != B_OK)
837		return B_BAD_VALUE;
838
839	return ImportBits(bitmap->Bits(), bitmap->BitsLength(),
840		bitmap->BytesPerRow(), bitmap->ColorSpace(), from, to, size);
841}
842
843
844status_t
845BBitmap::ImportBits(const BBitmap* bitmap, BPoint from, BPoint to, int32 width, int32 height)
846{
847	return ImportBits(bitmap, from, to, BSize(width - 1, height - 1));
848}
849
850
851/*!	\brief Returns the overlay_restrictions structure for this bitmap
852*/
853status_t
854BBitmap::GetOverlayRestrictions(overlay_restrictions* restrictions) const
855{
856	if ((fFlags & B_BITMAP_WILL_OVERLAY) == 0)
857		return B_BAD_TYPE;
858
859	BPrivate::AppServerLink link;
860
861	link.StartMessage(AS_GET_BITMAP_OVERLAY_RESTRICTIONS);
862	link.Attach<int32>(fServerToken);
863
864	status_t status;
865	if (link.FlushWithReply(status) < B_OK)
866		return status;
867
868	link.Read(restrictions, sizeof(overlay_restrictions));
869	return B_OK;
870}
871
872
873/*!	\brief Adds a BView to the bitmap's view hierarchy.
874
875	The bitmap must accept views and the supplied view must not be child of
876	another parent.
877
878	\param view The view to be added.
879*/
880void
881BBitmap::AddChild(BView* view)
882{
883	if (fWindow != NULL)
884		fWindow->AddChild(view);
885}
886
887
888/*!	\brief Removes a BView from the bitmap's view hierarchy.
889	\param view The view to be removed.
890*/
891bool
892BBitmap::RemoveChild(BView* view)
893{
894	return fWindow != NULL ? fWindow->RemoveChild(view) : false;
895}
896
897
898/*!	\brief Returns the number of BViews currently belonging to the bitmap.
899	\return The number of BViews currently belonging to the bitmap.
900*/
901int32
902BBitmap::CountChildren() const
903{
904	return fWindow != NULL ? fWindow->CountChildren() : 0;
905}
906
907
908/*!	\brief Returns the BView at a certain index in the bitmap's list of views.
909	\param index The index of the BView to be returned.
910	\return The BView at index \a index or \c NULL, if the index is out of
911			range.
912*/
913BView*
914BBitmap::ChildAt(int32 index) const
915{
916	return fWindow != NULL ? fWindow->ChildAt(index) : NULL;
917}
918
919
920/*!	\brief Returns a bitmap's BView with a certain name.
921	\param name The name of the BView to be returned.
922	\return The BView with the name \a name or \c NULL, if the bitmap doesn't
923	know a view with that name.
924*/
925BView*
926BBitmap::FindView(const char* viewName) const
927{
928	return fWindow != NULL ? fWindow->FindView(viewName) : NULL;
929}
930
931
932/*!	\brief Returns a bitmap's BView at a certain location.
933	\param point The location.
934	\return The BView with located at \a point or \c NULL, if the bitmap
935	doesn't know a view at this location.
936*/
937BView*
938BBitmap::FindView(BPoint point) const
939{
940	return fWindow != NULL ? fWindow->FindView(point) : NULL;
941}
942
943
944/*!	\brief Locks the off-screen window that belongs to the bitmap.
945
946	The bitmap must accept views, if locking should work.
947
948	\return \c true, if the lock was acquired successfully, \c false
949			otherwise.
950*/
951bool
952BBitmap::Lock()
953{
954	return fWindow != NULL ? fWindow->Lock() : false;
955}
956
957
958/*!	\brief Unlocks the off-screen window that belongs to the bitmap.
959
960	The bitmap must accept views, if locking should work.
961*/
962void
963BBitmap::Unlock()
964{
965	if (fWindow != NULL)
966		fWindow->Unlock();
967}
968
969
970/*!	\brief Returns whether or not the bitmap's off-screen window is locked.
971
972	The bitmap must accept views, if locking should work.
973
974	\return \c true, if the caller owns a lock , \c false otherwise.
975*/
976bool
977BBitmap::IsLocked() const
978{
979	return fWindow != NULL ? fWindow->IsLocked() : false;
980}
981
982
983BBitmap&
984BBitmap::operator=(const BBitmap& source)
985{
986	_CleanUp();
987	fInitError = B_NO_INIT;
988
989	if (!source.IsValid())
990		return *this;
991
992	_InitObject(source.Bounds(), source.ColorSpace(), source.Flags(),
993		source.BytesPerRow(), B_MAIN_SCREEN_ID);
994	if (InitCheck() == B_OK)
995		memcpy(Bits(), source.Bits(), min_c(BitsLength(), source.BitsLength()));
996
997	return *this;
998}
999
1000
1001status_t
1002BBitmap::Perform(perform_code d, void* arg)
1003{
1004	return BArchivable::Perform(d, arg);
1005}
1006
1007// FBC
1008void BBitmap::_ReservedBitmap1() {}
1009void BBitmap::_ReservedBitmap2() {}
1010void BBitmap::_ReservedBitmap3() {}
1011
1012
1013#if 0
1014// get_shared_pointer
1015/*!	\brief ???
1016*/
1017char*
1018BBitmap::get_shared_pointer() const
1019{
1020	return NULL;	// not implemented
1021}
1022#endif
1023
1024int32
1025BBitmap::_ServerToken() const
1026{
1027	return fServerToken;
1028}
1029
1030
1031/*!	\brief Initializes the bitmap.
1032	\param bounds The bitmap dimensions.
1033	\param colorSpace The bitmap's color space.
1034	\param flags Creation flags.
1035	\param bytesPerRow The number of bytes per row the bitmap should use.
1036		   \c B_ANY_BYTES_PER_ROW to let the constructor choose an appropriate
1037		   value.
1038	\param screenID ???
1039*/
1040void
1041BBitmap::_InitObject(BRect bounds, color_space colorSpace, uint32 flags,
1042	int32 bytesPerRow, screen_id screenID, area_id area, ptrdiff_t areaOffset)
1043{
1044//printf("BBitmap::InitObject(bounds: BRect(%.1f, %.1f, %.1f, %.1f), format: %ld, flags: %ld, bpr: %ld\n",
1045//	   bounds.left, bounds.top, bounds.right, bounds.bottom, colorSpace, flags, bytesPerRow);
1046
1047	// TODO: Should we handle rounding of the "bounds" here? How does R5 behave?
1048
1049	status_t error = B_OK;
1050
1051#ifdef RUN_WITHOUT_APP_SERVER
1052	flags |= B_BITMAP_NO_SERVER_LINK;
1053#endif	// RUN_WITHOUT_APP_SERVER
1054
1055	_CleanUp();
1056
1057	// check params
1058	if (!bounds.IsValid() || !bitmaps_support_space(colorSpace, NULL)) {
1059		error = B_BAD_VALUE;
1060	} else {
1061		// bounds is in floats and might be valid but much larger than what we
1062		// can handle the size could not be expressed in int32
1063		double realSize = bounds.Width() * bounds.Height();
1064		if (realSize > (double)(INT_MAX / 4)) {
1065			fprintf(stderr, "bitmap bounds is much too large: "
1066				"BRect(%.1f, %.1f, %.1f, %.1f)\n",
1067				bounds.left, bounds.top, bounds.right, bounds.bottom);
1068			error = B_BAD_VALUE;
1069		}
1070	}
1071	if (error == B_OK) {
1072		int32 bpr = get_bytes_per_row(colorSpace, bounds.IntegerWidth() + 1);
1073		if (bytesPerRow < 0)
1074			bytesPerRow = bpr;
1075		else if (bytesPerRow < bpr)
1076// NOTE: How does R5 behave?
1077			error = B_BAD_VALUE;
1078	}
1079	// allocate the bitmap buffer
1080	if (error == B_OK) {
1081		// TODO: Let the app_server return the size when it allocated the bitmap
1082		int32 size = bytesPerRow * (bounds.IntegerHeight() + 1);
1083
1084		if ((flags & B_BITMAP_NO_SERVER_LINK) != 0) {
1085			fBasePointer = (uint8*)malloc(size);
1086			if (fBasePointer) {
1087				fSize = size;
1088				fColorSpace = colorSpace;
1089				fBounds = bounds;
1090				fBytesPerRow = bytesPerRow;
1091				fFlags = flags;
1092			} else
1093				error = B_NO_MEMORY;
1094		} else {
1095			BPrivate::AppServerLink link;
1096
1097			if (area >= B_OK) {
1098				// Use area provided by client
1099
1100				area_info info;
1101				get_area_info(area, &info);
1102
1103				// Area should be owned by current team. Client should clone area if needed.
1104				if (info.team != getpid())
1105					error = B_BAD_VALUE;
1106				else {
1107					link.StartMessage(AS_RECONNECT_BITMAP);
1108					link.Attach<BRect>(bounds);
1109					link.Attach<color_space>(colorSpace);
1110					link.Attach<uint32>(flags);
1111					link.Attach<int32>(bytesPerRow);
1112					link.Attach<int32>(0);
1113					link.Attach<int32>(area);
1114					link.Attach<int32>(areaOffset);
1115
1116					if (link.FlushWithReply(error) == B_OK && error == B_OK) {
1117						link.Read<int32>(&fServerToken);
1118						link.Read<area_id>(&fServerArea);
1119
1120						if (fServerArea >= B_OK) {
1121							fSize = size;
1122							fColorSpace = colorSpace;
1123							fBounds = bounds;
1124							fBytesPerRow = bytesPerRow;
1125							fFlags = flags;
1126							fArea = area;
1127							fAreaOffset = areaOffset;
1128
1129							fBasePointer = (uint8*)info.address + areaOffset;
1130						} else
1131							error = fServerArea;
1132					}
1133				}
1134			} else {
1135				// Ask the server (via our owning application) to create a bitmap.
1136
1137				// Attach Data:
1138				// 1) BRect bounds
1139				// 2) color_space space
1140				// 3) int32 bitmap_flags
1141				// 4) int32 bytes_per_row
1142				// 5) int32 screen_id::id
1143				link.StartMessage(AS_CREATE_BITMAP);
1144				link.Attach<BRect>(bounds);
1145				link.Attach<color_space>(colorSpace);
1146				link.Attach<uint32>(flags);
1147				link.Attach<int32>(bytesPerRow);
1148				link.Attach<int32>(screenID.id);
1149
1150				if (link.FlushWithReply(error) == B_OK && error == B_OK) {
1151					// server side success
1152					// Get token
1153					link.Read<int32>(&fServerToken);
1154
1155					uint8 allocationFlags;
1156					link.Read<uint8>(&allocationFlags);
1157					link.Read<area_id>(&fServerArea);
1158					link.Read<int32>(&fAreaOffset);
1159
1160					BPrivate::ServerMemoryAllocator* allocator
1161						= BApplication::Private::ServerAllocator();
1162
1163					if ((allocationFlags & kNewAllocatorArea) != 0) {
1164						error = allocator->AddArea(fServerArea, fArea,
1165							fBasePointer, size);
1166					} else {
1167						error = allocator->AreaAndBaseFor(fServerArea, fArea,
1168							fBasePointer);
1169						if (error == B_OK)
1170							fBasePointer += fAreaOffset;
1171					}
1172
1173					if ((allocationFlags & kFramebuffer) != 0) {
1174						// The base pointer will now point to an overlay_client_data
1175						// structure bytes per row might be modified to match
1176						// hardware constraints
1177						link.Read<int32>(&bytesPerRow);
1178						size = bytesPerRow * (bounds.IntegerHeight() + 1);
1179					}
1180
1181					if (fServerArea >= B_OK) {
1182						fSize = size;
1183						fColorSpace = colorSpace;
1184						fBounds = bounds;
1185						fBytesPerRow = bytesPerRow;
1186						fFlags = flags;
1187					} else
1188						error = fServerArea;
1189				}
1190			}
1191
1192
1193			if (error < B_OK) {
1194				fBasePointer = NULL;
1195				fServerToken = -1;
1196				fArea = -1;
1197				fServerArea = -1;
1198				fAreaOffset = -1;
1199				// NOTE: why not "0" in case of error?
1200				fFlags = flags;
1201			} else {
1202				BAutolock _(sBitmapListLock);
1203				sBitmapList.AddItem(this);
1204			}
1205		}
1206		fWindow = NULL;
1207	}
1208
1209	fInitError = error;
1210
1211	if (fInitError == B_OK) {
1212		// clear to white if the flags say so.
1213		if (flags & (B_BITMAP_CLEAR_TO_WHITE | B_BITMAP_ACCEPTS_VIEWS)) {
1214			if (fColorSpace == B_CMAP8) {
1215				// "255" is the "transparent magic" index for B_CMAP8 bitmaps
1216				// use the correct index for "white"
1217				memset(fBasePointer, 65, fSize);
1218			} else {
1219				// should work for most colorspaces
1220				memset(fBasePointer, 0xff, fSize);
1221			}
1222		}
1223		// TODO: Creating an offscreen window with a non32 bit bitmap
1224		// copies the current content of the bitmap to a back buffer.
1225		// So at this point the bitmap has to be already cleared to white.
1226		// Better move the above code to the server so the problem looks more
1227		// clear.
1228		if (flags & B_BITMAP_ACCEPTS_VIEWS) {
1229			fWindow = new(std::nothrow) BWindow(Bounds(), fServerToken);
1230			if (fWindow) {
1231				// A BWindow starts life locked and is unlocked
1232				// in Show(), but this window is never shown and
1233				// it's message loop is never started.
1234				fWindow->Unlock();
1235			} else
1236				fInitError = B_NO_MEMORY;
1237		}
1238	}
1239}
1240
1241
1242/*!	\brief Cleans up any memory allocated by the bitmap and
1243		informs the server to do so as well (if needed).
1244*/
1245void
1246BBitmap::_CleanUp()
1247{
1248	if (fWindow != NULL) {
1249		if (fWindow->Lock())
1250			delete fWindow;
1251		fWindow = NULL;
1252			// this will leak fWindow if it couldn't be locked
1253	}
1254
1255	if (fBasePointer == NULL)
1256		return;
1257
1258	if ((fFlags & B_BITMAP_NO_SERVER_LINK) != 0) {
1259		free(fBasePointer);
1260	} else if (fServerToken != -1) {
1261		BPrivate::AppServerLink link;
1262		// AS_DELETE_BITMAP:
1263		// Attached Data:
1264		//	1) int32 server token
1265		link.StartMessage(AS_DELETE_BITMAP);
1266		link.Attach<int32>(fServerToken);
1267		link.Flush();
1268
1269		// The server areas are deleted via kMsgDeleteServerMemoryArea message
1270
1271		fArea = -1;
1272		fServerToken = -1;
1273		fAreaOffset = -1;
1274
1275		BAutolock _(sBitmapListLock);
1276		sBitmapList.RemoveItem(this);
1277	}
1278	fBasePointer = NULL;
1279}
1280
1281
1282void
1283BBitmap::_AssertPointer()
1284{
1285	if (fBasePointer == NULL && fServerArea >= B_OK && fAreaOffset == -1) {
1286		// We lazily clone our own areas - if the bitmap is part of the usual
1287		// server memory area, or is a B_BITMAP_NO_SERVER_LINK bitmap, it
1288		// already has its data.
1289		fArea = clone_area("shared bitmap area", (void**)&fBasePointer,
1290			B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA, fServerArea);
1291	}
1292}
1293
1294
1295void
1296BBitmap::_ReconnectToAppServer()
1297{
1298	BPrivate::AppServerLink link;
1299
1300	link.StartMessage(AS_RECONNECT_BITMAP);
1301	link.Attach<BRect>(fBounds);
1302	link.Attach<color_space>(fColorSpace);
1303	link.Attach<uint32>(fFlags);
1304	link.Attach<int32>(fBytesPerRow);
1305	link.Attach<int32>(0);
1306	link.Attach<int32>(fArea);
1307	link.Attach<int32>(fAreaOffset);
1308
1309	status_t error;
1310	if (link.FlushWithReply(error) == B_OK && error == B_OK) {
1311		// server side success
1312		// Get token
1313		link.Read<int32>(&fServerToken);
1314
1315		link.Read<area_id>(&fServerArea);
1316	}
1317}
1318