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