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