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