xref: /haiku/src/servers/app/drawing/DrawingEngine.cpp (revision f2b4344867e97c3f4e742a1b4a15e6879644601a)
1 /*
2  * Copyright 2001-2009, Haiku, Inc.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Stephan Aßmus <superstippi@gmx.de>
7  */
8 
9 
10 #include "DrawingEngine.h"
11 
12 #include <Bitmap.h>
13 #include <stdio.h>
14 #include <algorithm>
15 #include <stack>
16 
17 #include "DrawState.h"
18 #include "GlyphLayoutEngine.h"
19 #include "Painter.h"
20 #include "ServerBitmap.h"
21 #include "ServerCursor.h"
22 #include "RenderingBuffer.h"
23 
24 #include "drawing_support.h"
25 
26 
27 #if DEBUG
28 #	define ASSERT_PARALLEL_LOCKED() \
29 	{ if (!IsParallelAccessLocked()) debugger("not parallel locked!"); }
30 #	define ASSERT_EXCLUSIVE_LOCKED() \
31 	{ if (!IsExclusiveAccessLocked()) debugger("not exclusive locked!"); }
32 #else
33 #	define ASSERT_PARALLEL_LOCKED()
34 #	define ASSERT_EXCLUSIVE_LOCKED()
35 #endif
36 
37 
38 static inline void
39 make_rect_valid(BRect& rect)
40 {
41 	if (rect.left > rect.right) {
42 		float temp = rect.left;
43 		rect.left = rect.right;
44 		rect.right = temp;
45 	}
46 	if (rect.top > rect.bottom) {
47 		float temp = rect.top;
48 		rect.top = rect.bottom;
49 		rect.bottom = temp;
50 	}
51 }
52 
53 
54 static inline void
55 extend_by_stroke_width(BRect& rect, float penSize)
56 {
57 	// "- 0.5" because if stroke width == 1, we don't need to extend
58 	float inset = -ceilf(penSize / 2.0 - 0.5);
59 	rect.InsetBy(inset, inset);
60 }
61 
62 
63 class AutoFloatingOverlaysHider {
64 	public:
65 		AutoFloatingOverlaysHider(HWInterface* interface, const BRect& area)
66 			:
67 			fInterface(interface),
68 			fHidden(interface->HideFloatingOverlays(area))
69 		{
70 		}
71 
72 		AutoFloatingOverlaysHider(HWInterface* interface)
73 			:
74 			fInterface(interface),
75 			fHidden(fInterface->HideFloatingOverlays())
76 		{
77 		}
78 
79 		~AutoFloatingOverlaysHider()
80 		{
81 			if (fHidden)
82 				fInterface->ShowFloatingOverlays();
83 		}
84 
85 		bool WasHidden() const
86 		{
87 			return fHidden;
88 		}
89 
90 	private:
91 		HWInterface*	fInterface;
92 		bool			fHidden;
93 
94 };
95 
96 
97 //	#pragma mark -
98 
99 
100 DrawingEngine::DrawingEngine(HWInterface* interface)
101 	:
102 	fPainter(new Painter()),
103 	fGraphicsCard(NULL),
104 	fAvailableHWAccleration(0),
105 	fSuspendSyncLevel(0),
106 	fCopyToFront(true)
107 {
108 	SetHWInterface(interface);
109 }
110 
111 
112 DrawingEngine::~DrawingEngine()
113 {
114 	SetHWInterface(NULL);
115 	delete fPainter;
116 }
117 
118 
119 // #pragma mark - locking
120 
121 
122 bool
123 DrawingEngine::LockParallelAccess()
124 {
125 	return fGraphicsCard->LockParallelAccess();
126 }
127 
128 
129 #if DEBUG
130 bool
131 DrawingEngine::IsParallelAccessLocked() const
132 {
133 	return fGraphicsCard->IsParallelAccessLocked();
134 }
135 #endif
136 
137 
138 void
139 DrawingEngine::UnlockParallelAccess()
140 {
141 	fGraphicsCard->UnlockParallelAccess();
142 }
143 
144 
145 bool
146 DrawingEngine::LockExclusiveAccess()
147 {
148 	return fGraphicsCard->LockExclusiveAccess();
149 }
150 
151 
152 bool
153 DrawingEngine::IsExclusiveAccessLocked() const
154 {
155 	return fGraphicsCard->IsExclusiveAccessLocked();
156 }
157 
158 
159 void
160 DrawingEngine::UnlockExclusiveAccess()
161 {
162 	fGraphicsCard->UnlockExclusiveAccess();
163 }
164 
165 
166 // #pragma mark -
167 
168 
169 void
170 DrawingEngine::FrameBufferChanged()
171 {
172 	if (!fGraphicsCard) {
173 		fPainter->DetachFromBuffer();
174 		fAvailableHWAccleration = 0;
175 		return;
176 	}
177 
178 	// NOTE: locking is probably bogus, since we are called
179 	// in the thread that changed the frame buffer...
180 	if (LockExclusiveAccess()) {
181 		fPainter->AttachToBuffer(fGraphicsCard->DrawingBuffer());
182 		// available HW acceleration might have changed
183 		fAvailableHWAccleration = fGraphicsCard->AvailableHWAcceleration();
184 		UnlockExclusiveAccess();
185 	}
186 }
187 
188 
189 void
190 DrawingEngine::SetHWInterface(HWInterface* interface)
191 {
192 	if (fGraphicsCard == interface)
193 		return;
194 
195 	if (fGraphicsCard)
196 		fGraphicsCard->RemoveListener(this);
197 
198 	fGraphicsCard = interface;
199 
200 	if (fGraphicsCard)
201 		fGraphicsCard->AddListener(this);
202 
203 	FrameBufferChanged();
204 }
205 
206 
207 void
208 DrawingEngine::SetCopyToFrontEnabled(bool enable)
209 {
210 	fCopyToFront = enable;
211 }
212 
213 
214 void
215 DrawingEngine::CopyToFront(/*const*/ BRegion& region)
216 {
217 	fGraphicsCard->InvalidateRegion(region);
218 }
219 
220 
221 // #pragma mark -
222 
223 
224 //! the DrawingEngine needs to be locked!
225 void
226 DrawingEngine::ConstrainClippingRegion(const BRegion* region)
227 {
228 	ASSERT_PARALLEL_LOCKED();
229 
230 	fPainter->ConstrainClipping(region);
231 }
232 
233 
234 void
235 DrawingEngine::SetDrawState(const DrawState* state, int32 xOffset,
236 	int32 yOffset)
237 {
238 	fPainter->SetDrawState(state, xOffset, yOffset);
239 }
240 
241 
242 void
243 DrawingEngine::SetHighColor(const rgb_color& color)
244 {
245 	fPainter->SetHighColor(color);
246 }
247 
248 
249 void
250 DrawingEngine::SetLowColor(const rgb_color& color)
251 {
252 	fPainter->SetLowColor(color);
253 }
254 
255 
256 void
257 DrawingEngine::SetPenSize(float size)
258 {
259 	fPainter->SetPenSize(size);
260 }
261 
262 
263 void
264 DrawingEngine::SetStrokeMode(cap_mode lineCap, join_mode joinMode,
265 	float miterLimit)
266 {
267 	fPainter->SetStrokeMode(lineCap, joinMode, miterLimit);
268 }
269 
270 
271 void
272 DrawingEngine::SetBlendingMode(source_alpha srcAlpha, alpha_function alphaFunc)
273 {
274 	fPainter->SetBlendingMode(srcAlpha, alphaFunc);
275 }
276 
277 
278 void
279 DrawingEngine::SetPattern(const struct pattern& pattern)
280 {
281 	fPainter->SetPattern(pattern, false);
282 }
283 
284 
285 void
286 DrawingEngine::SetDrawingMode(drawing_mode mode)
287 {
288 	fPainter->SetDrawingMode(mode);
289 }
290 
291 
292 void
293 DrawingEngine::SetDrawingMode(drawing_mode mode, drawing_mode& oldMode)
294 {
295 	oldMode = fPainter->DrawingMode();
296 	fPainter->SetDrawingMode(mode);
297 }
298 
299 
300 void
301 DrawingEngine::SetFont(const ServerFont& font)
302 {
303 	fPainter->SetFont(font);
304 }
305 
306 
307 void
308 DrawingEngine::SetFont(const DrawState* state)
309 {
310 	fPainter->SetFont(state);
311 }
312 
313 
314 // #pragma mark -
315 
316 
317 void
318 DrawingEngine::SuspendAutoSync()
319 {
320 	ASSERT_PARALLEL_LOCKED();
321 
322 	fSuspendSyncLevel++;
323 }
324 
325 
326 void
327 DrawingEngine::Sync()
328 {
329 	ASSERT_PARALLEL_LOCKED();
330 
331 	fSuspendSyncLevel--;
332 	if (fSuspendSyncLevel == 0)
333 		fGraphicsCard->Sync();
334 }
335 
336 
337 // #pragma mark -
338 
339 
340 // CopyRegion() does a topological sort of the rects in the
341 // region. The algorithm was suggested by Ingo Weinhold.
342 // It compares each rect with each rect and builds a tree
343 // of successors so we know the order in which they can be copied.
344 // For example, let's suppose these rects are in a BRegion:
345 //                        ************
346 //                        *    B     *
347 //                        ************
348 //      *************
349 //      *           *
350 //      *     A     ****************
351 //      *           **             *
352 //      **************             *
353 //                   *     C       *
354 //                   *             *
355 //                   *             *
356 //                   ***************
357 // When copying stuff from LEFT TO RIGHT, TOP TO BOTTOM, the
358 // result of the sort will be C, A, B. For this direction, we search
359 // for the rects that have no neighbors to their right and to their
360 // bottom, These can be copied without drawing into the area of
361 // rects yet to be copied. If you move from RIGHT TO LEFT, BOTTOM TO TOP,
362 // you go look for the ones that have no neighbors to their top and left.
363 //
364 // Here I draw some rays to illustrate LEFT TO RIGHT, TOP TO BOTTOM:
365 //                        ************
366 //                        *    B     *
367 //                        ************
368 //      *************
369 //      *           *
370 //      *     A     ****************-----------------
371 //      *           **             *
372 //      **************             *
373 //                   *     C       *
374 //                   *             *
375 //                   *             *
376 //                   ***************
377 //                   |
378 //                   |
379 //                   |
380 //                   |
381 // There are no rects in the area defined by the rays to the right
382 // and bottom of rect C, so that's the one we want to copy first
383 // (for positive x and y offsets).
384 // Since A is to the left of C and B is to the top of C, The "node"
385 // for C will point to the nodes of A and B as its "successors". Therefor,
386 // A and B will have an "indegree" of 1 for C pointing to them. C will
387 // have an "indegree" of 0, because there was no rect to which C
388 // was to the left or top of. When comparing A and B, neither is left
389 // or top from the other and in the sense that the algorithm cares about.
390 
391 // NOTE: comparison of coordinates assumes that rects don't overlap
392 // and don't share the actual edge either (as is the case in BRegions).
393 
394 struct node {
395 	node()
396 	{
397 		pointers = NULL;
398 	}
399 
400 	node(const BRect& r, int32 maxPointers)
401 	{
402 		init(r, maxPointers);
403 	}
404 
405 	~node()
406 	{
407 		delete [] pointers;
408 	}
409 
410 	void init(const BRect& r, int32 maxPointers)
411 	{
412 		rect = r;
413 		pointers = new node*[maxPointers];
414 		in_degree = 0;
415 		next_pointer = 0;
416 	}
417 
418 	void push(node* node)
419 	{
420 		pointers[next_pointer] = node;
421 		next_pointer++;
422 	}
423 
424 	node* top()
425 	{
426 		return pointers[next_pointer];
427 	}
428 
429 	node* pop()
430 	{
431 		node* ret = top();
432 		next_pointer--;
433 		return ret;
434 	}
435 
436 	BRect	rect;
437 	int32	in_degree;
438 	node**	pointers;
439 	int32	next_pointer;
440 };
441 
442 
443 static bool
444 is_left_of(const BRect& a, const BRect& b)
445 {
446 	return (a.right < b.left);
447 }
448 
449 
450 static bool
451 is_above(const BRect& a, const BRect& b)
452 {
453 	return (a.bottom < b.top);
454 }
455 
456 
457 void
458 DrawingEngine::CopyRegion(/*const*/ BRegion* region, int32 xOffset,
459 	int32 yOffset)
460 {
461 	ASSERT_PARALLEL_LOCKED();
462 
463 	BRect frame = region->Frame();
464 	frame = frame | frame.OffsetByCopy(xOffset, yOffset);
465 
466 	AutoFloatingOverlaysHider _(fGraphicsCard, frame);
467 
468 	int32 count = region->CountRects();
469 
470 	// TODO: make this step unnecessary
471 	// (by using different stack impl inside node)
472 	node nodes[count];
473 	for (int32 i= 0; i < count; i++) {
474 		nodes[i].init(region->RectAt(i), count);
475 	}
476 
477 	for (int32 i = 0; i < count; i++) {
478 		BRect a = region->RectAt(i);
479 		for (int32 k = i + 1; k < count; k++) {
480 			BRect b = region->RectAt(k);
481 			int cmp = 0;
482 			// compare horizontally
483 			if (xOffset > 0) {
484 				if (is_left_of(a, b)) {
485 					cmp -= 1;
486 				} else if (is_left_of(b, a)) {
487 					cmp += 1;
488 				}
489 			} else if (xOffset < 0) {
490 				if (is_left_of(a, b)) {
491 					cmp += 1;
492 				} else if (is_left_of(b, a)) {
493 					cmp -= 1;
494 				}
495 			}
496 			// compare vertically
497 			if (yOffset > 0) {
498 				if (is_above(a, b)) {
499 					cmp -= 1;
500 				} else if (is_above(b, a)) {
501 					cmp += 1;
502 				}
503 			} else if (yOffset < 0) {
504 				if (is_above(a, b)) {
505 					cmp += 1;
506 				} else if (is_above(b, a)) {
507 					cmp -= 1;
508 				}
509 			}
510 			// add appropriate node as successor
511 			if (cmp > 0) {
512 				nodes[i].push(&nodes[k]);
513 				nodes[k].in_degree++;
514 			} else if (cmp < 0) {
515 				nodes[k].push(&nodes[i]);
516 				nodes[i].in_degree++;
517 			}
518 		}
519 	}
520 	// put all nodes onto a stack that have an "indegree" count of zero
521 	std::stack<node*> inDegreeZeroNodes;
522 	for (int32 i = 0; i < count; i++) {
523 		if (nodes[i].in_degree == 0) {
524 			inDegreeZeroNodes.push(&nodes[i]);
525 		}
526 	}
527 	// pop the rects from the stack, do the actual copy operation
528 	// and decrease the "indegree" count of the other rects not
529 	// currently on the stack and to which the current rect pointed
530 	// to. If their "indegree" count reaches zero, put them onto the
531 	// stack as well.
532 
533 	clipping_rect* sortedRectList = NULL;
534 	int32 nextSortedIndex = 0;
535 
536 	if (fAvailableHWAccleration & HW_ACC_COPY_REGION)
537 		sortedRectList = new clipping_rect[count];
538 
539 	while (!inDegreeZeroNodes.empty()) {
540 		node* n = inDegreeZeroNodes.top();
541 		inDegreeZeroNodes.pop();
542 
543 		// do the software implementation or add to sorted
544 		// rect list for using the HW accelerated version
545 		// later
546 		if (sortedRectList) {
547 			sortedRectList[nextSortedIndex].left	= (int32)n->rect.left;
548 			sortedRectList[nextSortedIndex].top		= (int32)n->rect.top;
549 			sortedRectList[nextSortedIndex].right	= (int32)n->rect.right;
550 			sortedRectList[nextSortedIndex].bottom	= (int32)n->rect.bottom;
551 			nextSortedIndex++;
552 		} else {
553 			BRect touched = CopyRect(n->rect, xOffset, yOffset);
554 			fGraphicsCard->Invalidate(touched);
555 		}
556 
557 		for (int32 k = 0; k < n->next_pointer; k++) {
558 			n->pointers[k]->in_degree--;
559 			if (n->pointers[k]->in_degree == 0)
560 				inDegreeZeroNodes.push(n->pointers[k]);
561 		}
562 	}
563 
564 	// trigger the HW accelerated version if it was available
565 	if (sortedRectList) {
566 		fGraphicsCard->CopyRegion(sortedRectList, count, xOffset, yOffset);
567 		if (fGraphicsCard->IsDoubleBuffered()) {
568 			fGraphicsCard->Invalidate(
569 				region->Frame().OffsetByCopy(xOffset, yOffset));
570 		}
571 	}
572 
573 	delete[] sortedRectList;
574 }
575 
576 
577 void
578 DrawingEngine::InvertRect(BRect r)
579 {
580 	ASSERT_PARALLEL_LOCKED();
581 
582 	make_rect_valid(r);
583 	r = fPainter->ClipRect(r);
584 	if (!r.IsValid())
585 		return;
586 
587 	AutoFloatingOverlaysHider _(fGraphicsCard, r);
588 
589 	// try hardware optimized version first
590 	if (fAvailableHWAccleration & HW_ACC_INVERT_REGION) {
591 		BRegion region(r);
592 		region.IntersectWith(fPainter->ClippingRegion());
593 		fGraphicsCard->InvertRegion(region);
594 	} else {
595 		fPainter->InvertRect(r);
596 	}
597 
598 	_CopyToFront(r);
599 }
600 
601 
602 void
603 DrawingEngine::DrawBitmap(ServerBitmap* bitmap, const BRect& bitmapRect,
604 	const BRect& viewRect, uint32 options)
605 {
606 	ASSERT_PARALLEL_LOCKED();
607 
608 	BRect clipped = fPainter->ClipRect(viewRect);
609 	if (clipped.IsValid()) {
610 		AutoFloatingOverlaysHider _(fGraphicsCard, clipped);
611 
612 		fPainter->DrawBitmap(bitmap, bitmapRect, viewRect, options);
613 
614 		_CopyToFront(clipped);
615 	}
616 }
617 
618 
619 void
620 DrawingEngine::DrawArc(BRect r, const float& angle, const float& span,
621 	bool filled)
622 {
623 	ASSERT_PARALLEL_LOCKED();
624 
625 	make_rect_valid(r);
626 	fPainter->AlignEllipseRect(&r, filled);
627 	BRect clipped(r);
628 
629 	if (!filled)
630 		extend_by_stroke_width(clipped, fPainter->PenSize());
631 
632 	clipped = fPainter->ClipRect(r);
633 
634 	if (clipped.IsValid()) {
635 		AutoFloatingOverlaysHider _(fGraphicsCard, clipped);
636 
637 		float xRadius = r.Width() / 2.0;
638 		float yRadius = r.Height() / 2.0;
639 		BPoint center(r.left + xRadius,
640 					  r.top + yRadius);
641 
642 		if (filled)
643 			fPainter->FillArc(center, xRadius, yRadius, angle, span);
644 		else
645 			fPainter->StrokeArc(center, xRadius, yRadius, angle, span);
646 
647 		_CopyToFront(clipped);
648 	}
649 }
650 
651 
652 void
653 DrawingEngine::FillArc(BRect r, const float& angle, const float& span,
654 	const BGradient& gradient)
655 {
656 	ASSERT_PARALLEL_LOCKED();
657 
658 	make_rect_valid(r);
659 	fPainter->AlignEllipseRect(&r, true);
660 	BRect clipped(r);
661 
662 	clipped = fPainter->ClipRect(r);
663 
664 	if (clipped.IsValid()) {
665 		AutoFloatingOverlaysHider _(fGraphicsCard, clipped);
666 
667 		float xRadius = r.Width() / 2.0;
668 		float yRadius = r.Height() / 2.0;
669 		BPoint center(r.left + xRadius,
670 					  r.top + yRadius);
671 
672 		fPainter->FillArc(center, xRadius, yRadius, angle, span, gradient);
673 
674 		_CopyToFront(clipped);
675 	}
676 }
677 
678 
679 void
680 DrawingEngine::DrawBezier(BPoint* pts, bool filled)
681 {
682 	ASSERT_PARALLEL_LOCKED();
683 
684 	// TODO: figure out bounds and hide cursor depending on that
685 	AutoFloatingOverlaysHider _(fGraphicsCard);
686 
687 	BRect touched = fPainter->DrawBezier(pts, filled);
688 
689 	_CopyToFront(touched);
690 }
691 
692 
693 void
694 DrawingEngine::FillBezier(BPoint* pts, const BGradient& gradient)
695 {
696 	ASSERT_PARALLEL_LOCKED();
697 
698 	// TODO: figure out bounds and hide cursor depending on that
699 	AutoFloatingOverlaysHider _(fGraphicsCard);
700 
701 	BRect touched = fPainter->FillBezier(pts, gradient);
702 
703 	_CopyToFront(touched);
704 }
705 
706 
707 void
708 DrawingEngine::DrawEllipse(BRect r, bool filled)
709 {
710 	ASSERT_PARALLEL_LOCKED();
711 
712 	make_rect_valid(r);
713 	BRect clipped = r;
714 	fPainter->AlignEllipseRect(&clipped, filled);
715 
716 	if (!filled)
717 		extend_by_stroke_width(clipped, fPainter->PenSize());
718 
719 	clipped.left = floorf(clipped.left);
720 	clipped.top = floorf(clipped.top);
721 	clipped.right = ceilf(clipped.right);
722 	clipped.bottom = ceilf(clipped.bottom);
723 
724 	clipped = fPainter->ClipRect(clipped);
725 
726 	if (clipped.IsValid()) {
727 		AutoFloatingOverlaysHider _(fGraphicsCard, clipped);
728 
729 		fPainter->DrawEllipse(r, filled);
730 
731 		_CopyToFront(clipped);
732 	}
733 }
734 
735 
736 void
737 DrawingEngine::FillEllipse(BRect r, const BGradient& gradient)
738 {
739 	ASSERT_PARALLEL_LOCKED();
740 
741 	make_rect_valid(r);
742 	BRect clipped = r;
743 	fPainter->AlignEllipseRect(&clipped, true);
744 
745 	clipped.left = floorf(clipped.left);
746 	clipped.top = floorf(clipped.top);
747 	clipped.right = ceilf(clipped.right);
748 	clipped.bottom = ceilf(clipped.bottom);
749 
750 	clipped = fPainter->ClipRect(clipped);
751 
752 	if (clipped.IsValid()) {
753 		AutoFloatingOverlaysHider _(fGraphicsCard, clipped);
754 
755 		fPainter->FillEllipse(r, gradient);
756 
757 		_CopyToFront(clipped);
758 	}
759 }
760 
761 
762 void
763 DrawingEngine::DrawPolygon(BPoint* ptlist, int32 numpts, BRect bounds,
764 	bool filled, bool closed)
765 {
766 	ASSERT_PARALLEL_LOCKED();
767 
768 	make_rect_valid(bounds);
769 	if (!filled)
770 		extend_by_stroke_width(bounds, fPainter->PenSize());
771 	bounds = fPainter->ClipRect(bounds);
772 	if (bounds.IsValid()) {
773 		AutoFloatingOverlaysHider _(fGraphicsCard, bounds);
774 
775 		fPainter->DrawPolygon(ptlist, numpts, filled, closed);
776 
777 		_CopyToFront(bounds);
778 	}
779 }
780 
781 
782 void
783 DrawingEngine::FillPolygon(BPoint* ptlist, int32 numpts, BRect bounds,
784 	const BGradient& gradient, bool closed)
785 {
786 	ASSERT_PARALLEL_LOCKED();
787 
788 	make_rect_valid(bounds);
789 	bounds = fPainter->ClipRect(bounds);
790 	if (bounds.IsValid()) {
791 		AutoFloatingOverlaysHider _(fGraphicsCard, bounds);
792 
793 		fPainter->FillPolygon(ptlist, numpts, gradient, closed);
794 
795 		_CopyToFront(bounds);
796 	}
797 }
798 
799 
800 // #pragma mark - rgb_color
801 
802 
803 void
804 DrawingEngine::StrokePoint(const BPoint& pt, const rgb_color& color)
805 {
806 	StrokeLine(pt, pt, color);
807 }
808 
809 
810 /*!	This function is only used by Decorators,
811 	it assumes a one pixel wide line
812 */
813 void
814 DrawingEngine::StrokeLine(const BPoint& start, const BPoint& end,
815 	const rgb_color& color)
816 {
817 	ASSERT_PARALLEL_LOCKED();
818 
819 	BRect touched(start, end);
820 	make_rect_valid(touched);
821 	touched = fPainter->ClipRect(touched);
822 	AutoFloatingOverlaysHider _(fGraphicsCard, touched);
823 
824 	if (!fPainter->StraightLine(start, end, color)) {
825 		rgb_color previousColor = fPainter->HighColor();
826 		drawing_mode previousMode = fPainter->DrawingMode();
827 
828 		fPainter->SetHighColor(color);
829 		fPainter->SetDrawingMode(B_OP_OVER);
830 		fPainter->StrokeLine(start, end);
831 
832 		fPainter->SetDrawingMode(previousMode);
833 		fPainter->SetHighColor(previousColor);
834 	}
835 
836 	_CopyToFront(touched);
837 }
838 
839 
840 //!	This function is used to draw a one pixel wide rect
841 void
842 DrawingEngine::StrokeRect(BRect r, const rgb_color& color)
843 {
844 	ASSERT_PARALLEL_LOCKED();
845 
846 	make_rect_valid(r);
847 	BRect clipped = fPainter->ClipRect(r);
848 	if (clipped.IsValid()) {
849 		AutoFloatingOverlaysHider _(fGraphicsCard, clipped);
850 
851 		fPainter->StrokeRect(r, color);
852 
853 		_CopyToFront(clipped);
854 	}
855 }
856 
857 
858 void
859 DrawingEngine::FillRect(BRect r, const rgb_color& color)
860 {
861 	ASSERT_PARALLEL_LOCKED();
862 
863 	// NOTE: Write locking because we might use HW acceleration.
864 	// This needs to be investigated, I'm doing this because of
865 	// gut feeling.
866 	make_rect_valid(r);
867 	r = fPainter->ClipRect(r);
868 	if (!r.IsValid())
869 		return;
870 
871 	AutoFloatingOverlaysHider overlaysHider(fGraphicsCard, r);
872 
873 	// try hardware optimized version first
874 	if (fAvailableHWAccleration & HW_ACC_FILL_REGION) {
875 		BRegion region(r);
876 		region.IntersectWith(fPainter->ClippingRegion());
877 		fGraphicsCard->FillRegion(region, color,
878 			fSuspendSyncLevel == 0 || overlaysHider.WasHidden());
879 	} else {
880 		fPainter->FillRect(r, color);
881 	}
882 
883 	_CopyToFront(r);
884 }
885 
886 
887 void
888 DrawingEngine::FillRegion(BRegion& r, const rgb_color& color)
889 {
890 	ASSERT_PARALLEL_LOCKED();
891 
892 	// NOTE: region expected to be already clipped correctly!!
893 	BRect frame = r.Frame();
894 	if (!fPainter->Bounds().Contains(frame)) {
895 		// NOTE: I am not quite sure yet how this can happen, but apparently it
896 		// can (see bug #634).
897 		// This function is used for internal app_server painting, in the case of
898 		// bug #634, the background of views is painted. But the view region
899 		// should never be outside the frame buffer bounds.
900 //		char message[1024];
901 //		BRect bounds = fPainter->Bounds();
902 //		sprintf(message, "FillRegion() - painter: (%d, %d)->(%d, %d), region: (%d, %d)->(%d, %d)",
903 //			(int)bounds.left, (int)bounds.top, (int)bounds.right, (int)bounds.bottom,
904 //			(int)frame.left, (int)frame.top, (int)frame.right, (int)frame.bottom);
905 //		debugger(message);
906 		return;
907 	}
908 
909 	AutoFloatingOverlaysHider overlaysHider(fGraphicsCard, frame);
910 
911 	// try hardware optimized version first
912 	if ((fAvailableHWAccleration & HW_ACC_FILL_REGION) != 0
913 		&& frame.Width() * frame.Height() > 100) {
914 		fGraphicsCard->FillRegion(r, color, fSuspendSyncLevel == 0
915 			|| overlaysHider.WasHidden());
916 	} else {
917 		int32 count = r.CountRects();
918 		for (int32 i = 0; i < count; i++)
919 			fPainter->FillRectNoClipping(r.RectAtInt(i), color);
920 	}
921 
922 	_CopyToFront(frame);
923 }
924 
925 
926 // #pragma mark - DrawState
927 
928 
929 void
930 DrawingEngine::StrokeRect(BRect r)
931 {
932 	ASSERT_PARALLEL_LOCKED();
933 
934 	// support invalid rects
935 	make_rect_valid(r);
936 	BRect clipped(r);
937 	extend_by_stroke_width(clipped, fPainter->PenSize());
938 	clipped = fPainter->ClipRect(clipped);
939 	if (clipped.IsValid()) {
940 		AutoFloatingOverlaysHider _(fGraphicsCard, clipped);
941 
942 		fPainter->StrokeRect(r);
943 
944 		_CopyToFront(clipped);
945 	}
946 }
947 
948 
949 void
950 DrawingEngine::FillRect(BRect r)
951 {
952 	ASSERT_PARALLEL_LOCKED();
953 
954 	make_rect_valid(r);
955 	r = fPainter->AlignAndClipRect(r);
956 	if (!r.IsValid())
957 		return;
958 
959 	AutoFloatingOverlaysHider overlaysHider(fGraphicsCard, r);
960 
961 	bool doInSoftware = true;
962 	if ((r.Width() + 1) * (r.Height() + 1) > 100.0) {
963 		// try hardware optimized version first
964 		// if the rect is large enough
965 		if ((fAvailableHWAccleration & HW_ACC_FILL_REGION) != 0) {
966 			if (fPainter->Pattern() == B_SOLID_HIGH
967 				&& (fPainter->DrawingMode() == B_OP_COPY
968 					|| fPainter->DrawingMode() == B_OP_OVER)) {
969 				BRegion region(r);
970 				region.IntersectWith(fPainter->ClippingRegion());
971 				fGraphicsCard->FillRegion(region, fPainter->HighColor(),
972 					fSuspendSyncLevel == 0 || overlaysHider.WasHidden());
973 				doInSoftware = false;
974 			} else if (fPainter->Pattern() == B_SOLID_LOW
975 					&& fPainter->DrawingMode() == B_OP_COPY) {
976 				BRegion region(r);
977 				region.IntersectWith(fPainter->ClippingRegion());
978 				fGraphicsCard->FillRegion(region, fPainter->LowColor(),
979 					fSuspendSyncLevel == 0 || overlaysHider.WasHidden());
980 				doInSoftware = false;
981 			}
982 		}
983 	}
984 
985 	if (doInSoftware && (fAvailableHWAccleration & HW_ACC_INVERT_REGION) != 0
986 		&& fPainter->Pattern() == B_SOLID_HIGH
987 		&& fPainter->DrawingMode() == B_OP_INVERT) {
988 		BRegion region(r);
989 		region.IntersectWith(fPainter->ClippingRegion());
990 		fGraphicsCard->InvertRegion(region);
991 		doInSoftware = false;
992 	}
993 
994 	if (doInSoftware)
995 		fPainter->FillRect(r);
996 
997 	_CopyToFront(r);
998 }
999 
1000 
1001 void
1002 DrawingEngine::FillRect(BRect r, const BGradient& gradient)
1003 {
1004 	ASSERT_PARALLEL_LOCKED();
1005 
1006 	make_rect_valid(r);
1007 	r = fPainter->AlignAndClipRect(r);
1008 	if (!r.IsValid())
1009 		return;
1010 
1011 	AutoFloatingOverlaysHider overlaysHider(fGraphicsCard, r);
1012 
1013 	fPainter->FillRect(r, gradient);
1014 
1015 	_CopyToFront(r);
1016 }
1017 
1018 
1019 void
1020 DrawingEngine::FillRegion(BRegion& r)
1021 {
1022 	ASSERT_PARALLEL_LOCKED();
1023 
1024 	BRect clipped = fPainter->ClipRect(r.Frame());
1025 	if (!clipped.IsValid())
1026 		return;
1027 
1028 	AutoFloatingOverlaysHider overlaysHider(fGraphicsCard, clipped);
1029 
1030 	bool doInSoftware = true;
1031 	// try hardware optimized version first
1032 	if ((fAvailableHWAccleration & HW_ACC_FILL_REGION) != 0) {
1033 		if (fPainter->Pattern() == B_SOLID_HIGH
1034 			&& (fPainter->DrawingMode() == B_OP_COPY
1035 				|| fPainter->DrawingMode() == B_OP_OVER)) {
1036 			r.IntersectWith(fPainter->ClippingRegion());
1037 			fGraphicsCard->FillRegion(r, fPainter->HighColor(),
1038 				fSuspendSyncLevel == 0 || overlaysHider.WasHidden());
1039 			doInSoftware = false;
1040 		} else if (fPainter->Pattern() == B_SOLID_LOW
1041 			&& fPainter->DrawingMode() == B_OP_COPY) {
1042 			r.IntersectWith(fPainter->ClippingRegion());
1043 			fGraphicsCard->FillRegion(r, fPainter->LowColor(),
1044 				fSuspendSyncLevel == 0 || overlaysHider.WasHidden());
1045 			doInSoftware = false;
1046 		}
1047 	}
1048 
1049 	if (doInSoftware && (fAvailableHWAccleration & HW_ACC_INVERT_REGION) != 0
1050 		&& fPainter->Pattern() == B_SOLID_HIGH
1051 		&& fPainter->DrawingMode() == B_OP_INVERT) {
1052 		r.IntersectWith(fPainter->ClippingRegion());
1053 		fGraphicsCard->InvertRegion(r);
1054 		doInSoftware = false;
1055 	}
1056 
1057 	if (doInSoftware) {
1058 		BRect touched = fPainter->FillRect(r.RectAt(0));
1059 
1060 		int32 count = r.CountRects();
1061 		for (int32 i = 1; i < count; i++)
1062 			touched = touched | fPainter->FillRect(r.RectAt(i));
1063 	}
1064 
1065 	_CopyToFront(r.Frame());
1066 }
1067 
1068 
1069 void
1070 DrawingEngine::FillRegion(BRegion& r, const BGradient& gradient)
1071 {
1072 	ASSERT_PARALLEL_LOCKED();
1073 
1074 	BRect clipped = fPainter->ClipRect(r.Frame());
1075 	if (!clipped.IsValid())
1076 		return;
1077 
1078 	AutoFloatingOverlaysHider overlaysHider(fGraphicsCard, clipped);
1079 
1080 	BRect touched = fPainter->FillRect(r.RectAt(0), gradient);
1081 
1082 	int32 count = r.CountRects();
1083 	for (int32 i = 1; i < count; i++)
1084 		touched = touched | fPainter->FillRect(r.RectAt(i), gradient);
1085 
1086 	_CopyToFront(r.Frame());
1087 }
1088 
1089 
1090 void
1091 DrawingEngine::DrawRoundRect(BRect r, float xrad, float yrad, bool filled)
1092 {
1093 	ASSERT_PARALLEL_LOCKED();
1094 
1095 	// NOTE: the stroke does not extend past "r" in R5,
1096 	// though I consider this unexpected behaviour.
1097 	make_rect_valid(r);
1098 	BRect clipped = fPainter->ClipRect(r);
1099 
1100 	clipped.left = floorf(clipped.left);
1101 	clipped.top = floorf(clipped.top);
1102 	clipped.right = ceilf(clipped.right);
1103 	clipped.bottom = ceilf(clipped.bottom);
1104 
1105 	if (clipped.IsValid()) {
1106 		AutoFloatingOverlaysHider _(fGraphicsCard, clipped);
1107 
1108 		BRect touched = filled ? fPainter->FillRoundRect(r, xrad, yrad)
1109 			: fPainter->StrokeRoundRect(r, xrad, yrad);
1110 
1111 		_CopyToFront(touched);
1112 	}
1113 }
1114 
1115 
1116 void
1117 DrawingEngine::FillRoundRect(BRect r, float xrad, float yrad,
1118 	const BGradient& gradient)
1119 {
1120 	ASSERT_PARALLEL_LOCKED();
1121 
1122 	// NOTE: the stroke does not extend past "r" in R5,
1123 	// though I consider this unexpected behaviour.
1124 	make_rect_valid(r);
1125 	BRect clipped = fPainter->ClipRect(r);
1126 
1127 	clipped.left = floorf(clipped.left);
1128 	clipped.top = floorf(clipped.top);
1129 	clipped.right = ceilf(clipped.right);
1130 	clipped.bottom = ceilf(clipped.bottom);
1131 
1132 	if (clipped.IsValid()) {
1133 		AutoFloatingOverlaysHider _(fGraphicsCard, clipped);
1134 
1135 		BRect touched = fPainter->FillRoundRect(r, xrad, yrad, gradient);
1136 
1137 		_CopyToFront(touched);
1138 	}
1139 }
1140 
1141 
1142 void
1143 DrawingEngine::DrawShape(const BRect& bounds, int32 opCount,
1144 	const uint32* opList, int32 ptCount, const BPoint* ptList, bool filled,
1145 	const BPoint& viewToScreenOffset, float viewScale)
1146 {
1147 	ASSERT_PARALLEL_LOCKED();
1148 
1149 // TODO: bounds probably does not take curves and arcs into account...
1150 //	BRect clipped(bounds);
1151 //	if (!filled)
1152 //		extend_by_stroke_width(clipped, fPainter->PenSize());
1153 //	clipped = fPainter->ClipRect(bounds);
1154 //
1155 //	clipped.left = floorf(clipped.left);
1156 //	clipped.top = floorf(clipped.top);
1157 //	clipped.right = ceilf(clipped.right);
1158 //	clipped.bottom = ceilf(clipped.bottom);
1159 //
1160 //	if (!clipped.IsValid())
1161 //		return;
1162 //
1163 //	AutoFloatingOverlaysHider _(fGraphicsCard, clipped);
1164 	AutoFloatingOverlaysHider _(fGraphicsCard);
1165 
1166 	BRect touched = fPainter->DrawShape(opCount, opList, ptCount, ptList,
1167 		filled, viewToScreenOffset, viewScale);
1168 
1169 	_CopyToFront(touched);
1170 }
1171 
1172 
1173 void
1174 DrawingEngine::FillShape(const BRect& bounds, int32 opCount,
1175 	const uint32* opList, int32 ptCount, const BPoint* ptList,
1176 	const BGradient& gradient, const BPoint& viewToScreenOffset,
1177 	float viewScale)
1178 {
1179 	ASSERT_PARALLEL_LOCKED();
1180 
1181 // TODO: bounds probably does not take curves and arcs into account...
1182 //	BRect clipped = fPainter->ClipRect(bounds);
1183 //
1184 //	clipped.left = floorf(clipped.left);
1185 //	clipped.top = floorf(clipped.top);
1186 //	clipped.right = ceilf(clipped.right);
1187 //	clipped.bottom = ceilf(clipped.bottom);
1188 //
1189 //	if (!clipped.IsValid())
1190 //		return;
1191 //
1192 //	AutoFloatingOverlaysHider _(fGraphicsCard, clipped);
1193 	AutoFloatingOverlaysHider _(fGraphicsCard);
1194 
1195 	BRect touched = fPainter->FillShape(opCount, opList, ptCount, ptList,
1196 		gradient, viewToScreenOffset, viewScale);
1197 
1198 	_CopyToFront(touched);
1199 }
1200 
1201 
1202 void
1203 DrawingEngine::DrawTriangle(BPoint* pts, const BRect& bounds, bool filled)
1204 {
1205 	ASSERT_PARALLEL_LOCKED();
1206 
1207 	BRect clipped(bounds);
1208 	if (!filled)
1209 		extend_by_stroke_width(clipped, fPainter->PenSize());
1210 	clipped = fPainter->ClipRect(clipped);
1211 	if (clipped.IsValid()) {
1212 		AutoFloatingOverlaysHider _(fGraphicsCard, clipped);
1213 
1214 		if (filled)
1215 			fPainter->FillTriangle(pts[0], pts[1], pts[2]);
1216 		else
1217 			fPainter->StrokeTriangle(pts[0], pts[1], pts[2]);
1218 
1219 		_CopyToFront(clipped);
1220 	}
1221 }
1222 
1223 
1224 void
1225 DrawingEngine::FillTriangle(BPoint* pts, const BRect& bounds,
1226 	const BGradient& gradient)
1227 {
1228 	ASSERT_PARALLEL_LOCKED();
1229 
1230 	BRect clipped(bounds);
1231 	clipped = fPainter->ClipRect(clipped);
1232 	if (clipped.IsValid()) {
1233 		AutoFloatingOverlaysHider _(fGraphicsCard, clipped);
1234 
1235 		fPainter->FillTriangle(pts[0], pts[1], pts[2], gradient);
1236 
1237 		_CopyToFront(clipped);
1238 	}
1239 }
1240 
1241 
1242 void
1243 DrawingEngine::StrokeLine(const BPoint& start, const BPoint& end)
1244 {
1245 	ASSERT_PARALLEL_LOCKED();
1246 
1247 	BRect touched(start, end);
1248 	make_rect_valid(touched);
1249 	extend_by_stroke_width(touched, fPainter->PenSize());
1250 	touched = fPainter->ClipRect(touched);
1251 	if (touched.IsValid()) {
1252 		AutoFloatingOverlaysHider _(fGraphicsCard, touched);
1253 
1254 		fPainter->StrokeLine(start, end);
1255 
1256 		_CopyToFront(touched);
1257 	}
1258 }
1259 
1260 
1261 void
1262 DrawingEngine::StrokeLineArray(int32 numLines,
1263 	const ViewLineArrayInfo *lineData)
1264 {
1265 	ASSERT_PARALLEL_LOCKED();
1266 
1267 	if (!lineData || numLines <= 0)
1268 		return;
1269 
1270 	// figure out bounding box for line array
1271 	const ViewLineArrayInfo* data = (const ViewLineArrayInfo*)&lineData[0];
1272 	BRect touched(min_c(data->startPoint.x, data->endPoint.x),
1273 		min_c(data->startPoint.y, data->endPoint.y),
1274 		max_c(data->startPoint.x, data->endPoint.x),
1275 		max_c(data->startPoint.y, data->endPoint.y));
1276 
1277 	for (int32 i = 1; i < numLines; i++) {
1278 		data = (const ViewLineArrayInfo*)&lineData[i];
1279 		BRect box(min_c(data->startPoint.x, data->endPoint.x),
1280 			min_c(data->startPoint.y, data->endPoint.y),
1281 			max_c(data->startPoint.x, data->endPoint.x),
1282 			max_c(data->startPoint.y, data->endPoint.y));
1283 		touched = touched | box;
1284 	}
1285 	extend_by_stroke_width(touched, fPainter->PenSize());
1286 	touched = fPainter->ClipRect(touched);
1287 	if (touched.IsValid()) {
1288 		AutoFloatingOverlaysHider _(fGraphicsCard, touched);
1289 
1290 		data = (const ViewLineArrayInfo*)&(lineData[0]);
1291 
1292 		// store current graphics state, we mess with the
1293 		// high color and pattern...
1294 		rgb_color oldColor = fPainter->HighColor();
1295 		struct pattern pattern = fPainter->Pattern();
1296 
1297 		fPainter->SetHighColor(data->color);
1298 		fPainter->SetPattern(B_SOLID_HIGH);
1299 		fPainter->StrokeLine(data->startPoint, data->endPoint);
1300 
1301 		for (int32 i = 1; i < numLines; i++) {
1302 			data = (const ViewLineArrayInfo*)&(lineData[i]);
1303 			fPainter->SetHighColor(data->color);
1304 			fPainter->StrokeLine(data->startPoint, data->endPoint);
1305 		}
1306 
1307 		// restore correct drawing state highcolor and pattern
1308 		fPainter->SetHighColor(oldColor);
1309 		fPainter->SetPattern(pattern);
1310 
1311 		_CopyToFront(touched);
1312 	}
1313 }
1314 
1315 
1316 // #pragma mark -
1317 
1318 
1319 BPoint
1320 DrawingEngine::DrawString(const char* string, int32 length,
1321 	const BPoint& pt, escapement_delta* delta)
1322 {
1323 	ASSERT_PARALLEL_LOCKED();
1324 
1325 	BPoint penLocation = pt;
1326 
1327 	// try a fast clipping path
1328 	if (fPainter->ClippingRegion() && fPainter->Font().Rotation() == 0.0f) {
1329 		float fontSize = fPainter->Font().Size();
1330 		BRect clippingFrame = fPainter->ClippingRegion()->Frame();
1331 		if (pt.x - fontSize > clippingFrame.right
1332 			|| pt.y + fontSize < clippingFrame.top
1333 			|| pt.y - fontSize > clippingFrame.bottom) {
1334 			penLocation.x += StringWidth(string, length, delta);
1335 			return penLocation;
1336 		}
1337 	}
1338 
1339 	// use a FontCacheRefernece to speed up the second pass of
1340 	// drawing the string
1341 	FontCacheReference cacheReference;
1342 
1343 //bigtime_t now = system_time();
1344 // TODO: BoundingBox is quite slow!! Optimizing it will be beneficial.
1345 // Cursiously, the DrawString after it is actually faster!?!
1346 // TODO: make the availability of the hardware cursor part of the
1347 // HW acceleration flags and skip all calculations for HideFloatingOverlays
1348 // in case we don't have one.
1349 // TODO: Watch out about penLocation and use Painter::PenLocation() when
1350 // not using BoundindBox anymore.
1351 	BRect b = fPainter->BoundingBox(string, length, pt, &penLocation, delta,
1352 		&cacheReference);
1353 	// stop here if we're supposed to render outside of the clipping
1354 	b = fPainter->ClipRect(b);
1355 	if (b.IsValid()) {
1356 //printf("bounding box '%s': %lld µs\n", string, system_time() - now);
1357 		AutoFloatingOverlaysHider _(fGraphicsCard, b);
1358 
1359 //now = system_time();
1360 		BRect touched = fPainter->DrawString(string, length, pt, delta,
1361 			&cacheReference);
1362 //printf("drawing string: %lld µs\n", system_time() - now);
1363 
1364 		_CopyToFront(touched);
1365 	}
1366 
1367 	return penLocation;
1368 }
1369 
1370 
1371 BPoint
1372 DrawingEngine::DrawString(const char* string, int32 length,
1373 	const BPoint* offsets)
1374 {
1375 	ASSERT_PARALLEL_LOCKED();
1376 
1377 	// use a FontCacheRefernece to speed up the second pass of
1378 	// drawing the string
1379 	FontCacheReference cacheReference;
1380 
1381 	BPoint penLocation;
1382 	BRect b = fPainter->BoundingBox(string, length, offsets, &penLocation,
1383 		&cacheReference);
1384 	// stop here if we're supposed to render outside of the clipping
1385 	b = fPainter->ClipRect(b);
1386 	if (b.IsValid()) {
1387 //printf("bounding box '%s': %lld µs\n", string, system_time() - now);
1388 		AutoFloatingOverlaysHider _(fGraphicsCard, b);
1389 
1390 //now = system_time();
1391 		BRect touched = fPainter->DrawString(string, length, offsets,
1392 			&cacheReference);
1393 //printf("drawing string: %lld µs\n", system_time() - now);
1394 
1395 		_CopyToFront(touched);
1396 	}
1397 
1398 	return penLocation;
1399 }
1400 
1401 
1402 float
1403 DrawingEngine::StringWidth(const char* string, int32 length,
1404 	escapement_delta* delta)
1405 {
1406 	return fPainter->StringWidth(string, length, delta);
1407 }
1408 
1409 
1410 float
1411 DrawingEngine::StringWidth(const char* string, int32 length,
1412 	const ServerFont& font, escapement_delta* delta)
1413 {
1414 	return font.StringWidth(string, length, delta);
1415 }
1416 
1417 
1418 // #pragma mark -
1419 
1420 
1421 ServerBitmap*
1422 DrawingEngine::DumpToBitmap()
1423 {
1424 	return NULL;
1425 }
1426 
1427 
1428 status_t
1429 DrawingEngine::ReadBitmap(ServerBitmap* bitmap, bool drawCursor, BRect bounds)
1430 {
1431 	ASSERT_EXCLUSIVE_LOCKED();
1432 
1433 	RenderingBuffer* buffer = fGraphicsCard->FrontBuffer();
1434 	if (buffer == NULL)
1435 		return B_ERROR;
1436 
1437 	BRect clip(0, 0, buffer->Width() - 1, buffer->Height() - 1);
1438 	bounds = bounds & clip;
1439 	AutoFloatingOverlaysHider _(fGraphicsCard, bounds);
1440 
1441 	status_t result = bitmap->ImportBits(buffer->Bits(), buffer->BitsLength(),
1442 		buffer->BytesPerRow(), buffer->ColorSpace(),
1443 		bounds.LeftTop(), BPoint(0, 0),
1444 		bounds.IntegerWidth() + 1, bounds.IntegerHeight() + 1);
1445 
1446 	if (drawCursor) {
1447 		ServerCursorReference cursorRef = fGraphicsCard->Cursor();
1448 		ServerCursor* cursor = cursorRef.Get();
1449 		if (!cursor)
1450 			return result;
1451 		int32 cursorWidth = cursor->Width();
1452 		int32 cursorHeight = cursor->Height();
1453 
1454 		BPoint cursorPosition = fGraphicsCard->CursorPosition();
1455 		cursorPosition -= bounds.LeftTop() + cursor->GetHotSpot();
1456 
1457 		BBitmap cursorArea(BRect(0, 0, cursorWidth - 1, cursorHeight - 1),
1458 			B_BITMAP_NO_SERVER_LINK, B_RGBA32);
1459 
1460 		cursorArea.ImportBits(bitmap->Bits(), bitmap->BitsLength(),
1461 			bitmap->BytesPerRow(), bitmap->ColorSpace(),
1462 			cursorPosition,	BPoint(0, 0),
1463 			cursorWidth, cursorHeight);
1464 
1465 		uint8* bits = (uint8*)cursorArea.Bits();
1466 		uint8* cursorBits = (uint8*)cursor->Bits();
1467 		for (int32 i = 0; i < cursorHeight; i++) {
1468 			for (int32 j = 0; j < cursorWidth; j++) {
1469 				uint8 alpha = 255 - cursorBits[3];
1470 				bits[0] = ((bits[0] * alpha) >> 8) + cursorBits[0];
1471 				bits[1] = ((bits[1] * alpha) >> 8) + cursorBits[1];
1472 				bits[2] = ((bits[2] * alpha) >> 8) + cursorBits[2];
1473 				cursorBits += 4;
1474 				bits += 4;
1475 			}
1476 		}
1477 
1478 		bitmap->ImportBits(cursorArea.Bits(), cursorArea.BitsLength(),
1479 			cursorArea.BytesPerRow(), cursorArea.ColorSpace(),
1480 			BPoint(0, 0), cursorPosition,
1481 			cursorWidth, cursorHeight);
1482 	}
1483 
1484 	return result;
1485 }
1486 
1487 
1488 // #pragma mark -
1489 
1490 
1491 BRect
1492 DrawingEngine::CopyRect(BRect src, int32 xOffset, int32 yOffset) const
1493 {
1494 	// TODO: assumes drawing buffer is 32 bits (which it currently always is)
1495 	BRect dst;
1496 	RenderingBuffer* buffer = fGraphicsCard->DrawingBuffer();
1497 	if (buffer) {
1498 		BRect clip(0, 0, buffer->Width() - 1, buffer->Height() - 1);
1499 
1500 		dst = src;
1501 		dst.OffsetBy(xOffset, yOffset);
1502 
1503 		if (clip.Intersects(src) && clip.Intersects(dst)) {
1504 			uint32 bytesPerRow = buffer->BytesPerRow();
1505 			uint8* bits = (uint8*)buffer->Bits();
1506 
1507 			// clip source rect
1508 			src = src & clip;
1509 			// clip dest rect
1510 			dst = dst & clip;
1511 			// move dest back over source and clip source to dest
1512 			dst.OffsetBy(-xOffset, -yOffset);
1513 			src = src & dst;
1514 
1515 			// calc offset in buffer
1516 			bits += (int32)src.left * 4 + (int32)src.top * bytesPerRow;
1517 
1518 			uint32 width = src.IntegerWidth() + 1;
1519 			uint32 height = src.IntegerHeight() + 1;
1520 
1521 			_CopyRect(bits, width, height, bytesPerRow, xOffset, yOffset);
1522 
1523 			// offset dest again, because it is return value
1524 			dst.OffsetBy(xOffset, yOffset);
1525 		}
1526 	}
1527 	return dst;
1528 }
1529 
1530 
1531 void
1532 DrawingEngine::_CopyRect(uint8* src, uint32 width, uint32 height,
1533 	uint32 bytesPerRow, int32 xOffset, int32 yOffset) const
1534 {
1535 	// TODO: assumes drawing buffer is 32 bits (which it currently always is)
1536 	int32 xIncrement;
1537 	int32 yIncrement;
1538 
1539 	if (yOffset == 0 && xOffset > 0) {
1540 		// copy from right to left
1541 		xIncrement = -1;
1542 		src += (width - 1) * 4;
1543 	} else {
1544 		// copy from left to right
1545 		xIncrement = 1;
1546 	}
1547 
1548 	if (yOffset > 0) {
1549 		// copy from bottom to top
1550 		yIncrement = -bytesPerRow;
1551 		src += (height - 1) * bytesPerRow;
1552 	} else {
1553 		// copy from top to bottom
1554 		yIncrement = bytesPerRow;
1555 	}
1556 
1557 	uint8* dst = src + yOffset * bytesPerRow + xOffset * 4;
1558 
1559 	if (xIncrement == 1) {
1560 		uint8 tmpBuffer[width * 4];
1561 		for (uint32 y = 0; y < height; y++) {
1562 			// NOTE: read into temporary scanline buffer,
1563 			// avoid memcpy because it might be graphics card memory
1564 			gfxcpy32(tmpBuffer, src, width * 4);
1565 			// write back temporary scanline buffer
1566 			// NOTE: **don't read and write over the PCI bus
1567 			// at the same time**
1568 			memcpy(dst, tmpBuffer, width * 4);
1569 // NOTE: this (instead of the two pass copy above) might
1570 // speed up QEMU -> ?!? (would depend on how it emulates
1571 // the PCI bus...)
1572 // TODO: would be nice if we actually knew
1573 // if we're operating in graphics memory or main memory...
1574 //memcpy(dst, src, width * 4);
1575 			src += yIncrement;
1576 			dst += yIncrement;
1577 		}
1578 	} else {
1579 		for (uint32 y = 0; y < height; y++) {
1580 			uint32* srcHandle = (uint32*)src;
1581 			uint32* dstHandle = (uint32*)dst;
1582 			for (uint32 x = 0; x < width; x++) {
1583 				*dstHandle = *srcHandle;
1584 				srcHandle += xIncrement;
1585 				dstHandle += xIncrement;
1586 			}
1587 			src += yIncrement;
1588 			dst += yIncrement;
1589 		}
1590 	}
1591 }
1592 
1593 
1594 inline void
1595 DrawingEngine::_CopyToFront(const BRect& frame)
1596 {
1597 	if (fCopyToFront)
1598 		fGraphicsCard->Invalidate(frame);
1599 }
1600