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