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