xref: /haiku/src/servers/app/ServerBitmap.cpp (revision 0c93c0a807b27096abbfad677436afb7d1712d4a)
1 /*
2  * Copyright 2001-2006, Haiku.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		DarkWyrm <bpmagic@columbus.rr.com>
7  *		Axel Dörfler, axeld@pinc-software.de
8  */
9 
10 
11 #include "ServerBitmap.h"
12 #include "ClientMemoryAllocator.h"
13 #include "ColorConversion.h"
14 #include "HWInterface.h"
15 #include "Overlay.h"
16 
17 #include <new>
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 
22 using std::nothrow;
23 
24 /*!
25 	A word about memory housekeeping and why it's implemented this way:
26 
27 	The reason why this looks so complicated is to optimize the most common
28 	path (bitmap creation from the application), and don't cause any further
29 	memory allocations for maintaining memory in that case.
30 	If a bitmap was allocated this way, both, the fAllocator and fAllocationCookie
31 	members are used.
32 
33 	For overlays, the allocator only allocates a small piece of client memory
34 	for use with the overlay_client_data structure - the actual buffer will be
35 	placed in the graphics frame buffer and is allocated by the graphics driver.
36 
37 	If the memory was allocated on the app_server heap, neither fAllocator, nor
38 	fAllocationCookie are used, and the buffer is just freed in that case when
39 	the bitmap is destructed. This method is mainly used for cursors.
40 */
41 
42 
43 /*!
44 	\brief Constructor called by the BitmapManager (only).
45 	\param rect Size of the bitmap.
46 	\param space Color space of the bitmap
47 	\param flags Various bitmap flags to tweak the bitmap as defined in Bitmap.h
48 	\param bytesperline Number of bytes in each row. -1 implies the default value. Any
49 	value less than the the default will less than the default will be overridden, but any value
50 	greater than the default will result in the number of bytes specified.
51 	\param screen Screen assigned to the bitmap.
52 */
53 ServerBitmap::ServerBitmap(BRect rect, color_space space,
54 						   int32 flags, int32 bytesPerRow,
55 						   screen_id screen)
56 	:
57 	fAllocator(NULL),
58 	fAllocationCookie(NULL),
59 	fOverlay(NULL),
60 	fBuffer(NULL),
61 	fReferenceCount(1),
62 	// WARNING: '1' is added to the width and height.
63 	// Same is done in FBBitmap subclass, so if you
64 	// modify here make sure to do the same under
65 	// FBBitmap::SetSize(...)
66 	fWidth(rect.IntegerWidth() + 1),
67 	fHeight(rect.IntegerHeight() + 1),
68 	fBytesPerRow(0),
69 	fSpace(space),
70 	fFlags(flags),
71 	fBitsPerPixel(0)
72 	// fToken is initialized (if used) by the BitmapManager
73 {
74 	_HandleSpace(space, bytesPerRow);
75 }
76 
77 
78 //! Copy constructor does not copy the buffer.
79 ServerBitmap::ServerBitmap(const ServerBitmap* bmp)
80 	:
81 	fAllocator(NULL),
82 	fAllocationCookie(NULL),
83 	fOverlay(NULL),
84 	fBuffer(NULL),
85 	fReferenceCount(1)
86 {
87 	if (bmp) {
88 		fWidth			= bmp->fWidth;
89 		fHeight			= bmp->fHeight;
90 		fBytesPerRow	= bmp->fBytesPerRow;
91 		fSpace			= bmp->fSpace;
92 		fFlags			= bmp->fFlags;
93 		fBitsPerPixel	= bmp->fBitsPerPixel;
94 	} else {
95 		fWidth			= 0;
96 		fHeight			= 0;
97 		fBytesPerRow	= 0;
98 		fSpace			= B_NO_COLOR_SPACE;
99 		fFlags			= 0;
100 		fBitsPerPixel	= 0;
101 	}
102 }
103 
104 
105 ServerBitmap::~ServerBitmap()
106 {
107 	if (fAllocator != NULL)
108 		fAllocator->Free(AllocationCookie());
109 	else
110 		free(fBuffer);
111 
112 	delete fOverlay;
113 		// deleting the overlay will also free the overlay buffer
114 }
115 
116 
117 void
118 ServerBitmap::Acquire()
119 {
120 	atomic_add(&fReferenceCount, 1);
121 }
122 
123 
124 bool
125 ServerBitmap::_Release()
126 {
127 	if (atomic_add(&fReferenceCount, -1) == 1)
128 		return true;
129 
130 	return false;
131 }
132 
133 
134 /*!
135 	\brief Internal function used by subclasses
136 
137 	Subclasses should call this so the buffer can automagically
138 	be allocated on the heap.
139 */
140 void
141 ServerBitmap::_AllocateBuffer(void)
142 {
143 	uint32 length = BitsLength();
144 	if (length > 0) {
145 		delete[] fBuffer;
146 		fBuffer = new(nothrow) uint8[length];
147 	}
148 }
149 
150 
151 /*!
152 	\brief Internal function used to translate color space values to appropriate internal
153 	values.
154 	\param space Color space for the bitmap.
155 	\param bytesPerRow Number of bytes per row to be used as an override.
156 */
157 void
158 ServerBitmap::_HandleSpace(color_space space, int32 bytesPerRow)
159 {
160 	// calculate the minimum bytes per row
161 	// set fBitsPerPixel
162 	int32 minBPR = 0;
163 	switch(space) {
164 		// 32-bit
165 		case B_RGB32:
166 		case B_RGBA32:
167 		case B_RGB32_BIG:
168 		case B_RGBA32_BIG:
169 		case B_UVL32:
170 		case B_UVLA32:
171 		case B_LAB32:
172 		case B_LABA32:
173 		case B_HSI32:
174 		case B_HSIA32:
175 		case B_HSV32:
176 		case B_HSVA32:
177 		case B_HLS32:
178 		case B_HLSA32:
179 		case B_CMY32:
180 		case B_CMYA32:
181 		case B_CMYK32:
182 			minBPR = fWidth * 4;
183 			fBitsPerPixel = 32;
184 			break;
185 
186 		// 24-bit
187 		case B_RGB24_BIG:
188 		case B_RGB24:
189 		case B_LAB24:
190 		case B_UVL24:
191 		case B_HSI24:
192 		case B_HSV24:
193 		case B_HLS24:
194 		case B_CMY24:
195 		// TODO: These last two are calculated
196 		// (width + 3) / 4 * 12
197 		// in Bitmap.cpp, I don't understand why though.
198 		case B_YCbCr444:
199 		case B_YUV444:
200 			minBPR = fWidth * 3;
201 			fBitsPerPixel = 24;
202 			break;
203 
204 		// 16-bit
205 		case B_YUV9:
206 		case B_YUV12:
207 		case B_RGB15:
208 		case B_RGBA15:
209 		case B_RGB16:
210 		case B_RGB16_BIG:
211 		case B_RGB15_BIG:
212 		case B_RGBA15_BIG:
213 			minBPR = fWidth * 2;
214 			fBitsPerPixel = 16;
215 			break;
216 
217 		case B_YCbCr422:
218 		case B_YUV422:
219 			minBPR = (fWidth + 3) / 4 * 8;
220 				// TODO: huh? why not simply fWidth * 2 ?!?
221 			fBitsPerPixel = 16;
222 			break;
223 
224 		// 8-bit
225 		case B_CMAP8:
226 		case B_GRAY8:
227 			minBPR = fWidth;
228 			fBitsPerPixel = 8;
229 			break;
230 
231 		// 1-bit
232 		case B_GRAY1:
233 			minBPR = (fWidth + 7) / 8;
234 			fBitsPerPixel = 1;
235 			break;
236 
237 		// TODO: ??? get a clue what these mean
238 		case B_YCbCr411:
239 		case B_YUV411:
240 		case B_YUV420:
241 		case B_YCbCr420:
242 			minBPR = (fWidth + 3) / 4 * 6;
243 			fBitsPerPixel = 0;
244 			break;
245 
246 		case B_NO_COLOR_SPACE:
247 		default:
248 			fBitsPerPixel = 0;
249 			break;
250 	}
251 	if (minBPR > 0 || bytesPerRow > 0) {
252 		// add the padding or use the provided bytesPerRow if sufficient
253 		if (bytesPerRow >= minBPR) {
254 			fBytesPerRow = bytesPerRow;
255 		} else {
256 			fBytesPerRow = ((minBPR + 3) / 4) * 4;
257 		}
258 	}
259 }
260 
261 
262 status_t
263 ServerBitmap::ImportBits(const void *bits, int32 bitsLength, int32 bytesPerRow,
264 	color_space colorSpace)
265 {
266 	if (!bits || bitsLength < 0 || bytesPerRow <= 0)
267 		return B_BAD_VALUE;
268 
269 	return BPrivate::ConvertBits(bits, fBuffer, bitsLength, BitsLength(),
270 		bytesPerRow, fBytesPerRow, colorSpace, fSpace, fWidth, fHeight);
271 }
272 
273 
274 status_t
275 ServerBitmap::ImportBits(const void *bits, int32 bitsLength, int32 bytesPerRow,
276 	color_space colorSpace, BPoint from, BPoint to, int32 width, int32 height)
277 {
278 	if (!bits || bitsLength < 0 || bytesPerRow <= 0 || width < 0 || height < 0)
279 		return B_BAD_VALUE;
280 
281 	return BPrivate::ConvertBits(bits, fBuffer, bitsLength, BitsLength(),
282 		bytesPerRow, fBytesPerRow, colorSpace, fSpace, from, to, width,
283 		height);
284 }
285 
286 
287 area_id
288 ServerBitmap::Area() const
289 {
290 	if (fAllocator != NULL)
291 		return fAllocator->Area(AllocationCookie());
292 
293 	return B_ERROR;
294 }
295 
296 
297 uint32
298 ServerBitmap::AreaOffset() const
299 {
300 	if (fAllocator != NULL)
301 		return fAllocator->AreaOffset(AllocationCookie());
302 
303 	return 0;
304 }
305 
306 
307 void
308 ServerBitmap::SetOverlay(::Overlay* cookie)
309 {
310 	fOverlay = cookie;
311 }
312 
313 
314 ::Overlay*
315 ServerBitmap::Overlay() const
316 {
317 	return fOverlay;
318 }
319 
320 
321 void
322 ServerBitmap::PrintToStream()
323 {
324 	printf("Bitmap@%p: (%ld:%ld), space %ld, bpr %ld, buffer %p\n",
325 		this, fWidth, fHeight, (int32)fSpace, fBytesPerRow, fBuffer);
326 }
327 
328 
329 //	#pragma mark -
330 
331 
332 UtilityBitmap::UtilityBitmap(BRect rect, color_space space,
333 							 int32 flags, int32 bytesperline,
334 							 screen_id screen)
335 	: ServerBitmap(rect, space, flags, bytesperline, screen)
336 {
337 	_AllocateBuffer();
338 }
339 
340 
341 UtilityBitmap::UtilityBitmap(const ServerBitmap* bitmap)
342 	: ServerBitmap(bitmap)
343 {
344 	_AllocateBuffer();
345 
346 	if (bitmap->Bits())
347 		memcpy(Bits(), bitmap->Bits(), bitmap->BitsLength());
348 }
349 
350 
351 UtilityBitmap::UtilityBitmap(const uint8* alreadyPaddedData,
352 							 uint32 width, uint32 height,
353 							 color_space format)
354 	: ServerBitmap(BRect(0, 0, width - 1, height - 1), format, 0)
355 {
356 	_AllocateBuffer();
357 	if (Bits())
358 		memcpy(Bits(), alreadyPaddedData, BitsLength());
359 }
360 
361 
362 UtilityBitmap::~UtilityBitmap()
363 {
364 }
365