Layer.cpp revision bde8b9c6e0e93228febce69548748d26d62cb254
1/*
2 * Copyright (c) 2001-2005, 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 *		Stephan A��mus <superstippi@gmx.de>
9 */
10
11/**	Class used for tracking drawing context and screen clipping.
12 *	One Layer per client BWindow (WindowBorder) and each BView therein.
13 */
14
15#include <string.h>
16#include <stdio.h>
17#include <stdlib.h>
18
19#include <AppDefs.h>
20#include <Message.h>
21#include <Region.h>
22#include <View.h>
23
24#include "DebugInfoManager.h"
25#include "DrawingEngine.h"
26#include "DrawState.h"
27#include "PortLink.h"
28#include "RootLayer.h"
29#include "ServerApp.h"
30#include "ServerProtocol.h"
31#include "ServerWindow.h"
32#include "WinBorder.h"
33#include "Layer.h"
34#include "ServerBitmap.h"
35
36//#define DEBUG_LAYER
37#ifdef DEBUG_LAYER
38#	define STRACE(x) printf x
39#else
40#	define STRACE(x) ;
41#endif
42
43
44Layer::Layer(BRect frame, const char* name, int32 token,
45	uint32 resize, uint32 flags, DrawingEngine* driver)
46	:
47	fName(name),
48	fFrame(frame),
49	fScrollingOffset(0.0, 0.0),
50
51	fDriver(driver),
52	fRootLayer(NULL),
53	fWindow(NULL),
54	fOwner(NULL),
55
56	fDrawState(new DrawState),
57
58	fParent(NULL),
59	fPreviousSibling(NULL),
60	fNextSibling(NULL),
61	fFirstChild(NULL),
62	fLastChild(NULL),
63
64	fViewToken(token),
65	fFlags(flags),
66	fResizeMode(resize),
67	fEventMask(0UL),
68	fEventOptions(0UL),
69
70	fHidden(false),
71	fIsTopLayer(false),
72	fViewColor(255, 255, 255, 255),
73
74	fBackgroundBitmap(NULL),
75	fOverlayBitmap(NULL)
76{
77	if (!frame.IsValid()) {
78		char helper[1024];
79		sprintf(helper, "Layer::Layer(BRect(%.1f, %.1f, %.1f, %.1f), name: %s, token: %ld) - frame is invalid\n",
80			frame.left, frame.top, frame.right, frame.bottom, name, token);
81		CRITICAL(helper);
82		fFrame.Set(0, 0, 1, 1);
83	}
84
85	if (!fDriver)
86		CRITICAL("You MUST have a valid driver to init a Layer object\n");
87
88	// NOTE: This flag is forwarded to a DrawState setting, even
89	// though it is actually not part of a "state". However,
90	// it is an important detail of a graphics context, and we
91	// have no other means to pass this setting on to the DrawingEngine
92	// other than through the DrawState. If we ever add a flag
93	// B_ANTI_ALIASING to the view flags, it would have to be passed
94	// in the same way. Though when breaking binary compatibility,
95	// we might want to make this an actual part of a "state" (with
96	// a different API to set these).
97	// Note that the flag is also tested (updated) in Push/PopState and
98	// SetFlags().
99	fDrawState->SetSubPixelPrecise(fFlags & B_SUBPIXEL_PRECISE);
100
101	STRACE(("Layer(%s) successfuly created\n", Name()));
102}
103
104
105Layer::~Layer()
106{
107	delete fDrawState;
108
109	if (fWindow != NULL)
110		fWindow->App()->ViewTokens().RemoveToken(ViewToken());
111
112	Layer* child = fFirstChild;
113	while (child != NULL) {
114		Layer* nextChild = child->fNextSibling;
115
116		delete child;
117		child = nextChild;
118	}
119}
120
121
122/*!
123	\brief Adds a child layer to the current one
124	\param layer a new child layer
125	\param serverWin the serverwindow to which the layer will belong
126
127	Unlike the BView version, if the layer already belongs to another, then
128	it spits an error to stdout and returns.
129*/
130void
131Layer::AddChild(Layer* child, ServerWindow* window)
132{
133	STRACE(("Layer(%s)::AddChild(%s)\n", Name(), child->Name()));
134
135	if (child->fParent != NULL) {
136		printf("ERROR: AddChild(): Layer already has a parent\n");
137		return;
138	}
139
140	// 1) attach layer to the tree structure
141	child->fParent = this;
142
143	// if we have children already, bump the current last child back one and
144	// make the new child the last layer
145	if (fLastChild) {
146		child->fPreviousSibling = fLastChild;
147		fLastChild->fNextSibling = child;
148	} else {
149		fFirstChild = child;
150	}
151	fLastChild = child;
152
153	// if we have no RootLayer yet, then there is no need to set any parameters --
154	// they will be set when the RootLayer for this tree will be added
155	// to the main tree structure.
156	if (!fRootLayer) {
157		STRACE(("Layer(%s)::AddChild(%s) END\n", Name(), child->Name()));
158		return;
159	}
160
161	// 2) Iterate over the newly-added layer and all its children, setting the
162	//	root layer and server window and also rebuilding the full-size region
163	//	for every descendant of the newly-added layer
164
165	Layer* stop = child;
166	while (true) {
167		// action block
168
169		// 2.1) set the RootLayer for this object.
170		child->SetRootLayer(child->fParent->fRootLayer);
171
172		// 2.2) this Layer must know if it has a ServerWindow object attached.
173		child->fWindow = window;
174
175		// insert view into local token space
176		window->App()->ViewTokens().SetToken(child->ViewToken(),
177			B_HANDLER_TOKEN, child);
178
179		// tree parsing algorithm
180		if (child->fFirstChild) {
181			// go deep
182			child = child->fFirstChild;
183		} else {
184			// go right or up
185
186			if (child == stop) // our trip is over
187				break;
188
189			if (child->fNextSibling) {
190				// go right
191				child = child->fNextSibling;
192			} else {
193				// go up
194				while (child->fParent->fNextSibling == NULL && child->fParent != stop)
195					child = child->fParent;
196
197				if (child->fParent == stop) // that's enough!
198					break;
199
200				child = child->fParent->fNextSibling;
201			}
202		}
203	}
204}
205
206
207/*!
208	\brief Removes a child layer from the current one
209	\param layer the layer to remove
210
211	If the layer does not belong to the the current layer, then this function
212	spits out an error to stdout and returns
213*/
214void
215Layer::RemoveChild(Layer *child)
216{
217	STRACE(("Layer(%s)::RemoveChild(%s)\n", Name(), child->Name()));
218
219	if (!child->fParent) {
220		printf("ERROR: RemoveChild(): Layer doesn't have a parent\n");
221		return;
222	}
223	if (child->fParent != this) {
224		printf("ERROR: RemoveChild(): Layer is not a child of this layer\n");
225		return;
226	}
227
228	// 1) remove this layer from the main tree.
229
230	// Take care of fParent
231	child->fParent = NULL;
232
233	if (fFirstChild == child)
234		fFirstChild = child->fNextSibling;
235
236	if (fLastChild == child)
237		fLastChild = child->fPreviousSibling;
238
239	// Take care of siblings
240	if (child->fPreviousSibling != NULL)
241		child->fPreviousSibling->fNextSibling = child->fNextSibling;
242
243	if (child->fNextSibling != NULL)
244		child->fNextSibling->fPreviousSibling = child->fPreviousSibling;
245
246	child->fPreviousSibling = NULL;
247	child->fNextSibling = NULL;
248	child->_ClearVisibleRegions();
249
250	// 2) Iterate over all of the removed-layer's descendants and unset the
251	//	root layer, server window, and all redraw-related regions
252
253	Layer* stop = child;
254	while (true) {
255		// action block
256
257		// 2.1) set the RootLayer for this object.
258		child->SetRootLayer(NULL);
259		// 2.2) this Layer must know if it has a ServerWindow object attached.
260		if (child->Window())
261			child->Window()->App()->ViewTokens().RemoveToken(child->ViewToken());
262		child->fWindow = NULL;
263
264		// tree parsing algorithm
265		if (child->fFirstChild) {
266			// go deep
267			child = child->fFirstChild;
268		} else {
269			// go right or up
270			if (child == stop) // out trip is over
271				break;
272
273			if (child->fNextSibling) {
274				// go right
275				child = child->fNextSibling;
276			} else {
277				// go up
278				while (child->fParent->fNextSibling == NULL && child->fParent != stop)
279					child = child->fParent;
280
281				if (child->fParent == stop) // that enough!
282					break;
283
284				child = child->fParent->fNextSibling;
285			}
286		}
287	}
288}
289
290
291//! Removes the calling layer from the tree
292void
293Layer::RemoveSelf()
294{
295	// A Layer removes itself from the tree (duh)
296	if (fParent == NULL) {
297		printf("ERROR: RemoveSelf(): Layer doesn't have a parent\n");
298		return;
299	}
300	fParent->RemoveChild(this);
301}
302
303
304/*!
305	\return true if the child is owned by this Layer, false if not
306*/
307bool
308Layer::HasChild(Layer* layer)
309{
310	for (Layer* child = FirstChild(); child; child = child->NextLayer()) {
311		if (child == layer)
312			return true;
313	}
314	return false;
315}
316
317
318//! Returns the number of children
319uint32
320Layer::CountChildren() const
321{
322	uint32 count = 0;
323	Layer* child = FirstChild();
324	while (child != NULL) {
325		child = child->NextLayer();
326		count++;
327	}
328	return count;
329}
330
331
332/*!
333	\brief Returns the layer at the given point
334	\param pt The point to look the layer at
335	\return The layer containing the point or NULL if no layer found
336*/
337Layer*
338Layer::LayerAt(BPoint where)
339{
340	if (fVisible.Contains(where))
341		return this;
342
343	if (fFullVisible.Contains(where)) {
344		for (Layer* child = LastChild(); child; child = child->PreviousLayer()) {
345			if (Layer* layer = child->LayerAt(where))
346				return layer;
347		}
348	}
349
350	return NULL;
351}
352
353
354Layer*
355Layer::FirstChild() const
356{
357	return fFirstChild;
358}
359
360
361Layer*
362Layer::NextLayer() const
363{
364	return fNextSibling;
365}
366
367
368Layer*
369Layer::PreviousLayer() const
370{
371	return fPreviousSibling;
372}
373
374
375Layer*
376Layer::LastChild() const
377{
378	return fLastChild;
379}
380
381
382void
383Layer::SetName(const char* name)
384{
385	fName.SetTo(name);
386}
387
388
389void
390Layer::SetUserClipping(const BRegion& region)
391{
392	fDrawState->SetClippingRegion(region);
393
394	// rebuild clipping
395	_RebuildDrawingRegion();
396}
397
398
399void
400Layer::SetFlags(uint32 flags)
401{
402	fFlags = flags;
403	fDrawState->SetSubPixelPrecise(fFlags & B_SUBPIXEL_PRECISE);
404}
405
406
407void
408Layer::SetEventMask(uint32 eventMask, uint32 options)
409{
410	fEventMask = eventMask;
411	fEventOptions = options;
412}
413
414
415void
416Layer::Draw(const BRect &rect)
417{
418#ifdef DEBUG_LAYER
419	printf("Layer(%s)::Draw: ", Name());
420	rect.PrintToStream();
421#endif
422
423	if (!ViewColor().IsTransparentMagic())
424		fDriver->FillRect(rect, ViewColor());
425}
426
427/*!
428	\brief Shows the layer
429	\param invalidate Invalidate the region when showing the layer. defaults to true
430*/
431void
432Layer::Show(bool invalidate)
433{
434	STRACE(("Layer(%s)::Show()\n", Name()));
435	if(!IsHidden()) {
436		// an ancestor may be hidden. OK, we're not visible,
437		// but we're changing our visibility state
438		fHidden	= false;
439		return;
440	}
441
442	fHidden	= false;
443
444	if (invalidate) {
445		// compute the region this layer wants for itself
446		BRegion	invalid;
447		GetOnScreenRegion(invalid);
448		if (invalid.CountRects() > 0) {
449			fParent->MarkForRebuild(invalid);
450			GetRootLayer()->MarkForRedraw(invalid);
451
452			fParent->TriggerRebuild();
453			GetRootLayer()->TriggerRedraw();
454		}
455	}
456}
457
458/*!
459	\brief Shows the layer
460	\param invalidate Invalidate the region when hiding the layer. defaults to true
461*/
462void
463Layer::Hide(bool invalidate)
464{
465	STRACE(("Layer(%s)::Hide()\n", Name()));
466	if (IsHidden()) {
467		// an ancestor may be hidden. OK, we're not visible,
468		// but we're changing our visibility state
469		fHidden	= true;
470		return;
471	}
472
473	fHidden	= true;
474	if (invalidate && fFullVisible.CountRects() > 0) {
475		BRegion invalid(fFullVisible);
476
477		fParent->MarkForRebuild(invalid);
478		GetRootLayer()->MarkForRedraw(invalid);
479
480		fParent->TriggerRebuild();
481		GetRootLayer()->TriggerRedraw();
482	}
483}
484
485//! Returns true if the layer is hidden
486bool
487Layer::IsHidden(void) const
488{
489	if (fHidden)
490		return true;
491
492	if (fParent)
493			return fParent->IsHidden();
494
495	return fHidden;
496}
497
498
499void
500Layer::PushState()
501{
502	fDrawState = fDrawState->PushState();
503	fDrawState->SetSubPixelPrecise(fFlags & B_SUBPIXEL_PRECISE);
504}
505
506
507void
508Layer::PopState()
509{
510	if (fDrawState->PreviousState() == NULL) {
511		fprintf(stderr, "WARNING: User called BView(%s)::PopState(), but there is NO state on stack!\n", Name());
512		return;
513	}
514
515	bool rebuildClipping = fDrawState->ClippingRegion() != NULL;
516
517	fDrawState = fDrawState->PopState();
518	fDrawState->SetSubPixelPrecise(fFlags & B_SUBPIXEL_PRECISE);
519
520	// rebuild clipping
521	// (the clipping from the popped state is not effective anymore)
522	if (rebuildClipping)
523		_RebuildDrawingRegion();
524}
525
526
527//! Matches the BView call of the same name
528BRect
529Layer::Bounds() const
530{
531	BRect r(fFrame);
532	r.OffsetTo(ScrollingOffset());
533	return r;
534}
535
536
537//! Matches the BView call of the same name
538BRect
539Layer::Frame() const
540{
541	return fFrame;
542}
543
544
545//! Moves the layer by specified values, complete with redraw
546void
547Layer::MoveBy(float x, float y)
548{
549	STRACE(("Layer(%s)::MoveBy()\n", Name()));
550
551	if (x == 0.0f && y == 0.0f)
552		return;
553
554	// must lock, even if we change frame coordinates
555	if (fParent && !IsHidden() && GetRootLayer() && GetRootLayer()->Lock()) {
556		fFrame.OffsetBy(x, y);
557
558		BRegion oldFullVisible(fFullVisible);
559
560		// we'll invalidate the old position and the new, maxmial one.
561		BRegion invalid;
562		GetOnScreenRegion(invalid);
563		invalid.Include(&fFullVisible);
564
565		fParent->MarkForRebuild(invalid);
566		fParent->TriggerRebuild();
567
568		// done rebuilding regions, now copy common parts and redraw regions that became visible
569
570		// include the actual and the old fullVisible regions. later, we'll exclude the common parts.
571		BRegion	redrawReg(fFullVisible);
572		redrawReg.Include(&oldFullVisible);
573
574		// offset to layer's new location so that we can calculate the common region.
575		oldFullVisible.OffsetBy(x, y);
576
577		// finally we have the region that needs to be redrawn.
578		redrawReg.Exclude(&oldFullVisible);
579
580		// by intersecting the old fullVisible offseted to layer's new location, with the current
581		// fullVisible, we'll have the common region which can be copied using HW acceleration.
582		oldFullVisible.IntersectWith(&fFullVisible);
583
584		// offset back and instruct the HW to do the actual copying.
585		oldFullVisible.OffsetBy(-x, -y);
586		GetDrawingEngine()->CopyRegion(&oldFullVisible, x, y);
587
588		GetRootLayer()->MarkForRedraw(redrawReg);
589		GetRootLayer()->TriggerRedraw();
590
591		GetRootLayer()->Unlock();
592	}
593	else {
594		// just offset to the new position
595		fFrame.OffsetBy(x, y);
596	}
597
598	MovedByHook(x, y);
599
600	_SendViewCoordUpdateMsg();
601}
602
603
604//! Resize the layer by the specified amount, complete with redraw
605void
606Layer::ResizeBy(float x, float y)
607{
608	STRACE(("Layer(%s)::ResizeBy()\n", Name()));
609
610	if (x == 0.0f && y == 0.0f)
611		return;
612
613	// must lock, even if we change frame coordinates
614	if (fParent && !IsHidden() && GetRootLayer() && GetRootLayer()->Lock()) {
615		fFrame.Set(fFrame.left, fFrame.top, fFrame.right+x, fFrame.bottom+y);
616
617// TODO: you should call this hook function AFTER all region rebuilding
618//		 and redrawing stuff
619		ResizedByHook(x, y, false);
620
621// TODO: ResizedByHook(x,y,true) is called from inside _ResizeLayerFrameBy
622//		 Should call this AFTER region rebuilding and redrawing.
623		// resize children using their resize_mask.
624		for (Layer *child = LastChild(); child != NULL; child = child->PreviousLayer())
625			child->_ResizeLayerFrameBy(x, y);
626
627		BRegion oldFullVisible(fFullVisible);
628		// this is required to invalidate the old border
629		BRegion oldVisible(fVisible);
630
631		// in case they moved, bottom, right and center aligned layers must be redrawn
632		BRegion redrawMore;
633		_RezizeLayerRedrawMore(redrawMore, x, y);
634
635		// we'll invalidate the old area and the new, maxmial one.
636		BRegion invalid;
637		GetOnScreenRegion(invalid);
638		invalid.Include(&fFullVisible);
639
640		fParent->MarkForRebuild(invalid);
641		fParent->TriggerRebuild();
642
643		// done rebuilding regions, now redraw regions that became visible
644
645		// what's invalid, are the differences between to old and the new fullVisible region
646		// 1) in case we grow.
647		BRegion redrawReg(fFullVisible);
648		redrawReg.Exclude(&oldFullVisible);
649		// 2) in case we shrink
650		BRegion redrawReg2(oldFullVisible);
651		redrawReg2.Exclude(&fFullVisible);
652		// 3) combine.
653		redrawReg.Include(&redrawReg2);
654
655		// for center, right and bottom alligned layers, redraw their old positions
656		redrawReg.Include(&redrawMore);
657
658		// layers that had their frame modified must be entirely redrawn.
659		_RezizeLayerRedrawMore(redrawReg, x, y);
660
661		// include layer's visible region in case we want a full update on resize
662		if (fFlags & B_FULL_UPDATE_ON_RESIZE && fVisible.Frame().IsValid()) {
663			_ResizeLayerFullUpdateOnResize(redrawReg, x, y);
664
665			redrawReg.Include(&fVisible);
666			redrawReg.Include(&oldVisible);
667		}
668
669		GetRootLayer()->MarkForRedraw(redrawReg);
670		GetRootLayer()->TriggerRedraw();
671
672		GetRootLayer()->Unlock();
673	}
674	// just resize our frame and those of out descendants if their resize mask says so
675	else {
676		fFrame.Set(fFrame.left, fFrame.top, fFrame.right+x, fFrame.bottom+y);
677
678// TODO: you should call this hook function AFTER all region rebuilding
679//		 and redrawing stuff
680		ResizedByHook(x, y, false);
681
682// TODO: ResizedByHook(x,y,true) is called from inside _ResizeLayerFrameBy
683//		 Should call this AFTER region rebuilding and redrawing.
684		// resize children using their resize_mask.
685		for (Layer *child = LastChild(); child != NULL; child = child->PreviousLayer())
686			child->_ResizeLayerFrameBy(x, y);
687	}
688
689	_SendViewCoordUpdateMsg();
690}
691
692
693//! scrolls the layer by the specified amount, complete with redraw
694void
695Layer::ScrollBy(float x, float y)
696{
697	STRACE(("Layer(%s)::ScrollBy()\n", Name()));
698
699	if (x == 0.0f && y == 0.0f)
700		return;
701
702	fScrollingOffset.x += x;
703	fScrollingOffset.y += y;
704
705	// must lock, even if we change frame/origin coordinates
706	if (!IsHidden() && GetRootLayer() && GetRootLayer()->Lock()) {
707
708		// set the region to be invalidated.
709		BRegion invalid(fFullVisible);
710
711		MarkForRebuild(invalid);
712
713		TriggerRebuild();
714
715		// for the moment we say that the whole surface needs to be redraw.
716		BRegion redrawReg(fFullVisible);
717
718		// offset old region so that we can start comparing.
719		invalid.OffsetBy(x, y);
720
721		// compute the common region. we'll use HW acc to copy this to the new location.
722		invalid.IntersectWith(&fFullVisible);
723		GetDrawingEngine()->CopyRegion(&invalid, -x, -y);
724
725		// common region goes back to its original location. then, by excluding
726		// it from curent fullVisible we'll obtain the region that needs to be redrawn.
727		invalid.OffsetBy(-x, -y);
728// TODO: a quick fix for the scrolling problem!!! FIX THIS!
729//		redrawReg.Exclude(&invalid);
730
731		GetRootLayer()->MarkForRedraw(redrawReg);
732		GetRootLayer()->TriggerRedraw();
733
734		GetRootLayer()->Unlock();
735	}
736
737	ScrolledByHook(x, y);
738
739// TODO: I think we should update the client-side that bounds rect has modified
740//	SendViewCoordUpdateMsg();
741}
742
743void
744Layer::CopyBits(BRect& src, BRect& dst, int32 xOffset, int32 yOffset)
745{
746	// NOTE: The correct behaviour is this:
747	// * The region that is copied is the
748	//   src rectangle, no matter if it fits
749	//   into the dst rectangle. It is copied
750	//   by the offset dst.LeftTop() - src.LeftTop()
751	// * The dst rectangle is used for invalidation:
752	//   Any area in the dst rectangle that could
753	//   not be copied from src (because either the
754	//   src rectangle was not big enough, or because there
755	//   were parts cut off by the current layer clipping),
756	//   are triggering BView::Draw() to be called
757	//   and for these parts only.
758
759	if (!GetRootLayer())
760		return;
761
762	if (!IsHidden() && GetRootLayer()->Lock()) {
763		// the region that is going to be copied
764		BRegion copyRegion(src);
765
766		// apply the current clipping of the layer
767		copyRegion.IntersectWith(&fVisible);
768
769		// offset the region to the destination
770		// and apply the current clipping there as well
771		copyRegion.OffsetBy(xOffset, yOffset);
772		copyRegion.IntersectWith(&fVisible);
773
774		// the region at the destination that needs invalidation
775		BRegion redrawReg(dst);
776		// exclude the region drawn by the copy operation
777// TODO: quick fix for our scrolling problem. FIX THIS!
778//		redrawReg.Exclude(&copyRegion);
779		// apply the current clipping as well
780		redrawReg.IntersectWith(&fVisible);
781
782		// move the region back for the actual operation
783		copyRegion.OffsetBy(-xOffset, -yOffset);
784
785		GetDrawingEngine()->CopyRegion(&copyRegion, xOffset, yOffset);
786
787		// trigger the redraw
788		GetRootLayer()->MarkForRedraw(redrawReg);
789		GetRootLayer()->TriggerRedraw();
790
791		GetRootLayer()->Unlock();
792	}
793}
794
795
796void
797Layer::MouseDown(BMessage *msg, BPoint where)
798{
799}
800
801
802void
803Layer::MouseUp(BMessage *msg, BPoint where)
804{
805}
806
807
808void
809Layer::MouseMoved(BMessage *msg, BPoint where)
810{
811}
812
813
814void
815Layer::MouseWheelChanged(BMessage *msg, BPoint where)
816{
817}
818
819
820void
821Layer::WorkspaceActivated(int32 index, bool active)
822{
823}
824
825
826void
827Layer::WorkspacesChanged(uint32 oldWorkspaces, uint32 newWorkspaces)
828{
829}
830
831
832void
833Layer::Activated(bool active)
834{
835}
836
837
838BPoint
839Layer::ScrollingOffset() const
840{
841	return fScrollingOffset;
842}
843
844
845void
846Layer::SetDrawingOrigin(BPoint origin)
847{
848	fDrawState->SetOrigin(origin);
849
850	// rebuild clipping
851	if (fDrawState->ClippingRegion())
852		_RebuildDrawingRegion();
853}
854
855
856BPoint
857Layer::DrawingOrigin() const
858{
859	BPoint origin(fDrawState->Origin());
860	float scale = Scale();
861
862	origin.x *= scale;
863	origin.y *= scale;
864
865	return origin;
866}
867
868
869void
870Layer::SetScale(float scale)
871{
872	fDrawState->SetScale(scale);
873
874	// rebuild clipping
875	if (fDrawState->ClippingRegion())
876		_RebuildDrawingRegion();
877}
878
879
880float
881Layer::Scale() const
882{
883	return CurrentState()->Scale();
884}
885
886void
887Layer::SetViewColor(const RGBColor& color)
888{
889	fViewColor = color;
890}
891
892
893void
894Layer::SetBackgroundBitmap(const ServerBitmap* bitmap)
895{
896	// TODO: What about reference counting?
897	// "Release" old fBackgroundBitmap and "Aquire" new one?
898	fBackgroundBitmap = bitmap;
899}
900
901// SetOverlayBitmap
902void
903Layer::SetOverlayBitmap(const ServerBitmap* bitmap)
904{
905	// TODO: What about reference counting?
906	// "Release" old fOverlayBitmap and "Aquire" new one?
907	fOverlayBitmap = bitmap;
908}
909
910void
911Layer::MovedByHook(float dx, float dy)
912{
913	if (Window() && !IsTopLayer())
914		_AddToViewsWithInvalidCoords();
915}
916
917void
918Layer::ResizedByHook(float dx, float dy, bool automatic)
919{
920	if (Window() && !IsTopLayer())
921		_AddToViewsWithInvalidCoords();
922}
923
924void
925Layer::ScrolledByHook(float dx, float dy)
926{
927	// empty.
928}
929
930//! converts a point from local to parent's coordinate system
931void
932Layer::ConvertToParent(BPoint* pt) const
933{
934	if (fParent) {
935		BPoint origin = ScrollingOffset();
936		pt->x -= origin.x;
937		pt->y -= origin.y;
938		pt->x += fFrame.left;
939		pt->y += fFrame.top;
940	}
941}
942
943//! converts a rect from local to parent's coordinate system
944void
945Layer::ConvertToParent(BRect* rect) const
946{
947	if (fParent) {
948		BPoint origin = ScrollingOffset();
949		rect->OffsetBy(-origin.x, -origin.y);
950		rect->OffsetBy(fFrame.left, fFrame.top);
951	}
952}
953
954//! converts a region from local to parent's coordinate system
955void
956Layer::ConvertToParent(BRegion* reg) const
957{
958	if (fParent) {
959		BPoint origin = ScrollingOffset();
960		reg->OffsetBy(-origin.x, -origin.y);
961		reg->OffsetBy(fFrame.left, fFrame.top);
962	}
963}
964
965//! converts a point from parent's to local coordinate system
966void
967Layer::ConvertFromParent(BPoint* pt) const
968{
969	if (fParent) {
970		BPoint origin = ScrollingOffset();
971		pt->x += origin.x;
972		pt->y += origin.y;
973		pt->x -= fFrame.left;
974		pt->y -= fFrame.top;
975	}
976}
977
978//! converts a rect from parent's to local coordinate system
979void
980Layer::ConvertFromParent(BRect* rect) const
981{
982	if (fParent) {
983		BPoint origin = ScrollingOffset();
984		rect->OffsetBy(origin.x, origin.y);
985		rect->OffsetBy(-fFrame.left, -fFrame.top);
986	}
987}
988
989//! converts a region from parent's to local coordinate system
990void
991Layer::ConvertFromParent(BRegion* reg) const
992{
993	if (fParent) {
994		BPoint origin = ScrollingOffset();
995		reg->OffsetBy(origin.x, origin.y);
996		reg->OffsetBy(-fFrame.left, -fFrame.top);
997	}
998}
999
1000//! converts a point from local to screen coordinate system
1001void
1002Layer::ConvertToScreen(BPoint* pt) const
1003{
1004	if (fParent) {
1005		ConvertToParent(pt);
1006		fParent->ConvertToScreen(pt);
1007	}
1008}
1009
1010//! converts a rect from local to screen coordinate system
1011void
1012Layer::ConvertToScreen(BRect* rect) const
1013{
1014	if (fParent) {
1015		ConvertToParent(rect);
1016		fParent->ConvertToScreen(rect);
1017	}
1018}
1019
1020//! converts a region from local to screen coordinate system
1021void
1022Layer::ConvertToScreen(BRegion* reg) const
1023{
1024	if (fParent) {
1025		ConvertToParent(reg);
1026		fParent->ConvertToScreen(reg);
1027	}
1028}
1029
1030//! converts a point from screen to local coordinate system
1031void
1032Layer::ConvertFromScreen(BPoint* pt) const
1033{
1034	if (fParent) {
1035		ConvertFromParent(pt);
1036		fParent->ConvertFromScreen(pt);
1037	}
1038}
1039
1040//! converts a rect from screen to local coordinate system
1041void
1042Layer::ConvertFromScreen(BRect* rect) const
1043{
1044	if (fParent) {
1045		ConvertFromParent(rect);
1046		fParent->ConvertFromScreen(rect);
1047	}
1048}
1049
1050//! converts a region from screen to local coordinate system
1051void
1052Layer::ConvertFromScreen(BRegion* reg) const
1053{
1054	if (fParent) {
1055		ConvertFromParent(reg);
1056		fParent->ConvertFromScreen(reg);
1057	}
1058}
1059
1060//! converts a point from local *drawing* to screen coordinate system
1061void
1062Layer::ConvertToScreenForDrawing(BPoint* pt) const
1063{
1064	if (fParent) {
1065		fDrawState->Transform(pt);
1066		// NOTE: from here on, don't use the
1067		// "*ForDrawing()" versions of the parent!
1068		ConvertToParent(pt);
1069		fParent->ConvertToScreen(pt);
1070	}
1071}
1072
1073//! converts a rect from local *drawing* to screen coordinate system
1074void
1075Layer::ConvertToScreenForDrawing(BRect* rect) const
1076{
1077	if (fParent) {
1078		fDrawState->Transform(rect);
1079		// NOTE: from here on, don't use the
1080		// "*ForDrawing()" versions of the parent!
1081		ConvertToParent(rect);
1082		fParent->ConvertToScreen(rect);
1083	}
1084}
1085
1086//! converts a region from local *drawing* to screen coordinate system
1087void
1088Layer::ConvertToScreenForDrawing(BRegion* region) const
1089{
1090	if (fParent) {
1091		fDrawState->Transform(region);
1092		// NOTE: from here on, don't use the
1093		// "*ForDrawing()" versions of the parent!
1094		ConvertToParent(region);
1095		fParent->ConvertToScreen(region);
1096	}
1097}
1098
1099//! converts a point from screen to local coordinate system
1100void
1101Layer::ConvertFromScreenForDrawing(BPoint* pt) const
1102{
1103	if (fParent) {
1104		ConvertFromParent(pt);
1105		fParent->ConvertFromScreen(pt);
1106
1107		fDrawState->InverseTransform(pt);
1108	}
1109}
1110
1111void
1112Layer::_ResizeLayerFrameBy(float x, float y)
1113{
1114	uint16 rm = fResizeMode & 0x0000FFFF;
1115	BRect newFrame = fFrame;
1116
1117	if ((rm & 0x0F00U) == _VIEW_LEFT_ << 8)
1118		newFrame.left += 0.0f;
1119	else if ((rm & 0x0F00U) == _VIEW_RIGHT_ << 8)
1120		newFrame.left += x;
1121	else if ((rm & 0x0F00U) == _VIEW_CENTER_ << 8)
1122		newFrame.left += x/2;
1123
1124	if ((rm & 0x000FU) == _VIEW_LEFT_)
1125		newFrame.right += 0.0f;
1126	else if ((rm & 0x000FU) == _VIEW_RIGHT_)
1127		newFrame.right += x;
1128	else if ((rm & 0x000FU) == _VIEW_CENTER_)
1129		newFrame.right += x/2;
1130
1131	if ((rm & 0xF000U) == _VIEW_TOP_ << 12)
1132		newFrame.top += 0.0f;
1133	else if ((rm & 0xF000U) == _VIEW_BOTTOM_ << 12)
1134		newFrame.top += y;
1135	else if ((rm & 0xF000U) == _VIEW_CENTER_ << 12)
1136		newFrame.top += y/2;
1137
1138	if ((rm & 0x00F0U) == _VIEW_TOP_ << 4)
1139		newFrame.bottom += 0.0f;
1140	else if ((rm & 0x00F0U) == _VIEW_BOTTOM_ << 4)
1141		newFrame.bottom += y;
1142	else if ((rm & 0x00F0U) == _VIEW_CENTER_ << 4)
1143		newFrame.bottom += y/2;
1144
1145	if (newFrame != fFrame) {
1146		float offsetX, offsetY;
1147		float dx, dy;
1148
1149		dx = newFrame.Width() - fFrame.Width();
1150		dy = newFrame.Height() - fFrame.Height();
1151		offsetX = newFrame.left - fFrame.left;
1152		offsetY = newFrame.top - fFrame.top;
1153
1154		fFrame = newFrame;
1155
1156		if (offsetX != 0.0f || offsetY != 0.0f) {
1157			MovedByHook(offsetX, offsetY);
1158		}
1159
1160		if (dx != 0.0f || dy != 0.0f) {
1161			// call hook function
1162			ResizedByHook(dx, dy, true); // automatic
1163
1164			for (Layer* child = LastChild(); child; child = child->PreviousLayer())
1165				child->_ResizeLayerFrameBy(dx, dy);
1166		}
1167	}
1168}
1169
1170
1171void
1172Layer::_RezizeLayerRedrawMore(BRegion &reg, float dx, float dy)
1173{
1174	if (dx == 0 && dy == 0)
1175		return;
1176
1177	for (Layer* child = LastChild(); child; child = child->PreviousLayer()) {
1178		uint16 rm = child->fResizeMode & 0x0000FFFF;
1179
1180		if ((rm & 0x0F0F) == (uint16)B_FOLLOW_LEFT_RIGHT || (rm & 0xF0F0) == (uint16)B_FOLLOW_TOP_BOTTOM) {
1181			// NOTE: this is not exactly corect, but it works :-)
1182			// Normaly we shoud've used the child's old, required region - the one returned
1183			// from get_user_region() with the old frame, and the current one. child->Bounds()
1184			// works for the moment so we leave it like this.
1185
1186			// calculate the old bounds.
1187			BRect	oldBounds(child->Bounds());
1188			if ((rm & 0x0F0F) == (uint16)B_FOLLOW_LEFT_RIGHT)
1189				oldBounds.right -=dx;
1190			if ((rm & 0xF0F0) == (uint16)B_FOLLOW_TOP_BOTTOM)
1191				oldBounds.bottom -=dy;
1192
1193			// compute the region that became visible because we got bigger OR smaller.
1194			BRegion	regZ(child->Bounds());
1195			regZ.Include(oldBounds);
1196			regZ.Exclude(oldBounds & child->Bounds());
1197
1198			child->ConvertToScreen(&regZ);
1199
1200			// intersect that with this'(not child's) fullVisible region
1201			regZ.IntersectWith(&fFullVisible);
1202			reg.Include(&regZ);
1203
1204			child->_RezizeLayerRedrawMore(reg,
1205				(rm & 0x0F0F) == (uint16)B_FOLLOW_LEFT_RIGHT? dx: 0,
1206				(rm & 0xF0F0) == (uint16)B_FOLLOW_TOP_BOTTOM? dy: 0);
1207
1208			// above, OR this:
1209			// reg.Include(&child->fFullVisible);
1210		} else if (((rm & 0x0F0F) == (uint16)B_FOLLOW_RIGHT && dx != 0)
1211			|| ((rm & 0x0F0F) == (uint16)B_FOLLOW_H_CENTER && dx != 0)
1212			|| ((rm & 0xF0F0) == (uint16)B_FOLLOW_BOTTOM && dy != 0)
1213			|| ((rm & 0xF0F0) == (uint16)B_FOLLOW_V_CENTER && dy != 0)) {
1214			reg.Include(&child->fFullVisible);
1215		}
1216	}
1217}
1218
1219
1220void
1221Layer::_ResizeLayerFullUpdateOnResize(BRegion &reg, float dx, float dy)
1222{
1223	if (dx == 0 && dy == 0)
1224		return;
1225
1226	for (Layer* child = LastChild(); child; child = child->PreviousLayer()) {
1227		uint16 rm = child->fResizeMode & 0x0000FFFF;
1228
1229		if ((rm & 0x0F0F) == (uint16)B_FOLLOW_LEFT_RIGHT || (rm & 0xF0F0) == (uint16)B_FOLLOW_TOP_BOTTOM) {
1230			if (child->fFlags & B_FULL_UPDATE_ON_RESIZE && child->fVisible.CountRects() > 0)
1231				reg.Include(&child->fVisible);
1232
1233			child->_ResizeLayerFullUpdateOnResize(reg,
1234				(rm & 0x0F0F) == (uint16)B_FOLLOW_LEFT_RIGHT? dx: 0,
1235				(rm & 0xF0F0) == (uint16)B_FOLLOW_TOP_BOTTOM? dy: 0);
1236		}
1237	}
1238}
1239
1240
1241/*!
1242	\brief Returns the region of the layer that is within the screen region
1243*/
1244void
1245Layer::GetOnScreenRegion(BRegion &region)
1246{
1247	// 1) set to frame in screen coords
1248	BRect frame(Bounds());
1249	ConvertToScreen(&frame);
1250	region.Set(frame);
1251
1252	// 2) intersect with screen region
1253	BRegion screenRegion(GetRootLayer()->Bounds());
1254	region.IntersectWith(&screenRegion);
1255
1256/*
1257	// 3) impose user constrained regions
1258	DrawState *stackData = fDrawState;
1259	while (stackData) {
1260		if (stackData->ClippingRegion()) {
1261			reg.IntersectWith(stackData->ClippingRegion());
1262		}
1263		stackData = stackData->PreviousState();
1264	}*/
1265}
1266
1267
1268void
1269Layer::_RebuildVisibleRegions(const BRegion &invalid,
1270	const BRegion &parentLocalVisible, const Layer *startFrom)
1271{
1272/*
1273	// no point in continuing if this layer is hidden.
1274	if (fHidden)
1275		return;
1276
1277	// no need to go deeper if the parent doesn't have a visible region anymore
1278	// and our fullVisible region is also empty.
1279	if (!parentLocalVisible.Frame().IsValid() && !(fFullVisible.CountRects() > 0))
1280		return;
1281
1282	bool fullRebuild = false;
1283
1284	// intersect maximum wanted region with the invalid region
1285	BRegion common;
1286	GetOnScreenRegion(common);
1287	common.IntersectWith(&invalid);
1288
1289	// if the resulted region is not valid, this layer is not in the catchment area
1290	// of the region being invalidated
1291	if (!common.CountRects() > 0)
1292		return;
1293
1294	// now intersect with parent's visible part of the region that was/is invalidated
1295	common.IntersectWith(&parentLocalVisible);
1296
1297	// exclude the invalid region
1298	fFullVisible.Exclude(&invalid);
1299	fVisible.Exclude(&invalid);
1300
1301	// put in what's really visible
1302	fFullVisible.Include(&common);
1303
1304	// allow this layer to hide some parts from its children
1305	_ReserveRegions(common);
1306
1307	for (Layer *child = LastChild(); child; child = child->PreviousLayer()) {
1308		if (child == startFrom)
1309			fullRebuild = true;
1310
1311		if (fullRebuild)
1312			child->_RebuildVisibleRegions(invalid, common, child->LastChild());
1313
1314		// to let children know much they can take from parent's visible region
1315		common.Exclude(&child->fFullVisible);
1316	}
1317
1318	// include what's left after all children took what they could.
1319	fVisible.Include(&common);
1320*/
1321
1322// NOTE: I modified this method for the moment because of some issues that I have
1323//		 with the new public methods that I recently introduced.
1324//		 This code works very well, the single problem that it has it's that it
1325//		 rebuilds all the visible regions of its descendants.
1326// TODO: only rebuild what's needed. See above code.
1327// NOTE2: this does not affect the redrawing code.
1328
1329	// no point in continuing if this layer is hidden.
1330	if (fHidden)
1331		return;
1332
1333	// no need to go deeper if the parent doesn't have a visible region anymore
1334	if (!parentLocalVisible.Frame().IsValid())
1335		return;
1336
1337	BRegion common;
1338	GetOnScreenRegion(common);
1339
1340	// see how much you can take
1341	common.IntersectWith(&parentLocalVisible);
1342	fFullVisible = common;
1343	fVisible.MakeEmpty();
1344
1345	// allow this layer to hide some parts from its children
1346	_ReserveRegions(common);
1347
1348	for (Layer *child = LastChild(); child; child = child->PreviousLayer()) {
1349		child->_RebuildVisibleRegions(invalid, common, child->LastChild());
1350
1351		// to let children know much they can take from parent's visible region
1352		common.Exclude(&child->fFullVisible);
1353	}
1354
1355	// include what's left after all children took what they could.
1356	fVisible.Include(&common);
1357
1358	_RebuildDrawingRegion();
1359}
1360
1361
1362void
1363Layer::_RebuildDrawingRegion()
1364{
1365	fDrawingRegion = fVisible;
1366	// apply user clipping which is in native coordinate system
1367	if (const BRegion* userClipping = fDrawState->ClippingRegion()) {
1368		BRegion screenUserClipping(*userClipping);
1369		ConvertToScreenForDrawing(&screenUserClipping);
1370		fDrawingRegion.IntersectWith(&screenUserClipping);
1371	}
1372}
1373
1374
1375void
1376Layer::_ReserveRegions(BRegion &reg)
1377{
1378	// Empty for Layer objects
1379}
1380
1381
1382void
1383Layer::_ClearVisibleRegions()
1384{
1385	fDrawingRegion.MakeEmpty();
1386
1387	fVisible.MakeEmpty();
1388	fFullVisible.MakeEmpty();
1389	for (Layer *child = LastChild(); child; child = child->PreviousLayer())
1390		child->_ClearVisibleRegions();
1391}
1392
1393
1394/*!	Mark a region dirty so that the next region rebuild for us
1395	and our children will take this into account
1396*/
1397void
1398Layer::MarkForRebuild(const BRegion &dirty)
1399{
1400	fDirtyForRebuild.Include(&dirty);
1401}
1402
1403
1404/*!	This will trigger visible region recalculation for us and
1405	our descendants.
1406*/
1407void
1408Layer::TriggerRebuild()
1409{
1410	BRegion totalInvalidReg;
1411
1412	_GetAllRebuildDirty(&totalInvalidReg);
1413
1414	if (totalInvalidReg.CountRects() > 0) {
1415		BRegion localFullVisible(fFullVisible);
1416
1417//		localFullVisible.IntersectWith(&totalInvalidReg);
1418
1419		_ClearVisibleRegions();
1420
1421		_RebuildVisibleRegions(totalInvalidReg, localFullVisible, LastChild());
1422	}
1423}
1424
1425
1426//! find out the region for which we must rebuild the visible regions
1427void
1428Layer::_GetAllRebuildDirty(BRegion *totalReg)
1429{
1430	totalReg->Include(&fDirtyForRebuild);
1431
1432	for (Layer *child = LastChild(); child; child = child->PreviousLayer())
1433		child->_GetAllRebuildDirty(totalReg);
1434
1435	fDirtyForRebuild.MakeEmpty();
1436}
1437
1438
1439void
1440Layer::_AllRedraw(const BRegion &invalid)
1441{
1442	// couldn't find a simpler way to send _UPDATE_ message to client.
1443	WinBorder *wb = dynamic_cast<WinBorder*>(this);
1444	if (wb)
1445		wb->RequestClientRedraw(invalid);
1446
1447	if (fVisible.CountRects() > 0) {
1448		BRegion	updateReg(fVisible);
1449		updateReg.IntersectWith(&invalid);
1450
1451		if (updateReg.CountRects() > 0) {
1452			fDriver->ConstrainClippingRegion(&updateReg);
1453			Draw(updateReg.Frame());
1454			fDriver->ConstrainClippingRegion(NULL);
1455		}
1456	}
1457
1458	for (Layer *child = LastChild(); child != NULL; child = child->PreviousLayer()) {
1459		if (!child->IsHidden()) {
1460			BRegion common(child->fFullVisible);
1461			common.IntersectWith(&invalid);
1462
1463			if (common.CountRects() > 0)
1464				child->_AllRedraw(invalid);
1465		}
1466	}
1467}
1468
1469
1470void
1471Layer::_AddToViewsWithInvalidCoords() const
1472{
1473	if (fWindow) {
1474		fWindow->ClientViewsWithInvalidCoords().AddInt32("_token", fViewToken);
1475		fWindow->ClientViewsWithInvalidCoords().AddPoint("where", fFrame.LeftTop());
1476		fWindow->ClientViewsWithInvalidCoords().AddFloat("width", fFrame.Width());
1477		fWindow->ClientViewsWithInvalidCoords().AddFloat("height", fFrame.Height());
1478	}
1479}
1480
1481
1482void
1483Layer::_SendViewCoordUpdateMsg() const
1484{
1485	if (fWindow && !fWindow->ClientViewsWithInvalidCoords().IsEmpty()) {
1486		fWindow->SendMessageToClient(&fWindow->ClientViewsWithInvalidCoords());
1487		fWindow->ClientViewsWithInvalidCoords().MakeEmpty();
1488	}
1489}
1490