xref: /haiku/src/servers/app/drawing/HWInterface.cpp (revision d3d8b26997fac34a84981e6d2b649521de2cc45a)
1 /*
2  * Copyright 2005-2006, Haiku.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Stephan Aßmus <superstippi@gmx.de>
7  */
8 
9 
10 #include "HWInterface.h"
11 
12 #include "drawing_support.h"
13 
14 #include "RenderingBuffer.h"
15 #include "ServerCursor.h"
16 #include "SystemPalette.h"
17 #include "UpdateQueue.h"
18 
19 #include <stdio.h>
20 #include <string.h>
21 
22 
23 // constructor
24 HWInterface::HWInterface(bool doubleBuffered)
25 	: MultiLocker("hw interface lock"),
26 	  fCursorAreaBackup(NULL),
27 	  fCursor(NULL),
28 	  fDragBitmap(NULL),
29 	  fDragBitmapOffset(0, 0),
30 	  fCursorAndDragBitmap(NULL),
31 	  fCursorVisible(false),
32 	  fCursorObscured(false),
33 	  fCursorLocation(0, 0),
34 	  fDoubleBuffered(doubleBuffered),
35 //	  fUpdateExecutor(new UpdateQueue(this))
36 	  fUpdateExecutor(NULL)
37 {
38 }
39 
40 // destructor
41 HWInterface::~HWInterface()
42 {
43 	delete fCursorAreaBackup;
44 
45 	// The standard cursor doesn't belong us - the drag bitmap might
46 	if (fCursor != fCursorAndDragBitmap)
47 		delete fCursorAndDragBitmap;
48 
49 	delete fUpdateExecutor;
50 }
51 
52 // Initialize
53 status_t
54 HWInterface::Initialize()
55 {
56 	return MultiLocker::InitCheck();
57 }
58 
59 
60 status_t
61 HWInterface::GetAccelerantPath(BString &path)
62 {
63 	return B_ERROR;
64 }
65 
66 
67 status_t
68 HWInterface::GetDriverPath(BString &path)
69 {
70 	return B_ERROR;
71 }
72 
73 
74 // SetCursor
75 void
76 HWInterface::SetCursor(ServerCursor* cursor)
77 {
78 	if (WriteLock()) {
79 		// TODO: if a bitmap is being dragged, it could
80 		// be considered iritating to the user to change
81 		// cursor shapes while something is dragged.
82 		// The disabled code below would do this (except
83 		// for the minor annoyance that the cursor is not
84 		// updated when the drag is over)
85 //		if (fDragBitmap) {
86 //			// TODO: like a "+" or "-" sign when dragging some files to indicate
87 //			//		the current drag mode?
88 //			WriteUnlock();
89 //			return;
90 //		}
91 		if (fCursor != cursor) {
92 			BRect oldFrame = _CursorFrame();
93 
94 			if (fCursorAndDragBitmap == fCursor) {
95 				// make sure _AdoptDragBitmap doesn't delete a real cursor
96 				fCursorAndDragBitmap = NULL;
97 			}
98 
99 			if (fCursor)
100 				fCursor->Release();
101 
102 			fCursor = cursor;
103 
104 			if (fCursor)
105 				fCursor->Acquire();
106 
107 			Invalidate(oldFrame);
108 
109 			_AdoptDragBitmap(fDragBitmap, fDragBitmapOffset);
110 			Invalidate(_CursorFrame());
111 		}
112 		WriteUnlock();
113 	}
114 }
115 
116 // SetCursorVisible
117 void
118 HWInterface::SetCursorVisible(bool visible)
119 {
120 	if (WriteLock()) {
121 		if (fCursorVisible != visible) {
122 			// NOTE: _CursorFrame() will
123 			// return an invalid rect if
124 			// fCursorVisible == false!
125 			if (visible) {
126 				fCursorVisible = visible;
127 				fCursorObscured = false;
128 				BRect r = _CursorFrame();
129 
130 				_DrawCursor(r);
131 				Invalidate(r);
132 			} else {
133 				BRect r = _CursorFrame();
134 				fCursorVisible = visible;
135 
136 				_RestoreCursorArea();
137 				Invalidate(r);
138 			}
139 		}
140 		WriteUnlock();
141 	}
142 }
143 
144 // IsCursorVisible
145 bool
146 HWInterface::IsCursorVisible()
147 {
148 	bool visible = true;
149 	if (ReadLock()) {
150 		visible = fCursorVisible;
151 		ReadUnlock();
152 	}
153 	return visible;
154 }
155 
156 // ObscureCursor
157 void
158 HWInterface::ObscureCursor()
159 {
160 	if (WriteLock()) {
161 		if (!fCursorObscured) {
162 			SetCursorVisible(false);
163 			fCursorObscured = true;
164 		}
165 		WriteUnlock();
166 	}
167 }
168 
169 // MoveCursorTo
170 void
171 HWInterface::MoveCursorTo(const float& x, const float& y)
172 {
173 	if (WriteLock()) {
174 		BPoint p(x, y);
175 		if (p != fCursorLocation) {
176 			// unhide cursor if it is obscured only
177 			if (fCursorObscured) {
178 				// TODO: causes nested lock, which
179 				// the MultiLocker doesn't actually support?
180 				SetCursorVisible(true);
181 			}
182 			BRect oldFrame = _CursorFrame();
183 			fCursorLocation = p;
184 			if (fCursorVisible) {
185 				// Invalidate and _DrawCursor would not draw
186 				// anything if the cursor is hidden
187 				// (invalid cursor frame), but explicitly
188 				// testing for it here saves us some cycles
189 				if (fCursorAreaBackup) {
190 					// means we have a software cursor which we need to draw
191 					_RestoreCursorArea();
192 					_DrawCursor(_CursorFrame());
193 				}
194 				Invalidate(oldFrame);
195 				Invalidate(_CursorFrame());
196 			}
197 		}
198 		WriteUnlock();
199 	}
200 }
201 
202 // GetCursorPosition
203 BPoint
204 HWInterface::GetCursorPosition()
205 {
206 	BPoint location;
207 	if (ReadLock()) {
208 		location = fCursorLocation;
209 		ReadUnlock();
210 	}
211 	return location;
212 }
213 
214 // SetDragBitmap
215 void
216 HWInterface::SetDragBitmap(const ServerBitmap* bitmap,
217 						   const BPoint& offsetFromCursor)
218 {
219 	if (WriteLock()) {
220 		_AdoptDragBitmap(bitmap, offsetFromCursor);
221 		WriteUnlock();
222 	}
223 }
224 
225 // DrawingBuffer
226 RenderingBuffer*
227 HWInterface::DrawingBuffer() const
228 {
229 	if (IsDoubleBuffered())
230 		return BackBuffer();
231 	return FrontBuffer();
232 }
233 
234 // IsDoubleBuffered
235 bool
236 HWInterface::IsDoubleBuffered() const
237 {
238 	return fDoubleBuffered;
239 }
240 
241 // Invalidate
242 // * the object needs to be already locked!
243 status_t
244 HWInterface::Invalidate(const BRect& frame)
245 {
246 	if (IsDoubleBuffered()) {
247 		return CopyBackToFront(frame);
248 
249 // TODO: the remaining problem is the immediate wake up of the
250 // thread carrying out the updates, when I enable it, there
251 // seems to be a deadlock, but I didn't figure it out yet.
252 // Maybe the same bug is there without the wakeup, only, triggered
253 // less often.... scarry, huh?
254 /*		if (frame.IsValid()) {
255 			fUpdateExecutor->AddRect(frame);
256 			return B_OK;
257 		}
258 		return B_BAD_VALUE;*/
259 	} else {
260 //		_DrawCursor(frame);
261 	}
262 	return B_OK;
263 }
264 
265 // CopyBackToFront
266 // * the object must already be locked!
267 status_t
268 HWInterface::CopyBackToFront(const BRect& frame)
269 {
270 	RenderingBuffer* frontBuffer = FrontBuffer();
271 	RenderingBuffer* backBuffer = BackBuffer();
272 
273 	if (!backBuffer || !frontBuffer)
274 		return B_NO_INIT;
275 
276 	// we need to mess with the area, but it is const
277 	BRect area(frame);
278 	BRect bufferClip(backBuffer->Bounds());
279 
280 	if (area.IsValid() && area.Intersects(bufferClip)) {
281 
282 		// make sure we don't copy out of bounds
283 		area = bufferClip & area;
284 
285 		uint32 srcBPR = backBuffer->BytesPerRow();
286 		uint8* src = (uint8*)backBuffer->Bits();
287 
288 		// convert to integer coordinates
289 		int32 left = (int32)floorf(area.left);
290 		int32 top = (int32)floorf(area.top);
291 		int32 right = (int32)ceilf(area.right);
292 		int32 bottom = (int32)ceilf(area.bottom);
293 
294 		// offset to left top pixel in source buffer (always B_RGBA32)
295 		src += top * srcBPR + left * 4;
296 
297 		_CopyToFront(src, srcBPR, left, top, right, bottom);
298 		_DrawCursor(area);
299 
300 		return B_OK;
301 	}
302 	return B_BAD_VALUE;
303 }
304 
305 
306 overlay_token
307 HWInterface::AcquireOverlayChannel()
308 {
309 	return NULL;
310 }
311 
312 
313 void
314 HWInterface::ReleaseOverlayChannel(overlay_token token)
315 {
316 }
317 
318 
319 bool
320 HWInterface::CheckOverlayRestrictions(int32 width, int32 height, color_space colorSpace)
321 {
322 	return false;
323 }
324 
325 
326 const overlay_buffer*
327 HWInterface::AllocateOverlayBuffer(int32 width, int32 height, color_space space)
328 {
329 	return NULL;
330 }
331 
332 
333 void
334 HWInterface::FreeOverlayBuffer(const overlay_buffer* buffer)
335 {
336 }
337 
338 
339 void
340 HWInterface::ConfigureOverlay(Overlay* overlay)
341 {
342 }
343 
344 
345 void
346 HWInterface::HideOverlay(Overlay* overlay)
347 {
348 }
349 
350 
351 // HideSoftwareCursor
352 bool
353 HWInterface::HideSoftwareCursor(const BRect& area)
354 {
355 	if (fCursorAreaBackup && !fCursorAreaBackup->cursor_hidden) {
356 		BRect backupArea(fCursorAreaBackup->left,
357 						 fCursorAreaBackup->top,
358 						 fCursorAreaBackup->right,
359 						 fCursorAreaBackup->bottom);
360 		if (area.Intersects(backupArea)) {
361 			_RestoreCursorArea();
362 			return true;
363 		}
364 	}
365 	return false;
366 }
367 
368 // HideSoftwareCursor
369 void
370 HWInterface::HideSoftwareCursor()
371 {
372 	_RestoreCursorArea();
373 }
374 
375 // ShowSoftwareCursor
376 void
377 HWInterface::ShowSoftwareCursor()
378 {
379 	if (fCursorAreaBackup && fCursorAreaBackup->cursor_hidden) {
380 		_DrawCursor(_CursorFrame());
381 	}
382 }
383 
384 
385 // _DrawCursor
386 // * default implementation, can be used as fallback or for
387 //   software cursor
388 // * area is where we potentially draw the cursor, the cursor
389 //   might be somewhere else, in which case this function does nothing
390 void
391 HWInterface::_DrawCursor(BRect area) const
392 {
393 	RenderingBuffer* backBuffer = DrawingBuffer();
394 	if (!backBuffer || !area.IsValid())
395 		return;
396 
397 	BRect cf = _CursorFrame();
398 
399 	// make sure we don't copy out of bounds
400 	area = backBuffer->Bounds() & area;
401 
402 	if (cf.IsValid() && area.Intersects(cf)) {
403 		// clip to common area
404 		area = area & cf;
405 
406 		int32 left = (int32)area.left;
407 		int32 top = (int32)area.top;
408 		int32 right = (int32)area.right;
409 		int32 bottom = (int32)area.bottom;
410 		int32 width = right - left + 1;
411 		int32 height = bottom - top + 1;
412 
413 		// make a bitmap from the backbuffer
414 		// that has the cursor blended on top of it
415 
416 		// blending buffer
417 		uint8* buffer = new uint8[width * height * 4];
418 
419 		// offset into back buffer
420 		uint8* src = (uint8*)backBuffer->Bits();
421 		uint32 srcBPR = backBuffer->BytesPerRow();
422 		src += top * srcBPR + left * 4;
423 
424 		// offset into cursor bitmap
425 		uint8* crs = (uint8*)fCursorAndDragBitmap->Bits();
426 		uint32 crsBPR = fCursorAndDragBitmap->BytesPerRow();
427 		// since area is clipped to cf,
428 		// the diff between top and cf.top is always positive,
429 		// same for diff between left and cf.left
430 		crs += (top - (int32)floorf(cf.top)) * crsBPR
431 				+ (left - (int32)floorf(cf.left)) * 4;
432 
433 		uint8* dst = buffer;
434 
435 		if (fCursorAreaBackup && fCursorAreaBackup->buffer) {
436 			fCursorAreaBackup->cursor_hidden = false;
437 			// remember which area the backup contains
438 			fCursorAreaBackup->left = left;
439 			fCursorAreaBackup->top = top;
440 			fCursorAreaBackup->right = right;
441 			fCursorAreaBackup->bottom = bottom;
442 			uint8* bup = fCursorAreaBackup->buffer;
443 			uint32 bupBPR = fCursorAreaBackup->bpr;
444 
445 			// blending and backup of drawing buffer
446 			for (int32 y = top; y <= bottom; y++) {
447 				uint8* s = src;
448 				uint8* c = crs;
449 				uint8* d = dst;
450 				uint8* b = bup;
451 
452 				for (int32 x = left; x <= right; x++) {
453 					*(uint32*)b = *(uint32*)s;
454 					// assumes backbuffer alpha = 255
455 					// assuming pre-multiplied cursor bitmap
456 					int a = 255 - c[3];
457 					d[0] = ((int)(b[0] * a + 255) >> 8) + c[0];
458 					d[1] = ((int)(b[1] * a + 255) >> 8) + c[1];
459 					d[2] = ((int)(b[2] * a + 255) >> 8) + c[2];
460 
461 					s += 4;
462 					c += 4;
463 					d += 4;
464 					b += 4;
465 				}
466 				crs += crsBPR;
467 				src += srcBPR;
468 				dst += width * 4;
469 				bup += bupBPR;
470 			}
471 		} else {
472 			// blending
473 			for (int32 y = top; y <= bottom; y++) {
474 				uint8* s = src;
475 				uint8* c = crs;
476 				uint8* d = dst;
477 				for (int32 x = left; x <= right; x++) {
478 					// assumes backbuffer alpha = 255
479 					// assuming pre-multiplied cursor bitmap
480 					uint8 a = 255 - c[3];
481 					d[0] = ((s[0] * a + 255) >> 8) + c[0];
482 					d[1] = ((s[1] * a + 255) >> 8) + c[1];
483 					d[2] = ((s[2] * a + 255) >> 8) + c[2];
484 
485 					s += 4;
486 					c += 4;
487 					d += 4;
488 				}
489 				crs += crsBPR;
490 				src += srcBPR;
491 				dst += width * 4;
492 			}
493 		}
494 		// copy result to front buffer
495 		_CopyToFront(buffer, width * 4, left, top, right, bottom);
496 
497 		delete[] buffer;
498 	}
499 }
500 
501 // _CopyToFront
502 //
503 // * source is assumed to be already at the right offset
504 // * source is assumed to be in B_RGBA32 format
505 // * location in front buffer is calculated
506 // * conversion from B_RGBA32 to format of front buffer is taken care of
507 void
508 HWInterface::_CopyToFront(uint8* src, uint32 srcBPR,
509 						  int32 x, int32 y,
510 						  int32 right, int32 bottom) const
511 {
512 	RenderingBuffer* frontBuffer = FrontBuffer();
513 
514 	uint8* dst = (uint8*)frontBuffer->Bits();
515 	uint32 dstBPR = frontBuffer->BytesPerRow();
516 
517 	// transfer, handle colorspace conversion
518 	switch (frontBuffer->ColorSpace()) {
519 		case B_RGB32:
520 		case B_RGBA32: {
521 			int32 bytes = (right - x + 1) * 4;
522 
523 			if (bytes > 0) {
524 				// offset to left top pixel in dest buffer
525 				dst += y * dstBPR + x * 4;
526 				// copy
527 				for (; y <= bottom; y++) {
528 					// bytes is guaranteed to be multiple of 4
529 					gfxcpy32(dst, src, bytes);
530 					dst += dstBPR;
531 					src += srcBPR;
532 				}
533 			} else
534 printf("nothing to copy\n");
535 			break;
536 		}
537 		// NOTE: on R5, B_RGB24 bitmaps are not supported by DrawBitmap()
538 		case B_RGB24: {
539 			// offset to left top pixel in dest buffer
540 			dst += y * dstBPR + x * 3;
541 			int32 left = x;
542 			// copy
543 			for (; y <= bottom; y++) {
544 				uint8* srcHandle = src;
545 				uint8* dstHandle = dst;
546 				for (x = left; x <= right; x++) {
547 					dstHandle[0] = srcHandle[0];
548 					dstHandle[1] = srcHandle[1];
549 					dstHandle[2] = srcHandle[2];
550 					dstHandle += 3;
551 					srcHandle += 4;
552 				}
553 				dst += dstBPR;
554 				src += srcBPR;
555 			}
556 			break;
557 		}
558 		case B_RGB16: {
559 			// offset to left top pixel in dest buffer
560 			dst += y * dstBPR + x * 2;
561 			int32 left = x;
562 			// copy
563 			// TODO: assumes BGR order, does this work on big endian as well?
564 			for (; y <= bottom; y++) {
565 				uint8* srcHandle = src;
566 				uint16* dstHandle = (uint16*)dst;
567 				for (x = left; x <= right; x++) {
568 					*dstHandle = (uint16)(((srcHandle[2] & 0xf8) << 8) |
569 										  ((srcHandle[1] & 0xfc) << 3) |
570 										  (srcHandle[0] >> 3));
571 					dstHandle ++;
572 					srcHandle += 4;
573 				}
574 				dst += dstBPR;
575 				src += srcBPR;
576 			}
577 			break;
578 		}
579 		case B_RGB15: {
580 			// offset to left top pixel in dest buffer
581 			dst += y * dstBPR + x * 2;
582 			int32 left = x;
583 			// copy
584 			// TODO: assumes BGR order, does this work on big endian as well?
585 			for (; y <= bottom; y++) {
586 				uint8* srcHandle = src;
587 				uint16* dstHandle = (uint16*)dst;
588 				for (x = left; x <= right; x++) {
589 					*dstHandle = (uint16)(((srcHandle[2] & 0xf8) << 7) |
590 										  ((srcHandle[1] & 0xf8) << 2) |
591 										  (srcHandle[0] >> 3));
592 					dstHandle ++;
593 					srcHandle += 4;
594 				}
595 				dst += dstBPR;
596 				src += srcBPR;
597 			}
598 			break;
599 		}
600 		case B_CMAP8: {
601 			const color_map *colorMap = SystemColorMap();
602 			// offset to left top pixel in dest buffer
603 			dst += y * dstBPR + x;
604 			int32 left = x;
605 			uint16 index;
606 			// copy
607 			// TODO: assumes BGR order again
608 			for (; y <= bottom; y++) {
609 				uint8* srcHandle = src;
610 				uint8* dstHandle = dst;
611 				for (x = left; x <= right; x++) {
612 					index = ((srcHandle[2] & 0xf8) << 7) | ((srcHandle[1] & 0xf8) << 2) | (srcHandle[0] >> 3);
613 					*dstHandle = colorMap->index_map[index];
614 					dstHandle ++;
615 					srcHandle += 4;
616 				}
617 				dst += dstBPR;
618 				src += srcBPR;
619 			}
620 
621 			break;
622 		}
623 		case B_GRAY8: {
624 			// offset to left top pixel in dest buffer
625 			dst += y * dstBPR + x;
626 			int32 left = x;
627 			// copy
628 			// TODO: assumes BGR order, does this work on big endian as well?
629 			for (; y <= bottom; y++) {
630 				uint8* srcHandle = src;
631 				uint8* dstHandle = dst;
632 				for (x = left; x <= right; x++) {
633 					*dstHandle = (308 * srcHandle[2] + 600 * srcHandle[1] + 116 * srcHandle[0]) / 1024;
634 					dstHandle ++;
635 					srcHandle += 4;
636 				}
637 				dst += dstBPR;
638 				src += srcBPR;
639 			}
640 			break;
641 		}
642 		default:
643 			fprintf(stderr, "HWInterface::CopyBackToFront() - unsupported front buffer format!\n");
644 			break;
645 	}
646 }
647 
648 
649 // _CursorFrame
650 //
651 // PRE: the object must be locked
652 BRect
653 HWInterface::_CursorFrame() const
654 {
655 	BRect frame(0.0, 0.0, -1.0, -1.0);
656 	if (fCursorAndDragBitmap && fCursorVisible) {
657 		frame = fCursorAndDragBitmap->Bounds();
658 		frame.OffsetTo(fCursorLocation - fCursorAndDragBitmap->GetHotSpot());
659 	}
660 	return frame;
661 }
662 
663 // _RestoreCursorArea
664 void
665 HWInterface::_RestoreCursorArea() const
666 {
667 	if (fCursorAreaBackup && !fCursorAreaBackup->cursor_hidden) {
668 		_CopyToFront(fCursorAreaBackup->buffer,
669 					 fCursorAreaBackup->bpr,
670 					 fCursorAreaBackup->left,
671 					 fCursorAreaBackup->top,
672 					 fCursorAreaBackup->right,
673 					 fCursorAreaBackup->bottom);
674 
675 		fCursorAreaBackup->cursor_hidden = true;
676 	}
677 }
678 
679 // _AdoptDragBitmap
680 void
681 HWInterface::_AdoptDragBitmap(const ServerBitmap* bitmap, const BPoint& offset)
682 {
683 	// TODO: support other colorspaces/convert bitmap
684 	if (bitmap && !(bitmap->ColorSpace() == B_RGB32
685 		|| bitmap->ColorSpace() == B_RGBA32)) {
686 		fprintf(stderr, "HWInterface::_AdoptDragBitmap() - bitmap has yet unsupported colorspace\n");
687 		return;
688 	}
689 
690 	_RestoreCursorArea();
691 	BRect cursorFrame = _CursorFrame();
692 
693 	if (fCursorAndDragBitmap && fCursorAndDragBitmap != fCursor) {
694 		delete fCursorAndDragBitmap;
695 		fCursorAndDragBitmap = NULL;
696 	}
697 
698 	if (bitmap) {
699 		BRect bitmapFrame = bitmap->Bounds();
700 		if (fCursor) {
701 			// put bitmap frame and cursor frame into the same
702 			// coordinate space (the cursor location is the origin)
703 			bitmapFrame.OffsetTo(BPoint(-offset.x, -offset.y));
704 
705 			BRect cursorFrame(fCursor->Bounds());
706 			BPoint hotspot(fCursor->GetHotSpot());
707 				// the hotspot is at the origin
708 			cursorFrame.OffsetTo(-hotspot.x, -hotspot.y);
709 
710 			BRect combindedBounds = bitmapFrame | cursorFrame;
711 
712 			BPoint shift;
713 			shift.x = -combindedBounds.left;
714 			shift.y = -combindedBounds.top;
715 
716 			combindedBounds.OffsetBy(shift);
717 			cursorFrame.OffsetBy(shift);
718 			bitmapFrame.OffsetBy(shift);
719 
720 			fCursorAndDragBitmap = new ServerCursor(combindedBounds,
721 													bitmap->ColorSpace(), 0,
722 													hotspot + shift);
723 
724 			// clear the combined buffer
725 			uint8* dst = (uint8*)fCursorAndDragBitmap->Bits();
726 			uint32 dstBPR = fCursorAndDragBitmap->BytesPerRow();
727 
728 			memset(dst, 0, fCursorAndDragBitmap->BitsLength());
729 
730 			// put drag bitmap into combined buffer
731 			uint8* src = (uint8*)bitmap->Bits();
732 			uint32 srcBPR = bitmap->BytesPerRow();
733 
734 			dst += (int32)bitmapFrame.top * dstBPR + (int32)bitmapFrame.left * 4;
735 
736 			uint32 width = bitmapFrame.IntegerWidth() + 1;
737 			uint32 height = bitmapFrame.IntegerHeight() + 1;
738 
739 			for (uint32 y = 0; y < height; y++) {
740 				memcpy(dst, src, srcBPR);
741 				dst += dstBPR;
742 				src += srcBPR;
743 			}
744 
745 			// compose cursor into combined buffer
746 			dst = (uint8*)fCursorAndDragBitmap->Bits();
747 			dst += (int32)cursorFrame.top * dstBPR + (int32)cursorFrame.left * 4;
748 
749 			src = (uint8*)fCursor->Bits();
750 			srcBPR = fCursor->BytesPerRow();
751 
752 			width = cursorFrame.IntegerWidth() + 1;
753 			height = cursorFrame.IntegerHeight() + 1;
754 
755 			for (uint32 y = 0; y < height; y++) {
756 				uint8* d = dst;
757 				uint8* s = src;
758 				for (uint32 x = 0; x < width; x++) {
759 					// takes two semi-transparent pixels
760 					// with unassociated alpha (not pre-multiplied)
761 					// and stays within non-premultiplied color space
762 					if (s[3] > 0) {
763 						if (s[3] == 255) {
764 							d[0] = s[0];
765 							d[1] = s[1];
766 							d[2] = s[2];
767 							d[3] = 255;
768 						} else {
769 							uint8 alphaRest = 255 - s[3];
770 							uint32 alphaTemp = (65025 - alphaRest * (255 - d[3]));
771 							uint32 alphaDest = d[3] * alphaRest;
772 							uint32 alphaSrc = 255 * s[3];
773 							d[0] = (d[0] * alphaDest + s[0] * alphaSrc) / alphaTemp;
774 							d[1] = (d[1] * alphaDest + s[1] * alphaSrc) / alphaTemp;
775 							d[2] = (d[2] * alphaDest + s[2] * alphaSrc) / alphaTemp;
776 							d[3] = alphaTemp / 255;
777 						}
778 					}
779 					// TODO: make sure the alpha is always upside down,
780 					// then it doesn't need to be done when drawing the cursor
781 					// (see _DrawCursor())
782 //					d[3] = 255 - d[3];
783 					d += 4;
784 					s += 4;
785 				}
786 				dst += dstBPR;
787 				src += srcBPR;
788 			}
789 
790 			// handle pre-multiplication with alpha
791 			// for faster compositing during cursor drawing
792 			width = combindedBounds.IntegerWidth() + 1;
793 			height = combindedBounds.IntegerHeight() + 1;
794 
795 			dst = (uint8*)fCursorAndDragBitmap->Bits();
796 
797 			for (uint32 y = 0; y < height; y++) {
798 				uint8* d = dst;
799 				for (uint32 x = 0; x < width; x++) {
800 					d[0] = (d[0] * d[3]) >> 8;
801 					d[1] = (d[1] * d[3]) >> 8;
802 					d[2] = (d[2] * d[3]) >> 8;
803 					d += 4;
804 				}
805 				dst += dstBPR;
806 			}
807 		} else {
808 			fCursorAndDragBitmap = new ServerCursor(bitmap->Bits(),
809 													bitmapFrame.IntegerWidth() + 1,
810 													bitmapFrame.IntegerHeight() + 1,
811 													bitmap->ColorSpace());
812 			fCursorAndDragBitmap->SetHotSpot(BPoint(-offset.x, -offset.y));
813 		}
814 	} else {
815 		fCursorAndDragBitmap = fCursor;
816 	}
817 
818 	Invalidate(cursorFrame);
819 
820 // NOTE: the EventDispatcher does the reference counting stuff for us
821 // TODO: You can not simply call Release() on a ServerBitmap like you
822 // can for a ServerCursor... it could be changed, but there are linking
823 // troubles with the test environment that need to be solved than.
824 //	if (fDragBitmap)
825 //		fDragBitmap->Release();
826 	fDragBitmap = bitmap;
827 	fDragBitmapOffset = offset;
828 //	if (fDragBitmap)
829 //		fDragBitmap->Acquire();
830 
831 	delete fCursorAreaBackup;
832 	fCursorAreaBackup = NULL;
833 
834 	if (!fCursorAndDragBitmap)
835 		return;
836 
837 	if (fCursorAndDragBitmap && !IsDoubleBuffered()) {
838 		BRect cursorBounds = fCursorAndDragBitmap->Bounds();
839 		fCursorAreaBackup = new buffer_clip(cursorBounds.IntegerWidth() + 1,
840 											cursorBounds.IntegerHeight() + 1);
841 	}
842  	_DrawCursor(_CursorFrame());
843 }
844 
845 
846 
847 
848