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