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