1 /*
2 * Copyright (c) 2001-2015, Haiku, Inc.
3 * Distributed under the terms of the MIT license.
4 *
5 * Authors:
6 * DarkWyrm <bpmagic@columbus.rr.com>
7 * Adi Oanca <adioanca@gmail.com>
8 * Axel Dörfler, axeld@pinc-software.de
9 * Stephan Aßmus <superstippi@gmx.de>
10 * Marcus Overhagen <marcus@overhagen.de>
11 * Adrien Destugues <pulkomandy@pulkomandy.tk
12 * Julian Harnath <julian.harnath@rwth-aachen.de>
13 * Joseph Groover <looncraz@looncraz.net>
14 */
15 #include "View.h"
16
17 #include <new>
18 #include <stdio.h>
19
20 #include "AlphaMask.h"
21 #include "Desktop.h"
22 #include "DrawingEngine.h"
23 #include "DrawState.h"
24 #include "Layer.h"
25 #include "Overlay.h"
26 #include "ServerApp.h"
27 #include "ServerBitmap.h"
28 #include "ServerCursor.h"
29 #include "ServerPicture.h"
30 #include "ServerWindow.h"
31 #include "Window.h"
32
33 #include "BitmapHWInterface.h"
34 #include "drawing_support.h"
35
36 #include <List.h>
37 #include <Message.h>
38 #include <PortLink.h>
39 #include <View.h> // for resize modes
40 #include <WindowPrivate.h>
41
42 #include <GradientLinear.h>
43 #include <GradientRadial.h>
44 #include <GradientRadialFocus.h>
45 #include <GradientDiamond.h>
46 #include <GradientConic.h>
47
48
49 using std::nothrow;
50
51
52 void
resize_frame(IntRect & frame,uint32 resizingMode,int32 x,int32 y)53 resize_frame(IntRect& frame, uint32 resizingMode, int32 x, int32 y)
54 {
55 // follow with left side
56 if ((resizingMode & 0x0F00U) == _VIEW_RIGHT_ << 8)
57 frame.left += x;
58 else if ((resizingMode & 0x0F00U) == _VIEW_CENTER_ << 8)
59 frame.left += x / 2;
60
61 // follow with right side
62 if ((resizingMode & 0x000FU) == _VIEW_RIGHT_)
63 frame.right += x;
64 else if ((resizingMode & 0x000FU) == _VIEW_CENTER_)
65 frame.right += x / 2;
66
67 // follow with top side
68 if ((resizingMode & 0xF000U) == _VIEW_BOTTOM_ << 12)
69 frame.top += y;
70 else if ((resizingMode & 0xF000U) == _VIEW_CENTER_ << 12)
71 frame.top += y / 2;
72
73 // follow with bottom side
74 if ((resizingMode & 0x00F0U) == _VIEW_BOTTOM_ << 4)
75 frame.bottom += y;
76 else if ((resizingMode & 0x00F0U) == _VIEW_CENTER_ << 4)
77 frame.bottom += y / 2;
78 }
79
80
81 // #pragma mark -
82
83
View(IntRect frame,IntPoint scrollingOffset,const char * name,int32 token,uint32 resizeMode,uint32 flags)84 View::View(IntRect frame, IntPoint scrollingOffset, const char* name,
85 int32 token, uint32 resizeMode, uint32 flags)
86 :
87 fName(name),
88 fToken(token),
89
90 fFrame(frame),
91 fScrollingOffset(scrollingOffset),
92
93 fViewColor((rgb_color){ 255, 255, 255, 255 }),
94 fWhichViewColor(B_NO_COLOR),
95 fWhichViewColorTint(B_NO_TINT),
96 fViewBitmap(NULL),
97 fBitmapResizingMode(0),
98 fBitmapOptions(0),
99
100 fResizeMode(resizeMode),
101 fFlags(flags),
102
103 // Views start visible by default
104 fHidden(false),
105 fVisible(true),
106 fBackgroundDirty(true),
107 fIsDesktopBackground(false),
108
109 fEventMask(0),
110 fEventOptions(0),
111
112 fWindow(NULL),
113 fParent(NULL),
114
115 fFirstChild(NULL),
116 fPreviousSibling(NULL),
117 fNextSibling(NULL),
118 fLastChild(NULL),
119
120 fCursor(NULL),
121 fPicture(NULL),
122
123 fLocalClipping((BRect)Bounds()),
124 fScreenClipping(),
125 fScreenClippingValid(false),
126 fUserClipping(NULL),
127 fScreenAndUserClipping(NULL)
128 {
129 if (fDrawState.IsSet())
130 fDrawState->SetSubPixelPrecise(fFlags & B_SUBPIXEL_PRECISE);
131 }
132
133
~View()134 View::~View()
135 {
136 // iterate over children and delete each one
137 View* view = fFirstChild;
138 while (view) {
139 View* toast = view;
140 view = view->fNextSibling;
141 delete toast;
142 }
143 }
144
145
146 IntRect
Bounds() const147 View::Bounds() const
148 {
149 IntRect bounds(fScrollingOffset.x, fScrollingOffset.y,
150 fScrollingOffset.x + fFrame.Width(),
151 fScrollingOffset.y + fFrame.Height());
152 return bounds;
153 }
154
155
156 void
ConvertToVisibleInTopView(IntRect * bounds) const157 View::ConvertToVisibleInTopView(IntRect* bounds) const
158 {
159 *bounds = *bounds & Bounds();
160 // NOTE: this step is necessary even if we don't have a parent!
161 bounds->OffsetBy(fFrame.left - fScrollingOffset.x,
162 fFrame.top - fScrollingOffset.y);
163
164 if (fParent)
165 fParent->ConvertToVisibleInTopView(bounds);
166 }
167
168
169 void
AttachedToWindow(::Window * window)170 View::AttachedToWindow(::Window* window)
171 {
172 fWindow = window;
173
174 // an ugly hack to detect the desktop background
175 if (window->Feel() == kDesktopWindowFeel && Parent() == TopView())
176 fIsDesktopBackground = true;
177
178 // insert view into local token space
179 if (fWindow != NULL) {
180 fWindow->ServerWindow()->App()->ViewTokens().SetToken(fToken,
181 B_HANDLER_TOKEN, this);
182 }
183
184 // attach child views as well
185 for (View* child = FirstChild(); child; child = child->NextSibling())
186 child->AttachedToWindow(window);
187 }
188
189
190 void
DetachedFromWindow()191 View::DetachedFromWindow()
192 {
193 // remove view from local token space
194 if (fWindow != NULL && fWindow->ServerWindow()->App() != NULL)
195 fWindow->ServerWindow()->App()->ViewTokens().RemoveToken(fToken);
196
197 fWindow = NULL;
198 // detach child views as well
199 for (View* child = FirstChild(); child; child = child->NextSibling())
200 child->DetachedFromWindow();
201 }
202
203
204 // #pragma mark -
205
206
207 DrawingEngine*
GetDrawingEngine() const208 View::GetDrawingEngine() const
209 {
210 return Window()->GetDrawingEngine();
211 }
212
213
214 ServerPicture*
GetPicture(int32 token) const215 View::GetPicture(int32 token) const
216 {
217 return Window()->ServerWindow()->App()->GetPicture(token);
218 }
219
220
221 void
ResyncDrawState()222 View::ResyncDrawState()
223 {
224 return Window()->ServerWindow()->ResyncDrawState();
225 }
226
227
228 void
UpdateCurrentDrawingRegion()229 View::UpdateCurrentDrawingRegion()
230 {
231 return Window()->ServerWindow()->UpdateCurrentDrawingRegion();
232 }
233
234
235 void
AddChild(View * view)236 View::AddChild(View* view)
237 {
238 if (view->fParent) {
239 printf("View::AddChild() - View already has a parent\n");
240 return;
241 }
242
243 view->fParent = this;
244
245 if (!fLastChild) {
246 // no children yet
247 fFirstChild = view;
248 } else {
249 // append view to formerly last child
250 fLastChild->fNextSibling = view;
251 view->fPreviousSibling = fLastChild;
252 }
253 fLastChild = view;
254
255 view->UpdateVisibleDeep(fVisible);
256
257 if (view->IsVisible())
258 RebuildClipping(false);
259
260 if (fWindow) {
261 view->AttachedToWindow(fWindow);
262
263 if (view->IsVisible()) {
264 // trigger redraw
265 IntRect clippedFrame = view->Frame();
266 ConvertToVisibleInTopView(&clippedFrame);
267
268 BRegion dirty;
269 dirty.Set((clipping_rect)clippedFrame);
270 fWindow->MarkContentDirtyAsync(dirty);
271 }
272 }
273 }
274
275
276 bool
RemoveChild(View * view)277 View::RemoveChild(View* view)
278 {
279 if (view == NULL || view->fParent != this) {
280 printf("View::RemoveChild(%p - %s) - View is not child of "
281 "this (%p) view!\n", view, view ? view->Name() : NULL, this);
282 return false;
283 }
284
285 view->fParent = NULL;
286
287 if (fLastChild == view)
288 fLastChild = view->fPreviousSibling;
289 // view->fNextSibling would be NULL
290
291 if (fFirstChild == view )
292 fFirstChild = view->fNextSibling;
293 // view->fPreviousSibling would be NULL
294
295 // connect child before and after view
296 if (view->fPreviousSibling)
297 view->fPreviousSibling->fNextSibling = view->fNextSibling;
298
299 if (view->fNextSibling)
300 view->fNextSibling->fPreviousSibling = view->fPreviousSibling;
301
302 // view has no siblings anymore
303 view->fPreviousSibling = NULL;
304 view->fNextSibling = NULL;
305
306 if (view->IsVisible()) {
307 Overlay* overlay = view->_Overlay();
308 if (overlay != NULL)
309 overlay->Hide();
310
311 RebuildClipping(false);
312 }
313
314 if (fWindow) {
315 view->DetachedFromWindow();
316
317 if (fVisible && view->IsVisible()) {
318 // trigger redraw
319 IntRect clippedFrame = view->Frame();
320 ConvertToVisibleInTopView(&clippedFrame);
321
322 BRegion dirty;
323 dirty.Set((clipping_rect)clippedFrame);
324 fWindow->MarkContentDirtyAsync(dirty);
325 }
326 }
327
328 return true;
329 }
330
331
332 View*
TopView()333 View::TopView()
334 {
335 // returns the top level view of the hirarchy,
336 // it doesn't have to be the top level of a window
337
338 if (fParent)
339 return fParent->TopView();
340
341 return this;
342 }
343
344
345 uint32
CountChildren(bool deep) const346 View::CountChildren(bool deep) const
347 {
348 uint32 count = 0;
349 for (View* child = FirstChild(); child; child = child->NextSibling()) {
350 count++;
351 if (deep) {
352 count += child->CountChildren(deep);
353 }
354 }
355 return count;
356 }
357
358
359 void
CollectTokensForChildren(BList * tokenMap) const360 View::CollectTokensForChildren(BList* tokenMap) const
361 {
362 for (View* child = FirstChild(); child; child = child->NextSibling()) {
363 tokenMap->AddItem((void*)child);
364 child->CollectTokensForChildren(tokenMap);
365 }
366 }
367
368
369 #if 0
370 bool
371 View::MarkAt(DrawingEngine* engine, const BPoint& where, int32 level)
372 {
373 BRect rect(fFrame.left, fFrame.top, fFrame.right, fFrame.bottom);
374
375 if (Parent() != NULL) {
376 Parent()->ConvertToScreen(&rect);
377 if (!rect.Contains(where))
378 return false;
379
380 engine->StrokeRect(rect, (rgb_color){level * 30, level * 30, level * 30});
381 }
382
383
384 bool found = false;
385 for (View* child = FirstChild(); child; child = child->NextSibling()) {
386 found |= child->MarkAt(engine, where, level + 1);
387 }
388
389 if (!found) {
390 rgb_color color = {0};
391 switch (level % 2) {
392 case 0: color.green = rand() % 256; break;
393 case 1: color.blue = rand() % 256; break;
394 }
395
396 rect.InsetBy(1, 1);
397 //engine->FillRegion(fLocalClipping, (rgb_color){255, 255, 0, 10});
398 engine->StrokeRect(rect, color);
399 rect.InsetBy(1, 1);
400 engine->StrokeRect(rect, color);
401 }
402
403 return true;
404 }
405 #endif
406
407
408 void
FindViews(uint32 flags,BObjectList<View> & list,int32 & left)409 View::FindViews(uint32 flags, BObjectList<View>& list, int32& left)
410 {
411 if ((Flags() & flags) == flags) {
412 list.AddItem(this);
413 left--;
414 return;
415 }
416
417 for (View* child = FirstChild(); child; child = child->NextSibling()) {
418 child->FindViews(flags, list, left);
419 if (left == 0)
420 break;
421 }
422 }
423
424
425 bool
HasView(View * view)426 View::HasView(View* view)
427 {
428 if (view == this)
429 return true;
430
431 for (View* child = FirstChild(); child; child = child->NextSibling()) {
432 if (child->HasView(view))
433 return true;
434 }
435
436 return false;
437 }
438
439
440 View*
ViewAt(const BPoint & where)441 View::ViewAt(const BPoint& where)
442 {
443 if (!fVisible)
444 return NULL;
445
446 IntRect frame = Frame();
447 if (Parent() != NULL)
448 Parent()->LocalToScreenTransform().Apply(&frame);
449
450 if (!frame.Contains(where))
451 return NULL;
452
453 for (View* child = FirstChild(); child; child = child->NextSibling()) {
454 View* view = child->ViewAt(where);
455 if (view != NULL)
456 return view;
457 }
458
459 return this;
460 }
461
462
463 // #pragma mark -
464
465
466 void
SetName(const char * string)467 View::SetName(const char* string)
468 {
469 fName.SetTo(string);
470 }
471
472
473 void
SetFlags(uint32 flags)474 View::SetFlags(uint32 flags)
475 {
476 uint32 oldFlags = fFlags;
477 fFlags = flags;
478
479 // Child view with B_TRANSPARENT_BACKGROUND flag change clipping of
480 // parent view.
481 if (fParent != NULL
482 && IsVisible()
483 && (((oldFlags & B_TRANSPARENT_BACKGROUND) != 0)
484 != ((fFlags & B_TRANSPARENT_BACKGROUND) != 0))) {
485 fParent->RebuildClipping(false);
486 }
487
488 fDrawState->SetSubPixelPrecise(fFlags & B_SUBPIXEL_PRECISE);
489 }
490
491
492 void
SetViewBitmap(ServerBitmap * bitmap,IntRect sourceRect,IntRect destRect,int32 resizingMode,int32 options)493 View::SetViewBitmap(ServerBitmap* bitmap, IntRect sourceRect,
494 IntRect destRect, int32 resizingMode, int32 options)
495 {
496 if (fViewBitmap != NULL) {
497 Overlay* overlay = _Overlay();
498
499 if (bitmap != NULL) {
500 // take over overlay token from current overlay (if it has any)
501 Overlay* newOverlay = bitmap->Overlay();
502
503 if (overlay != NULL && newOverlay != NULL)
504 newOverlay->TakeOverToken(overlay);
505 } else if (overlay != NULL)
506 overlay->Hide();
507 }
508
509 fViewBitmap.SetTo(bitmap, false);
510 fBitmapSource = sourceRect;
511 fBitmapDestination = destRect;
512 fBitmapResizingMode = resizingMode;
513 fBitmapOptions = options;
514
515 _UpdateOverlayView();
516 }
517
518
519 ::Overlay*
_Overlay() const520 View::_Overlay() const
521 {
522 if (fViewBitmap == NULL)
523 return NULL;
524
525 return fViewBitmap->Overlay();
526 }
527
528
529 void
_UpdateOverlayView() const530 View::_UpdateOverlayView() const
531 {
532 Overlay* overlay = _Overlay();
533 if (overlay == NULL)
534 return;
535
536 IntRect destination = fBitmapDestination;
537 LocalToScreenTransform().Apply(&destination);
538
539 overlay->Configure(fBitmapSource, destination);
540 }
541
542
543 /*!
544 This method is called whenever the window is resized or moved - would
545 be nice to have a better solution for this, though.
546 */
547 void
UpdateOverlay()548 View::UpdateOverlay()
549 {
550 if (!IsVisible())
551 return;
552
553 if (_Overlay() != NULL) {
554 _UpdateOverlayView();
555 } else {
556 // recursively ask children of this view
557
558 for (View* child = FirstChild(); child; child = child->NextSibling()) {
559 child->UpdateOverlay();
560 }
561 }
562 }
563
564
565 // #pragma mark -
566
567
568 void
_LocalToScreenTransform(SimpleTransform & transform) const569 View::_LocalToScreenTransform(SimpleTransform& transform) const
570 {
571 const View* view = this;
572 int32 offsetX = 0;
573 int32 offsetY = 0;
574 do {
575 offsetX += view->fFrame.left - view->fScrollingOffset.x;
576 offsetY += view->fFrame.top - view->fScrollingOffset.y;
577 view = view->fParent;
578 } while (view != NULL);
579
580 transform.AddOffset(offsetX, offsetY);
581 }
582
583
584 void
_ScreenToLocalTransform(SimpleTransform & transform) const585 View::_ScreenToLocalTransform(SimpleTransform& transform) const
586 {
587 const View* view = this;
588 int32 offsetX = 0;
589 int32 offsetY = 0;
590 do {
591 offsetX += view->fScrollingOffset.x - view->fFrame.left;
592 offsetY += view->fScrollingOffset.y - view->fFrame.top;
593 view = view->fParent;
594 } while (view != NULL);
595
596 transform.AddOffset(offsetX, offsetY);
597 }
598
599
600 // #pragma mark -
601
602
603 void
MoveBy(int32 x,int32 y,BRegion * dirtyRegion)604 View::MoveBy(int32 x, int32 y, BRegion* dirtyRegion)
605 {
606 if (x == 0 && y == 0)
607 return;
608
609 fFrame.OffsetBy(x, y);
610
611 // to move on screen, we must not be hidden and we must have a parent
612 if (fVisible && fParent && dirtyRegion) {
613 #if 1
614 // based on redraw on new location
615 // the place were we are now visible
616 IntRect newVisibleBounds(Bounds());
617 // we can use the frame of the old
618 // local clipping to see which parts need invalidation
619 IntRect oldVisibleBounds(newVisibleBounds);
620 oldVisibleBounds.OffsetBy(-x, -y);
621 LocalToScreenTransform().Apply(&oldVisibleBounds);
622
623 ConvertToVisibleInTopView(&newVisibleBounds);
624
625 dirtyRegion->Include((clipping_rect)oldVisibleBounds);
626 // newVisibleBounds already is in screen coords
627 dirtyRegion->Include((clipping_rect)newVisibleBounds);
628 #else
629 // blitting version, invalidates
630 // old contents
631 IntRect oldVisibleBounds(Bounds());
632 IntRect newVisibleBounds(oldVisibleBounds);
633 oldVisibleBounds.OffsetBy(-x, -y);
634 LocalToScreenTransform().Apply(&oldVisibleBounds);
635
636 // NOTE: using ConvertToVisibleInTopView()
637 // instead of ConvertToScreen()! see below
638 ConvertToVisibleInTopView(&newVisibleBounds);
639
640 newVisibleBounds.OffsetBy(-x, -y);
641
642 // clipping oldVisibleBounds to newVisibleBounds
643 // makes sure we don't copy parts hidden under
644 // parent views
645 BRegion* region = fWindow->GetRegion();
646 if (region) {
647 region->Set(oldVisibleBounds & newVisibleBounds);
648 fWindow->CopyContents(region, x, y);
649
650 region->Set(oldVisibleBounds);
651 newVisibleBounds.OffsetBy(x, y);
652 region->Exclude((clipping_rect)newVisibleBounds);
653 dirtyRegion->Include(dirty);
654
655 fWindow->RecycleRegion(region);
656 }
657
658 #endif
659 }
660
661 if (!fParent) {
662 // the top view's screen clipping does not change,
663 // because no parts are clipped away from parent
664 // views
665 _MoveScreenClipping(x, y, true);
666 } else {
667 // parts might have been revealed from underneath
668 // the parent, or might now be hidden underneath
669 // the parent, this is taken care of when building
670 // the screen clipping
671 InvalidateScreenClipping();
672 }
673 }
674
675
676 void
ResizeBy(int32 x,int32 y,BRegion * dirtyRegion)677 View::ResizeBy(int32 x, int32 y, BRegion* dirtyRegion)
678 {
679 if (x == 0 && y == 0)
680 return;
681
682 fFrame.right += x;
683 fFrame.bottom += y;
684
685 if (fVisible && dirtyRegion) {
686 IntRect oldBounds(Bounds());
687 oldBounds.right -= x;
688 oldBounds.bottom -= y;
689
690 BRegion* dirty = fWindow->GetRegion();
691 if (!dirty)
692 return;
693
694 dirty->Set((clipping_rect)Bounds());
695 dirty->Include((clipping_rect)oldBounds);
696
697 if (!(fFlags & B_FULL_UPDATE_ON_RESIZE)) {
698 // the dirty region is just the difference of
699 // old and new bounds
700 dirty->Exclude((clipping_rect)(oldBounds & Bounds()));
701 }
702
703 InvalidateScreenClipping();
704
705 if (dirty->CountRects() > 0) {
706 if ((fFlags & B_DRAW_ON_CHILDREN) == 0) {
707 // exclude children, they are expected to
708 // include their own dirty regions in ParentResized()
709 for (View* child = FirstChild(); child;
710 child = child->NextSibling()) {
711 if (!child->IsVisible()
712 || (child->fFlags & B_TRANSPARENT_BACKGROUND) != 0) {
713 continue;
714 }
715 IntRect previousChildVisible(
716 child->Frame() & oldBounds & Bounds());
717 if (dirty->Frame().Intersects(previousChildVisible)) {
718 dirty->Exclude((clipping_rect)previousChildVisible);
719 }
720 }
721 }
722
723 LocalToScreenTransform().Apply(dirty);
724 dirtyRegion->Include(dirty);
725 }
726 fWindow->RecycleRegion(dirty);
727 }
728
729 // layout the children
730 for (View* child = FirstChild(); child; child = child->NextSibling())
731 child->ParentResized(x, y, dirtyRegion);
732
733 // view bitmap
734 if (fViewBitmap != NULL)
735 resize_frame(fBitmapDestination, fBitmapResizingMode, x, y);
736
737 // at this point, children are at their new locations,
738 // so we can rebuild the clipping
739 // TODO: when the implementation of Hide() and Show() is
740 // complete, see if this should be avoided
741 RebuildClipping(false);
742 }
743
744
745 void
ParentResized(int32 x,int32 y,BRegion * dirtyRegion)746 View::ParentResized(int32 x, int32 y, BRegion* dirtyRegion)
747 {
748 IntRect newFrame = fFrame;
749 resize_frame(newFrame, fResizeMode & 0x0000ffff, x, y);
750
751 if (newFrame != fFrame) {
752 // careful, MoveBy will change fFrame
753 int32 widthDiff = (int32)(newFrame.Width() - fFrame.Width());
754 int32 heightDiff = (int32)(newFrame.Height() - fFrame.Height());
755
756 MoveBy(newFrame.left - fFrame.left,
757 newFrame.top - fFrame.top, dirtyRegion);
758
759 ResizeBy(widthDiff, heightDiff, dirtyRegion);
760 } else {
761 // TODO: this covers the fact that our screen clipping might change
762 // when the parent changes its size, even though our frame stays
763 // the same - there might be a way to test for this, but axeld doesn't
764 // know, stippi should look into this when he's back :)
765 InvalidateScreenClipping();
766 }
767 }
768
769
770 void
ScrollBy(int32 x,int32 y,BRegion * dirtyRegion)771 View::ScrollBy(int32 x, int32 y, BRegion* dirtyRegion)
772 {
773 if (!fVisible || !fWindow) {
774 fScrollingOffset.x += x;
775 fScrollingOffset.y += y;
776 return;
777 }
778
779 // blitting version, invalidates
780 // old contents
781
782 // remember old bounds for tracking dirty region
783 IntRect oldBounds(Bounds());
784
785 // NOTE: using ConvertToVisibleInTopView()
786 // instead of ConvertToScreen(), this makes
787 // sure we don't try to move or invalidate an
788 // area hidden underneath the parent view
789 ConvertToVisibleInTopView(&oldBounds);
790
791 // find the area of the view that can be scrolled,
792 // contents are shifted in the opposite direction from scrolling
793 IntRect stillVisibleBounds(oldBounds);
794 stillVisibleBounds.OffsetBy(x, y);
795 stillVisibleBounds = stillVisibleBounds & oldBounds;
796
797 fScrollingOffset.x += x;
798 fScrollingOffset.y += y;
799
800 // do the blit, this will make sure
801 // that other more complex dirty regions
802 // are taken care of
803 BRegion* copyRegion = fWindow->GetRegion();
804 if (!copyRegion)
805 return;
806 copyRegion->Set((clipping_rect)stillVisibleBounds);
807 fWindow->CopyContents(copyRegion, -x, -y);
808
809 // find the dirty region as far as we are
810 // concerned
811 BRegion* dirty = copyRegion;
812 // reuse copyRegion and call it dirty
813
814 dirty->Set((clipping_rect)oldBounds);
815 stillVisibleBounds.OffsetBy(-x, -y);
816 dirty->Exclude((clipping_rect)stillVisibleBounds);
817 dirtyRegion->Include(dirty);
818
819 fWindow->RecycleRegion(dirty);
820
821 // the screen clipping of this view and it's
822 // childs is no longer valid
823 InvalidateScreenClipping();
824 RebuildClipping(false);
825 }
826
827
828 void
CopyBits(IntRect src,IntRect dst,BRegion & windowContentClipping)829 View::CopyBits(IntRect src, IntRect dst, BRegion& windowContentClipping)
830 {
831 if (!fVisible || !fWindow)
832 return;
833
834 // TODO: figure out what to do when we have a transform which is not
835 // a dilation
836 BAffineTransform transform = CurrentState()->CombinedTransform();
837 if (!transform.IsIdentity() && transform.IsDilation()) {
838 BPoint points[4] = { src.LeftTop(), src.RightBottom(),
839 dst.LeftTop(), dst.RightBottom() };
840 transform.Apply(&points[0], 4);
841 src.Set(points[0].x, points[0].y, points[1].x, points[1].y);
842 dst.Set(points[2].x, points[2].y, points[3].x, points[3].y);
843 }
844
845 // TODO: confirm that in R5 this call is affected by origin and scale
846
847 // blitting version
848
849 int32 xOffset = dst.left - src.left;
850 int32 yOffset = dst.top - src.top;
851
852 // figure out which part can be blittet
853 IntRect visibleSrc(src);
854 ConvertToVisibleInTopView(&visibleSrc);
855
856 IntRect visibleSrcAtDest(src);
857 visibleSrcAtDest.OffsetBy(xOffset, yOffset);
858 ConvertToVisibleInTopView(&visibleSrcAtDest);
859
860 // clip src to visible at dest
861 visibleSrcAtDest.OffsetBy(-xOffset, -yOffset);
862 visibleSrc = visibleSrc & visibleSrcAtDest;
863
864 // do the blit, this will make sure
865 // that other more complex dirty regions
866 // are taken care of
867 BRegion* copyRegion = fWindow->GetRegion();
868 if (!copyRegion)
869 return;
870
871 // move src rect to destination here for efficiency reasons
872 visibleSrc.OffsetBy(xOffset, yOffset);
873
874 // we need to interstect the copyRegion two times, onces
875 // at the source and once at the destination (here done
876 // the other way arround but it doesn't matter)
877 // the reason for this is that we are not supposed to visually
878 // copy children in the source rect and neither to copy onto
879 // children in the destination rect...
880 copyRegion->Set((clipping_rect)visibleSrc);
881 BRegion *screenAndUserClipping
882 = &ScreenAndUserClipping(&windowContentClipping);
883 copyRegion->IntersectWith(screenAndUserClipping);
884 copyRegion->OffsetBy(-xOffset, -yOffset);
885 copyRegion->IntersectWith(screenAndUserClipping);
886
887 // do the actual blit
888 fWindow->CopyContents(copyRegion, xOffset, yOffset);
889
890 // find the dirty region as far as we are concerned
891 IntRect dirtyDst(dst);
892 ConvertToVisibleInTopView(&dirtyDst);
893
894 BRegion* dirty = fWindow->GetRegion();
895 if (!dirty) {
896 fWindow->RecycleRegion(copyRegion);
897 return;
898 }
899
900 // offset copyRegion to destination again
901 copyRegion->OffsetBy(xOffset, yOffset);
902 // start with destination given by user
903 dirty->Set((clipping_rect)dirtyDst);
904 // exclude the part that we could copy
905 dirty->Exclude(copyRegion);
906
907 dirty->IntersectWith(screenAndUserClipping);
908 fWindow->MarkContentDirty(*dirty, *dirty);
909
910 fWindow->RecycleRegion(dirty);
911 fWindow->RecycleRegion(copyRegion);
912 }
913
914
915 // #pragma mark -
916
917
918 void
ColorUpdated(color_which which,rgb_color color)919 View::ColorUpdated(color_which which, rgb_color color)
920 {
921 float tint = B_NO_TINT;
922
923 if (fWhichViewColor == which)
924 SetViewColor(tint_color(color, fWhichViewColorTint));
925
926 if (CurrentState()->HighUIColor(&tint) == which)
927 CurrentState()->SetHighColor(tint_color(color, tint));
928
929 if (CurrentState()->LowUIColor(&tint) == which)
930 CurrentState()->SetLowColor(tint_color(color, tint));
931
932 for (View* child = FirstChild(); child != NULL;
933 child = child->NextSibling()) {
934
935 child->ColorUpdated(which, color);
936 }
937 }
938
939
940 void
SetViewUIColor(color_which which,float tint)941 View::SetViewUIColor(color_which which, float tint)
942 {
943 if (which != B_NO_COLOR) {
944 DesktopSettings settings(fWindow->Desktop());
945 SetViewColor(tint_color(settings.UIColor(which), tint));
946 }
947
948 fWhichViewColor = which;
949 fWhichViewColorTint = tint;
950 }
951
952
953 color_which
ViewUIColor(float * tint)954 View::ViewUIColor(float* tint)
955 {
956 if (tint != NULL)
957 *tint = fWhichViewColorTint;
958
959 return fWhichViewColor;
960 }
961
962
963 // #pragma mark -
964
965
966 void
PushState()967 View::PushState()
968 {
969 DrawState* previousState = fDrawState.Detach();
970 DrawState* newState = previousState->PushState();
971 if (newState == NULL)
972 newState = previousState;
973
974 fDrawState.SetTo(newState);
975 // In BeAPI, B_SUBPIXEL_PRECISE is a view flag, and not affected by the
976 // view state. Our implementation moves it to the draw state, but let's
977 // be compatible with the API here and make it survive accross state
978 // changes.
979 fDrawState->SetSubPixelPrecise(fFlags & B_SUBPIXEL_PRECISE);
980 }
981
982
983 void
PopState()984 View::PopState()
985 {
986 if (fDrawState->PreviousState() == NULL) {
987 fprintf(stderr, "WARNING: User called BView(%s)::PopState(), "
988 "but there is NO state on stack!\n", Name());
989 return;
990 }
991
992 bool rebuildClipping = fDrawState->HasAdditionalClipping();
993
994 fDrawState.SetTo(fDrawState->PopState());
995 fDrawState->SetSubPixelPrecise(fFlags & B_SUBPIXEL_PRECISE);
996
997 // rebuild clipping
998 // (the clipping from the popped state is not effective anymore)
999 if (rebuildClipping)
1000 RebuildClipping(false);
1001 }
1002
1003
1004 // #pragma mark -
1005
1006
1007 void
SetEventMask(uint32 eventMask,uint32 options)1008 View::SetEventMask(uint32 eventMask, uint32 options)
1009 {
1010 fEventMask = eventMask;
1011 fEventOptions = options;
1012 }
1013
1014
1015 void
SetCursor(ServerCursor * cursor)1016 View::SetCursor(ServerCursor* cursor)
1017 {
1018 if (cursor == fCursor)
1019 return;
1020
1021 fCursor.SetTo(cursor, false);
1022 }
1023
1024
1025 void
SetPicture(ServerPicture * picture)1026 View::SetPicture(ServerPicture* picture)
1027 {
1028 if (picture == fPicture)
1029 return;
1030
1031 fPicture.SetTo(picture, false);
1032 }
1033
1034
1035 void
BlendAllLayers()1036 View::BlendAllLayers()
1037 {
1038 if (fPicture == NULL)
1039 return;
1040 Layer* layer = dynamic_cast<Layer*>(fPicture.Get());
1041 if (layer == NULL)
1042 return;
1043 BlendLayer(layer);
1044 }
1045
1046
1047 void
Draw(DrawingEngine * drawingEngine,const BRegion * effectiveClipping,const BRegion * windowContentClipping,bool deep)1048 View::Draw(DrawingEngine* drawingEngine, const BRegion* effectiveClipping,
1049 const BRegion* windowContentClipping, bool deep)
1050 {
1051 if (!fVisible) {
1052 // child views cannot be visible either
1053 return;
1054 }
1055
1056 if (fViewBitmap != NULL || fViewColor != B_TRANSPARENT_COLOR) {
1057 // we can only draw within our own area
1058 BRegion* redraw;
1059 if ((fFlags & B_DRAW_ON_CHILDREN) != 0) {
1060 // The client may actually want to prevent the background to
1061 // be painted outside the user clipping.
1062 redraw = fWindow->GetRegion(
1063 ScreenAndUserClipping(windowContentClipping));
1064 } else {
1065 // Ignore user clipping as in BeOS for painting the background.
1066 redraw = fWindow->GetRegion(
1067 _ScreenClipping(windowContentClipping));
1068 }
1069 if (!redraw)
1070 return;
1071 // add the current clipping
1072 redraw->IntersectWith(effectiveClipping);
1073
1074 Overlay* overlayCookie = _Overlay();
1075
1076 if (fViewBitmap != NULL && overlayCookie == NULL) {
1077 // draw view bitmap
1078 // TODO: support other options!
1079 BRect rect = fBitmapDestination;
1080 PenToScreenTransform().Apply(&rect);
1081
1082 align_rect_to_pixels(&rect);
1083
1084 if (fBitmapOptions & B_TILE_BITMAP_Y) {
1085 // move rect up as much as needed
1086 while (rect.top > redraw->Frame().top)
1087 rect.OffsetBy(0.0, -(rect.Height() + 1));
1088 }
1089 if (fBitmapOptions & B_TILE_BITMAP_X) {
1090 // move rect left as much as needed
1091 while (rect.left > redraw->Frame().left)
1092 rect.OffsetBy(-(rect.Width() + 1), 0.0);
1093 }
1094
1095 // XXX: locking removed because the Window keeps the engine locked
1096 // because it keeps track of syncing right now
1097
1098 // lock the drawing engine for as long as we need the clipping
1099 // to be valid
1100 if (rect.IsValid()/* && drawingEngine->Lock()*/) {
1101 drawingEngine->ConstrainClippingRegion(redraw);
1102
1103 drawing_mode oldMode;
1104 drawingEngine->SetDrawingMode(B_OP_COPY, oldMode);
1105
1106 if (fBitmapOptions & B_TILE_BITMAP) {
1107 // tile across entire view
1108
1109 float start = rect.left;
1110 while (rect.top < redraw->Frame().bottom) {
1111 while (rect.left < redraw->Frame().right) {
1112 drawingEngine->DrawBitmap(fViewBitmap,
1113 fBitmapSource, rect, fBitmapOptions);
1114 rect.OffsetBy(rect.Width() + 1, 0.0);
1115 }
1116 rect.OffsetBy(start - rect.left, rect.Height() + 1);
1117 }
1118 // nothing left to be drawn
1119 redraw->MakeEmpty();
1120 } else if (fBitmapOptions & B_TILE_BITMAP_X) {
1121 // tile in x direction
1122
1123 while (rect.left < redraw->Frame().right) {
1124 drawingEngine->DrawBitmap(fViewBitmap, fBitmapSource,
1125 rect, fBitmapOptions);
1126 rect.OffsetBy(rect.Width() + 1, 0.0);
1127 }
1128 // remove horizontal stripe from clipping
1129 rect.left = redraw->Frame().left;
1130 rect.right = redraw->Frame().right;
1131 redraw->Exclude(rect);
1132 } else if (fBitmapOptions & B_TILE_BITMAP_Y) {
1133 // tile in y direction
1134
1135 while (rect.top < redraw->Frame().bottom) {
1136 drawingEngine->DrawBitmap(fViewBitmap, fBitmapSource,
1137 rect, fBitmapOptions);
1138 rect.OffsetBy(0.0, rect.Height() + 1);
1139 }
1140 // remove vertical stripe from clipping
1141 rect.top = redraw->Frame().top;
1142 rect.bottom = redraw->Frame().bottom;
1143 redraw->Exclude(rect);
1144 } else {
1145 // no tiling at all
1146
1147 drawingEngine->DrawBitmap(fViewBitmap, fBitmapSource,
1148 rect, fBitmapOptions);
1149 redraw->Exclude(rect);
1150 }
1151
1152 drawingEngine->SetDrawingMode(oldMode);
1153
1154 // NOTE: It is ok not to reset the clipping, that
1155 // would only waste time
1156 // drawingEngine->Unlock();
1157 }
1158
1159 }
1160
1161 if (fViewColor != B_TRANSPARENT_COLOR) {
1162 // fill visible region with view color,
1163 // this version of FillRegion ignores any
1164 // clipping, that's why "redraw" needs to
1165 // be correct
1166 // see #634
1167 // if (redraw->Frame().left < 0 || redraw->Frame().top < 0) {
1168 // char message[1024];
1169 // BRect c = effectiveClipping->Frame();
1170 // BRect w = windowContentClipping->Frame();
1171 // BRect r = redraw->Frame();
1172 // sprintf(message, "invalid background: current clipping: (%d, %d)->(%d, %d), "
1173 // "window content: (%d, %d)->(%d, %d), redraw: (%d, %d)->(%d, %d)",
1174 // (int)c.left, (int)c.top, (int)c.right, (int)c.bottom,
1175 // (int)w.left, (int)w.top, (int)w.right, (int)w.bottom,
1176 // (int)r.left, (int)r.top, (int)r.right, (int)r.bottom);
1177 // debugger(message);
1178 // }
1179
1180 drawingEngine->FillRegion(*redraw, overlayCookie != NULL
1181 ? overlayCookie->Color() : fViewColor);
1182 }
1183
1184 fWindow->RecycleRegion(redraw);
1185 }
1186
1187 fBackgroundDirty = false;
1188
1189 // let children draw
1190 if (deep) {
1191 for (View* child = FirstChild(); child; child = child->NextSibling()) {
1192 child->Draw(drawingEngine, effectiveClipping,
1193 windowContentClipping, deep);
1194 }
1195 }
1196 }
1197
1198
1199 // #pragma mark -
1200
1201
1202 void
MouseDown(BMessage * message,BPoint where)1203 View::MouseDown(BMessage* message, BPoint where)
1204 {
1205 // empty hook method
1206 }
1207
1208
1209 void
MouseUp(BMessage * message,BPoint where)1210 View::MouseUp(BMessage* message, BPoint where)
1211 {
1212 // empty hook method
1213 }
1214
1215
1216 void
MouseMoved(BMessage * message,BPoint where)1217 View::MouseMoved(BMessage* message, BPoint where)
1218 {
1219 // empty hook method
1220 }
1221
1222
1223 // #pragma mark -
1224
1225
1226 void
SetHidden(bool hidden)1227 View::SetHidden(bool hidden)
1228 {
1229 if (fHidden != hidden) {
1230 fHidden = hidden;
1231
1232 // recurse into children and update their visible flag
1233 bool oldVisible = fVisible;
1234 UpdateVisibleDeep(fParent ? fParent->IsVisible() : !fHidden);
1235 if (oldVisible != fVisible) {
1236 // Include or exclude us from the parent area, and update the
1237 // children's clipping as well when the view will be visible
1238 if (fParent)
1239 fParent->RebuildClipping(fVisible);
1240 else
1241 RebuildClipping(fVisible);
1242
1243 if (fWindow) {
1244 // trigger a redraw
1245 IntRect clippedBounds = Bounds();
1246 ConvertToVisibleInTopView(&clippedBounds);
1247
1248 BRegion dirty, expose;
1249 dirty.Set((clipping_rect)clippedBounds);
1250 fWindow->MarkContentDirty(dirty, expose);
1251 }
1252 }
1253 }
1254 }
1255
1256
1257 bool
IsHidden() const1258 View::IsHidden() const
1259 {
1260 return fHidden;
1261 }
1262
1263
1264 void
UpdateVisibleDeep(bool parentVisible)1265 View::UpdateVisibleDeep(bool parentVisible)
1266 {
1267 bool wasVisible = fVisible;
1268
1269 fVisible = parentVisible && !fHidden;
1270 for (View* child = FirstChild(); child; child = child->NextSibling())
1271 child->UpdateVisibleDeep(fVisible);
1272
1273 // overlay handling
1274
1275 Overlay* overlay = _Overlay();
1276 if (overlay == NULL)
1277 return;
1278
1279 if (fVisible && !wasVisible)
1280 _UpdateOverlayView();
1281 else if (!fVisible && wasVisible)
1282 overlay->Hide();
1283 }
1284
1285
1286 // #pragma mark -
1287
1288
1289 void
MarkBackgroundDirty()1290 View::MarkBackgroundDirty()
1291 {
1292 if (fBackgroundDirty)
1293 return;
1294 fBackgroundDirty = true;
1295 for (View* child = FirstChild(); child; child = child->NextSibling())
1296 child->MarkBackgroundDirty();
1297 }
1298
1299
1300 void
AddTokensForViewsInRegion(BPrivate::PortLink & link,BRegion & region,BRegion * windowContentClipping)1301 View::AddTokensForViewsInRegion(BPrivate::PortLink& link, BRegion& region,
1302 BRegion* windowContentClipping)
1303 {
1304 if (!fVisible)
1305 return;
1306
1307 {
1308 // NOTE: use scope in order to reduce stack space requirements
1309
1310 // This check will prevent descending the view hierarchy
1311 // any further than necessary
1312 IntRect screenBounds(Bounds());
1313 LocalToScreenTransform().Apply(&screenBounds);
1314 if (!region.Intersects((clipping_rect)screenBounds))
1315 return;
1316
1317 // Unfortunately, we intersecting another region, but otherwise
1318 // we couldn't provide the exact update rect to the client
1319 BRegion localDirty = _ScreenClipping(windowContentClipping);
1320 localDirty.IntersectWith(®ion);
1321 if (localDirty.CountRects() > 0) {
1322 link.Attach<int32>(fToken);
1323 link.Attach<BRect>(localDirty.Frame());
1324 }
1325 }
1326
1327 for (View* child = FirstChild(); child; child = child->NextSibling())
1328 child->AddTokensForViewsInRegion(link, region, windowContentClipping);
1329 }
1330
1331
1332 void
PrintToStream() const1333 View::PrintToStream() const
1334 {
1335 printf("View: %s\n", Name());
1336 printf(" fToken: %" B_PRId32 "\n", fToken);
1337 printf(" fFrame: IntRect(%" B_PRId32 ", %" B_PRId32 ", %" B_PRId32 ", %" B_PRId32 ")\n",
1338 fFrame.left, fFrame.top, fFrame.right, fFrame.bottom);
1339 printf(" fScrollingOffset: IntPoint(%" B_PRId32 ", %" B_PRId32 ")\n",
1340 fScrollingOffset.x, fScrollingOffset.y);
1341 printf(" fHidden: %d\n", fHidden);
1342 printf(" fVisible: %d\n", fVisible);
1343 printf(" fWindow: %p\n", fWindow);
1344 printf(" fParent: %p\n", fParent);
1345 printf(" fLocalClipping:\n");
1346 fLocalClipping.PrintToStream();
1347 printf(" fScreenClipping:\n");
1348 fScreenClipping.PrintToStream();
1349 printf(" valid: %d\n", fScreenClippingValid);
1350
1351 printf(" fUserClipping:\n");
1352 if (fUserClipping.IsSet())
1353 fUserClipping->PrintToStream();
1354 else
1355 printf(" none\n");
1356
1357 printf(" fScreenAndUserClipping:\n");
1358 if (fScreenAndUserClipping.IsSet())
1359 fScreenAndUserClipping->PrintToStream();
1360 else
1361 printf(" invalid\n");
1362
1363 printf(" state:\n");
1364 printf(" user clipping: %d\n", fDrawState->HasClipping());
1365 BPoint origin = fDrawState->CombinedOrigin();
1366 printf(" origin: BPoint(%.1f, %.1f)\n", origin.x, origin.y);
1367 printf(" scale: %.2f\n", fDrawState->CombinedScale());
1368 printf("\n");
1369 }
1370
1371
1372 void
RebuildClipping(bool deep)1373 View::RebuildClipping(bool deep)
1374 {
1375 // the clipping spans over the bounds area
1376 fLocalClipping.Set((clipping_rect)Bounds());
1377
1378 if (View* child = FirstChild()) {
1379 // if this view does not draw over children,
1380 // exclude all children from the clipping
1381 if ((fFlags & B_DRAW_ON_CHILDREN) == 0) {
1382 BRegion* childrenRegion = fWindow->GetRegion();
1383 if (!childrenRegion)
1384 return;
1385
1386 for (; child; child = child->NextSibling()) {
1387 if (child->IsVisible()
1388 && (child->fFlags & B_TRANSPARENT_BACKGROUND) == 0) {
1389 childrenRegion->Include((clipping_rect)child->Frame());
1390 }
1391 }
1392
1393 fLocalClipping.Exclude(childrenRegion);
1394 fWindow->RecycleRegion(childrenRegion);
1395 }
1396 // if the operation is "deep", make children rebuild their
1397 // clipping too
1398 if (deep) {
1399 for (child = FirstChild(); child; child = child->NextSibling())
1400 child->RebuildClipping(true);
1401 }
1402 }
1403
1404 // add the user clipping in case there is one
1405 if (fDrawState->HasClipping()) {
1406 // NOTE: in case the user sets a user defined clipping region,
1407 // rebuilding the clipping is a bit more expensive because there
1408 // is no separate "drawing region"... on the other
1409 // hand, views for which this feature is actually used will
1410 // probably not have any children, so it is not that expensive
1411 // after all
1412 if (!fUserClipping.IsSet()) {
1413 fUserClipping.SetTo(new (nothrow) BRegion);
1414 if (!fUserClipping.IsSet())
1415 return;
1416 }
1417
1418 fDrawState->GetCombinedClippingRegion(fUserClipping.Get());
1419 } else {
1420 fUserClipping.SetTo(NULL);
1421 }
1422
1423 fScreenAndUserClipping.SetTo(NULL);
1424 fScreenClippingValid = false;
1425 }
1426
1427
1428 BRegion&
ScreenAndUserClipping(const BRegion * windowContentClipping,bool force) const1429 View::ScreenAndUserClipping(const BRegion* windowContentClipping, bool force) const
1430 {
1431 // no user clipping - return screen clipping directly
1432 if (!fUserClipping.IsSet())
1433 return _ScreenClipping(windowContentClipping, force);
1434
1435 // combined screen and user clipping already valid
1436 if (fScreenAndUserClipping.IsSet())
1437 return *fScreenAndUserClipping.Get();
1438
1439 // build a new combined user and screen clipping
1440 fScreenAndUserClipping.SetTo(new (nothrow) BRegion(*fUserClipping.Get()));
1441 if (!fScreenAndUserClipping.IsSet())
1442 return fScreenClipping;
1443
1444 LocalToScreenTransform().Apply(fScreenAndUserClipping.Get());
1445 fScreenAndUserClipping->IntersectWith(
1446 &_ScreenClipping(windowContentClipping, force));
1447 return *fScreenAndUserClipping.Get();
1448 }
1449
1450
1451 void
InvalidateScreenClipping()1452 View::InvalidateScreenClipping()
1453 {
1454 // TODO: appearantly, we are calling ScreenClipping() on
1455 // views who's parents don't have a valid screen clipping yet,
1456 // this messes up the logic that for any given view with
1457 // fScreenClippingValid == false, all children have
1458 // fScreenClippingValid == false too. If this could be made the
1459 // case, we could save some performance here with the commented
1460 // out check, since InvalidateScreenClipping() might be called
1461 // frequently.
1462 // TODO: investigate, if InvalidateScreenClipping() could be
1463 // called in "deep" and "non-deep" mode, ie. see if there are
1464 // any cases where the children would still have valid screen
1465 // clipping, even though the parent's screen clipping becomes
1466 // invalid.
1467 // if (!fScreenClippingValid)
1468 // return;
1469
1470 fScreenAndUserClipping.SetTo(NULL);
1471 fScreenClippingValid = false;
1472 // invalidate the childrens screen clipping as well
1473 for (View* child = FirstChild(); child; child = child->NextSibling()) {
1474 child->InvalidateScreenClipping();
1475 }
1476 }
1477
1478
1479 BRegion&
_ScreenClipping(const BRegion * windowContentClipping,bool force) const1480 View::_ScreenClipping(const BRegion* windowContentClipping, bool force) const
1481 {
1482 if (!fScreenClippingValid || force) {
1483 fScreenClipping = fLocalClipping;
1484 LocalToScreenTransform().Apply(&fScreenClipping);
1485
1486 // see if parts of our bounds are hidden underneath
1487 // the parent, the local clipping does not account for this
1488 IntRect clippedBounds = Bounds();
1489 ConvertToVisibleInTopView(&clippedBounds);
1490 if (clippedBounds.Width() < fScreenClipping.Frame().Width()
1491 || clippedBounds.Height() < fScreenClipping.Frame().Height()) {
1492 BRegion temp;
1493 temp.Set((clipping_rect)clippedBounds);
1494 fScreenClipping.IntersectWith(&temp);
1495 }
1496
1497 fScreenClipping.IntersectWith(windowContentClipping);
1498 fScreenClippingValid = true;
1499 }
1500
1501 return fScreenClipping;
1502 }
1503
1504
1505 void
_MoveScreenClipping(int32 x,int32 y,bool deep)1506 View::_MoveScreenClipping(int32 x, int32 y, bool deep)
1507 {
1508 if (fScreenClippingValid) {
1509 fScreenClipping.OffsetBy(x, y);
1510 fScreenAndUserClipping.SetTo(NULL);
1511 }
1512
1513 if (deep) {
1514 // move the childrens screen clipping as well
1515 for (View* child = FirstChild(); child; child = child->NextSibling()) {
1516 child->_MoveScreenClipping(x, y, deep);
1517 }
1518 }
1519 }
1520
1521