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