grab from latest android



git-svn-id: http://skia.googlecode.com/svn/trunk@27 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/views/SkStackViewLayout.cpp b/src/views/SkStackViewLayout.cpp
new file mode 100644
index 0000000..ae2e9e8
--- /dev/null
+++ b/src/views/SkStackViewLayout.cpp
@@ -0,0 +1,262 @@
+#include "SkStackViewLayout.h"
+
+SkStackViewLayout::SkStackViewLayout()
+{
+	fMargin.set(0, 0, 0, 0);
+	fSpacer	= 0;
+	fOrient	= kHorizontal_Orient;
+	fPack	= kStart_Pack;
+	fAlign	= kStart_Align;
+	fRound	= false;
+}
+
+void SkStackViewLayout::setOrient(Orient ori)
+{
+	SkASSERT((unsigned)ori < kOrientCount);
+	fOrient = SkToU8(ori);
+}
+
+void SkStackViewLayout::getMargin(SkRect* margin) const
+{
+	if (margin)
+		*margin = fMargin;
+}
+
+void SkStackViewLayout::setMargin(const SkRect& margin)
+{
+	fMargin = margin;
+}
+
+void SkStackViewLayout::setSpacer(SkScalar spacer)
+{
+	fSpacer = spacer;
+}
+
+void SkStackViewLayout::setPack(Pack pack)
+{
+	SkASSERT((unsigned)pack < kPackCount);
+	fPack = SkToU8(pack);
+}
+
+void SkStackViewLayout::setAlign(Align align)
+{
+	SkASSERT((unsigned)align < kAlignCount);
+	fAlign = SkToU8(align);
+}
+
+void SkStackViewLayout::setRound(bool r)
+{
+	fRound = SkToU8(r);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+typedef SkScalar (*AlignProc)(SkScalar childLimit, SkScalar parentLimit);
+typedef SkScalar (SkView::*GetSizeProc)() const;
+typedef void (SkView::*SetLocProc)(SkScalar coord);
+typedef void (SkView::*SetSizeProc)(SkScalar coord);
+
+static SkScalar left_align_proc(SkScalar childLimit, SkScalar parentLimit) { return 0; }
+static SkScalar center_align_proc(SkScalar childLimit, SkScalar parentLimit) { return SkScalarHalf(parentLimit - childLimit); }
+static SkScalar right_align_proc(SkScalar childLimit, SkScalar parentLimit) { return parentLimit - childLimit; }
+static SkScalar fill_align_proc(SkScalar childLimit, SkScalar parentLimit) { return 0; }
+
+/*	Measure the main-dimension for all the children. If a child is marked flex in that direction
+	ignore its current value but increment the counter for flexChildren
+*/
+static SkScalar compute_children_limit(SkView* parent, GetSizeProc sizeProc, int* count,
+									   uint32_t flexMask, int* flexCount)
+{
+	SkView::B2FIter	iter(parent);
+	SkView*			child;
+	SkScalar		limit = 0;
+	int				n = 0, flex = 0;
+
+	while ((child = iter.next()) != NULL)
+	{
+		n += 1;
+		if (child->getFlags() & flexMask)
+			flex += 1;
+		else
+			limit += (child->*sizeProc)();
+	}
+	if (count)
+		*count = n;
+	if (flexCount)
+		*flexCount = flex;
+	return limit;
+}
+
+void SkStackViewLayout::onLayoutChildren(SkView* parent)
+{
+	static AlignProc gAlignProcs[] = {
+		left_align_proc,
+		center_align_proc,
+		right_align_proc,
+		fill_align_proc
+	};
+
+	SkScalar			startM, endM, crossStartM, crossLimit;
+	GetSizeProc			mainGetSizeP, crossGetSizeP;
+	SetLocProc			mainLocP, crossLocP;
+	SetSizeProc			mainSetSizeP, crossSetSizeP;
+	SkView::Flag_Mask	flexMask;
+
+	if (fOrient == kHorizontal_Orient)
+	{
+		startM		= fMargin.fLeft;
+		endM		= fMargin.fRight;
+		crossStartM	= fMargin.fTop;
+		crossLimit	= -fMargin.fTop - fMargin.fBottom;
+
+		mainGetSizeP	= &SkView::width;
+		crossGetSizeP	= &SkView::height;
+		mainLocP	= &SkView::setLocX;
+		crossLocP	= &SkView::setLocY;
+
+		mainSetSizeP  = &SkView::setWidth;
+		crossSetSizeP = &SkView::setHeight;
+
+		flexMask	= SkView::kFlexH_Mask;
+	}
+	else
+	{
+		startM		= fMargin.fTop;
+		endM		= fMargin.fBottom;
+		crossStartM	= fMargin.fLeft;
+		crossLimit	= -fMargin.fLeft - fMargin.fRight;
+
+		mainGetSizeP	= &SkView::height;
+		crossGetSizeP	= &SkView::width;
+		mainLocP	= &SkView::setLocY;
+		crossLocP	= &SkView::setLocX;
+
+		mainSetSizeP  = &SkView::setHeight;
+		crossSetSizeP = &SkView::setWidth;
+
+		flexMask	= SkView::kFlexV_Mask;
+	}
+	crossLimit += (parent->*crossGetSizeP)();
+	if (fAlign != kStretch_Align)
+		crossSetSizeP = NULL;
+
+	int			childCount, flexCount;
+	SkScalar	childLimit = compute_children_limit(parent, mainGetSizeP, &childCount, flexMask, &flexCount);
+
+	if (childCount == 0)
+		return;
+
+	childLimit += (childCount - 1) * fSpacer;
+
+	SkScalar		parentLimit = (parent->*mainGetSizeP)() - startM - endM;
+	SkScalar		pos = startM + gAlignProcs[fPack](childLimit, parentLimit);
+	SkScalar		flexAmount = 0;
+	SkView::B2FIter	iter(parent);
+	SkView*			child;
+
+	if (flexCount > 0 && parentLimit > childLimit)
+		flexAmount = (parentLimit - childLimit) / flexCount;
+
+	while ((child = iter.next()) != NULL)
+	{
+		if (fRound)
+			pos = SkIntToScalar(SkScalarRound(pos));
+		(child->*mainLocP)(pos);
+		SkScalar crossLoc = crossStartM + gAlignProcs[fAlign]((child->*crossGetSizeP)(), crossLimit);
+		if (fRound)
+			crossLoc = SkIntToScalar(SkScalarRound(crossLoc));
+		(child->*crossLocP)(crossLoc);
+
+		if (crossSetSizeP)
+			(child->*crossSetSizeP)(crossLimit);
+		if (child->getFlags() & flexMask)
+			(child->*mainSetSizeP)(flexAmount);
+		pos += (child->*mainGetSizeP)() + fSpacer;
+	}
+}
+
+//////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef SK_DEBUG
+	static void assert_no_attr(const SkDOM& dom, const SkDOM::Node* node, const char attr[])
+	{
+		const char* value = dom.findAttr(node, attr);
+		if (value)
+			SkDebugf("unknown attribute %s=\"%s\"\n", attr, value);
+	}
+#else
+	#define assert_no_attr(dom, node, attr)
+#endif
+
+void SkStackViewLayout::onInflate(const SkDOM& dom, const SkDOM::Node* node)
+{
+	int			index;
+	SkScalar	value[4];
+
+	if ((index = dom.findList(node, "orient", "horizontal,vertical")) >= 0)
+		this->setOrient((Orient)index);
+	else
+		assert_no_attr(dom, node, "orient");
+
+	if (dom.findScalars(node, "margin", value, 4))
+	{
+		SkRect	margin;
+		margin.set(value[0], value[1], value[2], value[3]);
+		this->setMargin(margin);
+	}
+	else
+		assert_no_attr(dom, node, "margin");
+
+	if (dom.findScalar(node, "spacer", value))
+		this->setSpacer(value[0]);
+	else
+		assert_no_attr(dom, node, "spacer");
+
+	if ((index = dom.findList(node, "pack", "start,center,end")) >= 0)
+		this->setPack((Pack)index);
+	else
+		assert_no_attr(dom, node, "pack");
+
+	if ((index = dom.findList(node, "align", "start,center,end,stretch")) >= 0)
+		this->setAlign((Align)index);
+	else
+		assert_no_attr(dom, node, "align");
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+SkFillViewLayout::SkFillViewLayout()
+{
+	fMargin.setEmpty();
+}
+
+void SkFillViewLayout::getMargin(SkRect* r) const
+{
+	if (r)
+		*r = fMargin;
+}
+
+void SkFillViewLayout::setMargin(const SkRect& margin)
+{
+	fMargin = margin;
+}
+
+void SkFillViewLayout::onLayoutChildren(SkView* parent)
+{
+	SkView::B2FIter	iter(parent);
+	SkView*			child;
+
+	while ((child = iter.next()) != NULL)
+	{
+		child->setLoc(fMargin.fLeft, fMargin.fTop);
+		child->setSize(	parent->width() - fMargin.fRight - fMargin.fLeft,
+						parent->height() - fMargin.fBottom - fMargin.fTop);
+	}
+}
+
+void SkFillViewLayout::onInflate(const SkDOM& dom, const SkDOM::Node* node)
+{
+	this->INHERITED::onInflate(dom, node);
+	(void)dom.findScalars(node, "margin", (SkScalar*)&fMargin, 4);
+}
+