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