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