xref: /haiku/src/servers/app/drawing/DrawingEngine.cpp (revision 4f2fd49bdc6078128b1391191e4edac647044c3d)
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->FillArcGradient(center, xRadius, yRadius, angle, span,
643 								  gradient);
644 
645 		_CopyToFront(clipped);
646 	}
647 }
648 
649 
650 void
651 DrawingEngine::DrawBezier(BPoint* pts, bool filled)
652 {
653 	CRASH_IF_NOT_LOCKED
654 
655 	// TODO: figure out bounds and hide cursor depending on that
656 	AutoFloatingOverlaysHider _(fGraphicsCard);
657 
658 	BRect touched = fPainter->DrawBezier(pts, filled);
659 
660 	_CopyToFront(touched);
661 }
662 
663 
664 void
665 DrawingEngine::FillBezier(BPoint* pts, const BGradient& gradient)
666 {
667 	CRASH_IF_NOT_LOCKED
668 
669 	// TODO: figure out bounds and hide cursor depending on that
670 	AutoFloatingOverlaysHider _(fGraphicsCard);
671 
672 	BRect touched = fPainter->FillBezierGradient(pts, gradient);
673 
674 	_CopyToFront(touched);
675 }
676 
677 
678 void
679 DrawingEngine::DrawEllipse(BRect r, bool filled)
680 {
681 	CRASH_IF_NOT_LOCKED
682 
683 	make_rect_valid(r);
684 	BRect clipped = r;
685 	fPainter->AlignEllipseRect(&clipped, filled);
686 
687 	if (!filled)
688 		extend_by_stroke_width(clipped, fPainter->PenSize());
689 
690 	clipped.left = floorf(clipped.left);
691 	clipped.top = floorf(clipped.top);
692 	clipped.right = ceilf(clipped.right);
693 	clipped.bottom = ceilf(clipped.bottom);
694 
695 	clipped = fPainter->ClipRect(clipped);
696 
697 	if (clipped.IsValid()) {
698 		AutoFloatingOverlaysHider _(fGraphicsCard, clipped);
699 
700 		fPainter->DrawEllipse(r, filled);
701 
702 		_CopyToFront(clipped);
703 	}
704 }
705 
706 
707 void
708 DrawingEngine::FillEllipse(BRect r, const BGradient& gradient)
709 {
710 	CRASH_IF_NOT_LOCKED
711 
712 	make_rect_valid(r);
713 	BRect clipped = r;
714 	fPainter->AlignEllipseRect(&clipped, true);
715 
716 	clipped.left = floorf(clipped.left);
717 	clipped.top = floorf(clipped.top);
718 	clipped.right = ceilf(clipped.right);
719 	clipped.bottom = ceilf(clipped.bottom);
720 
721 	clipped = fPainter->ClipRect(clipped);
722 
723 	if (clipped.IsValid()) {
724 		AutoFloatingOverlaysHider _(fGraphicsCard, clipped);
725 
726 		fPainter->FillEllipseGradient(r, gradient);
727 
728 		_CopyToFront(clipped);
729 	}
730 }
731 
732 
733 void
734 DrawingEngine::DrawPolygon(BPoint* ptlist, int32 numpts, BRect bounds,
735 	bool filled, bool closed)
736 {
737 	CRASH_IF_NOT_LOCKED
738 
739 	make_rect_valid(bounds);
740 	if (!filled)
741 		extend_by_stroke_width(bounds, fPainter->PenSize());
742 	bounds = fPainter->ClipRect(bounds);
743 	if (bounds.IsValid()) {
744 		AutoFloatingOverlaysHider _(fGraphicsCard, bounds);
745 
746 		fPainter->DrawPolygon(ptlist, numpts, filled, closed);
747 
748 		_CopyToFront(bounds);
749 	}
750 }
751 
752 
753 void
754 DrawingEngine::FillPolygon(BPoint* ptlist, int32 numpts, BRect bounds,
755 	const BGradient& gradient, bool closed)
756 {
757 	CRASH_IF_NOT_LOCKED
758 
759 	make_rect_valid(bounds);
760 	bounds = fPainter->ClipRect(bounds);
761 	if (bounds.IsValid()) {
762 		AutoFloatingOverlaysHider _(fGraphicsCard, bounds);
763 
764 		fPainter->FillPolygonGradient(ptlist, numpts, gradient, closed);
765 
766 		_CopyToFront(bounds);
767 	}
768 }
769 
770 
771 // #pragma mark - rgb_color
772 
773 
774 void
775 DrawingEngine::StrokePoint(const BPoint& pt, const rgb_color& color)
776 {
777 	StrokeLine(pt, pt, color);
778 }
779 
780 // StrokeLine
781 //
782 // * this function is only used by Decorators
783 // * it assumes a one pixel wide line
784 void
785 DrawingEngine::StrokeLine(const BPoint& start, const BPoint& end,
786 	const rgb_color& color)
787 {
788 	CRASH_IF_NOT_LOCKED
789 
790 	BRect touched(start, end);
791 	make_rect_valid(touched);
792 	touched = fPainter->ClipRect(touched);
793 	AutoFloatingOverlaysHider _(fGraphicsCard, touched);
794 
795 	if (!fPainter->StraightLine(start, end, color)) {
796 		rgb_color previousColor = fPainter->HighColor();
797 		drawing_mode previousMode = fPainter->DrawingMode();
798 
799 		fPainter->SetHighColor(color);
800 		fPainter->SetDrawingMode(B_OP_OVER);
801 		fPainter->StrokeLine(start, end);
802 
803 		fPainter->SetDrawingMode(previousMode);
804 		fPainter->SetHighColor(previousColor);
805 	}
806 
807 	_CopyToFront(touched);
808 }
809 
810 // this function is used to draw a one pixel wide rect
811 void
812 DrawingEngine::StrokeRect(BRect r, const rgb_color &color)
813 {
814 	CRASH_IF_NOT_LOCKED
815 
816 	make_rect_valid(r);
817 	BRect clipped = fPainter->ClipRect(r);
818 	if (clipped.IsValid()) {
819 		AutoFloatingOverlaysHider _(fGraphicsCard, clipped);
820 
821 		fPainter->StrokeRect(r, color);
822 
823 		_CopyToFront(clipped);
824 	}
825 }
826 
827 
828 void
829 DrawingEngine::FillRect(BRect r, const rgb_color& color)
830 {
831 	CRASH_IF_NOT_LOCKED
832 
833 	// NOTE: Write locking because we might use HW acceleration.
834 	// This needs to be investigated, I'm doing this because of
835 	// gut feeling.
836 	make_rect_valid(r);
837 	r = fPainter->ClipRect(r);
838 	if (!r.IsValid())
839 		return;
840 
841 	AutoFloatingOverlaysHider overlaysHider(fGraphicsCard, r);
842 
843 	// try hardware optimized version first
844 	if (fAvailableHWAccleration & HW_ACC_FILL_REGION) {
845 		BRegion region(r);
846 		region.IntersectWith(fPainter->ClippingRegion());
847 		fGraphicsCard->FillRegion(region, color,
848 			fSuspendSyncLevel == 0 || overlaysHider.WasHidden());
849 	} else {
850 		fPainter->FillRect(r, color);
851 	}
852 
853 	_CopyToFront(r);
854 }
855 
856 
857 void
858 DrawingEngine::FillRegion(BRegion& r, const rgb_color& color)
859 {
860 	CRASH_IF_NOT_LOCKED
861 
862 	// NOTE: region expected to be already clipped correctly!!
863 	BRect frame = r.Frame();
864 	if (!fPainter->Bounds().Contains(frame)) {
865 		// NOTE: I am not quite sure yet how this can happen, but appearantly it can (see bug 634)
866 		// This function is used for internal app_server painting, in the case of bug 634,
867 		// the background of views is painted. But the view region should never be outside the
868 		// frame buffer bounds.
869 //		char message[1024];
870 //		BRect bounds = fPainter->Bounds();
871 //		sprintf(message, "FillRegion() - painter: (%d, %d)->(%d, %d), region: (%d, %d)->(%d, %d)",
872 //			(int)bounds.left, (int)bounds.top, (int)bounds.right, (int)bounds.bottom,
873 //			(int)frame.left, (int)frame.top, (int)frame.right, (int)frame.bottom);
874 //		debugger(message);
875 		return;
876 	}
877 
878 	AutoFloatingOverlaysHider overlaysHider(fGraphicsCard, frame);
879 
880 	// try hardware optimized version first
881 	if ((fAvailableHWAccleration & HW_ACC_FILL_REGION) != 0
882 		&& frame.Width() * frame.Height() > 100) {
883 		fGraphicsCard->FillRegion(r, color, fSuspendSyncLevel == 0
884 			|| overlaysHider.WasHidden());
885 	} else {
886 		int32 count = r.CountRects();
887 		for (int32 i = 0; i < count; i++)
888 			fPainter->FillRectNoClipping(r.RectAtInt(i), color);
889 	}
890 
891 	_CopyToFront(frame);
892 }
893 
894 // #pragma mark - DrawState
895 
896 void
897 DrawingEngine::StrokeRect(BRect r)
898 {
899 	CRASH_IF_NOT_LOCKED
900 
901 	// support invalid rects
902 	make_rect_valid(r);
903 	BRect clipped(r);
904 	extend_by_stroke_width(clipped, fPainter->PenSize());
905 	clipped = fPainter->ClipRect(clipped);
906 	if (clipped.IsValid()) {
907 		AutoFloatingOverlaysHider _(fGraphicsCard, clipped);
908 
909 		fPainter->StrokeRect(r);
910 
911 		_CopyToFront(clipped);
912 	}
913 }
914 
915 
916 void
917 DrawingEngine::FillRect(BRect r)
918 {
919 	CRASH_IF_NOT_LOCKED
920 
921 	make_rect_valid(r);
922 	r = fPainter->AlignAndClipRect(r);
923 	if (!r.IsValid())
924 		return;
925 
926 	AutoFloatingOverlaysHider overlaysHider(fGraphicsCard, r);
927 
928 	bool doInSoftware = true;
929 	if ((r.Width() + 1) * (r.Height() + 1) > 100.0) {
930 		// try hardware optimized version first
931 		// if the rect is large enough
932 		if ((fAvailableHWAccleration & HW_ACC_FILL_REGION) != 0) {
933 			if (fPainter->Pattern() == B_SOLID_HIGH
934 				&& (fPainter->DrawingMode() == B_OP_COPY
935 					|| fPainter->DrawingMode() == B_OP_OVER)) {
936 				BRegion region(r);
937 				region.IntersectWith(fPainter->ClippingRegion());
938 				fGraphicsCard->FillRegion(region, fPainter->HighColor(),
939 										  fSuspendSyncLevel == 0
940 										  || overlaysHider.WasHidden());
941 				doInSoftware = false;
942 			} else if (fPainter->Pattern() == B_SOLID_LOW
943 					&& fPainter->DrawingMode() == B_OP_COPY) {
944 				BRegion region(r);
945 				region.IntersectWith(fPainter->ClippingRegion());
946 				fGraphicsCard->FillRegion(region, fPainter->LowColor(),
947 										  fSuspendSyncLevel == 0
948 										  || overlaysHider.WasHidden());
949 				doInSoftware = false;
950 			}
951 		}
952 	}
953 
954 	if (doInSoftware && fAvailableHWAccleration & HW_ACC_INVERT_REGION
955 			&& fPainter->Pattern() == B_SOLID_HIGH
956 			&& fPainter->DrawingMode() == B_OP_INVERT) {
957 		BRegion region(r);
958 		region.IntersectWith(fPainter->ClippingRegion());
959 		fGraphicsCard->InvertRegion(region);
960 		doInSoftware = false;
961 	}
962 
963 	if (doInSoftware)
964 		fPainter->FillRect(r);
965 
966 	_CopyToFront(r);
967 }
968 
969 
970 void
971 DrawingEngine::FillRect(BRect r, const BGradient& gradient)
972 {
973 	CRASH_IF_NOT_LOCKED
974 
975 	make_rect_valid(r);
976 	r = fPainter->AlignAndClipRect(r);
977 	if (!r.IsValid())
978 		return;
979 
980 	AutoFloatingOverlaysHider overlaysHider(fGraphicsCard, r);
981 
982 	fPainter->FillRectGradient(r, gradient);
983 
984 	_CopyToFront(r);
985 }
986 
987 
988 void
989 DrawingEngine::FillRegion(BRegion& r)
990 {
991 	CRASH_IF_NOT_LOCKED
992 
993 	BRect clipped = fPainter->ClipRect(r.Frame());
994 	if (!clipped.IsValid())
995 		return;
996 
997 	AutoFloatingOverlaysHider overlaysHider(fGraphicsCard, clipped);
998 
999 	bool doInSoftware = true;
1000 	// try hardware optimized version first
1001 	if ((fAvailableHWAccleration & HW_ACC_FILL_REGION) != 0) {
1002 		if (fPainter->Pattern() == B_SOLID_HIGH
1003 			&& (fPainter->DrawingMode() == B_OP_COPY
1004 				|| fPainter->DrawingMode() == B_OP_OVER)) {
1005 			r.IntersectWith(fPainter->ClippingRegion());
1006 			fGraphicsCard->FillRegion(r, fPainter->HighColor(),
1007 									  fSuspendSyncLevel == 0
1008 									  || overlaysHider.WasHidden());
1009 			doInSoftware = false;
1010 		} else if (fPainter->Pattern() == B_SOLID_LOW
1011 				&& fPainter->DrawingMode() == B_OP_COPY) {
1012 			r.IntersectWith(fPainter->ClippingRegion());
1013 			fGraphicsCard->FillRegion(r, fPainter->LowColor(),
1014 									  fSuspendSyncLevel == 0
1015 									  || overlaysHider.WasHidden());
1016 			doInSoftware = false;
1017 		}
1018 	}
1019 
1020 	if (doInSoftware && fAvailableHWAccleration & HW_ACC_INVERT_REGION
1021 			&& fPainter->Pattern() == B_SOLID_HIGH
1022 			&& fPainter->DrawingMode() == B_OP_INVERT) {
1023 		r.IntersectWith(fPainter->ClippingRegion());
1024 		fGraphicsCard->InvertRegion(r);
1025 		doInSoftware = false;
1026 	}
1027 
1028 	if (doInSoftware) {
1029 
1030 		BRect touched = fPainter->FillRect(r.RectAt(0));
1031 
1032 		int32 count = r.CountRects();
1033 		for (int32 i = 1; i < count; i++)
1034 			touched = touched | fPainter->FillRect(r.RectAt(i));
1035 	}
1036 
1037 	_CopyToFront(r.Frame());
1038 }
1039 
1040 
1041 void
1042 DrawingEngine::FillRegion(BRegion& r, const BGradient& gradient)
1043 {
1044 	CRASH_IF_NOT_LOCKED
1045 
1046 	BRect clipped = fPainter->ClipRect(r.Frame());
1047 	if (!clipped.IsValid())
1048 		return;
1049 
1050 	AutoFloatingOverlaysHider overlaysHider(fGraphicsCard, clipped);
1051 
1052 	BRect touched = fPainter->FillRectGradient(r.RectAt(0), gradient);
1053 
1054 	int32 count = r.CountRects();
1055 	for (int32 i = 1; i < count; i++)
1056 		touched = touched | fPainter->FillRectGradient(r.RectAt(i), gradient);
1057 
1058 	_CopyToFront(r.Frame());
1059 }
1060 
1061 
1062 void
1063 DrawingEngine::DrawRoundRect(BRect r, float xrad, float yrad, bool filled)
1064 {
1065 	CRASH_IF_NOT_LOCKED
1066 
1067 	// NOTE: the stroke does not extend past "r" in R5,
1068 	// though I consider this unexpected behaviour.
1069 	make_rect_valid(r);
1070 	BRect clipped = fPainter->ClipRect(r);
1071 
1072 	clipped.left = floorf(clipped.left);
1073 	clipped.top = floorf(clipped.top);
1074 	clipped.right = ceilf(clipped.right);
1075 	clipped.bottom = ceilf(clipped.bottom);
1076 
1077 	if (clipped.IsValid()) {
1078 		AutoFloatingOverlaysHider _(fGraphicsCard, clipped);
1079 
1080 		BRect touched = filled ? fPainter->FillRoundRect(r, xrad, yrad)
1081 							   : fPainter->StrokeRoundRect(r, xrad, yrad);
1082 
1083 		_CopyToFront(touched);
1084 	}
1085 }
1086 
1087 
1088 void
1089 DrawingEngine::FillRoundRect(BRect r, float xrad, float yrad,
1090 	const BGradient& gradient)
1091 {
1092 	CRASH_IF_NOT_LOCKED
1093 
1094 	// NOTE: the stroke does not extend past "r" in R5,
1095 	// though I consider this unexpected behaviour.
1096 	make_rect_valid(r);
1097 	BRect clipped = fPainter->ClipRect(r);
1098 
1099 	clipped.left = floorf(clipped.left);
1100 	clipped.top = floorf(clipped.top);
1101 	clipped.right = ceilf(clipped.right);
1102 	clipped.bottom = ceilf(clipped.bottom);
1103 
1104 	if (clipped.IsValid()) {
1105 		AutoFloatingOverlaysHider _(fGraphicsCard, clipped);
1106 
1107 		BRect touched = fPainter->FillRoundRectGradient(r, xrad, yrad, gradient);
1108 
1109 		_CopyToFront(touched);
1110 	}
1111 }
1112 
1113 
1114 void
1115 DrawingEngine::DrawShape(const BRect& bounds, int32 opCount,
1116 	const uint32* opList, int32 ptCount, const BPoint* ptList, bool filled)
1117 {
1118 	CRASH_IF_NOT_LOCKED
1119 
1120 	// NOTE: hides cursor regardless of if and where
1121 	// shape is drawn on screen, TODO: optimize
1122 	AutoFloatingOverlaysHider _(fGraphicsCard);
1123 
1124 	BRect touched = fPainter->DrawShape(opCount, opList,
1125 										ptCount, ptList,
1126 										filled);
1127 
1128 	_CopyToFront(touched);
1129 }
1130 
1131 
1132 void
1133 DrawingEngine::FillShape(const BRect& bounds, int32 opCount,
1134 	const uint32* opList, int32 ptCount, const BPoint* ptList,
1135 	const BGradient& gradient)
1136 {
1137 	CRASH_IF_NOT_LOCKED
1138 
1139 	// NOTE: hides cursor regardless of if and where
1140 	// shape is drawn on screen, TODO: optimize
1141 	AutoFloatingOverlaysHider _(fGraphicsCard);
1142 
1143 	BRect touched = fPainter->FillShapeGradient(opCount, opList, ptCount,
1144 												ptList, gradient);
1145 
1146 	_CopyToFront(touched);
1147 }
1148 
1149 
1150 void
1151 DrawingEngine::DrawTriangle(BPoint* pts, const BRect& bounds, bool filled)
1152 {
1153 	CRASH_IF_NOT_LOCKED
1154 
1155 	BRect clipped(bounds);
1156 	if (!filled)
1157 		extend_by_stroke_width(clipped, fPainter->PenSize());
1158 	clipped = fPainter->ClipRect(clipped);
1159 	if (clipped.IsValid()) {
1160 		AutoFloatingOverlaysHider _(fGraphicsCard, clipped);
1161 
1162 		if (filled)
1163 			fPainter->FillTriangle(pts[0], pts[1], pts[2]);
1164 		else
1165 			fPainter->StrokeTriangle(pts[0], pts[1], pts[2]);
1166 
1167 		_CopyToFront(clipped);
1168 	}
1169 }
1170 
1171 void
1172 DrawingEngine::FillTriangle(BPoint* pts, const BRect& bounds,
1173 	const BGradient& gradient)
1174 {
1175 	CRASH_IF_NOT_LOCKED
1176 
1177 	BRect clipped(bounds);
1178 	clipped = fPainter->ClipRect(clipped);
1179 	if (clipped.IsValid()) {
1180 		AutoFloatingOverlaysHider _(fGraphicsCard, clipped);
1181 
1182 		fPainter->FillTriangleGradient(pts[0], pts[1], pts[2], gradient);
1183 
1184 		_CopyToFront(clipped);
1185 	}
1186 }
1187 
1188 // StrokeLine
1189 void
1190 DrawingEngine::StrokeLine(const BPoint &start, const BPoint &end)
1191 {
1192 	CRASH_IF_NOT_LOCKED
1193 
1194 	BRect touched(start, end);
1195 	make_rect_valid(touched);
1196 	extend_by_stroke_width(touched, fPainter->PenSize());
1197 	touched = fPainter->ClipRect(touched);
1198 	if (touched.IsValid()) {
1199 		AutoFloatingOverlaysHider _(fGraphicsCard, touched);
1200 
1201 		fPainter->StrokeLine(start, end);
1202 
1203 		_CopyToFront(touched);
1204 	}
1205 }
1206 
1207 // StrokeLineArray
1208 void
1209 DrawingEngine::StrokeLineArray(int32 numLines,
1210 	const LineArrayData *linedata)
1211 {
1212 	CRASH_IF_NOT_LOCKED
1213 
1214 	if (!linedata || numLines <= 0)
1215 		return;
1216 
1217 	// figure out bounding box for line array
1218 	const LineArrayData *data = (const LineArrayData *)&(linedata[0]);
1219 	BRect touched(min_c(data->pt1.x, data->pt2.x),
1220 				  min_c(data->pt1.y, data->pt2.y),
1221 				  max_c(data->pt1.x, data->pt2.x),
1222 				  max_c(data->pt1.y, data->pt2.y));
1223 
1224 	for (int32 i = 1; i < numLines; i++) {
1225 		data = (const LineArrayData *)&(linedata[i]);
1226 		BRect box(min_c(data->pt1.x, data->pt2.x),
1227 				  min_c(data->pt1.y, data->pt2.y),
1228 				  max_c(data->pt1.x, data->pt2.x),
1229 				  max_c(data->pt1.y, data->pt2.y));
1230 		touched = touched | box;
1231 	}
1232 	extend_by_stroke_width(touched, fPainter->PenSize());
1233 	touched = fPainter->ClipRect(touched);
1234 	if (touched.IsValid()) {
1235 		AutoFloatingOverlaysHider _(fGraphicsCard, touched);
1236 
1237 		data = (const LineArrayData *)&(linedata[0]);
1238 
1239 		// store current graphics state, we mess with the
1240 		// high color and pattern...
1241 		rgb_color oldColor = fPainter->HighColor();
1242 		struct pattern pattern = fPainter->Pattern();
1243 
1244 		fPainter->SetHighColor(data->color);
1245 		fPainter->SetPattern(B_SOLID_HIGH);
1246 		fPainter->StrokeLine(data->pt1, data->pt2);
1247 
1248 		for (int32 i = 1; i < numLines; i++) {
1249 			data = (const LineArrayData *)&(linedata[i]);
1250 			fPainter->SetHighColor(data->color);
1251 			fPainter->StrokeLine(data->pt1, data->pt2);
1252 		}
1253 
1254 		// restore correct drawing state highcolor and pattern
1255 		fPainter->SetHighColor(oldColor);
1256 		fPainter->SetPattern(pattern);
1257 
1258 		_CopyToFront(touched);
1259 	}
1260 }
1261 
1262 // #pragma mark -
1263 
1264 BPoint
1265 DrawingEngine::DrawString(const char* string, int32 length,
1266 						  const BPoint& pt, escapement_delta* delta)
1267 {
1268 	CRASH_IF_NOT_LOCKED
1269 
1270 	BPoint penLocation = pt;
1271 
1272 	// try a fast clipping path
1273 	if (fPainter->ClippingRegion() && fPainter->Font().Rotation() == 0.0f) {
1274 		float fontSize = fPainter->Font().Size();
1275 		BRect clippingFrame = fPainter->ClippingRegion()->Frame();
1276 		if (pt.x - fontSize > clippingFrame.right
1277 			|| pt.y + fontSize < clippingFrame.top
1278 			|| pt.y - fontSize > clippingFrame.bottom) {
1279 			penLocation.x += StringWidth(string, length, delta);
1280 			return penLocation;
1281 		}
1282 	}
1283 
1284 	// use a FontCacheRefernece to speed up the second pass of
1285 	// drawing the string
1286 	FontCacheReference cacheReference;
1287 
1288 //bigtime_t now = system_time();
1289 // TODO: BoundingBox is quite slow!! Optimizing it will be beneficial.
1290 // Cursiously, the DrawString after it is actually faster!?!
1291 // TODO: make the availability of the hardware cursor part of the
1292 // HW acceleration flags and skip all calculations for HideFloatingOverlays
1293 // in case we don't have one.
1294 // TODO: Watch out about penLocation and use Painter::PenLocation() when
1295 // not using BoundindBox anymore.
1296 	BRect b = fPainter->BoundingBox(string, length, pt, &penLocation, delta,
1297 		&cacheReference);
1298 	// stop here if we're supposed to render outside of the clipping
1299 	b = fPainter->ClipRect(b);
1300 	if (b.IsValid()) {
1301 //printf("bounding box '%s': %lld µs\n", string, system_time() - now);
1302 		AutoFloatingOverlaysHider _(fGraphicsCard, b);
1303 
1304 //now = system_time();
1305 		BRect touched = fPainter->DrawString(string, length, pt, delta,
1306 			&cacheReference);
1307 //printf("drawing string: %lld µs\n", system_time() - now);
1308 
1309 		_CopyToFront(touched);
1310 	}
1311 
1312 	return penLocation;
1313 }
1314 
1315 // StringWidth
1316 float
1317 DrawingEngine::StringWidth(const char* string, int32 length,
1318 						   escapement_delta* delta)
1319 {
1320 	return fPainter->StringWidth(string, length, delta);
1321 }
1322 
1323 // StringWidth
1324 float
1325 DrawingEngine::StringWidth(const char* string, int32 length,
1326 	const ServerFont& font, escapement_delta* delta)
1327 {
1328 	return font.StringWidth(string, length, delta);
1329 }
1330 
1331 // #pragma mark -
1332 
1333 // DumpToBitmap
1334 ServerBitmap*
1335 DrawingEngine::DumpToBitmap()
1336 {
1337 	return NULL;
1338 }
1339 
1340 status_t
1341 DrawingEngine::ReadBitmap(ServerBitmap *bitmap, bool drawCursor, BRect bounds)
1342 {
1343 	CRASH_IF_NOT_EXCLUSIVE_LOCKED
1344 
1345 	RenderingBuffer *buffer = fGraphicsCard->FrontBuffer();
1346 	if (!buffer)
1347 		return B_ERROR;
1348 
1349 	BRect clip(0, 0, buffer->Width() - 1, buffer->Height() - 1);
1350 	bounds = bounds & clip;
1351 	AutoFloatingOverlaysHider _(fGraphicsCard, bounds);
1352 
1353 	status_t result = bitmap->ImportBits(buffer->Bits(), buffer->BitsLength(),
1354 		buffer->BytesPerRow(), buffer->ColorSpace(),
1355 		bounds.LeftTop(), BPoint(0, 0),
1356 		bounds.IntegerWidth() + 1, bounds.IntegerHeight() + 1);
1357 
1358 	if (drawCursor) {
1359 		ServerCursorReference cursorRef = fGraphicsCard->Cursor();
1360 		ServerCursor* cursor = cursorRef.Cursor();
1361 		if (!cursor)
1362 			return result;
1363 		int32 cursorWidth = cursor->Width();
1364 		int32 cursorHeight = cursor->Height();
1365 
1366 		BPoint cursorPosition = fGraphicsCard->CursorPosition();
1367 		cursorPosition -= bounds.LeftTop() + cursor->GetHotSpot();
1368 
1369 		BBitmap cursorArea(BRect(0, 0, cursorWidth - 1, cursorHeight - 1),
1370 			B_BITMAP_NO_SERVER_LINK, B_RGBA32);
1371 
1372 		cursorArea.ImportBits(bitmap->Bits(), bitmap->BitsLength(),
1373 			bitmap->BytesPerRow(), bitmap->ColorSpace(),
1374 			cursorPosition,	BPoint(0, 0),
1375 			cursorWidth, cursorHeight);
1376 
1377 		uint8 *bits = (uint8 *)cursorArea.Bits();
1378 		uint8 *cursorBits = (uint8 *)cursor->Bits();
1379 		for (int32 i = 0; i < cursorHeight; i++) {
1380 			for (int32 j = 0; j < cursorWidth; j++) {
1381 				uint8 alpha = 255 - cursorBits[3];
1382 				bits[0] = ((bits[0] * alpha) >> 8) + cursorBits[0];
1383 				bits[1] = ((bits[1] * alpha) >> 8) + cursorBits[1];
1384 				bits[2] = ((bits[2] * alpha) >> 8) + cursorBits[2];
1385 				cursorBits += 4;
1386 				bits += 4;
1387 			}
1388 		}
1389 
1390 		bitmap->ImportBits(cursorArea.Bits(), cursorArea.BitsLength(),
1391 			cursorArea.BytesPerRow(), cursorArea.ColorSpace(),
1392 			BPoint(0, 0), cursorPosition,
1393 			cursorWidth, cursorHeight);
1394 	}
1395 
1396 	return result;
1397 }
1398 
1399 // #pragma mark -
1400 
1401 BRect
1402 DrawingEngine::_CopyRect(BRect src, int32 xOffset, int32 yOffset) const
1403 {
1404 	// TODO: assumes drawing buffer is 32 bits (which it currently always is)
1405 	BRect dst;
1406 	RenderingBuffer* buffer = fGraphicsCard->DrawingBuffer();
1407 	if (buffer) {
1408 		BRect clip(0, 0, buffer->Width() - 1, buffer->Height() - 1);
1409 
1410 		dst = src;
1411 		dst.OffsetBy(xOffset, yOffset);
1412 
1413 		if (clip.Intersects(src) && clip.Intersects(dst)) {
1414 			uint32 bytesPerRow = buffer->BytesPerRow();
1415 			uint8* bits = (uint8*)buffer->Bits();
1416 
1417 			// clip source rect
1418 			src = src & clip;
1419 			// clip dest rect
1420 			dst = dst & clip;
1421 			// move dest back over source and clip source to dest
1422 			dst.OffsetBy(-xOffset, -yOffset);
1423 			src = src & dst;
1424 
1425 			// calc offset in buffer
1426 			bits += (int32)src.left * 4 + (int32)src.top * bytesPerRow;
1427 
1428 			uint32 width = src.IntegerWidth() + 1;
1429 			uint32 height = src.IntegerHeight() + 1;
1430 
1431 			_CopyRect(bits, width, height, bytesPerRow, xOffset, yOffset);
1432 
1433 			// offset dest again, because it is return value
1434 			dst.OffsetBy(xOffset, yOffset);
1435 		}
1436 	}
1437 	return dst;
1438 }
1439 
1440 
1441 void
1442 DrawingEngine::_CopyRect(uint8* src, uint32 width, uint32 height,
1443 	uint32 bytesPerRow, int32 xOffset, int32 yOffset) const
1444 {
1445 	// TODO: assumes drawing buffer is 32 bits (which it currently always is)
1446 	int32 xIncrement;
1447 	int32 yIncrement;
1448 
1449 	if (yOffset == 0 && xOffset > 0) {
1450 		// copy from right to left
1451 		xIncrement = -1;
1452 		src += (width - 1) * 4;
1453 	} else {
1454 		// copy from left to right
1455 		xIncrement = 1;
1456 	}
1457 
1458 	if (yOffset > 0) {
1459 		// copy from bottom to top
1460 		yIncrement = -bytesPerRow;
1461 		src += (height - 1) * bytesPerRow;
1462 	} else {
1463 		// copy from top to bottom
1464 		yIncrement = bytesPerRow;
1465 	}
1466 
1467 	uint8* dst = src + yOffset * bytesPerRow + xOffset * 4;
1468 
1469 	if (xIncrement == 1) {
1470 		uint8 tmpBuffer[width * 4];
1471 		for (uint32 y = 0; y < height; y++) {
1472 			// NOTE: read into temporary scanline buffer,
1473 			// avoid memcpy because it might be graphics card memory
1474 			gfxcpy32(tmpBuffer, src, width * 4);
1475 			// write back temporary scanline buffer
1476 			// NOTE: **don't read and write over the PCI bus
1477 			// at the same time**
1478 			memcpy(dst, tmpBuffer, width * 4);
1479 // NOTE: this (instead of the two pass copy above) might
1480 // speed up QEMU -> ?!? (would depend on how it emulates
1481 // the PCI bus...)
1482 // TODO: would be nice if we actually knew
1483 // if we're operating in graphics memory or main memory...
1484 //memcpy(dst, src, width * 4);
1485 			src += yIncrement;
1486 			dst += yIncrement;
1487 		}
1488 	} else {
1489 		for (uint32 y = 0; y < height; y++) {
1490 			uint32* srcHandle = (uint32*)src;
1491 			uint32* dstHandle = (uint32*)dst;
1492 			for (uint32 x = 0; x < width; x++) {
1493 				*dstHandle = *srcHandle;
1494 				srcHandle += xIncrement;
1495 				dstHandle += xIncrement;
1496 			}
1497 			src += yIncrement;
1498 			dst += yIncrement;
1499 		}
1500 	}
1501 }
1502 
1503 
1504 inline void
1505 DrawingEngine::_CopyToFront(const BRect& frame)
1506 {
1507 	if (fCopyToFront)
1508 		fGraphicsCard->Invalidate(frame);
1509 }
1510 
1511 
1512