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